[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Need help understanding metaclassing

Chris Czub

10/25/2007 5:37:00 PM

I've been reading lots of Ruby tutorials trying to figure out
metaclassing - the one that got me closest was Why?s poignant guide to
Ruby, but I'm still struggling over some of the Ruby-specific syntax.

I attached a class I've been writing that needs to be highly extensible,
and it's loaded with comments I wrote to try to understand each part of
it. If any part of the comments are wrong, it would be nice to have my
misconceptions cleared up. I've only been using Ruby for a day and, wow.

Here's the part I'm having the hardest time figuring out, and Why?s
guide kind of skipped over it:

metaclass.instance_eval do
define_method( a ) do |val|
@attribs ||= {}
@attribs[a] = val
end
end

So, I understand that the block inside the instance_eval will be
executed in the instance of the object(meaning when I create a new
object, right?)

However, I don't understand the next part. define_method is a method
call to the method that is defined further down, right? But what is the
" do |val|" after the method call, and what is the point of the two
lines after that?

If anyone could explain this to me, I would be greatly indebted.

Attachments:
http://www.ruby-...attachment/776/user_...

--
Posted via http://www.ruby-....

19 Answers

David A. Black

10/25/2007 5:45:00 PM

0

Rick DeNatale

10/25/2007 6:33:00 PM

0

On 10/25/07, Chris Czub <chris.czub@gmail.com> wrote:
> I've been reading lots of Ruby tutorials trying to figure out
> metaclassing - the one that got me closest was Why?s poignant guide to
> Ruby, but I'm still struggling over some of the Ruby-specific syntax.
>
> I attached a class I've been writing that needs to be highly extensible,
> and it's loaded with comments I wrote to try to understand each part of
> it. If any part of the comments are wrong, it would be nice to have my
> misconceptions cleared up. I've only been using Ruby for a day and, wow.
>
> Here's the part I'm having the hardest time figuring out, and Why?s
> guide kind of skipped over it:
>
> metaclass.instance_eval do
> define_method( a ) do |val|
> @attribs ||= {}
> @attribs[a] = val
> end
> end
>
> So, I understand that the block inside the instance_eval will be
> executed in the instance of the object(meaning when I create a new
> object, right?)

Wrong!

the block argument to instance_eval is evaluated right away, in the
context of metaclass.

The context is missing but I'm assuming that this is inside a class
definition, and metaclass has been defined as a method to return the
singleton class. So lets say we had:

class Foo
metaclass #=> the singleton class of Foo.
metaclass.instance_eval do
# Inside this block self is bound to the singleton class of foo
define_method(:bar) {"bar"}
end
end

This has the same effect as
class Foo
def self.bar
"bar"
end
end

I.e. it defines a class method of Foo.

Now I'd usually use class_eval, or module_eval which do the same thing
but only work if the receiver is a class/module.

> However, I don't understand the next part. define_method is a method
> call to the method that is defined further down, right? But what is the
> " do |val|" after the method call, and what is the point of the two
> lines after that?

David A. Black has already answered this.

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denh...

Robert Dober

10/25/2007 6:55:00 PM

0

On 10/25/07, Chris Czub <chris.czub@gmail.com> wrote:
> I've been reading lots of Ruby tutorials trying to figure out
> metaclassing - the one that got me closest was Why?s poignant guide to
> Ruby, but I'm still struggling over some of the Ruby-specific syntax.
>
> I attached a class I've been writing that needs to be highly extensible,
> and it's loaded with comments I wrote to try to understand each part of
> it. If any part of the comments are wrong, it would be nice to have my
> misconceptions cleared up. I've only been using Ruby for a day and, wow.
>
> Here's the part I'm having the hardest time figuring out, and Why?s
> guide kind of skipped over it:
>
> metaclass.instance_eval do
> define_method( a ) do |val|
> @attribs ||= {}
> @attribs[a] = val
> end
> end
>
> So, I understand that the block inside the instance_eval will be
> executed in the instance of the object(meaning when I create a new
> object, right?)
>
> However, I don't understand the next part. define_method is a method
> call to the method that is defined further down, right? But what is the
> " do |val|" after the method call, and what is the point of the two
> lines after that?
>
> If anyone could explain this to me, I would be greatly indebted.
>
> Attachments:
> http://www.ruby-...attachment/776/user_...
>
> --
> Posted via http://www.ruby-....
>
>
Notwithstanding the answers you got already and they are very worthy
indeed I would like to add my grain of salt.
I like to see metaprogramming a little bit as program generation

A.module_eval {
define_method :b do |n| 42*n end
end

is just the same as the following of course
class A
def b n
42*n
end
end
I therefore imagine that define_method does write code, the following
is of course
only a metaphor

class Module
def define_method name, &blk
eval "def #{name}( #{blk.params} )
#{blk.body}
end"
end
end

HTH
Robert
--
what do I think about Ruby?
http://ruby-smalltalk.blo...

David A. Black

10/25/2007 7:00:00 PM

0

Daniel Waite

10/25/2007 7:29:00 PM

0

Rick Denatale wrote:
> class Foo
> metaclass #=> the singleton class of Foo.
> metaclass.instance_eval do
> # Inside this block self is bound to the singleton class of
> foo
> define_method(:bar) {"bar"}
> end
> end
>
> This has the same effect as
> class Foo
> def self.bar
> "bar"
> end
> end
>
> I.e. it defines a class method of Foo.
>
> Now I'd usually use class_eval, or module_eval which do the same thing
> but only work if the receiver is a class/module.

Hold on, now I'm confused. Given this...

class Creature

def singleton
class << self
self
end
end

end

c = Creature.new
cs = c.singleton

cs.instance_eval do
define_method(:eat) do
puts "You eat."
end
end

cs.eat # => errors:
NoMethodError: undefined method `eat' for
#<Class:#<Creature:0xb7f78ae8>>

Why is that? I've tried class_eval, too and I get the same thing. I
thought I understood this stuff pretty well but I guess not.
--
Posted via http://www.ruby-....

Daniel Waite

10/25/2007 7:32:00 PM

0

Daniel Waite wrote:
> cs.instance_eval do
> define_method(:eat) do
> puts "You eat."
> end
> end
>
> cs.eat # => errors:
> NoMethodError: undefined method `eat' for
> #<Class:#<Creature:0xb7f78ae8>>
>
> Why is that? I've tried class_eval, too and I get the same thing. I
> thought I understood this stuff pretty well but I guess not.

This works:

cs.instance_eval do
def eat
puts "You eat."
end
end

cs.eat # You eat.

What's up with define_method?
--
Posted via http://www.ruby-....

Chris Czub

10/25/2007 7:42:00 PM

0

Daniel Waite wrote:
> Daniel Waite wrote:
>> cs.instance_eval do
>> define_method(:eat) do
>> puts "You eat."
>> end
>> end
>>
>> cs.eat # => errors:
>> NoMethodError: undefined method `eat' for
>> #<Class:#<Creature:0xb7f78ae8>>
>>
>> Why is that? I've tried class_eval, too and I get the same thing. I
>> thought I understood this stuff pretty well but I guess not.
>
> This works:
>
> cs.instance_eval do
> def eat
> puts "You eat."
> end
> end
>
> cs.eat # You eat.
>
> What's up with define_method?

The method is put into the Creature class and is inaccessible in the
simpleton class.

Try this:

class Creature

def singleton
class << self
self
end
end

end

c = Creature.new
cs = c.singleton

cs.instance_eval do
define_method(:eat) do
puts "You eat."
end
end

c.eat
--
Posted via http://www.ruby-....

Daniel Waite

10/25/2007 7:47:00 PM

0

Chris Czub wrote:
> The method is put into the Creature class and is inaccessible in the
> simpleton class.

> Try this:

> class Creature
>
> def singleton
> class << self
> self
> end
> end
>
> end

> c = Creature.new
> cs = c.singleton
>
> cs.instance_eval do
> define_method(:eat) do
> puts "You eat."
> end
> end
>
> c.eat

That's the same code as above. Still doesn't work though. =)
--
Posted via http://www.ruby-....

Chris Czub

10/25/2007 7:56:00 PM

0

Daniel Waite wrote:
> That's the same code as above. Still doesn't work though. =)

Nope, it's c.eat instead of cs.eat... works for me! :)
--
Posted via http://www.ruby-....

Daniel Waite

10/25/2007 9:17:00 PM

0

Chris Czub wrote:
> Daniel Waite wrote:
>> That's the same code as above. Still doesn't work though. =)
>
> Nope, it's c.eat instead of cs.eat... works for me! :)

Hehe, I feel sheepish. (Yes, works for me, too.)

So... what I gather then is that it's possible to, from the viewpoint of
the singleton, duck back into the object that spawned it. Why you would
do that I don't know, but it can be done.

It looks like the only way to define a method on a singleton object is
to use...

cs.instance_eval do
def eat
puts "You eat."
end
end

I find that restrictive because you can't dynamically create a method
name.

It looks likes you can extend it with modules:

module Bounce

def bounce
puts "You bounce."
end

end

cs.extend Bounce
cs.bounce # You bounce.

What is special about the singleton object such that it cannot be
extended using define_method?
--
Posted via http://www.ruby-....