Ruby block: why doesn't this work?

M

markbuckingham

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
 
D

David Masover

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
 
M

Michael Guterl

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?
You need to make the info method call the block. See the code below.
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)
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 Guterl
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
 
M

Mark Buckingham

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

Thanks
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,066
Latest member
VytoKetoReviews

Latest Threads

Top