如何定义一次方法,但同时将它作为类方法和实例方法

ico*_*ast 0 ruby metaprogramming

有没有办法获取实例方法并将其添加到类中(反之亦然)?

这是我的尝试,但它失败了因为Ruby不让我将实例方法绑定到类:

#!/usr/bin/env ruby

SOMETHING = :a
class SomeClass
  def some_method(variable, value)
    case SOMETHING
    when :c
      "output for case C"
    when :a, :b
      "output for A or B"
    end
  end
  # here's my failed attampt to add some_method to SomeClass:
  self.instance_method(:some_method).bind(self)
end

# it works as an instance method
bash = SomeClass.new
puts bash.some_method("EDITOR","vim")

# but not as a class method... yet
puts SomeClass.some_method("EDITOR","vim")
Run Code Online (Sandbox Code Playgroud)

错误是"bind参数必须是SomeClass的实例".换句话说,我不能调用bind(self)因为self 是类而不是类的实例.

knu*_*nut 5

你可以用这个方法定义一个模块,include然后extend你的类:

在include定义实例方法的同时,extend定义类方法.

MWE:

SOMETHING = :a

module SomeClassMeth
  def some_method(variable, value)
    case SOMETHING
    when :c
      "output for case C"
    when :a, :b
      "output for A or B"
    end
  end
end
class SomeClass
  include SomeClassMeth
  extend SomeClassMeth
end

# it works as an instance method
bash = SomeClass.new
puts bash.some_method("EDITOR","vim")

# but not as a class method... yet
puts SomeClass.some_method("EDITOR","vim")
Run Code Online (Sandbox Code Playgroud)

但是要小心,如果你使用属性:

module SomeClassMeth
  def some_method(variable, value)
      @a
  end
end
class SomeClass
  @a = "@a in class"
  include SomeClassMeth
  extend SomeClassMeth

  def initialize
    @a = "@a in initialize"
  end

end

# it works as an instance method
bash = SomeClass.new
puts bash.some_method("EDITOR","vim")         #@a in initialize

# but not as a class method... yet
puts SomeClass.some_method("EDITOR","vim")  #@a in class
Run Code Online (Sandbox Code Playgroud)