Proc question

Hello,

Let’s say that I have created a proc like:

a = proc{ puts x } (NOT! a = proc{ |x| puts x })

In this case, x within the scope of the proc does not exist and proc ‘a’
is
unable to receive an argument to set it…

If I wanted to take proc ‘a’ and create another proc, which did include
arguments…

In fact, lets say I just wanted to grab an existing proc, modify the
parameters to include |*args|, knowing that within the existing proc, I
am
grabbing my passed variables from the args array, even though they, at
that
point, don’t exist…

I did find the ‘parameters’ method on Proc and I found that when a proc
has
arity of 0, parameters is an empty array, and then depending on the
argument, parameters will return something like [ [:opt, :x], [:opt, :y]
]
for |x, y| or [ [:rest, :args] ] for |*args|…

However, parameters, while it certain LOOKS like it is taking the values
if
I pass (<<) the appropriate values to it, they will not actually store.

I also played around a little bit with grabbing the binding of the proc
without parameters and then trying to create the required variables
within
that binding, but I didn’t try too hard which is probably why it didn’t
work, because in theory, that should be doable.

Is what I am attempting to do possible? Or is there a work-around that
isn’t too hacky?

Thanks in advance,

Daniel

irb(main):003:0> a.parameters.object_id
=> 70140113536380

Oh duh… I think the 108 degree heat was affecting me today :slight_smile: I did
actually, more aptly, try using send :instance_variable_set, [[:req,
:x],
[:req, :y]] without avail too…

I think someone more knowledgeable than I would have to explain exactly
why Binding#local_variable_set isn’t designed to solve problems such as
this (I’m sure there’s either a good technical, difficulty of
implementation or even language design reason). However, I do know it’s not
just that you’re doing it wrong, it just doesn’t support that behavior:

http://www.ruby-doc.org/core-2.1.2/Binding.html#method-i-local_variable_set

From the example code in the doc for that method, you can see that even
though Binding#local_variable_set works to set a variable in a binding,
actual code in the same scope that tries to reference said local variable
still raises a NameError.

While not particularly elegant, I did find a workable solution using
instance_exec or instance_exec and binding.

a, b, c = 1, 2, 3
instance_exec(&proc{ puts a, b, c }) #=> 1\n2\n3\n
However, wrapped within some sort of container like a module or method
so
we don’t have to worry about variable collisions.

Or bareword-esque within a single binding
b = binding
b.define_singleton_method(:myvar){ 3 }
b.instance_exec(&proc{ puts myvar })

Definitely a good place to start!

Thanks!

On Wed, Jul 2, 2014 at 8:18 AM, Daniel M. [email protected]
wrote:

arguments…

However, parameters, while it certain LOOKS like it is taking the values
if I pass (<<) the appropriate values to it, they will not actually store.

The array instance returned by #parameters is just for your information.
Mutating it has not effect because clearly, you’re just getting a new
array
instance each time you call #parameters (likely generated from internal
state you don’t have direct access to):

irb(main):001:0> a = proc { puts x }
=> #Proc:[email protected]:1(irb)
irb(main):002:0> a.parameters.object_id
=> 70140113542620
irb(main):003:0> a.parameters.object_id
=> 70140113536380

There is not way that I’m aware of to posthumously mutate a Proc. At
best,
you can #curry the proc to get a new proc, but that’s not a mutation of
the
original proc, just a way to “wrap” it.

I also played around a little bit with grabbing the binding of the proc
without parameters and then trying to create the required variables within
that binding, but I didn’t try too hard which is probably why it didn’t
work, because in theory, that should be doable.

Yeah, with the new #local_variable_set and #local_variable_get, it does
seem like it’d work to a.local_variable_set(:x, “hello world”) but as
you
figured out, it doesn’t, even though a.local_variable_get(:x) will
indicate
the set did in fact work.

Is what I am attempting to do possible? Or is there a work-around that
isn’t too hacky?

I think someone more knowledgeable than I would have to explain exactly
why
Binding#local_variable_set isn’t designed to solve problems such as this
(I’m sure there’s either a good technical, difficulty of implementation
or
even language design reason). However, I do know it’s not just that
you’re
doing it wrong, it just doesn’t support that behavior:

http://www.ruby-doc.org/core-2.1.2/Binding.html#method-i-local_variable_set

From the example code in the doc for that method, you can see that even
though Binding#local_variable_set works to set a variable in a
binding,
actual code in the same scope that tries to reference said local
variable
still raises a NameError.

On Wed, Jul 2, 2014 at 4:18 PM, Daniel M. [email protected]
wrote:

In fact, lets say I just wanted to grab an existing proc, modify the
parameters to include |*args|, knowing that within the existing proc, I am
grabbing my passed variables from the args array, even though they, at that
point, don’t exist…

Is what I am attempting to do possible? Or is there a work-around that isn’t
too hacky?

Frankly, I did not even fully understand what you are attempting to
do. I mean, technically yes. And there is no way I can think of that
would work. But why do you think you need that and what problem do
you want to solve with this?

Kind regards

robert

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs