From: Allen Lee Date: 2010-01-22T18:20:13+09:00 Subject: Re: Ruby equivalent of C# "using keword" and IDispose --00504502bdb5a01467047dbd535d Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable I finally came up with this toy: def using(res, options =3D { 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 =3D 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 =3D> "close" if you are targeting version before 1.9. Enjoy! allen 2010/1/22 J=F6rg W Mittag > > Peter Alvin wrote: > > What is the most expedient way to do this C# construct in Ruby? > > > > C#: using (myObj =3D new MyClass()) { > > // misc code here > > } //MyClass.Dispose automatically called here > > > > I wish to put stuff in MyClass.Dispose() to release resources... it mus= t > > 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 =3D 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 =3D 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(string connection, Func > block) > { > var handle =3D new DatabaseConnection(connection); > try > { > return block(handle); > } > finally > { > handle.Dispose(); > } > } > } > > And this is how you use it: > > DatabaseConnection.use("/path/to/db", (conn) =3D> > { > // 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 > > --00504502bdb5a01467047dbd535d--