2009-04-15 7 views
88

Dies ist nützlich, wenn Sie Klassenmethoden versuchen metaprogramatically zu erstellen:Wie verwende ich define_method um Klassenmethoden zu erstellen?

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 

Meine Antwort zu folgen ...

Antwort

166

Ich denke, in Ruby 1.9 können Sie dies tun:

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

A.loudly "my message" 

# >> MY MESSAGE 
+3

Bestätigte Arbeit in 1.9.2p0 – bloudermilk

+3

auch 'singleton_class.define_method' – Pyro

8

Abgeleitet von: Jay und Why, der auch Möglichkeiten bieten diese bisschen besser zu machen.

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

aktualisieren: von VR Beitrag unten; eine prägnante Methode (solange Sie eine Methode, um diese Art und Weise nur sind die Definition), die nach wie vor eigenständige ist:

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

aber beachten Sie, dass() mit schicken privaten Methoden wie define_method zuzugreifen() ist nicht unbedingt ein gute Idee (mein Verständnis ist, dass es in Ruby 1.9 weggeht).

+0

besser (?) Alternative kann sein, Dinge in ein Modul zu setzen und dann haben Sie Ihre create_class_method erweitern das Modul auf die Klasse ??? Siehe: http://blog.jayfields.com/2008/07/ruby-underuse-of-modules.html – Chinasaur

22

Ich ziehe define_method rufen mit senden, und Ich mag auch eine Metaklasse Methode erstellen die Metaklasse zuzugreifen:

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

Vielen Dank! Auf jeden Fall gibt es Möglichkeiten, dies für dich selbst schöner zu machen. Aber wenn Sie zum Beispiel an einem Open-Source-Plugin arbeiten, ist es besser, den Namensraum nicht mit 'Metaklasse' zu ​​verstopfen, daher ist es gut, die einfache, eigenständige Kurzschrift zu kennen. – Chinasaur

+0

Ich entschied mich, mit meiner ursprünglichen Antwort zu gehen. Mein Verständnis ist, dass send() verwendet, um auf private Methoden zuzugreifen, wenn Sie in Ruby 1.9 weggehen, so dass es nicht gut zu sein schien. Plus, wenn Sie mehr als eine Methode definieren, ist instance_evaling ein Block sauberer. – Chinasaur

+0

@Vincent Robert irgendeinen Link, der die Magie der Metaklassenmethode erklären würde? –

8

Dies ist der einfachste Weg in Ruby 1.8+:

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

Ich mag diesen wirklich. Klein, ordentlich, liest gut und ist tragbar. Natürlich könnte man fragen, was ich mit Ruby 1.8 im Jahr 2013 mache ... –

4

In Rails verwendet werden, wenn Sie Klassenmethode definieren möchten dynamisch s von Interesse:

module Concerns::Testable 
    extend ActiveSupport::Concern 

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

Sie auch, ohne sich auf define_method so etwas tun könnte:

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

Dies funktioniert für mich in Ruby 1.9.3

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

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

Das OP fragte nach Möglichkeiten, Klassenmethoden dynamisch zu definieren, ähnlich wie Methoden mit der 'define_method' Methode zur Definition von Instanzmethoden definiert werden können. Ihre Antwort ist nur die einfache Art, wie Methoden normalerweise ohne Metaprogrammierung definiert werden. –

+1

Es scheint, ich habe die Frage missverstanden. – Greg