Ruby block: why doesn't this work?

I’m trying to figure out why my code isn’t doing what I think it
should…

Basically, I’m trying to create a Info object, and do various things
to that new object within the block. For what ever reason though, it
doesn’t look like the code inside the block is getting executed at
all. (I’m trying to do something that looks kind of like
activerecord’s create_table method.)

So… with the print statements in the code, I’d expect to see output
from the address() and city() methods, but only the initialize method
prints anything. (I can even put complete nonsense in the address or
city methods, and nothing happens.)

What am I doing wrong?

Thanks!

class Info
attr_accessor :name, :address, :city

def initialize(name)
@name = name
print “name: #{name}\n”
end

def address(value)
@address = value
print “address: #{address}\n”
end

def city(value)
@city = value
print “city: #{city}\n”
end
end

def info(name)
Info.new(name)
end

info :Bob do |i|
i.address “123 Main St.”
i.city “Boston, MA”
end

On Friday 01 August 2008 22:04:01 [email protected] wrote:

Basically, I’m trying to create a Info object, and do various things
to that new object within the block.

What block? You mean this one?

info :Bob do |i|
i.address “123 Main St.”
i.city “Boston, MA”
end

But the “info” method you’ve defined doesn’t do anything with that
block:

def info(name)
Info.new(name)
end

The block has to be used somewhere within the body of that object.
(Trying not
to be too offensive here, but you have exactly zero code in place to do
anything with the block – which is why nothing happens to the block.)

What you probably want is either to turn it into a local variable:

def info(name, &block)
p block
Info.new(name, &block)
end

Of course, you’d have to change the constructor, too:

def initialize(name)
@name = name
yield self
end

It’s probably easier just to do this:

def info(name)
i = Info.new(name)
yield i
i
end

Or, if you have at least Ruby 1.8.7, this should work:

def info(name)
Info.new(name).tap do |i|
yield i
end
end

For what it’s worth, one of the benefits of open source is, if you’re
wondering “How did they do that??”, you can find out. Here’s a snip from
create_table:

def create_table(table_name, options = {})
table_definition = TableDefinition.new(self)

yield table_definition

end

Object#tap is also a nice illustration of how blocks can work. It’s
actually
written in C, but here’s how I fake it on 1.8.6:

class Object
def tap
yield self
self
end
end

On Fri, Aug 1, 2008 at 11:04 PM, [email protected]
[email protected] wrote:

from the address() and city() methods, but only the initialize method
prints anything. (I can even put complete nonsense in the address or
city methods, and nothing happens.)

What am I doing wrong?

You need to make the info method call the block. See the code below.

def address(value)
def info(name)
i = Info.new(name)
yield i
i
end

info :Bob do |i|
i.address “123 Main St.”
i.city “Boston, MA”
end

Also this code will currently give you errors because attr_accessor is
overwriting your existing method definitions. I recommend using the
‘fattr’ gem it will give you most of the functionality you desire.

HTH,
Michael G.
require ‘rubygems’
require ‘fattr’

class Info
fattr :name, :address, :city

def initialize(name)
self.name = name
end
end

def info(name)
i = Info.new(name)
yield i
i
end

bob = info ‘bob’ do |i|
i.address “123 foo lane”
i.city “oz”
end

puts bob.inspect

On Aug 1, 11:45 pm, David M. [email protected] wrote:

For what it’s worth, one of the benefits of open source is, if you’re
wondering “How did they do that??”, you can find out. Here’s a snip from
create_table:

Of course I thought of that about 20 minutes after posting. I was
tired, I guess. :slight_smile:

Thanks

On Aug 1, 11:48 pm, Michael G. [email protected] wrote:

bob = info ‘bob’ do |i|
i.address “123 foo lane”
i.city “oz”
end

puts bob.inspect

The yield worked, thanks.