Ruby Meta programming to create your own dynamic method

Source: Internet
Author: User

This article mainly introduced the Ruby metaprogramming to create its own dynamic method, this article explains the use of method_missing and respond_to? To create your own dynamic method, you need friends can refer to the following

Method_missing is a common technique for Ruby metaprogramming (metaprogramming). The basic idea is to invoke a method that does not exist by implementing a callback. A typical example is the dynamic lookup of a ActiveRecord (the Dynamics Finder). For example: We have email attributes so we can call User.find_by_email (' joe@example.com '), although, ActiveRecord::Base does not have a method called Find_by_email.

Respond_to? is not known as method_missing, often used when it is necessary to confirm that a feedback object needs to be confirmed so that no feedback object will result in a subsequent call error.

Here is an example of how to apply the two:

Example

We have classes legislator class, and now we want to add a find_by_first_name (' John ') dynamic call to it. Realize the function of find (: first_name => ' John ').

The code is as follows:

Class legislator

#假设这是一个真实的实现

def find (conditions = {})

End

#在本身定义毕竟这是他的方法

def self.method_missing (Method_sym, *arguments, &block)

# the ' argument ' is ' a Symbol, so your need to_s it if you want to pattern match

If method_sym.to_s =~/^find_by_ (. *) $/

Find ($1.to_sym => arguments.first)

Else

Super

End

End

End

So this time call

The code is as follows:

Legislator.respond_to? (: Find_by_first_name)

will prompt for an error, then continue

The code is as follows:

Class legislator

# omitted

# It's important to know Object defines respond_to to take two the method to check, and parameters:the to include PRI Vate methods

# http://www.ruby-doc.org/core/classes/Object.html#M000333

def self.respond_to? (Method_sym, include_private = False)

If method_sym.to_s =~/^find_by_ (. *) $/

True

Else

Super

End

End

End

As described in the code annotation respond_to? requires two parameters, if you do not provide will produce argumenterror.

Correlation Reflection DRY

If we notice that there are duplicate code here. We can refer to ActiveRecord implementations encapsulated in ActiveRecord::D ynamicfindermatch to avoid duplication in method_missing and respond_to.

The code is as follows:

Class Legislatordynamicfindermatch

Attr_accessor:attribute

def initialize (method_sym)

If method_sym.to_s =~/^find_by_ (. *) $/

@attribute = $1.to_sym

End

End

Def match?

@attribute!= Nil

End

End

Class legislator

def self.method_missing (Method_sym, *arguments, &block)

Match = Legislatordynamicfindermatch.new (method_sym)

If Match.match?

Find (Match.attribute => arguments.first)

Else

Super

End

End

def self.respond_to? (Method_sym, include_private = False)

If Legislatordynamicfindermatch.new (method_sym). Match?

True

Else

Super

End

End

End

Cache method_missing

Method_missing that can be repeated multiple times may consider caching.

Another thing we can learn from ActiveRecord is that when we define method_missing, we send the Now-defined method. As follows:

The code is as follows:

Class legislator

def self.method_missing (Method_sym, *arguments, &block)

Match = Legislatordynamicfindermatch.new (method_sym)

If Match.match?

Define_dynamic_finder (Method_sym, Match.attribute)

Send (Method_sym, Arguments.first)

Else

Super

End

End

Protected

def self.define_dynamic_finder (finder, attribute)

Class_eval <<-ruby

Def Self.#{finder} (#{attribute}) # def self.find_by_first_name (first_name)

Find (: #{attribute} => #{attribute}) # Find (: first_name => first_name)

End # End

Ruby

End

End

Test

The test section is as follows:

The code is as follows:

Describe Legislatordynamicfindermatch do

Describe ' find_by_first_name ' do

Before do

@match = legislatordynamicfindermatch.new (: find_by_first_name)

End

It ' should have attribute:first_name ' do

@match. Attribute.should =: first_name

End

It ' should is a match ' do

@match. Should Be_a_match

End

End

Describe ' ZOMG ' do

Before do

@match = Legislatordynamicfindermatch (: ZOMG)

End

It ' should have nil attribute ' do

@match. Attribute.should Be_nil

End

It ' should not being a match ' do

@match. Should_not Be_a_match

End

End

End

Here is the RSpec example:

The code is as follows:

Describe legislator, ' dynamic Find_by_first_name ' do

It ' should call find (: first_name => first_name) ' Do

Legislator.should_receive (: Find). With (: first_name => ' John ')

Legislator.find_by_first_name (' John ')

End

End

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.