Ruby syntax question: instance.method(args) { more_stuff }

Thanks a lot for the detailed reply, this is just what I needed!

···

-----Original Message-----
From: Brian Candler [mailto:B.Candler@pobox.com]
Sent: 01 May 2007 12:05
To: ruby-talk ML
Subject: Re: Ruby syntax question: instance.method(args) { more_stuff }

On Tue, May 01, 2007 at 07:14:43PM +0900, Nic Daniau wrote:

The API says "You may also specify optional arguments by setting
Image::Info <http://www.simplesystems.org/RMagick/doc/info.html&gt;
attributes in an associated block." Is this a standard syntax in Ruby
or is it specific to this write method? And how does it work, how can
I make my own method accept blocks too? any advantage over passing a
array of arguments?

It's fairly standard. It has the advantage of only being run when
required, e.g. zero times if no object ends up being created, or it
could be run multiple times. Compare:

    a = Array.new(2) { }
    a[0] << 'bar'
    a[1] << 'bap'

Here the initialization block is run twice, so you get two different
empty arrays. This is different to

    a = Array.new(2, )
    a[0] << 'bar'
    a[1] << 'bap'

Try it in irb, and look at 'a' afterwards in both cases.

For another example of this pattern, look at dependency injection, e.g.
http://wikis.onestepback.org/OSB/page/show/DependencyInjectionCode/DepIn
jRb
(site appears to be very slow at present)

In this case the advantage is that the initialization code is run at the
latest possible time; at the time the block is created not all the
values are known.

How to do it yourself?

  class Foo
    attr_accessor :x
    def initialize(&blk)
      instance_eval(&blk) if blk
    end
  end
  a = Foo.new { self.x = 99 }
  puts a.x

Also, I'm trying to pass my own instance variable in order to replace
the sample value of 50. So I've tried:

img.write("myimage.jpg") { self.quality = @my_object_quality }

Where @my_object_quality is defined as an instance variable on my
class def. But the interpreters seams to look for a @my_object_quality

instance variable *within* the RMagick class, which vaguely kind of
make sense. So how can I pass this instance variable into this method?

Simplest just to use a local variable:

   foo = @my_object_quality
   .... { self.quality = foo }

If there are lots of these, then pass an instance of yourself, as long
as you have public accessor methods.

   template = self
   ... { self.quality = template.quality }

and
why does it say "self.quality = 50" in the example and not "@quality =

50"?

I guess it's just standard accessor syntax, where it's considered
cleaner to call a setter method (which might implement additional logic)
rather than twiddle directly with instance variables in an object, which
are usually considered 'private'

Brian.