Creating a Method object with method while ignoring all class's public_methods [closed]

StackOverflow https://stackoverflow.com/questions/19594941

  •  01-07-2022
  •  | 
  •  

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?

Était-ce utile?

La 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.

Autres conseils

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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top