Code Challenge Revisted

makes sense. but the approach didn't fit. rather i took a differnt more
general appraoch which i think works out better. take a look:

  def bind(meth, proc=nil, &block)
    proc = block unless proc
    meth = meth.to_s
    alias_meth = meth[-1]==61 ? "__#{meth[0..-2]}__=" : "__#{meth}__"
    self.instance_eval {
      @___procs___ = {} unless @___procs___
      @___procs___[meth]=proc
    }
    return if self.respond_to? alias_meth
    self.instance_eval <<-"EOS"
      class << self
        alias_method :#{alias_meth}, :#{meth}
        def #{meth}(*args, &block)
          return if $___trigger___ == [self, :#{meth}]
          $___trigger___ = [self, :#{meth}] if $___trigger___ == nil
          x = send(:#{alias_meth}, *args, &block)
          @___procs___['#{meth}'].call(*args) # or x = here???
          $___trigger___ = nil
          return x
        end
      end
    EOS
  end

you can see i used a global variable, $___trigger___ to store the
original activator of the event/binding. if subsequent event/bindings
cause a loop back to the original it will stop there.

this works well, i think. and is general enough to include as a
modification to the Object class. but i have two concerns that i was
wondering if you had any thoughts on.

first, only a single binding will work. trying to add another cancels
out any previous. that's okay for my use, but thinking in terms of this
being a generally usable construct, could be problematic. that's one
advantage paul's and my original notion of how to do this has over
yours, but yours deals well with blocks, so i adopted yours.

secondly, there's the question of what to return. notice my remark in
the code. if you overide a method without returning what the original
method returns this could cause program breakage. but then again, the
override might specifically want for it to return something else. and
this problem is only worsened if the first problem mentioned above is
addressed.

does that make sense?

have any thoughts on these matters?

~transami

···

On Sun, 2002-07-28 at 17:47, Rich Kilmer wrote:

In the meantime, the simple way to fix your
infinite-loop problem is to NOT propagate updates from the binding
if what you are setting is already set.

  class << self
    alias_method :#{alias_meth}, :#{meth}
    def #{meth}(*args, &block)
      return if $___trigger___ == [self, :#{meth}]
      $___trigger___ = [self, :#{meth}] if $___trigger___ == nil
      x = send(:#{alias_meth}, *args, &block)
      @___procs___['#{meth}'].call(*args)     # or x = here???
      $___trigger___ = nil
      return x
    end
  end

quick addendum:

this does not require the array of [self, :#{meth}]. self will suffice.

      return if $___trigger___ == [self, :#{meth}]
      $___trigger___ = [self, :#{meth}] if $___trigger___ == nil

should read

      return if $___trigger___ == self
      $___trigger___ = self if $___trigger___ == nil

~transami

···

On Tue, 2002-07-30 at 00:15, Tom Sawyer wrote: