如何获取方法的引用?

Is it possible in Ruby to get a reference to methods of an object ( I would like to know if this can be done without procs/lambdas ) , for example , consider the following code :


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

Is it possible to do such thing ? I would like to avoid procs/lambdas because I want to be able to change the behaviour of A,B,C by subclassing .

#0

You want 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"

Now your code becomes:

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

#1

You can do this with lambdas while maintaining the ability to change behavior in subclasses:

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

#2

Ruby methods aren't first-class objects; it implements OO with message passing.

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

Or just call them directly:

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

#3

You can get a reference to the method by object.method(:method_name).

Eg: To get a reference to system method.

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

推荐文章

管理关键错误:日志和电子邮件

管理关键错误:日志和电子邮件

推荐文章

实现未知行的读写的最佳方法

实现未知行的读写的最佳方法

推荐文章

如何通过本地主机从JavaMail发送邮件

如何通过本地主机从JavaMail发送邮件

推荐文章

这个C型有什么问题

这个C型有什么问题

推荐文章

手动绘制按钮、工具栏、选项卡等的渐变?

手动绘制按钮、工具栏、选项卡等的渐变?

推荐文章

asp.net防止引发事件

asp.net防止引发事件

推荐文章

如何在Firefox的“视图>工具栏”菜单中以编程方式检测特定工具栏是否已启用

如何在Firefox的“视图>工具栏”菜单中以编程方式检测特定工具栏是否已启用

推荐文章

通过JSON/AJAX更新HTML

通过JSON/AJAX更新HTML

推荐文章

Codeigniter:php在视图中不工作!

Codeigniter:php在视图中不工作!

推荐文章

如何用grails在Acegi上指定自定义盐?

如何用grails在Acegi上指定自定义盐?

推荐文章

从MySql到Excel的PHP select语句。将日期格式化为YYYYMMDD

从MySql到Excel的PHP select语句。将日期格式化为YYYYMMDD

推荐文章

如何在雪豹和其他32位/64位问题上强制Python为32位

如何在雪豹和其他32位/64位问题上强制Python为32位

推荐文章

DBD::mysql-删除数据库的问题

DBD::mysql-删除数据库的问题

推荐文章

有人能解释一下这个密码吗?

有人能解释一下这个密码吗?

推荐文章

jquery、timer或chaining函数?

jquery、timer或chaining函数?

推荐文章

是否有方法获取由LINQ查询创建的SQL?

是否有方法获取由LINQ查询创建的SQL?