As a programming exercise, I've written a Ruby snippet that creates a class, instantiates two objects from that class, monkeypatches one object, and relies on method_missing to monkeypatch the other one.
Here's the deal. This works as intended:
class Monkey def chatter puts "I am a chattering monkey!" end def method_missing(m) puts "No #{m}, so I'll make one..." def screech puts "This is the new screech." end end end m1 = Monkey.new m2 = Monkey.new m1.chatter m2.chatter def m1.screech puts "Aaaaaargh!" end m1.screech m2.screech m2.screech m1.screech m2.screech
You'll notice that I have a parameter for method_missing. I did this because I was hoping to use define_method to dynamically create missing methods with the appropriate name. However, it doesn't work. In fact, even using define_method with a static name like so:
def method_missing(m) puts "No #{m}, so I'll make one..." define_method(:screech) do puts "This is the new screech." end end
Ends with the following result:
ArgumentError: wrong number of arguments (2 for 1) method method_missing in untitled document at line 9 method method_missing in untitled document at line 9 at top level in untitled document at line 26 Program exited.
What makes the error message more bewildering is that I only have one argument for method_missing
...
define_method is a method defined in Module class which you can use to create methods dynamically. To use define_method , you call it with the name of the new method and a block where the parameters of the block become the parameters of the new method.
Metaprogramming is a technique in which code operates on code rather than on data. It can be used to write programs that write code dynamically at run time. MetaProgramming gives Ruby the ability to open and modify classes, create methods on the fly and much more.
define_method
is a (private) method of the object Class. You are calling it from an instance. There is no instance method called define_method
, so it recurses to your method_missing
, this time with :define_method
(the name of the missing method), and :screech
(the sole argument you passed to define_method
).
Try this instead (to define the new method on all Monkey objects):
def method_missing(m) puts "No #{m}, so I'll make one..." self.class.send(:define_method, :screech) do puts "This is the new screech." end end
Or this (to define it only on the object it is called upon, using the object's "eigenclass"):
def method_missing(m) puts "No #{m}, so I'll make one..." class << self define_method(:screech) do puts "This is the new screech." end end end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With