2009-04-15 11 views
88

Esto es útil si usted está tratando de crear métodos de clase metaprogramatically:¿Cómo uso define_method para crear métodos de clase?

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 

Mi respuesta para seguir ...

Respuesta

166

Creo que en Ruby 1.9 se puede hacer esto:

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

A.loudly "my message" 

# >> MY MESSAGE 
+3

Confirmado trabajando en 1.9.2p0 – bloudermilk

+3

también 'singleton_class.define_method' – Pyro

8

Derivado de: Jay y Why, que también proporcionan maneras de hacer esto más bonita.

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

actualización: a partir de la contribución de VR a continuación; un método más concisa (siempre y cuando sólo se está definiendo un método de esta manera) que sigue siendo independiente:

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

pero tenga en cuenta que el uso de send() para acceder a métodos privados como define_method() no es necesariamente un buen idea (tengo entendido que se va en Ruby 1.9).

+0

mejor (?) alternativa puede ser poner las cosas en un módulo y luego hacer que su método create_class_method extienda el módulo a la clase ??? Ver: http://blog.jayfields.com/2008/07/ruby-underuse-of-modules.html – Chinasaur

22

prefiero utilizar envia a llamar define_method, y también me gusta crear un método metaclase para acceder a la metaclase:

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

¡Gracias! Definitivamente hay formas de hacer esto más agradable para ti. Pero si está trabajando en un complemento de código abierto, por ejemplo, creo que es mejor no bloquear el espacio de nombres con 'metaclass', por lo que es bueno saber la taquigrafía fácil e independiente. – Chinasaur

+0

Decidí ir con mi respuesta original. Según tengo entendido, usar send() para acceder a métodos privados si se va en Ruby 1.9, por lo que no me pareció una buena idea usarlo. Además, si está definiendo más de un método, la instancia_evaluación de un bloque es más clara. – Chinasaur

+0

@Vincent Robert ¿Algún enlace que explique la magia del método de metaclases? –

8

Esta es la forma más simple en Ruby 1.8+:

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

Me gusta mucho esta. Pequeño, aseado, lee bien y es portátil. Por supuesto, podrías preguntarme qué hago usando ruby ​​1.8 en 2013 ... –

4

Para ser utilizado en Rails si desea definir el método de clase S dinámicamente a partir de preocupación:

module Concerns::Testable 
    extend ActiveSupport::Concern 

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

También podría hacer algo como esto sin depender de 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

Esto funciona para mí en Ruby 1.9.3

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

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

El OP estaba pidiendo formas de definir dinámicamente métodos de clase similares a la forma en que se pueden definir los métodos usando el método 'define_method' para definir métodos de instancia. Su respuesta es simplemente la forma simple en que los métodos se definen normalmente sin metaprogramación. –

+1

Parece que no entendí la pregunta. – Greg

Cuestiones relacionadas