Question

So I'm making a gem and I've already had great input on it. Unfortunately there's a pretty important bug in it. This gem creates events that you can attach callbacks to, unfortunately, if you have a callback or an event with the same name as one of the class's public_methods, it bugs out. Here's a working example of the gem's bug with some test code underneath it:

# Portion of gem that causes bug
class DemoClass
  def initialize method_symbol
    @method = to_method(method_symbol)
  end

  def call(*args)
    @method.call(*args)
  end

  def some_private_method
    puts 'the private method was called (still bugged)'
  end

  private

  def to_method(method_symbol)
    # this right here references public methods when I don't want it to
    method(method_symbol)
  end
end

# Outside the gem
def some_method
  puts 'this is an original method being called'
end

def some_private_method
  puts 'the private method was NOT called. Bug fixed!'
end

non_bugged_instance = DemoClass.new(:some_method)
bugged_instance = DemoClass.new(:some_private_method)

non_bugged_instance.call
bugged_instance.call

Is there any way to have the private method to_method create method objects with the symbol :add that doesn't refer to the public method add, but instead the method that would be outside of that class?

Was it helpful?

Solution

The following code demonstare an example of passing a method deficed in the 'main' into a class via initializer.

class DemoClass
  def initialize method
    @method = method
  end

  def touch *args
    puts 'touch'
    @method.call *args
  end   
end

# Outside the gem
def some_method
  puts 'Unbugged method'
end

def some_private_method
  puts 'Bugged method'
end

non_bugged_instance = DemoClass.new( self.method :some_method )
bugged_instance = DemoClass.new( self.method :some_private_method )

puts "Non bugged touch"
non_bugged_instance.touch

puts "Bugged touch"
bugged_instance.touch

And output:

Non bugged touch
touch
Unbugged method
Bugged touch
touch
Bugged method

If you strongly wish to use only method names replace the class initializer with the following:

def initialize method_name
  @method = Kernel.method method_name
end

And class creation call to as:

non_bugged_instance = DemoClass.new :some_method
bugged_instance = DemoClass.new :some_private_method

But I earnestly advise to use the first option.

OTHER TIPS

Okay, so apparently, in order to reference the methods outside of the DemoClass, I needed to use the superclass method. Apparently, you also need to reference self.class or else it will try to call a public method named superclass. All together it will look like this:

# Portion of gem that causes bug
class DemoClass
  def initialize method_symbol
    @method = to_method(method_symbol)
  end

  def call(*args)
    @method.call(*args)
  end

  def some_private_method
    puts 'the private method was called (still bugged)'
  end

  private

  def to_method(method_symbol)
    # this right here references superclass methods like it's supposed to
    self.class.superclass.method(method_symbol)
  end
end

# Outside the gem
def some_method
  puts 'this is an original method being called'
end

def some_private_method
  puts 'the private method was NOT called. Bug fixed!'
end

non_bugged_instance = DemoClass.new(:some_method)
bugged_instance = DemoClass.new(:some_private_method)

non_bugged_instance.call
bugged_instance.call
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top