Create your own dynamic method for ruby metaprogramming

Source: Internet
Author: User

Create your own dynamic method for ruby metaprogramming

This article describes how to create a dynamic method for ruby metaprogramming. This article describes how to use method_missing and respond_to? Create your own dynamic method. For more information, see

Method_missing is a common method of Ruby metaprogramming. The basic idea is to call a non-existent Method for callback. A typical example is the dynamic query of ActiveRecord (dynamic finder ). For example, if you have the email attribute, you can call User. find_by_email ('Joe @ example.com '). Although ActiveRecord: Base does not have a method called find_by_email.

Respond_to? Not like method_missing, it is often used when you need to confirm a feedback object, so that there is no feedback object, resulting in subsequent call errors.

The following is an example of an application:

Example

We have a Legislator class. Now, we want to add a dynamic call of find_by_first_name ('john') to it. Implement the find (: first_name => 'john') function.

The Code is as follows:

Class Legislator

# Assume this is a real implementation

Def find (conditions = {})

End

# This is his method after being defined

Def self. method_missing (method_sym, * arguments, & block)

# The first argument is a Symbol, so you 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

Call

The Code is as follows:

Legislator. respond_to? (: Find_by_first_name)

An error will be prompted, so proceed

The Code is as follows:

Class Legislator

# Omitted

# It's important to know Object defines respond_to take two parameters: the method to check, and whether to include private 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 comment, respond_to? Two parameters are required. If not provided, ArgumentError is generated.

Related reflection DRY

If we notice that there are repeated codes. We can refer to the implementation of ActiveRecord encapsulated in ActiveRecord: DynamicFinderMatch to avoid 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

You can consider caching the repeated method_missing.

Another thing we can learn from ActiveRecord is to send the now-defined method when defining method_missing. 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. shocould =: first_name

End

It 'should be a Match' do

@ Match. shoshould be_a_match

End

End

Describe 'zomg 'do

Before do

@ Match = LegislatorDynamicFinderMatch (: zomg)

End

It 'should have nil attribute' do

@ Match. attribute. shoshould be_nil

End

It 'should not be a Match' do

@ Match. should_not be_a_match

End

End

End

The following is an example of RSpec:

The Code is as follows:

Describe Legislator, 'dynamic find_by_first_name 'do

It 'could call find (: first_name => first_name) 'do

Legislator. should_receive (: find). with (: first_name => 'john ')

Legislator. find_by_first_name ('john ')

End

End

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.