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