Default method for Ruby class

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

class MyClass

  def some_magic_method(*args)
    # stuff happens
  end

end

# create object
myob = MyClass.new

# implicitly call some_magic_method
myob 'x'

      

+3


source to share


3 answers


As @CarySwoveland mentioned 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 branch else

dispatches all other undefined methods to the original one method_missing

:

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

      



Which methods you use is up to you and is determined in this case by a regular expression /[xyz]/

.


Key methods: BasicObject#method_missing

, Object#send

. For more information check out this question , read "Eloquent Ruby" by Rus Olsen (from which this answer links)

+2


source


You can write a command class and use ruby ​​shortcut

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

MyClass.('x')

      



The MyClass.()

class method is used here by default call

.

+1


source


You want to call the class instance method

when the object is called as a function. This is already supported: an instance method call

is called when you "invoke" an object with a function call method ()

(see How do I reference a function in Ruby? For more details ).

class C
  def call(x)
    puts "Called with #{x}"
  end
end

obj = C.new
obj.(88) # Called with 88 => nil
obj (88) # NoMethodError: undefined method `obj' for main:Object

      

If you want the latter syntax, the horrible trick is the following (but only works at the top level if you don't bind):

module Kernel
  def method_missing(name,*args)
    obj = begin
      TOPLEVEL_BINDING.local_variable_get(name)
    rescue
      nil
    end
    return super if obj.nil? 
    obj.send :call, *args
  end
end

obj = C.new

obj 88 # Called with OK => nil

      

This example also wants to advise that you should always keep in mind who the receiver of your method calls is and what syntaxes are available for calling methods (especially if you do not include periods and parentheses).

class D
  def obj; C.new end
  def f
    #(obj) 88 # BAD 
    (obj).(88) 
    #obj() 88 # BAD 
    obj().(88) 
  end
end

      

The point is that you don't actually have functions, but methods that are called on objects. If you omit the receiver of a method call, then by default the receiver accepts the self

current object. But your example myob

does not show up as an explicit receiver (since there is no next dot as in myob.

), so the current object looks for a method myob

.

0


source







All Articles