Triggerful Ruby Gem: create dynamic callbacks to methods
1) get rid of conditionals

I think your main problem here is the nested conditionals that litter your code. This increases complexity and tends to be less readable.

You can get rid of those conditionals using a method like this :

def make_callable(object)
  case object
  when Proc, Method then object
  when Trigger      then -&gt;(*args){ object.trigger(*args) }
  else                   -&gt;(*args){ public_send object, *args }
  end
end


so you can do things like : 

@event = make_callable(event)
@callbacks = callbacks.map{ |c| make_callable c }


This way, all your callbacks will respond to call uniformly, so you won't need conditionals anymore.

2) use inheritance

As i see it, your @progression instance variable masks the need for two different behaviors, which means two different classes : a "silent" trigger, and a "verbose" one that extends the former.

class Trigger

  # factory method to instantiate the right type of callback.
  # I slightly changed the signature from the original #initialize
  # as I thought it would make more sense this way, 
  # but it is possible to keep the original one with minor tweaks
  #
  def self.factory(verbose, event, *callbacks)
    verbose ? Verbose.new(event, *callbacks) : new(event, *callbacks)
  end

  def initialize(event, *callbacks)
    @event = make_callable(event)
    @callbacks = callbacks.map{ |c| make_callable c }
  end

  # SNIP : this class would also expose add_callback, remove_callback, etc.

  def trigger(*args)
    @callbacks.each{ |c| c.call(*args) }
  end

  private 

  def make_callable(object)
    case object
    when Proc, Method then object
    when Trigger      then -&gt;(*args){ object.trigger(*args) }
    else                   -&gt;(*args){ public_send object, *args }
    end
  end
end

class Trigger::Verbose &lt; Trigger
  def trigger(*args)
    event_data = @event.call(*args)
    super(*args, event_data)
  end
end


As you can see, this simplifies the logic a lot, and makes clear that we have two different behaviors, which is invaluable for consumers of your API.