Re: Pass block instead of here document?

From: Morton G. [mailto:[email protected]]

report
eat 'burger', 'fries'
drink 'beer'
be_merry

end

def tell( obj, &to_do )
obj.instance_eval( &to_do )
end

class Foo
def say_hi
p “Hi!”
end
end

tell Foo.new do
say_hi
end
#=> “Hi!”

On Oct 25, 2006, at 3:31 PM, Gavin K. wrote:

end
#=> “Hi!”
It’s really that easy? Amazing! Ruby makes things so easy compared
with the other languages I’ve used that I’m constantly inventing hard
ways of doing what is too obvious for me to see.

Thanks for your help.

Regards, Morton

Hi –

On Thu, 26 Oct 2006, Morton G. wrote:

end
obj.instance_eval( &to_do )
end
#=> “Hi!”

It’s really that easy? Amazing! Ruby makes things so easy compared with the
other languages I’ve used that I’m constantly inventing hard ways of doing
what is too obvious for me to see.

It’s easy, but it can also be a bit obfuscating. For example:

class C
def initialize(thing)
@thing = thing
end

 def tell(&block)
   instance_eval(&block)
 end

end

c = C.new(“Hi”)

@thing = “Hello”
c.tell do
puts @thing # Hi
end

So you get some perhaps unwanted variable-shadowing, and similarly
with method calls.

David

On Oct 25, 2006, at 3:54 PM, [email protected] wrote:

module Kernel

end
@thing = thing
c.tell do
puts @thing # Hi
end

So you get some perhaps unwanted variable-shadowing, and similarly
with method calls.

I would expect that behavior and, in the situation I’m dealing with,
I think it’s an acceptable trade-off.

Regards, Morton

James Edward G. II wrote:

  instance_eval(&block)

So you get some perhaps unwanted variable-shadowing, and similarly
attr_reader :thing
def thing; “Hello” end
end

I know people frown on the instance_eval() trick, but this seems to be
less of a problem. You can just choose to use the variable when you
need it.

I dunno… the presence of “|obj|” changes the semantics of the rest of
the block. It’s so easy to comment out the |obj| and then suddenly
methods are handled in a surprising way:

c.tell do |obj|
thing # => “Hello”
end

c.tell do #|obj|
thing # => “Hi”
end

Visually, it doesn’t look like anything important has changed.

Seems like a bug magnet.

On Oct 25, 2006, at 2:54 PM, [email protected] wrote:

end

c = C.new(“Hi”)

@thing = “Hello”
c.tell do
puts @thing # Hi
end

So you get some perhaps unwanted variable-shadowing, and similarly
with method calls.

Greg Brown and I were playing around with a solution for the method
call issue at RubyConf. Here’s the code we came up with:

class C
def initialize(thing)
@thing = thing
end

attr_reader :thing

def tell(&block)
if block and block.arity == 1
block[self]
else
instance_eval(&block)
end
end
end

def thing; “Hello” end

c = C.new(“Hi”)

c.tell do
thing # => “Hi”
end

c.tell do |obj|
thing # => “Hello”
obj.thing # => “Hi”
end

I know people frown on the instance_eval() trick, but this seems to
be less of a problem. You can just choose to use the variable when
you need it.

Just a thought.

James Edward G. II

My understanding of blocks is at best still very shakey, but is there a
reason in all these that something like

def tell
yield self
end

would not have the desired effect.

Then with appropriate method missings etc you could call whatever you
like
in the block. If the drink and eat methods are already defined in the
object, they would be called as appropriate.

so to use it.

obj = Foo.new
obj.tell do
eat ‘burger’, ‘fries’
drink ‘beer’
end

Is there a reason that this would not have the same effect as the
instance_eval methods?

Hi –

On Thu, 26 Oct 2006, Daniel N wrote:

in the block. If the drink and eat methods are already defined in the
Is there a reason that this would not have the same effect as the
instance_eval methods?

Yes: instance_eval temporarily changes “self”, and that means that
bareword method calls like eat and drink will be directed to the Foo
object. Otherwise, it’s just like doing:

eat

in the middle of a program where you haven’t defined an eat method.

David

On Thu, 26 Oct 2006 04:31:31 +0900, Gavin K. wrote:

tell Foo.new do
report
eat ‘burger’, ‘fries’
drink ‘beer’
be_merry
end

def tell( obj, &to_do )
obj.instance_eval( &to_do )
end

Heck. Why bother with tell in the first place? Why not call
instance_eval
directly?

–Ken

On 10/25/06, James Edward G. II [email protected] wrote:

I know people frown on the instance_eval() trick, but this seems to
be less of a problem. You can just choose to use the variable when
you need it.

James, why do people frown upon instance_eval? I know you cannot speak
for all people, but what are the reasons to avoid it?

My only guess is that it would be slower than calling the block
directly – block[self] – as you showed in the code example.

Thoughts?

TwP

On Thu, 26 Oct 2006, Tim P. wrote:

My only guess is that it would be slower than calling the block
directly – block[self] – as you showed in the code example.

Thoughts?

the tk bindings work this way, and debugging can be frustrating:

harp:~ > cat a.rb
class C
def a() :a end
def c() :c end
def m(&b) instance_eval &b end
end
def b() :b end

p C.new.m{ mixed_scope = [a, b, c] }

harp:~ > ruby a.rb
[:a, :b, :c]

certainly has it’s application though…

-a

On 10/26/06, [email protected] [email protected] wrote:

end
obj = Foo.new
object. Otherwise, it’s just like doing:

eat

in the middle of a program where you haven’t defined an eat method.

I’m a bit lost with that. I think I don’t understand what is self
inside
the block. In the case of

def tell
yield self
end

obj = Foo.new
obj.tell do
eat ‘burger’, ‘fries’
drink ‘beer’
end

What is self inside the block?

Hello All,

Sorry but I do not really understand the way instance_eval is working
in this sample:

def tell( obj, &to_do )
obj.instance_eval( &to_do )
end

I’am new to Ruby and Metaprogramming and this method is still obscure to
me.
Can someone help ?
Thanks a lot,

Luc

On Oct 25, 2006, at 8:45 PM, Ken B. wrote:

end

def tell( obj, &to_do )
obj.instance_eval( &to_do )
end

Heck. Why bother with tell in the first place? Why not call
instance_eval
directly?

Syntactic sugar. I guess I have a sweet tooth.

Regards, Morton

Luc J. wrote:

me.
Can someone help ?
Thanks a lot,

Look at it this way: The items inside the block are evaluated
in the context of obj, rather than that of the tell method.

For example:

def tell( obj, &to_do )
p self
obj.instance_eval( &to_do )
end

If the to_do block were to print self, it would be the
same as obj (and different from what was printed before
the instance_eval).

HTH,
Hal

On Oct 25, 2006, at 10:32 PM, Tim P. wrote:

On 10/25/06, James Edward G. II [email protected] wrote:

I know people frown on the instance_eval() trick, but this seems to
be less of a problem. You can just choose to use the variable when
you need it.

James, why do people frown upon instance_eval? I know you cannot speak
for all people, but what are the reasons to avoid it?

I have literally seen code like this:

must_save = self
whatever do
# use must_save in here, even though self changed…
end

This is a sign of instance_eval() gone wrong, and Ara showed other
issues.

Many take this as a sign that you should never instance_eval() a
block like this, but I think that’s going a bit far. It’s very handy
in creating DSLs, for example.

James Edward G. II