2009/10/26 Stefano Crocco <stefano.crocco / alice.it>:
> On Monday 26 October 2009, Derek Smith wrote:
>> |Hi All,
>> |
>> |I want to test if a file open failed, yet I cannot get this to work.
>> |
>> |attempt 1:
>> |File.open( "#{RUNLOG}", "a" ) do |file| or raise StandardError ...
>> |
>> |
>> |attempt 2
>> |File.open( "#{RUNLOG}", "a" ) do |file|
>> |  ¨Âïäèåòå®®>> |
>> |
>> |or raise StabdardError ...
>> |end
>> |
>> |
>> |thank you!
>> |
>
> File.open will raise an exception if the file can't be opened. The exact
> exception will depend on what actually goes wrong and will be one of the
> classes under the Errno module. Unfortunately, I don't know exactly which
> class corresponds to which error (if I remember correctly, they may also
> depend on your system). If you want to rescue all those exceptions, you can
> use SystemCallError, which is the base class for all of them. For example, you
> can do the following:
>
> begin
>  ¨Âéìå®ïðå£ûÒÕÎÌÏÇý¢¢á¢© äï üæéìåü
> ..
>  ¨Âîä
> rescue SystemCallError
>  ¨Âáéóå ÓôáîäáòäÅòòï> end

This does not really make sense since you loose information and
SystemCallError is a StandardError already:

irb(main):002:0> SystemCallError.ancestors
=> [SystemCallError, StandardError, Exception, Object, Kernel, BasicObject]

> Both your attempts couldn't work because the syntax you used was invalid.he
> correct syntax would have been this:
>
> (File.open("#{RUNLOG}", "a") do |file|
> ..
> end) or raise StandardError
>
> The parentheses enclosing the call to File.open and its block is optional. I
> put it only for clarity. While the above syntax is correct, however, it won't
> work as you expected because File.open raises an exception when it fails.t
> would have worked if the method had returned false or nil on failure.

Please note that the block form of File.open returns the last value of
the block and not the File object:

irb(main):004:0> File.open("mm") {|io| 123}
=> 123

If you just want the boolean information whether the open succeeded or
not you can do this:

irb(main):010:0> File.open("mm").close || true rescue false
=> true
irb(main):011:0> File.open("not existent").close || true rescue false
=> false

However, Derek, generally it is better to work with exceptions the way
they are intended.  You do not _test_ whether you could do something
and branch the code but you _just do it_ and catch the error if it
surfaces.  That keeps the code short and also you can do the exception
handling in a much more appropriate place (i.e. up the call stack).

The "checking idiom" also has a logical flaw: even if the check
signals that the operation could succeed, the operation can still fail
when attempted (because the situation changes - someone changed
permissions of the file just this moment, the file was removed or your
process runs out of file descriptors because some other thread used
them up).  This means, even with the check you need to handle the
exception anyway.  The check does not add anything to the logic,
rather it makes things more complicated, costs time and conveys a
false notion of safety / robustness.

Kind regards

robert

-- 
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/