2010-01-10 13 views
12

Próbuję dowiedzieć się, jak tworzyć dynamicznie metodyRuby metoda class_eval

class MyClass 
    def initialize(dynamic_methods) 
    @arr = Array.new(dynamic_methods) 
    @arr.each { |m| 
     self.class.class_eval do 
     def m(*value) 
      puts value 
     end 
     end 
    } 
    end 
end 

tmp = MyClass.new ['method1', 'method2', 'method3'] 

Niestety to tylko tworzy metoda m, ale trzeba utworzyć metody oparte na wartości m, pomysły?

Odpowiedz

27

Istnieją dwa sposoby: zaakceptowanych

  1. Stosować define_method:

    @arr.each do |method| 
        self.class.class_eval do 
        define_method method do |*arguments| 
         puts arguments 
        end 
        end 
    end 
    
  2. Zastosowanie class_eval o argumencie:

    @arr.each do |method| 
        self.class.class_eval <<-EVAL 
        def #{method}(*arguments) 
         puts arguments 
        end 
        EVAL 
    end 
    

Pierwsza opcja zamienia zamknięcie na metodę, druga opcja ocenia ciąg (heredoc) i używa zwykłego wiązania metody. Druga opcja ma bardzo niewielką przewagę wydajności podczas wywoływania metod. Pierwsza opcja jest (prawdopodobnie) nieco bardziej czytelna.

+0

Dzięki, dokładnie to, czego potrzebowałem – Bob

+0

Możesz zauważyć, że musisz być bardziej ostrożny o drugiej metodzie, np. unikaj kodu, takiego jak https://github.com/rails/rails/blob/f1d8f2af72e21d41efd02488f1c2dcf829e17783/actionpack/lib/action_dispatch/routing/route_set.rb#L188-200 –

4
define_method(m) do |*values| 
    puts value 
end 
+0

Świetne, działa, ale jak określić wartość jako parametr opcjonalny? – Bob

+0

Och, po prostu dodaj do tego "*"? define_method (m) do | * wartość | – Bob

+1

Dobrze (właśnie to zredagowałem). Zwróć jednak uwagę, że '* wartość' nie oznacza" wartość jest argumentem opcjonalnym ". Oznacza to, że "wartość jest tablicą zawierającą wszystkie argumenty (z których może występować dowolny numer) – sepp2k

Powiązane problemy