Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Default method for Ruby class

Tags:

ruby

Is there a way to specify a class method such that when the object is used as if it were a function, that method is called? Something like this:

class MyClass

  def some_magic_method(*args)
    # stuff happens
  end

end

# create object
myob = MyClass.new

# implicitly call some_magic_method
myob 'x'
like image 706
tscheingeld Avatar asked Apr 08 '26 02:04

tscheingeld


2 Answers

You could write a command class and make use of a ruby shortcut

class MyClass
  def self.call(text)
    puts text
  end
end

MyClass.('x')

Here MyClass.() defaults to the call class method.

like image 178
S.Spencer Avatar answered Apr 09 '26 14:04

S.Spencer


As mentioned by @CarySwoveland in the comments you can use method_missing. A basic example is as follows:

class MyClass

  def method_missing(method_name, *args)
    if method_name.match?(/[xyz]/)
      send(:magic_method, args.first) 
    else
      super
    end
  end

  def magic_method(a)
    a = 'none' if a.nil?
    "xyz-magic method; argument(s): #{a}"
  end

end

myob = MyClass.new
myob.x    #=> "xyz-magic method; argument(s): none"
myob.x(1) #=> "xyz-magic method; argument(s): 1"

myob.y    #=> "xyz-magic method; argument(s): none"
myob.z    #=> "xyz-magic method; argument(s): none"

This captures all methods named x, y or z. Our else branch sends all other undefined methods to the original method_missing:

myob.v    #=> test.rb:7:in `method_missing': undefined method `v' for
              #<MyClass:0x000000021914f8> (NoMethodError)
              #from test.rb:25:in `<main>'

What methods you capture is up to you and is determined by the regex /[xyz]/ in this case.


Key methods: BasicObject#method_missing, Object#send. For further info check out this question, read Eloquent Ruby by Russ Olsen (from which this answer references)

like image 34
Sagar Pandya Avatar answered Apr 09 '26 14:04

Sagar Pandya