Mon, 18 Sep 06

Unified method_exists method for ruby

There are loads of different ways to check whether an object (class or instance) contains a given method.

In fact, there are so many different ways that I spent some time working out what was what.

I started out testing each of the relevant Module methods on both a class and instance. This was followed up by testing each of the relevant Object methods on both a class and instance. The full test suite is here.

I summarised the results into a more compact test suite here.

I think I’m correct in stating that there’s no one way to check for the existence of a method (be it public, protected or private) on a class. However, the test results make it slightly easier to scan and create such a method – three variants none-the-less.

The same statement goes for uniformly determining the existence of a method on an instance. Once again the tests helped derive the three implementations here.

Combining these two imlpementations provides us with a uniform method to determine whether the receiver contains a method represented by method_sym.

class Object
  def method_exists?(method_sym)
    methods = public_methods + protected_methods + private_methods
    methods.include?(method_sym.to_s)
  end
end
class Class
  def method_exists?(method_sym)
    methods = public_instance_methods + protected_instance_methods + private_instance_methods
    methods.include?(method_sym.to_s)
  end
end

class Foo
  def foo; end; public :foo
  def bar; end; protected :bar
  def baz; end; private :baz
end

require 'test/unit'

Class.new(Test::Unit::TestCase) do

  def assert_not(expr)
    assert ! expr
  end

  def assert_method_exists_is_working(receiver)
    [:foo, :bar, :baz].each do |sym|
      assert receiver.method_exists?(sym)
      assert receiver.method_exists?(sym.to_s)
    end
    assert_not receiver.method_exists?(:made_up_method)
    assert_not receiver.method_exists?('made_up_method')
  end

  def test_class
    assert_method_exists_is_working(Foo)
  end

  def test_instance
    assert_method_exists_is_working(Foo.new)
  end

end

What’s the point you ask? I genuinely have no idea. I’m sure there was one when I started but then my compulsiveness took over and I had to finish for no other reason than to finish.