2009-01-27 17 views
29

¿Es posible en Ruby para obtener una referencia a métodos de un objeto (me gustaría saber si esto puede hacerse sin proc/lambdas), por ejemplo, considere el siguiente código:¿Cómo puedo obtener una referencia a un método?


class X 
    def initialize 
    @map = {} 
    setup_map 
    end 

    private 
    def setup_map 
    # @map["a"] = get reference to a method 
    # @map["b"] = get reference to b method 
    # @map["c"] = get referebce to c method 
    end 

    public 
    def call(a) 
    @map["a"](a) if a > 10 
    @map["b"](a) if a > 20 
    @map["c"](a) if a > 30 
    end 

    def a(arg) 
    puts "a was called with #{arg}" 
    end 

    def b(arg) 
    puts "b was called with #{arg}" 
    end 

    def c(arg) 
    puts "c was called with #{arg}" 
    end 
end 

¿Es posible hacer tal cosa? Me gustaría evitar procs/lambdas porque quiero poder cambiar el comportamiento de A, B, C mediante subclases.

Respuesta

42

¿Quieres Object#method:

---------------------------------------------------------- Object#method 
    obj.method(sym) => method 
------------------------------------------------------------------------ 
    Looks up the named method as a receiver in obj, returning a Method 
    object (or raising NameError). The Method object acts as a closure 
    in obj's object instance, so instance variables and the value of 
    self remain available. 

     class Demo 
      def initialize(n) 
      @iv = n 
      end 
      def hello() 
      "Hello, @iv = #{@iv}" 
      end 
     end 

     k = Demo.new(99) 
     m = k.method(:hello) 
     m.call #=> "Hello, @iv = 99" 

     l = Demo.new('Fred') 
     m = l.method("hello") 
     m.call #=> "Hello, @iv = Fred" 

Ahora su código se convierte en:

private 
def setup_map 
    @map = { 
    'a' => method(:a), 
    'b' => method(:b), 
    'c' => method(:c) 
    } 
    # or, more succinctly 
    # @map = Hash.new { |_map,name| _map[name] = method(name.to_sym) } 
end 

public 
def call(arg) 
    @map["a"][arg] if arg > 10 
    @map["b"][arg] if arg > 20 
    @map["c"][arg] if arg > 30 
end 
+0

¡Genial! Eres el hombre :) – Geo

4

Usted puede hacer esto con lambdas, manteniendo la capacidad de cambiar el comportamiento en las subclases: métodos

class X 
    def initialize 
    @map = {} 
    setup_map 
    end 

    private 
    def setup_map 
    @map["a"] = lambda { |a| a(a) } 
    @map["b"] = lambda { |a| b(a) } 
    @map["c"] = lambda { |a| c(a) } 
    end 

    public 
    def call(a) 
    @map["a"].call(a) if a > 10 
    @map["b"].call(a) if a > 20 
    @map["c"].call(a) if a > 30 
    end 

    def a(arg) 
    puts "a was called with #{arg}" 
    end 

    def b(arg) 
    puts "b was called with #{arg}" 
    end 

    def c(arg) 
    puts "c was called with #{arg}" 
    end 
end 
+0

Esto funciona! Pero, ¿no hay forma de obtener una referencia real a un método? – Geo

+0

Lo mejor que puedes hacer es instalar.metodos y eso te da una variedad de cadenas. – Samuel

1

Rubí no son objetos de primera clase; implementa OO con el mensaje que pasa.

class X 
    def call(a) 
    self.send(:a, a) if a > 10 
    self.send(:b, a) if a > 20 
    self.send(:c, a) if a > 30 
    end 

    def a(arg) 
    puts "a was called with #{arg}" 
    end 

    def b(arg) 
    puts "b was called with #{arg}" 
    end 

    def c(arg) 
    puts "c was called with #{arg}" 
    end 
end 

O simplemente llamar directamente:

def call(a) 
    self.a(a) if a > 10 
    self.b(a) if a > 20 
    self.c(a) if a > 30 
end 
+0

Este fue un ejemplo simple. Para las clases que necesito escribir, tendré unos 20-30 métodos para verificar. Si los cheques no fueran muy elegantes, ¿verdad? – Geo

+0

Supuse que las declaraciones if eran aproximaciones para un cambio o búsqueda hash. "send (: a, a)" parece más simple que "@map [" a "] [arg]" para mí, más aún si hay muchos de ellos. – Ken

0

, usted puede obtener una referencia a la método por object.method(:method_name).

Por ejemplo: para obtener una referencia al método system.

m = self.method(:system) 
m.call('ls) 
Cuestiones relacionadas