2016-07-06 84 views
13

我想爲find_by特性創建一堆方法。我不想一遍又一遍地寫同樣的東西,所以我想使用元編程。define_method:如何動態創建具有參數的方法

說我想創建一個名稱查找方法,接受名稱作爲參數。我會怎麼做?我在過去使用了define_method,但是我沒有任何參數可以使用。 這是我的(壞)做法

["name", "brand"].each do |attribute| 
    define_method("self.find_by_#{attribute}") do |attr_| 
     all.each do |prod| 
     return prod if prod.attr_ == attr_ 
     end 
    end 
    end 

有什麼想法?提前致謝。

+0

請注意是否所有數據都是大型數據集,這可能會導致性能問題。另外我真心希望這是在rails的上下文之外,因爲rails已經爲每個屬性實現了'find_by_XXX'。 – engineersmnky

+1

注意:這將定義兩個名爲'self.find_by_name'和'self.find_by_brand'的方法。雖然可以創建這樣的方法,但是使用普通的方法調用語法來調用它們是不可能的,因爲'.'不是標識符中的合法字符。爲什麼要定義一個非法名稱的方法有什麼特別的理由嗎? –

+0

@engineersmnky 這不是鐵軌!都只是爲Toy商店的庫存系統返回一個'Products'數組。這是Udacity的Ruby Nanodegree的最終項目。 –

回答

19

如果我正確理解你的問題,你想是這樣的:

class Product 
    class << self 
    [:name, :brand].each do |attribute| 
     define_method :"find_by_#{attribute}" do |value| 
     all.find {|prod| prod.public_send(attribute) == value } 
     end 
    end 
    end 
end 

(我假設all方法返回一個Enu 。merable)以上

是更多或更少相當於定義這樣的兩類方法:

class Product 
    def self.find_by_name(value) 
    all.find {|prod| prod.name == value } 
    end 

    def self.find_by_brand(value) 
    all.find {|prod| prod.brand == value } 
    end 
end 
+0

這適用於我,但...你能解釋你是如何到這裏來的嗎?我搜索了'class << self',發現它打開了一個類並改變了它的行爲,但是爲什麼我需要在類內部自己做呢? –

+1

你需要這樣做,因爲你想定義一個類方法。沒有這些,'define_method'將定義一個實例方法,'define_method(「self。foo「)'在你的例子中不起作用 –

+0

非常感謝你!我會更多地研究它,讓它更適合Metaprogramming,但現在,你幫了我很多!:) –

1

,如果你看過這裏的例子http://apidock.com/ruby/Module/define_method你會發現這一個:

define_method(:my_method) do |foo, bar| # or even |*args| 
    # do something 
end 

相同

def my_method(foo, bar) 
    # do something 
end 
+1

這不斷給我一個NoMethodError:/ –

1

當你這樣做:define_method("self.find_by_#{attribute}")

這是不正確。 define_method的參數是帶有單個單詞的符號。

讓我告訴你一些正確的代碼,希望這將是明確的:

class MyClass < ActiveRecord::Base 
    ["name", "brand"].each do |attribute| 
    define_method(:"find_by_#{attribute}") do |attr_| 
     first(attribute.to_sym => attr_) 
    end 
    end 
end 

這將產生find_by_brandfind_by_name類方法。

請注意,如果您正在研究元編程,這對method_missing來說是一個很好的用例。 here's a tutorial使用method_missing來實現您將要使用的相同功能(find_by_<x>

+2

如果這是rails,那麼這是一個無用的練習,因爲'find_by_XXX'是define_method'也可以接受一個沒有問題的字符串 – engineersmnky

+0

'method_missing'是我討厭的東西,沒有簡單的方法可以找到用這種方法定義的方法,如果可能,避免使用 – akostadinov

+0

@akostadinov同意 –