Add ruby class methods or instance methods dynamically
Solution 1
Here's something re-worked to use class methods:
class B
def self.before_method
puts "before method"
end
def self.run(method)
define_singleton_method(method) do
before_method
puts "method #{method}"
end
end
end
Update: Using define_singleton_method
from Ruby 1.9 which properly assigns to the eigenclass.
Solution 2
To create instance methods dynamically, try
class Foo
LIST = %w(a b c)
LIST.each do |x|
define_method(x) do |arg|
return arg+5
end
end
end
Now any instance of Foo would have the method "a", "b", "c". Try
Foo.new.a(10)
To define class methods dynamically, try
class Foo
LIST = %w(a b c)
class << self
LIST.each do |x|
define_method(x) do |arg|
return arg+5
end
end
end
end
Then try
Foo.a(10)
Solution 3
Instance methods of an objects singleton class are singleton methods of the object itself. So if you do
class B
def self.run(method)
singleton_class = class << self; self; end
singleton_class.send(:define_method, method) do
puts "Method #{method}"
end
end
end
you can now call
B.run :foo
B.foo
=> Method foo
(Edit: added B.run :foo as per Lars Haugseth's comment)
purbon
Updated on June 28, 2022Comments
-
purbon almost 2 years
I am quite new to Ruby, so still learning. I was researching quite a bit about how to add methods dynamically, and I was successful to create instance methods, but not successful when creating class methods.
This is how I generated instance methods:
class B def before_method puts "before method" end def self.run(method) send :define_method, method do before_method puts "method #{method}" end end end class A < B run :m run :n end
Any idea about the best ways to create static methods?
My final task is to look for the best way to create "before" and "after" tasks for class methods.
-
purbon over 12 yearsCould you please tell me why its an edge case? I am quite new and would love to learn, xD!
-
tadman over 12 yearsPeople rarely create dynamic instance methods, and dynamic class methods are even rarer still. Sadly, the semantics are kind of ugly because of how infrequently it comes up. There's nothing wrong with doing it, but most people never will, that's all.
-
purbon over 12 yearsOk! Thanks! I have to say, I am learning, but quite happy with the language, although I sounds like a hype for me, xD!
-
user1678401 over 12 yearsThis probably isn't what you want: you've now added the method to Class, which means it is available in every class (B.class == Class). This is a problem especially because not every class has a 'before_method'. Try calling B.run 'foo', defining a class A and calling A.foo. It will fail with
NameError: undefined local variable or method
before_method' for A:Class` -
Lars Haugseth over 12 yearsYou'll want to do
B.run :foo
before you can callB.foo
. -
Lars Haugseth over 12 yearsYou can also avoid
send
by usingeigenclass.class_eval { define_method(method) { ... }}
-
Dave Newton over 12 yearsI thought people created dynamic methods fairly frequently in Ruby; that's where a lot of the "magic" comes from. Am I confusing terminology?
-
Marc-André Lafortune over 12 yearsEdited to use the official terminology of
singleton_class
, introduced in Ruby 1.9.2 -
purbon over 12 years@Confusion. Obviously all the magic here come throw inheritance, or could also be provided throw a mixin, lets say.
-
user1678401 over 12 years@Marc-André: ah, I wasn't aware there finally was a standard; we're still at 1.8.7. Now I'll have to unlearn our company standard 'eigenclass' :).
-
tadman over 12 yearsDynamic methods are created more often than in other languages, it's true, but that's still not something you'd ordinarily do. The syntax for creating class methods should be cleaned up so that simple questions like this aren't tricky to answer.
-
Guoliang Cao about 11 yearsAs pointed out by @Confusion, this will create methods on Class and is not what OP wants. This should not be accepted as the answer.
-
tadman almost 10 yearsThe edit here with
define_singleton_method
puts the method in the correct context.