finding one's self in the strangest places

Discussion in 'Ruby' started by Trans, Aug 19, 2005.

  1. Trans

    Trans Guest

    Hello,

    Thought this was interesting for a numbner of reasons, not the least of
    which is that I am suprised it even works. What it is is whay to do
    dynamic module mixins, i.e. including modules with macro-like changes
    in behavior. Note that the first three lines simply add those well
    known methods to the Binding class.

    require 'nano/binding/self'
    require 'nano/binding/%5B%5D%3D' # []=
    require 'nano/binding/local_variables'

    class Module

    def module_options
    @module_options ||= {}
    end

    alias_method :include_without_options, :include

    def include(*args)
    base = self
    options = args.last.is_a?(Hash) ? args.pop : {}
    mods = args.collect do |mod|
    mod.append_dynamic_features( self, options )
    mod
    end
    include_without_options(*mods)
    end

    # Note: Is this the best name for this callback?
    def append_dynamic_features( base, options )
    mod = self
    base.module_options[mod] = options
    end

    # vars is just a dummy slot, does nothing
    def dynamic_mixin( space, *vars )
    mod = space.self
    space.local_variables.each { |v|
    default = space[v.to_sym]
    space[v.to_sym] = lambda { |base|
    base.class.module_options[mod][v.to_sym] || default }
    }
    end

    end


    # try it

    if $0 == __FILE__

    module MyDynamix

    dynamic_mixin( binding, name='Tom' ) # name is local var

    define_method( :hello ) {
    puts "Hello from #{name[self]}"
    }

    define_method( :goodbye ) {
    puts "Goodbye from #{name[self]}"
    }

    end

    class MyClass
    include MyDynamix, :name => 'George'
    end

    m = MyClass.new
    m.hello #=> Hello from George
    m.goodbye #=> Hello from George

    class MyClass2
    include MyDynamix
    end

    m = MyClass2.new
    m.hello #=> Hello from Tom
    m.goodbye #=> Hello from Tom

    end

    What amazes me about this is that 'name' in 'name[self]' is a local
    variable assigned to a lambda, yet 'self' is not and rather belongs to
    the initialized instance of the class. How is that possible? How is
    execution of the lambda deferred til later? I think this is a
    facinating example of Ruby's "juggling" abilities.

    Also, it would be nice to be able to take this one step further, if it
    were possible NOT to have to explictly pass 'binding' via
    #dyanmic_mixin or pass 'self' via the local var lambda, then it would
    be perfect.

    T.
     
    Trans, Aug 19, 2005
    #1
    1. Advertising

  2. Trans wrote:

    > What amazes me about this is that 'name' in 'name[self]' is a local
    > variable assigned to a lambda, yet 'self' is not and rather belongs to
    > the initialized instance of the class. How is that possible? How is
    > execution of the lambda deferred til later? I think this is a
    > facinating example of Ruby's "juggling" abilities.


    The concept is generally known as "closure". The closure captures variable
    bindings so you can access them later:

    12:53:16 [source]: ruby -e 'x=10;f=lambda { x }; p f.call;x=20;p f.call'
    10
    20
    12:53:23 [source]:

    > Also, it would be nice to be able to take this one step further, if it
    > were possible NOT to have to explictly pass 'binding' via
    > #dyanmic_mixin or pass 'self' via the local var lambda, then it would
    > be perfect.


    There is a module that allows access to the bindinf of the caller. This
    would help you as it would make passing a binding explicit unnecessary.

    Kind regards

    robert
     
    Robert Klemme, Aug 19, 2005
    #2
    1. Advertising

  3. Trans

    Trans Guest

    Robert Klemme wrote:

    > The concept is generally known as "closure". The closure captures variable
    > bindings so you can access them later:


    Right. In this case it just seems more facinating in how the two
    closure-spaces (I don't know the proper terminology) are intermingling.

    > 12:53:16 [source]: ruby -e 'x=10;f=lambda { x }; p f.call;x=20;p f.call'
    > 10
    > 20
    > 12:53:23 [source]:
    >
    > > Also, it would be nice to be able to take this one step further, if it
    > > were possible NOT to have to explictly pass 'binding' via
    > > #dyanmic_mixin or pass 'self' via the local var lambda, then it would
    > > be perfect.

    >
    > There is a module that allows access to the binding of the caller. This
    > would help you as it would make passing a binding explicit unnecessary.


    Thanks. Binding.of_caller is of some, but limited use. Not sure how to
    rid '[self]' with it. In playing with this I again find another of
    these methods whose "receiver" is actually the point-of-execution, in
    this case #binding. (I was recently talking Module.nesting which is one
    too). Yet with #binding, it sure would be nice if it weren't so. Then
    Binding.of_caller wouldn't be needed, and one could just do
    binding_of_caller = mod.binding.

    T.
     
    Trans, Aug 19, 2005
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Ralf W. Grosse-Kunstleve
    Replies:
    16
    Views:
    596
    Lonnie Princehouse
    Jul 11, 2005
  2. Ralf W. Grosse-Kunstleve
    Replies:
    18
    Views:
    602
    Bengt Richter
    Jul 11, 2005
  3. Ralf W. Grosse-Kunstleve
    Replies:
    2
    Views:
    409
    Dan Sommers
    Jul 12, 2005
  4. falcon
    Replies:
    0
    Views:
    381
    falcon
    Jul 31, 2005
  5. Bart Kastermans
    Replies:
    6
    Views:
    409
    Bart Kastermans
    Jul 13, 2008
Loading...

Share This Page