2009-04-15 8 views
88

Jest to przydatne, jeśli starają się stworzyć metody klasy metaprogramatically:Jak używać metody define_method do tworzenia metod klas?

def self.create_methods(method_name) 
    # To create instance methods: 
    define_method method_name do 
     ... 
    end 

    # To create class methods that refer to the args on create_methods: 
    ??? 
end 

Moja odpowiedź do naśladowania ...

Odpowiedz

166

myślę w Ruby 1.9 można to zrobić:

class A 
    define_singleton_method :loudly do |message| 
    puts message.upcase 
    end 
end 

A.loudly "my message" 

# >> MY MESSAGE 
+3

Potwierdzona praca w 1.9.2p0 – bloudermilk

+3

także 'singleton_class.define_method' – Pyro

8

Pochodzi od: Jay i Why, który również zapewnić sposoby, aby to ładniej.

self.create_class_method(method_name) 
    (class << self; self; end).instance_eval do 
    define_method method_name do 
     ... 
    end 
    end 
end 

Aktualizacja: od wkładu VR jest poniżej; sposób bardziej zwięzły (tak długo, jak masz tylko jedną metodę definiowania ten sposób), że wciąż jest samodzielna:

self.create_class_method(method_name) 
    (class << self; self; end).send(:define_method, method_name) do 
    ... 
    end 
end 

jednak pamiętać, że przy użyciu send(), aby uzyskać dostęp do prywatnych metod, takich jak define_method() niekoniecznie jest dobre pomysł (rozumiem, że odchodzi w Ruby 1.9).

+0

lepsze (?) Alternatywą może być umieszczenie rzeczy w module, a następnie twój create_class_method rozszerzyć moduł na klasę ??? Zobacz: http://blog.jayfields.com/2008/07/ruby-underuse-of-modules.html – Chinasaur

22

wolę korzystania wysłać zadzwonić define_method i lubię też utworzyć metodę metaklasa dostęp do metaklasą:

class Object 
    def metaclass 
    class << self 
     self 
    end 
    end 
end 

class MyClass 
    # Defines MyClass.my_method 
    self.metaclass.send(:define_method, :my_method) do 
    ... 
    end 
end 
+2

Dzięki! Zdecydowanie istnieją sposoby, aby uczynić to ładniejszym dla siebie. Ale jeśli na przykład pracujesz nad wtyczką open source, myślę, że lepiej jest nie zapychać przestrzeni nazw za pomocą 'metaclass', więc dobrze jest znać prosty, samodzielny skrót. – Chinasaur

+0

Postanowiłem przejść z moją oryginalną odpowiedzią. Rozumiem, że za pomocą metody send() można uzyskać dostęp do prywatnych metod, jeśli znikają w Ruby 1.9, więc nie wydaje się, że dobrze jest użyć. Plus jeśli definiujesz więcej niż jedną metodę, instance_evaling blok jest czystszy. – Chinasaur

+0

@Vincent Robert dowolny link, który wyjaśniłby magię metody metaclass? –

8

To najprostszy sposób w Ruby 1.8+:

class A 
    class << self 
    def method_name 
     ... 
    end 
    end 
end 
+1

Naprawdę podoba mi się ten. Mały, schludny, dobrze czyta i jest przenośny. Oczywiście, możesz zapytać, co robię używając ruby ​​1.8 w 2013 ... –

4

Do użycia w Railsach, jeśli chcesz zdefiniować metodę klasy s dynamicznie z niepokojem:

module Concerns::Testable 
    extend ActiveSupport::Concern 

    included do 
    singleton_class.instance_eval do 
     define_method(:test) do 
     puts 'test' 
     end 
    end 
    end 
end 
-1

Można też zrobić coś takiego bez polegania na define_method:

A.class_eval do 
    def self.class_method_name(param) 
    puts param 
    end 
end 

A.class_method_name("hello") # outputs "hello" and returns nil 
-2

To działa na mnie w Ruby 1.9.3

class B 
    def self.class_method(param) 
     puts param 
    end 
end 

B.class_method("something") # outputs "something". 
+0

Program OP był proszony o sposoby dynamicznego definiowania metod klasowych w podobny sposób, w jaki metody można definiować za pomocą metody 'define_method' służącej do definiowania metod instancji. Twoja odpowiedź to prosty sposób, w jaki metody są definiowane normalnie bez metaprogramowania. –

+1

Wygląda na to, że źle zrozumiałem to pytanie. – Greg

Powiązane problemy