rubyclassmethodsinstance-variablesmethod-missing

Ruby: I need help understanding the following code involving method_missing(method, *args, &block)


I came across this code while trying to learn about creating your own method_missing method, and I don't understand it. What I don't understand are these parts: method_sym[-1] == "=" and method_sym[0..-2] What do they refer to? I tried some simulations in irb, but this just returned some weird stuff.

Could anyone break it down for me? I would really appreciate it. Thanks!

class UberHash
  def method_missing(method_sym, *args, &block)
    if method_sym[-1] == "="
      instance_variable_set("@#{method_sym[0..-2]}", args[0])
    else
      instance_variable_get("@#{method_sym}")
    end
  end
end

Solution

  • method_sym, i.e. the first argument of method_missing is the Symbol instance representing the name of the method. So, for example, if you call

    a.foo
    

    and Ruby fails to find foo method, a.method_missing(:foo) will be called.

    Next, Symbol#[] method is used to return nth character of the symbol or some characters range if you pass Range into it. -1 passed into this method represent "last character". -2 represents 'the character before the last one' etc. So:

    symbol = :foo
    symbol[-1]
    # => "o"
    symbol[0..-2]
    # => "fo"
    

    args represents all the arguments passed into missing method. So, if you call your method with:

    a.foo(arg1, arg2, arg3)
    

    args in missing_method will be:

    [arg1, arg2, arg3]
    

    Methods in Ruby can be named with = at the end , that's how you create setter methods, like:

    class A
      def foo=(value)
        @foo = value
      end
    end
    

    It's regular method and A.new.foo = some_value is only a syntactic sugar, under the hood, it's equivalent to A.new.foo=(some_value). So if you call

    b.foo = 'value'
    

    and the b.foo= is not defined, Ruby is going to call:

    b.method_missing(:foo=, 'value')
    

    thus the = as method_sym[-1].