Change Binding of a Proc

T

Trans

Is there any way to change the binding of a proc? I'm defining a proc
on the class level but I want to bind it to the instance level, eg.

class X

attr :s

dsl proc{ s+1 }, proc{ s+2 }

end

I'm able to turn the proc into an instance method, then capture the
UnboundMethod, then undefine it, then bind it to the instance in order
to call it, but that sure seems like a hek of a round about way to have
to do things.

Any better solutions?

Thanks,
T.
 
F

Florian Groß

Trans said:
I'm able to turn the proc into an instance method, then capture the
UnboundMethod, then undefine it, then bind it to the instance in order
to call it, but that sure seems like a hek of a round about way to have
to do things.

I wonder why you have to call a proc on an instance when it isn't used
as an instance method. Care to explain?
Any better solutions?

evil-ruby has Proc#self=. It's not one of the safer methods.
 
P

Pit Capitain

Trans said:
Is there any way to change the binding of a proc? I'm defining a proc
on the class level but I want to bind it to the instance level, eg.

class X
attr :s
dsl proc{ s+1 }, proc{ s+2 }
end

I'm able to turn the proc into an instance method, then capture the
UnboundMethod, then undefine it, then bind it to the instance in order
to call it, but that sure seems like a hek of a round about way to have
to do things.

Any better solutions?

instance_eval ?

Regards,
Pit
 
T

Trans

Florian said:
I wonder why you have to call a proc on an instance when it isn't used
as an instance method. Care to explain?

I'm writing a little parser and one defines a "state-machine" for the
parser to use. In it one defines tokens. The tokens can be paired
having a start and end regexp, but they can be in procs so that they
can react to parsing state. For example:

class MyMachine < StateParser::StateMachine

token :xnx, /x(.)x/, proc{ |match,state| /y#{match[1]}y/ }

end

The above would match on something like "x1x ... y1y". But also the
machine can have event hooks, and with those can also do the above like
this:

class MyMachine < StateParser::StateMachine

def initialize
@stack = []
end

token :xnx, /x(.)x/, proc{ |match,state| /y#{@stack.last}y/ }

def xnx( match, state )
puts "I just matched #{match[0]}"
@stack << match[1]
end

def end_xnx( match, state )
puts "I just end matched #{match[0]}"
@stack.pop
end

end
evil-ruby has Proc#self=. It's not one of the safer methods.

Beleive me, my current solution is evil enough as it is ;-)

T.
 
T

Trans

Pit said:
instance_eval ?

Now that seemed like a really smart solution --but when I try it I get
some really STRANGE behavior. In my code @start is assign to one of the
procs, so then:

s = @start
p s
p s.call
p machine.instance_eval{ s }
p machine.instance_eval{ s.call }
p machine.instance_eval{ s.call.call.call }

returns

#<Proc:0xb7cf868c@state_parser.rb:140>
#<Proc:0xb7cf868c@state_parser.rb:140>
#<Proc:0xb7cf868c@state_parser.rb:140>
#<Proc:0xb7cf868c@state_parser.rb:140>
#<Proc:0xb7cf868c@state_parser.rb:140>

How the hek?
 
T

Trans

Trans said:
Now that seemed like a really smart solution --but when I try it I get
some really STRANGE behavior. In my code @start is assign to one of the
procs, so then:

s = @start
p s
p s.call
p machine.instance_eval{ s }
p machine.instance_eval{ s.call }
p machine.instance_eval{ s.call.call.call }

returns

#<Proc:0xb7cf868c@state_parser.rb:140>
#<Proc:0xb7cf868c@state_parser.rb:140>
#<Proc:0xb7cf868c@state_parser.rb:140>
#<Proc:0xb7cf868c@state_parser.rb:140>
#<Proc:0xb7cf868c@state_parser.rb:140>

er...

irb(main):001:0> start = 10
=> 10
irb(main):002:0> start = lambda { start }
=> #<Proc:0xb7b2f700@(irb):2>
irb(main):003:0> start.call
=> #<Proc:0xb7b2f700@(irb):2>
 
D

David A. Black

Hi --

er...

irb(main):001:0> start = 10
=> 10
irb(main):002:0> start = lambda { start }
=> #<Proc:0xb7b2f700@(irb):2>
irb(main):003:0> start.call
=> #<Proc:0xb7b2f700@(irb):2>

That's because your lambda is a closure. It respects the binding of
start, which you've (re)bound to the lambda itself.


David
 
P

Pit Capitain

Trans said:
...
p machine.instance_eval{ s }
...

I meant: machine.instance_eval( &s )

In your tests you shouldn't define a local variable with the name of the
method you want to call in the proc:

# s = 12
x = proc { s }
machine.instance_eval( &x )

If you run this code, the "s" is resolved in the context of machine, but
if you remove the comment on the first line, the proc uses the local
variable.

Regards,
Pit
 
T

Trans

Pit said:
I meant: machine.instance_eval( &s )

In your tests you shouldn't define a local variable with the name of the
method you want to call in the proc:

# s = 12
x = proc { s }
machine.instance_eval( &x )

If you run this code, the "s" is resolved in the context of machine, but
if you remove the comment on the first line, the proc uses the local
variable.

Thanks, I'l play with it some more. Actually I realized what you meant
but I still had parameters to pass to the block -- and I don't see how
I can get those in there -- perhaps wrapping a proc in a proc?

Any which way I slice this it seems to be messy.

T.
 
T

Trans

David said:
That's because your lambda is a closure. It respects the binding of
start, which you've (re)bound to the lambda itself.

Yes, I recall this now. It's usefule with continuations. But it stills
seems odd, considering,

irb(main):001:0> s = proc { x }
=> #<Proc:0xb7b366a4@(irb):1>
irb(main):002:0> x = 1
=> 1
irb(main):003:0> s.call
NameError: undefined local variable or method `x' for main:Object
from (irb):1
from (irb):1:in `call'
from (irb):3

So I suspect it has something to do with paralled assignment?

T.
 
P

Pit Capitain

Trans said:
Thanks, I'l play with it some more. Actually I realized what you meant
but I still had parameters to pass to the block -- and I don't see how
I can get those in there -- perhaps wrapping a proc in a proc?

Any which way I slice this it seems to be messy.

Feel free to send me some more code samples, maybe even with unit tests
or another description of what you're trying to achieve. I can't promise
it, but if I have some free time I'll take a look.

Regards,
Pit
 
T

Trans

Pit said:
Feel free to send me some more code samples, maybe even with unit tests
or another description of what you're trying to achieve. I can't promise
it, but if I have some free time I'll take a look.

Regards,
Pit

Thanks Pit that's really nice of you. But I broke down and just turned
the procs into instance methods and had done with it. It works okay,
even though it's not what I originally had in mind.

I had want to soter those procs in a specal class, i.e.

class MyMachine
token :tag, proc {...}, proc {...}
end

When through

def token( name, start, stop )
tokens << Token.new( name, start, stop )
end

Later on I would have an instance of MyMachine, and I wanted to call on
those procs _as if_ they were defined as methods within it.

It just seems limiting that there'e no way to reassign the binding of a
proc. Is it really that tricky under the hood? It must be feasible b/c
I can define a method with a proc. So why isn't there an "invisible"
way to attach a proc to the instance level of a class --as if one were
defining a method, but not actually and then call on it elsewhere?

Hmmm... I guess what I'm asking for is a #bind method for Proc.

T.
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top