Define_method confusery

So I have some code which adds a method to a class based on user input like
this:

···

----------------------------------------------------------------

class Klass
# Do nowt originally
end

# Get the name of a method to add
puts "Enter the name of the method to add"
$stdout.flush

methodName = gets
methodName.chomp!

puts "Adding method #{methodName}"
$stdout.flush

# Add a method called 'methodName' to Klass
Klass.class_eval do
  define_method(methodName) do |*values|
    puts "Welcome to #{methodName}!"
    puts values.to_s
  end
end

# Try to invoke the new method
instance = Klass.new
instance.send(methodName, "---", "+++")

# List the methods of Klass
Klass.methods.sort.each do |method|
  puts "Klass##{methodName}"
end

----------------------------------------------------------------

So, the code appears to work fine, in that the send() method is able to call
the newly created method. So, does anyone know why is it when I list the
methods of the class Klass afterwards, the new method does not appear?

Also, is it possible to use define_method() to add class methods to classes,
rather than just instance methods? I can't seem to get it to work.

Regards,

Martin

[snip]

# List the methods of Klass
Klass.methods.sort.each do |method|

Try Klass.instance_methods.

···

On 9/28/06, Martin Coxall <pseudo.meta@gmail.com> wrote:

  puts "Klass##{methodName}"
end

----------------------------------------------------------------

Aha! That would do it. Thanks.

Do you know if it's possible to add class methods to classes using
define_method() then? It seems to work if I do a

define_method("Klass."+methodName)

However, when I then try to invoke using

Klass.send(methodName, "some stuff")

It doesn't work.

Regards,

Martin

···

On 9/28/06, Arnaud Bergeron <abergeron@gmail.com> wrote:

On 9/28/06, Martin Coxall <pseudo.meta@gmail.com> wrote:
[snip]
>
> # List the methods of Klass
> Klass.methods.sort.each do |method|

Try Klass.instance_methods.

You need to send define_method to the classes singleton class, and
that takes a trick:

rick@frodo:/public/rubyscripts$ cat def_class_meth.rb
#! /usr/bin/ruby

···

On 9/28/06, Martin Coxall <pseudo.meta@gmail.com> wrote:

On 9/28/06, Arnaud Bergeron <abergeron@gmail.com> wrote:
>
> On 9/28/06, Martin Coxall <pseudo.meta@gmail.com> wrote:
> [snip]
> >
> > # List the methods of Klass
> > Klass.methods.sort.each do |method|
>
> Try Klass.instance_methods.

Aha! That would do it. Thanks.

Do you know if it's possible to add class methods to classes using
define_method() then? It seems to work if I do a

define_method("Klass."+methodName)

However, when I then try to invoke using

Klass.send(methodName, "some stuff")

It doesn't work.

#

def create_method(name, klazz, meth = nil, &b)
  raise ArgumentError "give method or block, but not both" if meth &&
block_given?
  if block_given?
    klazz.send(:define_method, name, &b)
  else
    klazz.send(:define_method, name, meth)
  end
end

def create_class_method(name, klazz, meth=nil, &b)
  klazz_klazz = class << klazz; self; end
  create_method(name, klazz_klazz, meth, &b)
end

class Foo
end

create_method(:foo_inst_meth, Foo) {"This is an instance method of Foo"}
create_class_method(:foo_class_meth, Foo) {"This is a class method of Foo"}

puts Foo.new.foo_inst_meth
puts Foo.foo_class_meth

rick@frodo:/public/rubyscripts$ ruby def_class_meth.rb
def_class_meth.rb:5: warning: parenthesize argument(s) for future version
This is an instance method of Foo
This is a class method of Foo
rick@frodo:/public/rubyscripts$

Note that in ruby 1.9 send won't call a private method anymore, you
need to use funcall instead.
http://eigenclass.org/hiki.rb?Changes+in+Ruby+1.9#l18

--
Rick DeNatale

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

You need to send define_method to the classes singleton class, and
that takes a trick:

Okay, I think I understand why that is, but I'd better re-read Programming Ruby on Singleton classes.

def create_class_method(name, klazz, meth=nil, &b)
klazz_klazz = class << klazz; self; end
create_method(name, klazz_klazz, meth, &b)
end

Okay, I can kind of see that. I think. Um.

Thanks very much.

Martin