Ruby Meta Programming Dream Lover Method_missing Method Detailed _ruby Topic

Source: Internet
Author: User


I recently read some articles (such as this one) to promote the use of method_missing in Ruby.



Many people are steamy with method_missing, but are not careful to deal with each other's relationship. So, I want to explore this question:



* * What should I do with method_missing *



When should you resist the temptation of method_missing



First of all, never give in to Method_missing's charms until you've taken the time to think about how well you've done it. You know, in everyday life, there's very little to make you think that you need method_missing:



Daily: Method Agent



Case: I need a way for this class to be able to use another class



This is the most common use of method_missing I have ever seen. This is particularly prevalent in gems and Rails plug-ins. Its model is similar to this:


 code as follows:

Class A
def hi
Puts "Hi from #{self.class}"
End
End


Class B
DEF initialize
@b = A.new
End

def method_missing (Method_name, *args, &block)
@b.send (Method_name, *args, &block)
End
End

A.new.hi #=> Hi from A
B.new.hi #=> Hi from A


So, B has all the instance methods of a. But let's think about what happened when we called @b.hi. Your ruby environment goes along the inheritance chain to find hi this way, in the end, just before throwing a nomethoderror, it tuned method_missing this method.





In the example above, the situation is not bad, after all, there are two trivial classes to look for. But usually, we are programming in the context of Rails or some other framework. And your Rails model inherits from ActiveRecord, and it's integrated into a bunch of other classes, so now you have a high stack to crawl ... every time you call @b.hi!



Your good base friend: Define_method



Guess now you're complaining, "but Steve, I need method_missing." I tell you, don't forget in fact besides Mistress, you also have a loyal good base friend, call Define_method.



It allows you to dynamically define a method (as the name suggests). The great thing about it is that after it has been executed (usually after your classes are loaded), these methods exist in your class, simple and straightforward. When you create these methods, there is no inheritance chain to crawl.



Define_method is very loving and reliable, and can satisfy your daily life. Don't believe me? Next look ...


code as follows:

Class B
Define_method (: Hi) do
@b.hi
End
End

"But I have a big pile of methods to define!" "You complain





"No problem!" "I sell Meng Winks


 code as follows:

Class B
[: Hi,: Bye,: Achoo,: Gesundheit].each do |name|
Define_method (name) do
@b.send (name)
End
End
End

But I am too lazy to write them all!





You're a little hard to get.


 code as follows:

Class A
# ... lots of methods in
End
Class B
A.instance_methods.each do |name|
Define_method (name) do
@b.send (name)
End
End
End

What if I want to define a method that is not the same as the original?





Easy


 code as follows:

Class A
def hi
Puts "Hi."
End
End


Class B
A.instance_methods.each do |name|
Define_method ("What_is_#{name}") do
If @b.respond_to? (name)
@b.send (name)
Else
False
End
End
End
End

B.new.what_is_hi #=> "Hi."
B.NEW.WHAT_IS_WTF #=> False


Well, the code doesn't look elegant.





There's no way to do that. If you want the code to be easier to read, check out our Ruby delegation Library and Rails ActiveRecord delegation.



Well, let's summarize and see the real power of Define_method.



Modify the example from the ruby-doc.org


 code as follows:

Class A
def Fred
Puts "in Fred"
End
def create_method (name, &block)
Self.class.send (:d efine_method, name, &block)
End
Define_method (: Wilma) {puts "Charge it!"}
End
Class B < A
Define_method (: Barney, Instance_method (: Fred))
End





A = B.new
A.barney #=> in Fred
A.wilma #=> Charge It!
A.create_method (: Betty) {P self.to_s}
A.betty #=> B



when do you use method_missing?





Now you think that there is always a time to use it, or what else do you want it? That's right.



Dynamically named method (also named, meta method)



Case: I'm going to provide a set of methods based on a pattern. These methods do things as the name suggests. I may have never called these possible methods, but they must be available when I want to use them.



Now is the words! This is exactly what ActiveRecord is doing, providing you with search methods for dynamic builds based on attributes, such as Find_by_login_and_email (User_login, User_email).





 code as follows:

def method_missing (method_id, *arguments, &block)
If match = Dynamicfindermatch.match (method_id)
Attribute_names = Match.attribute_names
Super unless all_attributes_exists? (Attribute_names)
If Match.finder?
#. The Point
End # I OCD makes me unable to omit this
# ...
Else
Super # This is important, I'll tell your why in a second
End
End





Weigh



Method_missing is a perfect tradeoff when you have a whole bunch of meta methods to define and not necessarily use.



Think about the attribute-based lookup method in ActiveRecord. To define these methods with Define_method from head to toe, ActiveRecord needs to examine all the fields in each model's table and define methods for each possible field combination.


code as follows:

Find_by_email
Find_by_login
Find_by_name
find_by_id
Find_by_email_and_login
Find_by_email_and_login_and_name
Find_by_email_and_name
# ...





If your model has 10 fields, that's 10! (362880) A lookup method needs to be defined. Imagine that when your Rails project runs, there are so many methods that need to be defined once, and the Ruby environment has to put them all in memory.



Tiger Woods can't do anything.



* * Correct way to use method_missing



(The translator's wretched note: To go home, the following brief selected passage)



1, first check



Not every call has to be processed, you should first check to see if the call matches the mode of the Meta method you need to add:


 code as follows:

def method_missing (method_id, *arguments, &block)
If method_id.to_s =~/^what_is_[\w]+/
# do your thing
End
End

2, pack up





Check well, really want to deal with, please remember to wrap the function body in your good base friend, Define_method inside. So, the next time you don't need to find a mistress:


 code as follows:

def method_missing (method_id, *arguments, &block)
If method_id.to_s =~/^what_is_[\w]+/
Self.class.send:d Efine_method, method_id do
# do your thing
End
Self.send (method_id)
End
End

3, wipe the buttocks





I can not handle the method, perhaps the parent has a way, so super:


 code as follows:

def method_missing (method_id, *arguments, &block)
If method_id.to_s =~/^what_is_[\w]+/
Self.class.send:d Efine_method, method_id do
# do your thing
End
Self.send (method_id)
Else
Super
End
End





4. Telling the world


code as follows:

def respond_to? (method_id, include_private = False)
If method_id.to_s =~/^what_is_[\w]+/
True
Else
Super
End
End

To tell others, your class does not have this method for the time being, but it can actually respond to this method.





* * Summary * *



In every Ruby Programmer's life, these three methods play an important role. Define_method is your good base friend, Method_missing is an inseparable but also need xiangjingrubin mistress, and respond_to? It is your beloved son who is so free from danger.


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.