Re-define class method

I've got the following:

module ClassMethods
   def class_method
     "Class method"
   end
end

class Thing
   extend ClassMethods
end

Thing.class_method
=> "Class method"

... and I want to change the behaviour of that method at runtime. I tried this:

Thing.send(:define_method, :class_method, lambda{ "replaced" })

... but I still get this:

Thing.class_method
=> "Class method"

Am I close? What's the right way to do this?

Thanks,
David

OK - I've discovered that I can do this:

Thing.class.send(:define_method, :other_method, lambda{ "other" })
Thing.other_method
=> "other"

and even redefine it:

Thing.class.send(:define_method, :other_method, lambda{ "other redefined" })
Thing.other_method
=> "other redefined"

but if I try this:

Thing.class.send(:define_method, :class_method, lambda{ "replaced" })
Thing.class_method
=> "Class method"

So it looks like I can replace class methods that I define at runtime, but not the ones that were defined at load-time. Is that correct? Am I missing a step?

Thanks,
David

···

On Jul 12, 2006, at 9:58 PM, David Chelimsky wrote:

I've got the following:

module ClassMethods
  def class_method
    "Class method"
  end
end

class Thing
  extend ClassMethods
end

Thing.class_method
=> "Class method"

... and I want to change the behaviour of that method at runtime. I tried this:

Thing.send(:define_method, :class_method, lambda{ "replaced" })

... but I still get this:

Thing.class_method
=> "Class method"

Am I close? What's the right way to do this?

Well, I discovered the solution, thanks to our friend google, and got a much better understanding of singleton classes (though the fog hasn't completely dissipated). For anyone interested:

thing_singleton_class = class << Thing; self; end
thing_singleton_class.send(:define_method, :class_method, proc { "replaced" })

Thing.class_method
=> "replaced"

Cheers,
David

···

On Jul 12, 2006, at 10:08 PM, David Chelimsky wrote:

On Jul 12, 2006, at 9:58 PM, David Chelimsky wrote:

I've got the following:

module ClassMethods
  def class_method
    "Class method"
  end
end

class Thing
  extend ClassMethods
end

Thing.class_method
=> "Class method"

... and I want to change the behaviour of that method at runtime. I tried this:

Thing.send(:define_method, :class_method, lambda{ "replaced" })

... but I still get this:

Thing.class_method
=> "Class method"

Am I close? What's the right way to do this?

OK - I've discovered that I can do this:

Thing.class.send(:define_method, :other_method, lambda{ "other" })
Thing.other_method
=> "other"

and even redefine it:

Thing.class.send(:define_method, :other_method, lambda{ "other redefined" })
Thing.other_method
=> "other redefined"

but if I try this:

Thing.class.send(:define_method, :class_method, lambda{ "replaced" })
Thing.class_method
=> "Class method"

So it looks like I can replace class methods that I define at runtime, but not the ones that were defined at load-time. Is that correct? Am I missing a step?

Thanks,
David

Hi --

···

On Thu, 13 Jul 2006, David Chelimsky wrote:

Well, I discovered the solution, thanks to our friend google, and got a much better understanding of singleton classes (though the fog hasn't completely dissipated). For anyone interested:

thing_singleton_class = class << Thing; self; end
thing_singleton_class.send(:define_method, :class_method, proc { "replaced" })

Thing.class_method
=> "replaced"

Don't forget that you can do this much more concisely (unless you have
a specific need to go the long way round):

   def Thing.class_method
     "replaced"
   end

David

--
http://www.rubypowerandlight.com => Ruby/Rails training & consultancy
Ruby for Rails => RUBY FOR RAILS, the Ruby book for
                                                     Rails developers
http://dablog.rubypal.com => D[avid ]A[. ]B[lack's][ Web]log
dblack@wobblini.net => me

Thanks David. I definitely appreciate the conciseness of this, and will use that when I know the type. The problem I'm working on requires a solution to replacing singleton methods on arbitrary types at runtime, so I think I have to stick w/ the more cryptic version. Unless you have a different suggestion - I'm just getting my head wrapped around metaprogramming and singleton classes, so all suggestions are most welcome.

Thanks,
David

···

On Jul 13, 2006, at 5:33 AM, dblack@wobblini.net wrote:

On Thu, 13 Jul 2006, David Chelimsky wrote:

thing_singleton_class = class << Thing; self; end
thing_singleton_class.send(:define_method, :class_method, proc { "replaced" })

Thing.class_method
=> "replaced"

Don't forget that you can do this much more concisely (unless you have
a specific need to go the long way round):

  def Thing.class_method
    "replaced"
  end

Hi --

thing_singleton_class = class << Thing; self; end
thing_singleton_class.send(:define_method, :class_method, proc { "replaced" })

Thing.class_method
=> "replaced"

Don't forget that you can do this much more concisely (unless you have
a specific need to go the long way round):

def Thing.class_method
   "replaced"
end

Thanks David. I definitely appreciate the conciseness of this, and will use that when I know the type. The problem I'm working on requires a solution to replacing singleton methods on arbitrary types at runtime, so I think I have to stick w/ the more cryptic version. Unless you have a different suggestion - I'm just getting my head wrapped around metaprogramming and singleton classes, so all suggestions are most welcome.

There's an intermediate version, which might be usable depending on
how much you know in advance:

   class << Thing
     def class_method
       "replaced"
     end
   end

When you need a less concise version, because you're determining
things more dynamically, I would personally tend to use class_eval and
define_method without send:

meth = "class_method"
l = lambda { "replaced" }
(class << Thing; self; end).class_eval { define_method(meth,&l) }

And hopefully we'll eventually have a Kernel#singleton_class method to
make it all a little neater :slight_smile:

David

···

On Thu, 13 Jul 2006, David Chelimsky wrote:

On Jul 13, 2006, at 5:33 AM, dblack@wobblini.net wrote:

On Thu, 13 Jul 2006, David Chelimsky wrote:

--
http://www.rubypowerandlight.com => Ruby/Rails training & consultancy
Ruby for Rails => RUBY FOR RAILS (reviewed on
                                     Slashdot, 7/12/2006!)
http://dablog.rubypal.com => D[avid ]A[. ]B[lack's][ Web]log
dblack@wobblini.net => me

You can use David's method like this:

def redefine_method_for(klass)
  def klass.class_method
    "replaced"
  end
end

redefine_method_for Thing

p Thing.class_method
#=> "replaced"

Regards,
Sean

···

On 7/13/06, David Chelimsky <david@objectmentor.com> wrote:

On Jul 13, 2006, at 5:33 AM, dblack@wobblini.net wrote:

> On Thu, 13 Jul 2006, David Chelimsky wrote:
>
>> thing_singleton_class = class << Thing; self; end
>> thing_singleton_class.send(:define_method, :class_method, proc
>> { "replaced" })
>>
>> Thing.class_method
>> => "replaced"
>
> Don't forget that you can do this much more concisely (unless you have
> a specific need to go the long way round):
>
> def Thing.class_method
> "replaced"
> end

Thanks David. I definitely appreciate the conciseness of this, and
will use that when I know the type. The problem I'm working on
requires a solution to replacing singleton methods on arbitrary types
at runtime, so I think I have to stick w/ the more cryptic version.
Unless you have a different suggestion - I'm just getting my head
wrapped around metaprogramming and singleton classes, so all
suggestions are most welcome.

Thanks,
David

Excellent! Much cleaner.

Thanks,
David

···

On Jul 13, 2006, at 6:24 AM, dblack@wobblini.net wrote:

On Thu, 13 Jul 2006, David Chelimsky wrote:

thing_singleton_class = class << Thing; self; end
thing_singleton_class.send(:define_method, :class_method, proc { "replaced" })
Thing.class_method
=> "replaced"

I would personally tend to use class_eval and define_method without send:

meth = "class_method"
l = lambda { "replaced" }
(class << Thing; self; end).class_eval { define_method(meth,&l) }

Unfortunately (actually, rather fortunately :wink: ), both the class and the method name are determined at run time. David's dynamic suggestion (elsewhere in this thread) is working quite well.

Cheers, and thanks for the help!

David

···

On Jul 13, 2006, at 7:47 AM, Sean O'Halpin wrote:

On 7/13/06, David Chelimsky <david@objectmentor.com> wrote:

On Jul 13, 2006, at 5:33 AM, dblack@wobblini.net wrote:
> Don't forget that you can do this much more concisely (unless you have
> a specific need to go the long way round):
>
> def Thing.class_method
> "replaced"
> end

You can use David's method like this:

def redefine_method_for(klass)
def klass.class_method
   "replaced"
end
end

redefine_method_for Thing

p Thing.class_method
#=> "replaced"