Need help understanding metaclassing

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-forum.com/attachment/776/user_cleaned.rb

···

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

Hi --

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.

The do/end sequence is a code block. Have a look at some of the
tutorials -- they'll definitely talk about code blocks. When you pass
a code block to define_method, the code block serves as the method
body for the method you're defining.

The lines after that assign an empty hash to @aattribs (except if
@attribs is already set, the assignment is skipped; that's what ||=
does), and sets the value of @attribs[a] to val. val is the block
parameter, and will therefore also be a method parameter for the new
method.

David

···

On Fri, 26 Oct 2007, Chris Czub wrote:

--
Upcoming training by David A. Black/Ruby Power and Light, LLC:
   * Advancing With Rails, Edison, NJ, November 6-9
   * Advancing With Rails, Berlin, Germany, November 19-22
   * Intro to Rails, London, UK, December 3-6 (by Skills Matter)
See http://www.rubypal.com for details!

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.

···

On 10/25/07, Chris Czub <chris.czub@gmail.com> wrote:

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

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

···

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-forum.com/attachment/776/user_cleaned.rb

--
Posted via http://www.ruby-forum.com/\.

--
what do I think about Ruby?
http://ruby-smalltalk.blogspot.com/

Hi --

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 {

s/{/do/ :slight_smile:

  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

It's very key, though, that define_method takes a block, since that
gives the method body access to local variables.

David

···

On Fri, 26 Oct 2007, Robert Dober wrote:

--
Upcoming training by David A. Black/Ruby Power and Light, LLC:
   * Advancing With Rails, Edison, NJ, November 6-9
   * Advancing With Rails, Berlin, Germany, November 19-22
   * Intro to Rails, London, UK, December 3-6 (by Skills Matter)
See http://www.rubypal.com for details!

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-forum.com/\.

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-forum.com/\.

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-forum.com/\.

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-forum.com/\.

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! :slight_smile:

···

--
Posted via http://www.ruby-forum.com/\.

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! :slight_smile:

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-forum.com/\.

Right.

This is a slightly different case that I had described.

In my example

class Foo
    metaclass.instance_eval {define_method(:bar) {"bar"}}
end

It's Foo's singleton/metaclass which get the define_method call.

Whereas

this new case is equivalent to

c = Creature.new
c.singleton.instance_eval {define_method(:eat) {puts "You eat"}}

So in my case, the class Foo ends up with a new method, i.e. a class
method since Foo is a class,
but c ends up with a new singleton (instance) method.

And if you did

c.class.instance_eval{define_method(:walk) {puts "You walk"}}

An instance method would be created which would be invocable for all
instances of Creature, because this is the same as

Creature.instance)_eval ...

···

On 10/25/07, Chris Czub <chris.czub@gmail.com> 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! :slight_smile:
--

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

No, your code did exactly that.

c.eat worked, but did you try

Creature.new.eat

In other words, only the object referenced by c got the method.

···

On 10/25/07, Daniel Waite <rabbitblue@gmail.com> wrote:

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

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

a = "Hello World"
size = 42
class << a
  define_method :a do size end
end
class << a; self end.send :define_method, :b do size end

a.extend Module::new{
  define_method :c do size end
}
module M
  def d; size end
end
a.extend M
puts a.a
puts a.b
puts a.c
puts a.d

HTH
Robert

···

On 10/25/07, Daniel Waite <rabbitblue@gmail.com> wrote:

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! :slight_smile:

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.

--
what do I think about Ruby?
http://ruby-smalltalk.blogspot.com/

user = DefaultUser.new
    # Give them a random email address - TODO this should be changed so
that it first clears out
    # any user that might exist with that email address first to ensure
a proper creation. Oh well.
    user.email("john.doe#{rand(100)}@abc.com")

results in an error.

Why can't I use the attribute accessor? Rather - I understand why I
can't, because it was created in the User class rather than the
DefaultUser class, but how can I get access to it?

···

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

class User
    @users = {}
     class << self
         attr_reader :users
     end
     def initialize name
         email = nil
         loop do
            email = "#{name}@#{rand 1000}"
            break unless self.class.users[ email ]
         end
         self.class.users[ email ] = self
         ....

is this what you want?
R.

···

On 10/25/07, Chris Czub <chris.czub@gmail.com> wrote:

    user = DefaultUser.new
    # Give them a random email address - TODO this should be changed so
that it first clears out
    # any user that might exist with that email address first to ensure
a proper creation. Oh well.
    user.email("john.doe#{rand(100)}@abc.com")

results in an error.

Why can't I use the attribute accessor? Rather - I understand why I
can't, because it was created in the User class rather than the
DefaultUser class, but how can I get access to it?
--
Posted via http://www.ruby-forum.com/\.

--
what do I think about Ruby?
http://ruby-smalltalk.blogspot.com/

Robert Dober wrote:

Why can't I use the attribute accessor? Rather - I understand why I
can't, because it was created in the User class rather than the
DefaultUser class, but how can I get access to it?
--
Posted via http://www.ruby-forum.com/\.

class User
    @users = {}
     class << self
         attr_reader :users
     end
     def initialize name
         email = nil
         loop do
            email = "#{name}@#{rand 1000}"
            break unless self.class.users[ email ]
         end
         self.class.users[ email ] = self
         ....

is this what you want?
R.

I don't really want to define it in the User class, because it might not
belong to a particular user... maybe I am not making sense.

I am writing a testing application for many web sites that require user
registrations. Each website requires similar users, but different ones
might have additional fields required of a user, so my idea is to create
a metaclass of user for each user configuration a website might require.
So, for a web site based in the UK, the metaclass looks like this:

class UKUser < User
  attribs :address3, :i_own_or_work_for_a_small,
:my_small_business_has_its, :yes_please_send_me_the_mi, :postal
  first_name( "John" )
  last_name( "Doe" )
  email( "john.doe#{rand(100)}@abc.com" )
  address1( "1 Sunshine Parkway" )
  address2( "" )
  address3( "" )
  city( "London" )
  postal( "EH15 2JJ" )
  gender( "male" )
  phone( "(555)123-4567" )
  age( "18-25" )
        my_small_business_has_its( "no" )
        i_own_or_work_for_a_small( "no" )
        yes_please_send_me_the_mi( "no" )
end

So I am able to say

user = UKUser.new
user.address3("Apartment 12")
user.my_small_business_has_its("yes")

However, I cannot do this:

user.email("bob.smith@abc.com")

Any ideas?

···

On 10/25/07, Chris Czub <chris.czub@gmail.com> wrote:

--
Posted via http://www.ruby-forum.com/\.

Chris Czub wrote:

Any ideas?

Basically the same idea as why's solution to dwenthy's array:

class User
  def self.metaclass
    class << self; self; end
  end

  def self.attribs *args
    return @attribs if args.empty?
    attr_accessor *args
    args.each do |arg|
      metaclass.instance_eval do
        define_method(arg) do |val|
          @attribs ||= {}
          @attribs[arg] = val
        end
      end
    end

    class_eval do
      define_method(:initialize) do
        self.class.attribs.each do |attrib,val|
          instance_variable_set("@#{attrib}",val)
        end
      end
    end
  end
end

class UKUser < User
  attribs :name, :age, :weight
  name "john doe"
  age 25
  weight 170
end

u = UKUser.new
puts u.name
puts u.weight
puts u.not_real

···

--
Posted via http://www.ruby-forum.com/\.

Drew Olson wrote:

Chris Czub wrote:

Any ideas?

Basically the same idea as why's solution to dwenthy's array:

Someone else responded with:
"You added a singleton method email and an accessor pair email/email= to
the User class. The email method with no arguments called on User
instances is the reader, you need to use the email= method."

which is correct - the method user.email("") only works from the
standpoint of the singleton, but you CAN call user.email = "bla" from
outside the singleton context.

···

--
Posted via http://www.ruby-forum.com/\.

Chris Czub wrote:

Drew Olson wrote:

Chris Czub wrote:

Any ideas?

Basically the same idea as why's solution to dwenthy's array:

Someone else responded with:
"You added a singleton method email and an accessor pair email/email= to
the User class. The email method with no arguments called on User
instances is the reader, you need to use the email= method."

which is correct - the method user.email("") only works from the
standpoint of the singleton, but you CAN call user.email = "bla" from
outside the singleton context.

Not really sure what you're asking here, but I can tell you what my code
does. It adds methods to the metaclass associated with each symbol
passed to the attribs method. These essentially act like class methods
for any class the inherits from User. Then, I add a instance method
#initialize that is called when new objects are created and sets the
instance variables for that object to the values given in the class
methods. Make sense?

···

--
Posted via http://www.ruby-forum.com/\.