2009-04-15 13 views
88

Questo è utile se si sta cercando di creare metodi di classe metaprogramatically:Come utilizzare define_method per creare metodi di classe?

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 

La mia risposta a seguire ...

risposta

166

Penso che in Ruby 1.9 si può fare questo:

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

A.loudly "my message" 

# >> MY MESSAGE 
+3

Confermato lavorando in 1.9.2p0 – bloudermilk

+3

anche 'singleton_class.define_method' – Pyro

8

Derivato da: Jay e Why, che forniscono anche modi per rendere questo più bella.

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

Aggiornamento: dal contributo di VR di seguito; un metodo più conciso (a patto che si sta definendo un solo metodo in questo modo) che è ancora autonomo:

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

ma nota che l'uso di send() per accedere a metodi privati ​​come define_method() non è necessariamente una buona idea (la mia comprensione è che sta andando via in Ruby 1.9).

+0

meglio (?) alternativa potrebbe essere quella di mettere le cose in un modulo e poi avere il tuo create_class_method estendere il modulo sulla classe ??? Vedere: http://blog.jayfields.com/2008/07/ruby-underuse-of-modules.html – Chinasaur

22

Io preferisco usare invio per chiamare define_method, e mi piace anche di creare un metodo metaclasse per accedere al metaclasse:

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

Grazie! Sicuramente ci sono modi per renderlo più bello per te. Ma se stai lavorando ad un plugin open source, ad esempio, penso che sia più bello non intasare lo spazio dei nomi con 'metaclass', quindi è bello conoscere la stenografia semplice e autonoma. – Chinasaur

+0

Ho deciso di andare con la mia risposta originale. La mia comprensione è che usando send() per accedere ai metodi privati ​​se si va via in Ruby 1.9, quindi non sembra una cosa buona da usare. Inoltre, se stai definendo più di un metodo, instance_evaling un blocco è più pulito. – Chinasaur

+0

@Vincent Robert qualsiasi link che spiegherebbe la magia del metodo metaclass? –

8

Questo è il modo più semplice in Ruby 1.8+:

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

Mi piace molto questo. Piccolo, pulito, legge bene ed è portatile. Ovviamente, potresti chiedere cosa sto facendo usando Ruby 1.8 nel 2013 ... –

4

Da utilizzare in Rails se si desidera definire il metodo di classe s dinamicamente da riguardano:

module Concerns::Testable 
    extend ActiveSupport::Concern 

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

Si potrebbe anche fare qualcosa di simile senza fare affidamento su 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

Questo funziona per me in Ruby 1.9.3

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

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

L'OP chiedeva modi per definire dinamicamente i metodi di classe in modo simile al modo in cui i metodi possono essere definiti usando il metodo 'define_method' per definire i metodi di istanza. La tua risposta è semplicemente il modo in cui i metodi vengono definiti normalmente senza metaprogrammazione. –

+1

Sembrerebbe che abbia frainteso la domanda. – Greg

Problemi correlati