views:

111

answers:

2

I have a method which returns an File object. I need to know when the file is getting closed. This is not as simple as overwriting the close method. The close method is not called if the file is closed by the destructor.

It should work like this:

def something
    get_lock_on_file
    file File.new("foobar")
    file.on_close { release_lock_on_file }
    file
end

How do I implement file#on_close(&block) ?

+2  A: 

I am afraid there is nothing you can do. If the File#close method doesn't get called, then it's somewhat likely that the file will actually only be automatically closed by the operating system, when the Ruby interpreter exits. In other words: at the time that the file is closed, the Ruby interpreter (or at least your program) is long gone, so there is just no way that your program can be notified.

I guess you could achieve some somewhat reasonable coverage by

  • overriding the File object's #close method,
  • installing your own finalizer and
  • installing an at_exit handler.

However, all of these have their problems: the #close method might not get called. The finalizer is only run when the object is garbage collected, which may be much later than you expect (and if you never run out of memory, then the garbage collector never runs and the finalizer never gets called). And even the at_exit handler is not guaranteed to run, if the interpreter crashes.

Jörg W Mittag
+3  A: 

Define something like this ...

def something
  get_lock_on_file
  yield file
  release_lock_on_file
end

.. and use it like that:

something do |file|
  ...
end

Wrap yield with an error handling block if you need it.

yawn
My method must return the file.
johannes
add: file before the end of the def something
khelll