Binding#with

Binding#with

def with(_local_variables)
  eval("Proc.new{ |#{_local_variables.keys.join(',')}| binding

}").call(*_local_variables.values)
end

Try it:

b = binding.with(:a=>1)
b.eval('a')  #=> 1

Now, it there a way to add a “yield” to the binding? I tried:

def with(_local_variables, &_yields)
eval(“lambda{ |#{_local_variables.keys.join(’,’)},&yields| binding
}”).call(*_local_variables.values, &_yields)
end

b = binding.with{ |x| x+x}
b.eval('yields[1]')  #=> 2

but

b.eval('yield(1)')  #=> Error

On Sun, Nov 13, 2011 at 8:30 PM, Intransition [email protected]
wrote:

b.eval('a')  #=> 1

Note I had to explicitly define this in Binding to avoid the private
method
invocation.

Note that this didn’t work for me unless I passed a hash to
Binding#with,
because otherwise the syntax it generates looks like lambda{ |,&yields| binding } which is a syntax error

but

b.eval('yield(1)')  #=> Error

Seems doubtful, b/c I think yield only exists in methods, not in procs
(this is just based on behaviour I’ve experienced, not on an
implementation
level knowledge)

def l() yield 1 end
method(:l).call { |x| x + x } # => 2

vs

lambda { yield 1 }.call { |x| x + x }

~> -:1:in `block in ': no block given (yield) (LocalJumpError)

hmm… so maybe I can work around by using define_method(:temp, …
instead
of Proc.new

On Sunday, November 13, 2011 10:16:37 PM UTC-5, Josh C. wrote:

Note I had to explicitly define this in Binding to avoid the private method
invocation.

Sorry, I should have clarified that. Yes, that is the intent.

Note that this didn’t work for me unless I passed a hash to Binding#with,
because otherwise the syntax it generates looks like lambda{ |,&yields| binding } which is a syntax error

Good point, thanks.

Well, this seems to work:

def with(_hash, &_yield)
_hash = (_hash || {}).to_hash
code = <<-END
define_method(:_with) do |#{_hash.keys.join(’,’)}|
binding
end
END
(class << self; self; end).class_eval(code)
b = _with(_hash.values, &_yield)
(class << self; self; end).class_eval{ remove_method(:_with) }
return b
#eval(“Proc.new{ |#{_hash.keys.join(’,’)}| binding
}”).call(
_hash.values)
end

But alas, now I am loosing the context of original binding. Why is that?
I
thought define_method kept closure.

Try

q = 5
binding.with(:a => 10) { |x| x + x }.eval(‘yield q + a + 5’) # =>
Error

q being in the “context of the original binding”.

On Mon, Nov 14, 2011 at 10:41 AM, Intransition [email protected]
wrote:

(class << self; self; end).class_eval(code)

Not sure what you mean, it seems to work for me:

class Binding
def with(_hash={}, &_yield)
singleton_class.class_eval(<<-CODE)
define_method :_with do |#{_hash.keys.join(‘,’)}|
binding
end
CODE
bnd = _with(*_hash.values, &_yield)
singleton_class.class_eval { remove_method :_with }
bnd
end
end

RUBY_VERSION # => “1.9.3”
binding.with(:a => 10) { |x| x + x }.eval(‘yield a + 5’) # => 30

Wrapping head thoroughly round pole resulted in:

Create a new binding incorporating the current binding and

the given local settings hash and yield block.

The yield code was neccessary b/c Ruby does not respect the use

of yield in a lambda (boo hiss).

def with(_hash, &_yield)
_hash = (_hash || {}).to_hash

if _yield
  vars = eval('local_variables')
  vals = eval("[#{vars.join(',')}]")

  vars += _hash.keys
  vals += _hash.values

  code = <<-END
    def self.___with(#{vars.join(',')})
      binding
    end
    method(:___with)
  END
  eval(code).call(*vals, &_yield)

  #_args = _hash.empty? ? '' : '|' + _hash.keys.join(',') + ',&y|'
  #lamb = eval("lambda{#{_args} binding}")
  #(class << self; self; end).send(:define_method, :__temp__, &lamb)
  #method(:__temp__).call(*_hash.values, &_yield)
else
  _args = _hash.empty? ? '' : '|' + _hash.keys.join(',') + '|'
  eval("lambda{#{_args} binding}").call(*_hash.values)
end

Now, can it be thread safe?

Oh, make sure

class Hash
def to_hash; self; end unless method_defined?(:to_hash)
end

Da: Intransition [mailto:[email protected]]
Inviato: marted 15 novembre 2011 01:12
A: ruby-talk ML; [email protected]
Cc: ruby-talk ML; [email protected]
Oggetto: Re: Binding#with

Try

q = 5
binding.with(:a => 10) { |x| x + x }.eval(‘yield q + a + 5’) # =>
Error

q being in the “context of the original binding”.

Caselle da 1GB, trasmetti allegati fino a 3GB e in piu’ IMAP, POP3 e
SMTP autenticato? GRATIS solo con Email.it http://www.email.it/f

Sponsor:

Capodanno a Riccione, Pacchetto Relax: Mezza Pensione + bagno turco +
solarium + massaggio. Wifi e parcheggio gratis. 2 giorni euro 199 a
persona

Clicca qui: http://adv.email.it/cgi-bin/foclick.cgi?mid=11977&d=29-12

Da: Intransition [mailto:[email protected]]
Inviato: luned 14 novembre 2011 03:31
A: ruby-talk ML; [email protected]
Oggetto: Binding#with

Binding#with

def with(_local_variables)
  eval("Proc.new{ |#{_local_variables.keys.join(',')}| binding

}").call(*_local_variables.values)
end

Try it:

b = binding.with(:a=>1)
b.eval('a')  #=> 1

Now, it there a way to add a “yield” to the binding? I tried:

def with(_local_variables, &_yields)
eval(“lambda{ |#{_local_variables.keys.join(‘,’)},&yields| binding
}”).call(*_local_variables.values, &_yields)
end

b = binding.with{ |x| x+x}
b.eval('yields[1]')  #=> 2

but

b.eval('yield(1)')  #=> Error

Caselle da 1GB, trasmetti allegati fino a 3GB e in piu’ IMAP, POP3 e
SMTP autenticato? GRATIS solo con Email.it http://www.email.it/f

Sponsor:

Conto Arancio al 4,20%. Zero spese e massima liberta’, aprilo in due
minuti!

Clicca qui: http://adv.email.it/cgi-bin/foclick.cgi?mid=11919&d=29-12