ruby元程式設計之建立自己的動態方法

2022-09-26 05:30:19 字數 4003 閱讀 1215

method_missing是ruby元程式設計(metaprogramming)常用的手法。基本思想是通過實現呼叫不存在的方法,以便進行**。典型的例子是:activerecord的動態查詢(dynamic finder)。例如:我們有email屬性那麼就可以呼叫user.find_by_email('[email protected]'),雖然, activerecord::base並沒有乙個叫做find_by_email的方法。

respond_to? 並不如method_missing出名,常用在當需要確認乙個回饋物件需要確認,以便不會因為沒有反饋物件,而導致後面的呼叫出現錯誤。

下面是乙個應用這兩者的例子:

示例我們有類legislator class,現在,想要給它加乙個find_by_first_name('john')的動態呼叫。實現find(:first_name => 'john')的功能。

複製** **如下:

class legislator

#假設這是乙個真實的實現

def find(conditions = {})

end#在本身定義畢竟這是他的方法

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

endend

end那麼這個時候呼叫

複製** **如下:

legislator.respond_to?(:find_by_first_name) 

將會提示錯誤,那麼繼續

複製** **如下:

class legislator

# 省略

# it's important to know object defines respond_to to take two paramgoohxslweters: the method to check, and whether to include private methods

# def self.respond_to?(method_sym, include_private = false)

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

true

else

super

endend

end正如**注釋所述respond_to?需要兩個引數,如果,你沒有提供將會產生argumenterror。

相關反射 dry

如果我們注意到了這裡有重複的**。我們可以參考activerecord的實現封裝在activerecord::dynamicfindermatch,以便避免在method_missing和respond_to?中重複。

複製** **如下:

class legislatordynamicfindermatch

attr_accessor :attribute

def initialize(

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

@attribute = $1.to_sym

endend

def match?

@attribute != nil

endendclass legislator

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

match = legislatordynamicfindermatch.new(method_sym)

if match.match?

find(match.attribute => arguments.first)

else

super

endend

def self.respond_to?(method_sym, include_private = false)

if legislatordynamicfindermatch.new(method_sym).match?

true

else

super

endend

end快取 method_missing

重複多次的method_missing可以考慮快取。

另外乙個我們可以向activerecord 學習的是,當定義mwww.cppcns.comethod_missing的時候,傳送 now-defined方法。如下:

複製** **如下:

class legislator   

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

= legislatordynamicfindermatch.new(method_sym)

if match.match?

define_dynamic_finder(method_sym, match.attribute)

send(method_sym, arguments.first)

else

super

endend

protected

def self.define_dynamic_finder(finder, attribute)

class_eval <

def self.#(#)        # def self.find_by_first_name(first_name)

find(:# => #)   #   find(:first_name => first_name)

end                                     # end

ruby

endend測試

測試部分如下:

複製** **如下:

describe legislatordynamicfindermatch do

describe 'find_by_first_name' do

before do

&     @match = legislatordynamicfindermatch.new(:find_by_first_name)

endit 'should h**e attribute :first_name' do

@match.attribute.should == :first_name

endit 'should be a match' do

@match.should be_a_match

endend

describe 'zomg' do

before do

@match = legislatordynamicfindermatch(:zomg)

endit 'should h**e nil attribute' do

@match.attribute.should be_nil

endit 'should not be a match' do

@match.should_not be_a_match

endend

end下面是 rspec 例子:

複製** **如下:

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

本文標題: ruby元程式設計之建立自己的動態方法

本文位址:

ruby 建立自己的Ruby語言gem軟體包

準備用ruby寫一套測試自動化框架,但是好久沒有看這個東西了!也忘了很多東西!所以開此blog記錄我的學習一點一滴 今天看了gem,寫寫自己的心得體會,如何來製作我的gem檔案 首先我的機器上已經安裝了ruby1.8.5,我先查了一下我的gem版本 1 gem v 0.9.0 gem install...

物件導向的程式設計之建立物件

物件的定義 無序屬性的集合,屬性的值可以是基本值 物件或者函式.每個物件都是基於乙個應用型別建立的,這個引用型別可以是內建的 例如objectarraymath 也可以是使用者自定義的.所有的物件都是繼承自object的,因此我們可以從object著手建立物件.通過new 關鍵字建立物件 var p...

Shell程式設計之庫的建立與使用

庫的建立方法與shell指令碼一樣,只不過庫沒有實際的執行起始點。在定義庫時需要做的就是在其中定義函式以用來被其他shell指令碼呼叫。庫中的函式可以呼叫其所在庫的其他函式,也可呼叫其他庫中的函式。庫通常沒有副檔名,庫也不應以 開頭 因為它們不是被作業系統呼叫執行,而是被其他的shell呼叫 將庫包...