File open failure test

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|
    code here...

or raise StabdardError ...
end

thank you!

···

--
Posted via http://www.ruby-forum.com/.

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
  File.open("#{RUNLOG}", "a") do |file|
    ...
  end
rescue SystemCallError
  raise StandardError
end

Both your attempts couldn't work because the syntax you used was invalid. The
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. It
would have worked if the method had returned false or nil on failure.

I hope this helps

Stefano

···

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|
> code here...
>
>
>or raise StabdardError ...
>end
>
>
>thank you!
>

>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|
> code here...
>
>
>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
File.open("#{RUNLOG}", "a") do |file|
...
end
rescue SystemCallError
raise StandardError
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. The
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. It
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

···

2009/10/26 Stefano Crocco <stefano.crocco@alice.it>:

On Monday 26 October 2009, Derek Smith wrote:

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

Hi,

···

Am Montag, 26. Okt 2009, 18:40:20 +0900 schrieb Robert Klemme:

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

If you just want to test then ask:

  File.stat("xx").readable?

As Robert pointed out it is better straight to do what you want to
do and catch the exceptions where they happen.

Bertram

--
Bertram Scharpf
Stuttgart, Deutschland/Germany
http://www.bertram-scharpf.de

Bertram Scharpf wrote:

Hi,

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

If you just want to test then ask:

  File.stat("xx").readable?

As Robert pointed out it is better straight to do what you want to
do and catch the exceptions where they happen.

Bertram

Thanks you guys! I understand, but coming from (nasty) Perl land there
are
differences. But why the .close here File.open("mm").close ?
What does it do... auto close at end of the block?

···

Am Montag, 26. Okt 2009, 18:40:20 +0900 schrieb Robert Klemme:

--
Posted via http://www.ruby-forum.com/\.

Bertram Scharpf wrote:

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

If you just want to test then ask:

File.stat("xx").readable?

As Robert pointed out it is better straight to do what you want to
do and catch the exceptions where they happen.

Thanks you guys! I understand, but coming from (nasty) Perl land there
are
differences.

Indeed. The OO in Ruby is significantly different (and better) than
that in Perl. I suggest reading one or more of these:

- online tutorials about Ruby
- Pickaxe (only an old version available online via http://www.ruby-doc.org/\)
- David's "Well-Grounded Rubyist"

But why the .close here File.open("mm").close ?
What does it do... auto close at end of the block?

There is no block (no spoon either btw.). The file is opened and
closed immediately. But as said, rather use the block form without
beforehand checks. See also my blog article for some more discussion
on methods with blocks:

http://blog.rubybestpractices.com/posts/rklemme/001-Using_blocks_for_Robustness.html

Kind regards

robert

···

2009/10/26 Derek Smith <derekbellnersmith@yahoo.com>:

Am Montag, 26. Okt 2009, 18:40:20 +0900 schrieb Robert Klemme:

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

http://blog.rubybestpractices.com/posts/rklemme/001-Using_blocks_for_Robustness.html

Kind regards

robert

OK so in relation, I want to have a method for whose responsibility
is logging runtime errors such as failures to open or run OS commands.
However, when I intentionally made it fail, like putting in a non OS
command
it does not log? Any help on this or best practices?

thx!

For example:

#!/usr/bin/env ruby -w
require 'date'
require 'ftools'
require 'fileutils'

ENV['PATH'] =
'/usr/bin:/usr/sbin:/sbin:/bin:/usr/local/bin:/usr/local/vrep'
VERSIONS = 14.to_i
DB_DIR = "/usr/local/vrep/prod/db"
DB_BKUP1 = Dir.glob("#{DB_DIR}/*.gz")
DB_BKUP = "#{DB_DIR}/prod_db_bkup_"
RUNLOG = "/var/log/prod_db_bkup.log"
DBF = Dir.glob("#{DB_DIR}/*.sqlite3")

unless File.exists?( "#{RUNLOG}" )
    FileUtils.touch( "#{RUNLOG}" ) \
    >> warn("Touch file failed for /var/log/prod_db_bkup.log!")
end

d = Date.today
t = Time.now
h = Hash.new
    h["Sun"] = 0
    h["Mon"] = 1
    h["Tue"] = 2
    h["Wed"] = 3
    h["Thr"] = 4
    h["Fri"] = 5
    h["Sat"] = 6

def log_mtd(arg)
    File.open( "#{RUNLOG}", "a" ) do |file|
        file.puts(arg)
    end
end

def db_bkup(arg)
    Dir.chdir( "#{DB_DIR}" ) \
    >> die_mtd("Change_Dir_Failed_To_#{DB_DIR}_Dump_Will_Fail!")
    if DBF.length.to_i < 1
        die_mtd("#{DBF}_File_Is_Missing_Dump_Will_Not_Run.+(d.to_s).+(t.hour.to_s)")
    else
        %x(echo ".dump"|sqlite3 development.sqlite3 |gzip -c >
"#{DB_BKUP.+(arg)}") \
        >> die_mtd("SQL_Dump_Cmd_Failed.+(d.to_s).+(t.hour.to_s)")
    end
end

if DB_BKUP1.length.to_i >= 1
    File.open( "#{RUNLOG}", "a" ) do |file|
        h.each_pair do |key, value|
            if d.wday == value
                file.puts '+'
                65.times do file.print "=" end
                file.puts "\n","Beginning day: #{key} DB backup at
#{d.to_s} #{t.hour}:#{
t.min}","\n"
                file.puts "Executing command echo .dump|sqlite3
development.sqlite3 |gzip
-c","\n"
                65.times do file.print "=" end
                file.puts "\n",'+'
                db_bkup(key .+(d.to_s) .+(t.hour.to_s) .+(t.min.to_s))
            end
        end
    end ||
die_mtd("#{RUNLOG}_Did_Not_Open_.+(d.to_s).+(t.hour.to_s).+(t.min.to_s)")
end

···

--
Posted via http://www.ruby-forum.com/\.

You could start by omitting unnecessary string interpolation as you do
with RUNLOG all the time.

Also, why don't you put the weekday hash into a constant as well?
Btw, you could use an Array for this as well.

DAYS = %w{Sun Mon Tue} # ...

Other than that right now I don't have the time to further analyze
your example (which also seems to be missing something, e.g.
definition of die_mtd).

FileUtils.touch throws an exception if it fails. I believe you should
make yourself familiar with the concept of exception handling before
diving further into this project.

Kind regards

robert

···

2009/10/26 Derek Smith <derekbellnersmith@yahoo.com>:

OK so in relation, I want to have a method for whose responsibility
is logging runtime errors such as failures to open or run OS commands.
However, when I intentionally made it fail, like putting in a non OS
command
it does not log? Any help on this or best practices?

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

Derek Smith wrote:

unless File.exists?( "#{RUNLOG}" )
    FileUtils.touch( "#{RUNLOG}" ) \
    >> warn("Touch file failed for /var/log/prod_db_bkup.log!")
end

1. Why do you want to touch the file? You're going to write to it later
anyway. Opening the file in mode "a" will create it if necessary.

2. If you do touch the file, why would you want to continue if it fails?
If it does fail, you're almost bound to fail when you write to it
anyway.

def log_mtd(arg)
    File.open( "#{RUNLOG}", "a" ) do |file|
        file.puts(arg)
    end
end

Looks OK - as pointed out, File.open(RUNLOG,"a") is sufficient.

def db_bkup(arg)
    Dir.chdir( "#{DB_DIR}" ) \
    >> die_mtd("Change_Dir_Failed_To_#{DB_DIR}_Dump_Will_Fail!")

Dir.chdir will raise an exception if it fails, not return false/nil.

So you could do something like this:

  def db_bkup(arg)
    begin
      Dir.chdir(DBDIR)
    rescue
      die_mtd "Change_Dir_Failed_To_#{DB_DIR}_Dump_Will_Fail!"
    end

If you end up doing this a lot, you can write a helper function:

  def failex(msg)
    begin
      yield
    rescue
      die_mtd msg
    end
  end

  ...

  failex "Change_Dir_Failed_To_#{DB_DIR}_Dump_Will_Fail!" do
    Dir.chdir(DBDIR)
  end

(Note: 'rescue' by itself captures StandardError and subclasses. If you
want to catch absolutely all exceptions, use 'rescue Exception'. However
this will also catch things like programming errors)

But to be honest, this is not regular Ruby practice. You'd normally just
write your script without error handling, and let the program fail. It
will usually give a fairly obvious exception message itself. This is
easy to try out in irb:

Dir.chdir("/wibble")

Errno::ENOENT: No such file or directory - /wibble
  from (irb):3:in `chdir'
  from (irb):3

So if your program gave that message, it would be fairly clear where the
problem lies.

        %x(echo ".dump"|sqlite3 development.sqlite3 |gzip -c >
"#{DB_BKUP.+(arg)}") \
        >> die_mtd("SQL_Dump_Cmd_Failed.+(d.to_s).+(t.hour.to_s)")

%x{...} forks an new process to run the command, and will not raise an
exception if that program 'fails'. However you can check $? which is the
status of the most recently terminated child.

%x{flurble}

(irb):4: command not found: flurble
=> ""

$?

=> #<Process::Status: pid=7755,exited(127)>

$?.methods - Object.methods

=> ["success?", "exitstatus", "&", ">>", "stopped?", "stopsig", "to_i",
"coredump?", "to_int", "signaled?", "termsig", "pid", "exited?"]

$?.success?

=> false

So you would write your code as:

    res = %x{...whatever...}
    unless $?.success?
      die_mtd "SQL_Dump_Cmd_Failed with status #{$?.exitstatus}"
    end

Note that the stdout from the command is captured in 'res'. If you are
not going to make use of this, it's probably better to do

    system "...whatever..."

which will allow the child's stdout to go to your ruby script's stdout.

···

--
Posted via http://www.ruby-forum.com/\.

* Robert Klemme <shortcutter@googlemail.com> (2009-10-27) schrieb:

Just to play around with ruby 1.9:

DAYS = %w{Sun Mon Tue} # ...

You can construct the hash doing the opposite translation with:

DAYS_TO_I = DAYS.each_with_index.inject({}) { | h, (v, i) | h[v] = i; h }.freeze

Any more simple way to do that?

mfg, simon .... l

Not that I'm aware of. With a Hash you could use #invert but that is not available for Array it seems.

Kind regards

  robert

···

On 10/31/2009 10:02 AM, Simon Krahnke wrote:

* Robert Klemme <shortcutter@googlemail.com> (2009-10-27) schrieb:

Just to play around with ruby 1.9:

DAYS = %w{Sun Mon Tue} # ...

You can construct the hash doing the opposite translation with:

DAYS_TO_I = DAYS.each_with_index.inject({}) { | h, (v, i) | h[v] = i; h }.freeze

Any more simple way to do that?

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

* Robert Klemme <shortcutter@googlemail.com> (2009-10-31) schrieb:

···

On 10/31/2009 10:02 AM, Simon Krahnke wrote:

* Robert Klemme <shortcutter@googlemail.com> (2009-10-27) schrieb:

Just to play around with ruby 1.9:

DAYS = %w{Sun Mon Tue} # ...

You can construct the hash doing the opposite translation with:

DAYS_TO_I = DAYS.each_with_index.inject({}) { | h, (v, i) | h[v] = i; h }.freeze

Any more simple way to do that?

Not that I'm aware of. With a Hash you could use #invert but that is
not available for Array it seems.

There's Hash#invert? Never saw that before, thank you.

As usual, the Pickaxe is more descriptive than rdoc, the first mentions
that if multiple keys map to the same value, only one of the keys
survives the inversion.

mfg, simon .... l