I have just reviewed some in-depth concepts in ruby after a while of inactivity, today I would like to write an article about metaprogramming.
Metaprogramming concept:
According to Wikipedia:
1 2 | Metaprogramming is the writing of computer programs that write or manipulate other programs (or themselves) as their data, or that do part of the work at compile time that would otherwise be done at runtime. In many cases, this allows programmers to get more done in the same amount of time as they would take to write all the code manually, or it gives programs greater flexibility to efficiently handle new situations without recompilation. Or, more simply put: Metaprogramming is writing code that writes code during runtime to make your life easier. |
In a nutshell, metaprogramming is a technique that makes our code more flexible and dynamic. That is, it will allow the definition of methods and classes at runtime, keeping the code short and avoiding duplication.
The common method in metaprogramming
Send
Whenever you call a method on an object, you’re sending a “message” to that object. And “message” is the name of the method. The first parameter is the name of the method that we want to call, the other arguments are parameters corresponding to the parameters of the function we defined below. For example:
1 2 3 4 5 6 7 8 9 10 | class LearnSendMethod def dogs name puts "My name is " + name end end a = LearnSendMethod.new a.send(:dogs, "alsaka") |
respond_to?
This method will return true if the object responds with the input method name, it is a symbol (if you pass the string, it will also convert to symbol itself).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class LearnSendMethod def dogs name puts "My name is " + name end end a = LearnSendMethod.new if a.respond_to? :dogs a.send(:dogs, "alsaka") else puts "No method invalid" end |
However, if written as above, it can only find public methods, to find protected and private methods, you must pass the second parameter. Note that the second parameter of the method respond_to? Very important here, it denotes that respond_to? You can find all methods whose scope includes both protected and private methods. In the above example, if dogs is a private method, we would call the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class LearnSendMethod private def dogs name puts "My name is " + name end end a = LearnSendMethod.new if a.respond_to? :dogs, true a.send(:dogs, "alsaka") else puts "No method invalid" end |
instance_eval
I rewrite the above code a little to the full as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | class InstanceEvalMethod def initialize name @name = name end def dogs puts "My name is " + name end attr_reader :name end dog = InstanceEvalMethod.new "alaska" if dog.respond_to? :dogs, true dog.send(:dogs) else puts "No method invalid" end |
Currently I have called the dogs method to print out the name of the dog, but suppose in case I do not want to call the dogs method, I just want to know what the instance variable name of object a is. dog breeds were infused. Now I will use instance_eval. This method is called either block or string.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | class InstanceEvalMethod def initialize name @name = name end def dogs puts "My name is " + name end attr_reader :name end dogs = InstanceEvalMethod.new "alaska" if dog.respond_to? :dogs, true dog.instance_eval do puts @name end else puts "No method invalid" end |
module_eval, class_eval
The module_eval and class_eval methods are used on modules and classes, not objects. class_eval is an alias of module_eval. These methods are used to add / remove values of class variables from outside the class.
1 2 3 4 5 | class Dogs @@name = "alaska" end puts Dogs.class_eval("@@name") # => alaska |
Module_eval and class_eval can be used to add instance methods to a module or class. Although the two methods have different names, the functions are identical.
1 2 3 4 5 6 7 8 9 10 | class Dogs end Dogs.class_eval do def who "Pecgie" end end obj = Dogs.new puts obj.who # => Pecgie |
Note: class_eval defines instance methods, and instance_eval defines class_methods
method_missing
Method_missing is a method that ruby allows you to access inside an object and handle in case you call a method that doesn’t exist. It is a built-in method of the BasicObject class in Ruby Method_mising that takes three parameters:
- The first parameter is the name of the method you are trying to call
- The second parameter is the argument (* args) passed when calling to that method
- The third argument is a block (& block) the parameters of the method The second and third parameters can be empty if the method called does not pass the parameters.
1 2 3 4 5 6 7 8 9 | class MethodMissing def method_missing(m, *args, &block) puts "Called #{m} with #{args.inspect} and #{block}" end end MethodMissing.new.anything # => Called anything with [] and MethodMissing.new.anything(3, 4) { something } # => Called anything with [3, 4] and #<Proc: <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> :7> |
summary
Above is an important introduction about metaprogramming and some methods, there will be many other methods but within this article I only write some common methods when doing projects. Hope everyone can contribute ideas to improve the article!
References
http://ruby-metaprogramming.rubylearning.com/html/ruby_metaprogramming_3.html