Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > finding one's self in the strangest places

Reply
Thread Tools

finding one's self in the strangest places

 
 
Trans
Guest
Posts: n/a
 
      08-19-2005
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.

 
Reply With Quote
 
 
 
 
Robert Klemme
Guest
Posts: n/a
 
      08-19-2005
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

 
Reply With Quote
 
 
 
 
Trans
Guest
Posts: n/a
 
      08-19-2005

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.

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Changing self: if self is a tree how to set to a different self Bart Kastermans Python 6 07-13-2008 11:19 AM
__autoinit__ (Was: Proposal: reducing self.x=x; self.y=y;self.z=z boilerplate code) falcon Python 0 07-31-2005 05:41 PM
Re: __autoinit__ (Was: Proposal: reducing self.x=x; self.y=y;self.z=z boilerplate code) Ralf W. Grosse-Kunstleve Python 2 07-12-2005 03:20 AM
Proposal: reducing self.x=x; self.y=y; self.z=z boilerplate code Ralf W. Grosse-Kunstleve Python 16 07-11-2005 09:28 PM
__autoinit__ (Was: Proposal: reducing self.x=x; self.y=y;self.z=z boilerplate code) Ralf W. Grosse-Kunstleve Python 18 07-11-2005 04:01 PM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57