Ruby equivalent of C# "using keword" and IDispose

What is the most expedient way to do this C# construct in Ruby?

C#: using (myObj = new MyClass()) {
// misc code here
} //MyClass.Dispose automatically called here

I wish to put stuff in MyClass.Dispose() to release resources… it must
always be called.

Pete

2010/1/21 Peter A. [email protected]:

What is the most expedient way to do this C# construct in Ruby?

C#: using (myObj = new MyClass()) {
// misc code here
} //MyClass.Dispose automatically called here

I wish to put stuff in MyClass.Dispose() to release resources… it must
always be called.

You want “ensure”. See
http://blog.rubybestpractices.com/posts/rklemme/001-Using_blocks_for_Robustness.html
http://blog.rubybestpractices.com/posts/rklemme/002_Writing_Block_Methods.html

Kind regards

robert

Peter A. wrote:

What is the most expedient way to do this C# construct in Ruby?

C#: using (myObj = new MyClass()) {
// misc code here
} //MyClass.Dispose automatically called here

I wish to put stuff in MyClass.Dispose() to release resources… it must
always be called.

In a language with higher-order procedures like Ruby, adding a special
language construct for this is completely unnecessary. You just write
a method which accepts a piece of code as an argument, acquires the
resource, runs the piece of code and subsequently releases the
resource. This is the well-known “with-foo” pattern from Lisp,
basically. In Ruby, we generally use a factory-ish class method like
so:

class DatabaseConnection
  def self.use(*args)
    yield handle = new(*args)
  ensure
    handle.close
  end
end

This is how usage would look like:

DatabaseConnection.use('/path/to/sqlite.db') do |conn|
  conn.exec 'SELECT blah FROM blurb WHERE foo = 42;'
  conn.exec 'INSERT something INTO somewhere;'
end

This pattern is for example used by IO.open in the standard library:

File.open('/path/to/file', 'w+') do |f|
  f.puts 'Hello, World'
end

The two main differences between the two methods are:

  • in the Ruby version, the acquisition of the resource is hidden away
    inside the method, whereas in C#, the user is responsible for
    creating the resource. (You could, of course, write a generic
    method that simply takes any resource as a parameter. That’s just
    not the normal style in Ruby.)
  • in the C# version, there is a standardized agreement over what the
    name of the method for releasing the resource is (the Dispose()
    pattern) and there is even a type for it (the IDisposable
    interface)

Here’s what a more C# style implementation in Ruby would look like:

def using(handle)
  yield handle
ensure
  handle.dispose
end

using(MyClass.new) do |my_obj|
  # misc code here
end # MyClass#dispose automatically called here

BTW: you can do that in C#, too, now. It’s just that before lambda
expressions, local variable type inference and anonymous types were
introduced in C#, it would have been a lot of typing (in both senses
of the word). This is what the opposite would look like (i.e. Ruby
style implemented in C#):

class DatabaseConnection
{
    static T use<T>(string connection, Func<DatabaseConnection, T> 

block)
{
var handle = new DatabaseConnection(connection);
try
{
return block(handle);
}
finally
{
handle.Dispose();
}
}
}

And this is how you use it:

DatabaseConnection.use("/path/to/db", (conn) =>
{
    // misc code here
}); // MyClass.Dispose automatically called here

(If you don’t want to return a value, lose the T and replace Func with
Action.)

jwm

I finally came up with this toy:

def using(res, options = { release_with: :close })
yield res
ensure
if res.respond_to?(options[:release_with])
res.send(options[:release_with])
end
end

With using method, you can have C# style coding as follows:

using(db = SQLite3::Database.new(‘cart.db’)) {

}

Or you can make use of the block parameter:

using(SQLite3::Database.new(‘cart.db’)) { |db|

}

If, however, the resource you are about to use favers a different method
to
release, you can also specify it to using:

using(SQLite3::Database.new(‘cart.db’), release_with: “close”) { |db|

}

Note that you need to go back to :release_with => “close” if you are
targeting version before 1.9.

Enjoy!

allen

2010/1/22 Jörg W Mittag
<[email protected][email protected]

  1. I also considered

def using(res, close = :close)

over

def using(res, options = { release_with: :close })

however, I think

using(Res.new, release_with: “close”)

would be nicer than

using(Res.new, “close”)

so finally I chose what it is right now :slight_smile:

  1. The solution you provided as follows is definitely more robust due to
    respond_to? may not work as expected in the situation you mentioned and
    thanks!

res.send(options[:release_with]) rescue nil

allen

On Fri, Jan 22, 2010 at 5:32 PM, Robert K.

2010/1/22 Allen L. [email protected]:

I finally came up with this toy:

This looks interesting. Although I have to say that the functionality
should be rather built into the classes at hand (like e.g. File has)
IMHO.

def using(res, options = { release_with: :close })

Since you have a single option only you can as well do

def using(res, close = :close)

yield res
ensure
if res.respond_to?(options[:release_with])
res.send(options[:release_with])
end

I’d rather do

res.send(options[:release_with]) rescue nil

Because the idea of respond_to? and what the class really understands
may differ.

irb(main):001:0> class X
irb(main):002:1> def method_missing(s,*a,&b)
irb(main):003:2> “I can #{s}!”
irb(main):004:2> end
irb(main):005:1> end
=> nil
irb(main):006:0> o = X.new
=> #<X:0x101596fc>
irb(main):007:0> o.respond_to? :dance
=> false
irb(main):008:0> o.dance
=> “I can dance!”
irb(main):009:0> o.dance!
=> “I can dance!!”
irb(main):010:0>

end

Note that you need to go back to :release_with => “close” if you are
targeting version before 1.9.

This is not necessary if you just use a single additional parameter (see
above).

Kind regards

robert

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs