define anonymous module with closure

  • Thread starter I. E. Smith-Heisters
  • Start date
I

I. E. Smith-Heisters

Hi everyone,

I want to do this:

x, y = %w(x y)
definition = lambda{def z; x; end}
y.extend Module.new(&definition)
y.z # => 'x'

I expected x to be available within the closure, but it doesn't appear
to be. The only way I've found is with module_eval:

x, y = %w(x y)
mod = Module.new
mod.module_eval "def z; #{x.inspect}; end"
y.extend mod
y.z # => 'x'

Which I guess is fine, but I'm opposed to eval, and especially
eval'ing strings, on principle.

So:

Why doesn't the first option work? I saw something somewhere about the
argument to Module::new being called within some other scope/context/
whatsit?

Is there a way to do this without eval?

Thanks!
-Ian
 
A

ara.t.howard

x, y = %w(x y)
definition = lambda{def z; x; end}
y.extend Module.new(&definition)
y.z # => 'x'



cfp:~ > cat a.rb
x, y = %w( x y )

definition = lambda{ define_method:)z){ x } }

y.extend Module.new(&definition)

p y.z # => 'x'


cfp:~ > ruby a.rb
"x"


'def' creates a new scope - you lose the closure surrounding 'x'. to
keep it use 'define_method', which takes a block - aka closure.


a @ http://codeforpeople.com/
 
I

I. E. Smith-Heisters

cfp:~ > cat a.rb
x, y = %w( x y )

definition = lambda{ define_method:)z){ x } }

y.extend Module.new(&definition)

p y.z # => 'x'

cfp:~ > ruby a.rb
"x"

'def' creates a new scope - you lose the closure surrounding 'x'.  to  
keep it use 'define_method', which takes a block - aka closure.

a @http://codeforpeople.com/

brilliant! thanks for the explanation and solution all in one.
 
A

ara.t.howard

brilliant! thanks for the explanation and solution all in one.

np. if you need a block then:

cfp:~ > cat a.rb
x, y = %w( x y )

m = Module.new do
@@x = x

def z *args, &block
block.call if block
@@x
end
end

y.extend m

p y.z # => 'x'

y.z{ puts 'you need to do it this way if you want your method to take
a block' }


cfp:~ > ruby a.rb
"x"
you need to do it this way if you want your method to take a block


a @ http://codeforpeople.com/
 
J

James M. Lawrence

Ara said:
cfp:~ > ruby a.rb
"x"
you need to do it this way if you want your method to take a block

...if you are constrained to 1.8.6.

% ruby --version
ruby 1.8.7 (2008-08-11 patchlevel 72)

class A
define_method:)f) { |x, &block|
puts "A#f argument: #{x}"
block.call(88)
}
end

A.new.f(99) { |t|
puts "block called with: #{t}"
}
# => A#f argument: 99
# block called with: 88

Now if you want default parameters, you'll need Ara's example again.
Unless you use 1.9...

% ruby --version
ruby 1.9.0 (2008-09-15 revision 19346)

class A
t = ->(a = 11, b = 22) { a + b }
define_method:)g, &t)
end

a = A.new
p a.g # => 33
p a.g(33) # => 55
p a.g(33, 44) # => 77

From what I gathered, -> was introduced because

lambda { |a = 11, b = 22| a + b }

was too difficult or ambiguous to parse. My feeling is that -> should
be avoided if at all possible, no matter how difficult.

To me, -> is a step toward ruby jumping the shark. I want to yell,
"Fonzie, don't do it!" (Excuse the Americanisms.)
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,780
Messages
2,569,608
Members
45,252
Latest member
MeredithPl

Latest Threads

Top