iconoclast
iconoclast

Reputation: 22620

How to define a method once, but have it as both class method and instance method

Is there any way to take an instance method and add it to the class (or vice versa)?

Here's my attempt, but it fails because Ruby doesn't let me bind an instance method to the class:

#!/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")

The error is "bind argument must be an instance of SomeClass". In other words, I can't call bind(self) because self is the class rather than an instance of the class.

Upvotes: 0

Views: 66

Answers (1)

knut
knut

Reputation: 27855

You could define a module and include and extend it your class with this method:

With include you define the instance method, with extend you define the class method.

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")

But be careful, if you use attributes:

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

Upvotes: 5

Related Questions