Ruby Meta Programming Dream Lover Method

Source: Internet
Author: User
Tags inheritance

This article mainly introduced the Ruby meta Programming Dream Lover Method_missing Method Detailed explanation, this article explained how I should use Method_missing, the method proxy, Define_method, when uses method_missing, the meta method and so on content , the need for friends can refer to the following

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:

The code is 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, then look ...

The code is as follows:

Class B

Define_method (: Hi) do

@b.hi

End

End

"But I have a whole bunch of methods to define!" you complained.

"No problem!" I'm selling Meng.

The code is 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.

The code is 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

The code is 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

The code is 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 to do? Yes.

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 it's a man's words! This is exactly the way ActiveRecord used to provide you with search methods based on the dynamic construction of attributes, such as Find_by_login_and_email (User_login, User_email).

The code is 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.

The code is 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:

The code is 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:

The code is 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:

The code is 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

The code is 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 * *

These three methods play an important role in the life of every Ruby programmer. 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.