Define_method to add a Class method?

How do you use define_method (or an equivalent) to add a method to a
Class.

I want to create a class from a Database result set at runtime. I
was doing this by building a string and the evaling it, which works,
but wasn't all that rubyish and was ugly.

I am now using an Anonymous class ie Class.new{...} and everything is
great except I can't seem to create a class method this way.

I know I am missing something quite obvious, I just can't seem to
find it.

Any pointers would be greatly appreciated.

Thanks,

Walt

···

*****************************************************
Walter Szewelanczyk
IS Director
M.W. Sewall & CO. email : walter@mwsewall.com
259 Front St. Phone : (207) 442-7994 x 128
Bath, ME 04530 Fax : (207) 443-6284
*****************************************************

I'd stick with eval; it does the job. Something like this should work just
fine:

class_name = "MyClass"
code = "print 'Hello, world!\n'"
method_name = "my_method"

eval_string = <<-EVAL
  class #{class_name}
    def #{method_name}
      #{code}
    end
  end
EVAL

eval eval_string

o = MyClass.new
o.my_method #=> "Hello, world!\n"

  Sean O'Dell

···

On Friday 02 July 2004 12:42, walter@mwsewall.com wrote:

How do you use define_method (or an equivalent) to add a method to a
Class.

I want to create a class from a Database result set at runtime. I
was doing this by building a string and the evaling it, which works,
but wasn't all that rubyish and was ugly.

I am now using an Anonymous class ie Class.new{...} and everything is
great except I can't seem to create a class method this way.

I know I am missing something quite obvious, I just can't seem to
find it.

Any pointers would be greatly appreciated.

That was how original version worked, and I can seem to port
everything except the creation of the class methods using the
Class.new{...} syntax. It just seems as if I am missing something.
Can we not add a class method using define_method. I have tried it
in combination with instance_eval, module_eval, directly on the
class, within the class, etc but so far no luck.

I guess I just want to know if it can be done using a define_ method
or do we _have_ to use eval to add a class method this way.

Thanks,

Walt

···

On Friday 02 July 2004 12:42, walter@mwsewall.com wrote:
> How do you use define_method (or an equivalent) to add a method to a
> Class.
>
> I want to create a class from a Database result set at runtime. I
> was doing this by building a string and the evaling it, which works,
> but wasn't all that rubyish and was ugly.
>
> I am now using an Anonymous class ie Class.new{...} and everything
> is great except I can't seem to create a class method this way.
>
> I know I am missing something quite obvious, I just can't seem to
> find it.
>
> Any pointers would be greatly appreciated.

I'd stick with eval; it does the job. Something like this should work
just fine:

class_name = "MyClass"
code = "print 'Hello, world!\n'"
method_name = "my_method"

eval_string = <<-EVAL
  class #{class_name}
    def #{method_name}
      #{code}
    end
  end
EVAL

eval eval_string

o = MyClass.new
o.my_method #=> "Hello, world!\n"

Sean O'Dell

*****************************************************
Walter Szewelanczyk
IS Director
M.W. Sewall & CO. email : walter@mwsewall.com
259 Front St. Phone : (207) 442-7994 x 128
Bath, ME 04530 Fax : (207) 443-6284
*****************************************************

Using eval doesn't allow the method to be executed in the context in
which it was created, which is what define_method allows. You can make
it work by assigning a proc to a variable and then calling that proc
from the eval'd code, but that's overkill, since define_method does the
job:

  class Foo
    s = class << self; self; end
    l = 42 # local variable
    s.class_eval do
      define_method(:foo) do
        puts "here: #{l}"
      end
    end
  end

  Foo.foo #=> here: 42

We first get the singleton class and assign it to s, then call
define_method for the singleton class (we could call define_method from
inside the class << self block, but then we wouldn't have access to
local variables).

Paul

···

On Sat, Jul 03, 2004 at 04:53:26AM +0900, Sean O'Dell wrote:

I'd stick with eval; it does the job. Something like this should work
just fine:

Well, I can add a method to that same class I created with an eval, this way:

class MyClass
  define_method(:my_method2) do
    print("Hello, world, again!\n")
  end
end

o.my_method2 #=> "Hello, world, again!\n"

  Sean O'Dell

···

On Friday 02 July 2004 13:02, walter@mwsewall.com wrote:

> On Friday 02 July 2004 12:42, walter@mwsewall.com wrote:
> > How do you use define_method (or an equivalent) to add a method to a
> > Class.
> >
> > I want to create a class from a Database result set at runtime. I
> > was doing this by building a string and the evaling it, which works,
> > but wasn't all that rubyish and was ugly.
> >
> > I am now using an Anonymous class ie Class.new{...} and everything
> > is great except I can't seem to create a class method this way.
> >
> > I know I am missing something quite obvious, I just can't seem to
> > find it.
> >
> > Any pointers would be greatly appreciated.
>
> I'd stick with eval; it does the job. Something like this should work
> just fine:
>
> class_name = "MyClass"
> code = "print 'Hello, world!\n'"
> method_name = "my_method"
>
> eval_string = <<-EVAL
> class #{class_name}
> def #{method_name}
> #{code}
> end
> end
> EVAL
>
> eval eval_string
>
> o = MyClass.new
> o.my_method #=> "Hello, world!\n"
>
>
> Sean O'Dell

That was how original version worked, and I can seem to port
everything except the creation of the class methods using the
Class.new{...} syntax. It just seems as if I am missing something.
Can we not add a class method using define_method. I have tried it
in combination with instance_eval, module_eval, directly on the
class, within the class, etc but so far no luck.

I guess I just want to know if it can be done using a define_ method
or do we _have_ to use eval to add a class method this way.

<snip>

> I guess I just want to know if it can be done using a define_

method

> or do we _have_ to use eval to add a class method this way.

Well, I can add a method to that same class I created with an eval,
this way:

class MyClass
  define_method(:my_method2) do
    print("Hello, world, again!\n")
  end
end

o.my_method2 #=> "Hello, world, again!\n"

Sean O'Dell

that does work, but you are adding a method to an instance of the
class. I want to add a method to the class itself, and I want to be
able to do it to an anonymous class.

At this point this is purely academic. I have a working version, I
just think there is something I am not understanding as to why I can
seem to be able to dynamically add a class method. I can add dynamic
instance methods fine.

I am looking for the equivalent of

theClass = Class.new do
  def self.class_method
    puts "class_method called"
  end
end

theClass.class_method

but using define dynamically (it would really be returning something
that was passed into the method that is creating the class)

def create(data)
  Class.new{define_method('self.class_method', lamda{data.dup})}
end

puts create(%w{we made it}).class_method.join(" ")

and get "we made it"

that's the gist of what I am trying to do. As I said, its purely
academic at this point, just a curiosity.

Thanks,

Walt

···

*****************************************************
Walter Szewelanczyk
IS Director
M.W. Sewall & CO. email : walter@mwsewall.com
259 Front St. Phone : (207) 442-7994 x 128
Bath, ME 04530 Fax : (207) 443-6284
*****************************************************

walter@mwsewall.com schrieb:

<snip>
I want to add a method to the class itself, and I want to be able to do it to an anonymous class.

c = Class.new do
   class << self
     define_method :m do p "m" end
   end
end

c.m # ==> "m"

HTH

Regards,
Pit

walter@mwsewall.com schrieb:
> <snip>
> I want to add a method to the class itself, and I want to be
> able to do it to an anonymous class.

c = Class.new do
   class << self
     define_method :m do p "m" end
   end
end

c.m # ==> "m"

HTH

Regards,
Pit

Excellent, That does work as expected. I did try that previously,
but my error was trying to pass in data to that context.

def create(data)
  Class.new do
    my_lambda = lambda{data}
    define_method("instance", my_lambda) #this is fine
    
    class << self
      define_method("ok_method"){"ok method"} #this is fine
      
      # the next method will throw a
      # undefined local variable or method `my_lambda'
      # for #<Class:#<Class:0x2a67840>> (NameError)
      define_method("data_passed_in", my_lambda)
    end
  end
end
puts create("data").data_passed_in

I tried several similar variations. I'll have to look into the
scoping rules more to see how to overcome this. It just shows me I
need to study the language more.

Thanks everyone,

Walt

···

*****************************************************
Walter Szewelanczyk
IS Director
M.W. Sewall & CO. email : walter@mwsewall.com
259 Front St. Phone : (207) 442-7994 x 128
Bath, ME 04530 Fax : (207) 443-6284
*****************************************************

Hi,

At Sat, 3 Jul 2004 08:46:48 +0900,
walter@mwsewall.com wrote in [ruby-talk:105154]:

def create(data)
  Class.new do
    my_lambda = lambda{data}
    define_method("instance", my_lambda) #this is fine
    

      (class << self; self; end).class_eval do

      define_method("ok_method"){"ok method"} #this is fine
      define_method("data_passed_in", my_lambda)
    end
  end
end

Or:

  class Result
    def instance
      self.class.data_passed_in
    end
    class << self
      def ok_method
        "ok_method"
      end
      def data_passed_in
        @data
      end
    end
  end

  def create(data)
    Class.new(Result) {@data = data}
  end

···

--
Nobu Nakada

Hi,

At Sat, 3 Jul 2004 08:46:48 +0900,
walter@mwsewall.com wrote in [ruby-talk:105154]:
> def create(data)
> Class.new do
> my_lambda = lambda{data}
> define_method("instance", my_lambda) #this is fine
>
      (class << self; self; end).class_eval do
> define_method("ok_method"){"ok method"} #this is fine
> define_method("data_passed_in", my_lambda)
> end
> end
> end

Or:

  class Result
    def instance
      self.class.data_passed_in
    end
    class << self
      def ok_method
        "ok_method"
      end
      def data_passed_in
        @data
      end
    end
  end

  def create(data)
    Class.new(Result) {@data = data}
  end

--
Nobu Nakada

Thanks Nobu,

The part I missed was setting @data within the scope of the new
class.
so this now works..
  def create(data)
    Class.new do
      @data = data
      class << self
        define_method("data_passed_in"){@data}
      end
      define_method("q"){"we are in q"}
    end
  end

  create("some data").data_passed_in

Now that I look at it this morning I can't believe I missed that.
Also I didn't realize that you could pass in a Class while creating
an anonymous class and extend that in the body of new. Very cool.

Thanks again, I knew I was missing something.

Walt

···

*****************************************************
Walter Szewelanczyk
IS Director
M.W. Sewall & CO. email : walter@mwsewall.com
259 Front St. Phone : (207) 442-7994 x 128
Bath, ME 04530 Fax : (207) 443-6284
*****************************************************