是否将`def self.method_name`和`def method_name`缩短为一个方法?

时间:2017-02-04 23:29:34

标签: ruby

所以说我有这个课程:

class This
  def a(that)
    puts that
  end

  def self.b(that)
    puts that
  end
end

This.b("Hello!") # => passes
This.a("Hello!") # => fails

the_class = This.new()
the_class.b("Hello!") # => fails
the_class.a("Hello!") # => passes

有没有办法将这两个方法缩短为一个能够在未初始化的对象上调用的方法,并且能够在已初始化的对象上调用,或者我总是必须编写这样的方法两次?

2 个答案:

答案 0 :(得分:6)

您可以将功能提取到模块中,并extendinclude

module A
  def a(that)
    puts that
  end
end

class This
  include A # defines instance methods
  extend A # defines class methods
end

This.a("foo") # => "foo"
This.new.a("foo") # => "foo"

虽然我认为includeextend更常见,而不是两者兼而有之。原因是实例方法通常依赖于实例状态,而类方法则不依赖于实例方法。如果您有实例This.new并想要调用类方法,则可以使用.class,即This.new.class.a

答案 1 :(得分:1)

以下代码使用一些元编程技巧将任何类方法自动复制到该类的实例。

module AutoAddMethods

  def singleton_method_added(symbol)
    define_method(symbol, method(symbol).to_proc)
  end

end

class Foo
  extend AutoAddMethods
  @bar = 39

  def initialize
    @bar = 42
  end

  def test_one # Only added as an instance method.
    puts "One #{@bar.inspect}"
  end

  def self.test_two # Added as both an instance and class method.
    puts "Two #{@bar.inspect}"
  end

end

i = Foo.new
i.test_one
i.test_two

Foo.test_two

这是我的测试运行输出:

One 42
Two 39
Two 39

test_two方法可以从类及其实例中调用。它就像在课堂上一样运行。