Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > Restore Kernel.binding to a previous state

Reply
Thread Tools

Restore Kernel.binding to a previous state

 
 
Hans Sjunnesson
Guest
Posts: n/a
 
      02-22-2007
Hey all,

I'm implementing a simple queue system with which I'm evaling 'jobs',
like so:

code = lambda {eval(job)}
code.call

Where 'job' is a string containing ruby code.
The problem I'm having is that I need these jobs to evaluate in a
clean environment, uncluttered by the previous jobs. What I'd like is
something along the lines of this:

temp = Kernel.binding
code = lambda {eval(job)}
code.call
Kernel.binding = temp

Though that looks sort of dangerous.
Another idea might be to be able to create a binding which is a deep
copy of the current binding. I'm not sure if this has been done before.

 
Reply With Quote
 
 
 
 
ara.t.howard@noaa.gov
Guest
Posts: n/a
 
      02-22-2007
On Fri, 23 Feb 2007, Hans Sjunnesson wrote:

> Hey all,
>
> I'm implementing a simple queue system with which I'm evaling 'jobs',
> like so:
>
> code = lambda {eval(job)}
> code.call
>
> Where 'job' is a string containing ruby code.
> The problem I'm having is that I need these jobs to evaluate in a
> clean environment, uncluttered by the previous jobs. What I'd like is
> something along the lines of this:
>
> temp = Kernel.binding
> code = lambda {eval(job)}
> code.call
> Kernel.binding = temp
>
> Though that looks sort of dangerous.
> Another idea might be to be able to create a binding which is a deep
> copy of the current binding. I'm not sure if this has been done before.
>


http://www.linuxjournal.com/article/7922
http://codeforpeople.com/lib/ruby/rq/

if you're on windows you're out of luck though. in any case, all you need is
a closure defined early on in your program. from there you evaluate the code.
for example

harp:~ > cat a.rb
require 'thread'

jq = SizedQueue.new 1
rq = SizedQueue.new 1

runner = Thread.new do
loop do
job = jq.pop

rq.push Thread.new{
$SAFE = 4
begin
eval job
rescue Exception => e
e
end
}.value
end
end

x = 42

jq.push 'x = 42.0; x'
p rq.pop

jq.push 'x = :forty_two; x'
p rq.pop


harp:~ > ruby a.rb
42.0
:forty_two


basically you set of a thread server which, itself, is a thread. the top
level thread is a closure of the initial context, so each new thread only has
access to that clean environment. this does not reset the environment, but it
does run each job in a clean one without poluting the current one.

regards.

-a
--
be kind whenever possible... it is always possible.
- the dalai lama

 
Reply With Quote
 
 
 
 
Ben Bleything
Guest
Posts: n/a
 
      02-22-2007
On Fri, Feb 23, 2007, Hans Sjunnesson wrote:
> Where 'job' is a string containing ruby code.
> The problem I'm having is that I need these jobs to evaluate in a
> clean environment, uncluttered by the previous jobs. What I'd like is
> something along the lines of this:
>
> temp = Kernel.binding
> code = lambda {eval(job)}
> code.call
> Kernel.binding = temp


I have (what I believe to be) a similar problem in some code I'm working
on. It allows plugins written by the user to be executed, but each time
it needs a clean environment. I'm taking advantage of the fact that you
can pass eval a binding in which to execute. I have a simple binding
factory which just creates new instances of itself and returns their
binding:

class BindingFactory
def self::get_binding
return self.new.send( :binding )
end
end

eval( action, BindingFactory.get_binding )

For my purposes, it works like a charm:

>> ex1 = "a = :sym"

=> "a = :sym"
>> ex2 = "puts a"

=> "puts a"
>> eval ex1, BindingFactory.get_binding

=> :sym
>> eval ex2, BindingFactory.get_binding

NameError: undefined local variable or method `a' for #<BindingFactory:0x406f60f4>
from (irb):18:in `send'
from (irb):18:in `get_binding'
from (irb):24
from :0

Is that helpful?

Ben

 
Reply With Quote
 
Hans Sjunnesson
Guest
Posts: n/a
 
      02-22-2007
On Feb 22, 5:01 pm, Ben Bleything <(E-Mail Removed)> wrote:
> On Fri, Feb 23, 2007, Hans Sjunnesson wrote:
> > Where 'job' is a string containing ruby code.
> > The problem I'm having is that I need these jobs to evaluate in a
> > clean environment, uncluttered by the previous jobs. What I'd like is
> > something along the lines of this:

>
> > temp = Kernel.binding
> > code = lambda {eval(job)}
> > code.call
> > Kernel.binding = temp

>
> I have (what I believe to be) a similar problem in some code I'm working
> on. It allows plugins written by the user to be executed, but each time
> it needs a clean environment. I'm taking advantage of the fact that you
> can pass eval a binding in which to execute. I have a simple binding
> factory which just creates new instances of itself and returns their
> binding:
>
> class BindingFactory
> def self::get_binding
> return self.new.send( :binding )
> end
> end
>
> eval( action, BindingFactory.get_binding )
>
> For my purposes, it works like a charm:
>
> >> ex1 = "a = :sym"

> => "a = :sym"
> >> ex2 = "puts a"

> => "puts a"
> >> eval ex1, BindingFactory.get_binding

> => :sym
> >> eval ex2, BindingFactory.get_binding

>
> NameError: undefined local variable or method `a' for #<BindingFactory:0x406f60f4>
> from (irb):18:in `send'
> from (irb):18:in `get_binding'
> from (irb):24
> from :0
>
> Is that helpful?
>
> Ben


Helpful - yes, in finding out that using eval might not be what I'm
after.
I thought, at first, that a binding housed the entirety of a running
ruby process' context.

I'm wanting to run ruby snippets like the below:

require 'rake'
default = task :default do
# do stuff
end
default.invoke

But for my problem, I might be better off using Kernel::system, and
invoking ruby in an external process, even though I'd really like my
little code-snippet to be able to access, for instance, the Logger
I've set up in my queue-system.
I might get away with that by modifying your BindingFactory to pass
objects into the created binding as local variables. But stuff like
rake modify the running context in more ways than setting local
variables.

 
Reply With Quote
 
ara.t.howard@noaa.gov
Guest
Posts: n/a
 
      02-22-2007
On Fri, 23 Feb 2007, Hans Sjunnesson wrote:

>> Ben

>
> Helpful - yes, in finding out that using eval might not be what I'm
> after.
> I thought, at first, that a binding housed the entirety of a running
> ruby process' context.
>
> I'm wanting to run ruby snippets like the below:
>
> require 'rake'
> default = task :default do
> # do stuff
> end
> default.invoke
>
> But for my problem, I might be better off using Kernel::system, and
> invoking ruby in an external process, even though I'd really like my
> little code-snippet to be able to access, for instance, the Logger
> I've set up in my queue-system.
> I might get away with that by modifying your BindingFactory to pass
> objects into the created binding as local variables. But stuff like
> rake modify the running context in more ways than setting local
> variables.
>
>


why don't you fork?

-a
--
be kind whenever possible... it is always possible.
- the dalai lama

 
Reply With Quote
 
Ben Bleything
Guest
Posts: n/a
 
      02-22-2007
On Fri, Feb 23, 2007, Hans Sjunnesson wrote:
> Helpful - yes, in finding out that using eval might not be what I'm
> after. I thought, at first, that a binding housed the entirety of a
> running ruby process' context.


Sort of. It includes the context of wherever the binding was created.
If you call binding in the top level of your script, you'll get all of
that context that you can execute inside of.

> I'm wanting to run ruby snippets like the below:
>
> require 'rake'
> default = task :default do
> # do stuff
> end
> default.invoke


That's exactly what I'm doing

> But for my problem, I might be better off using Kernel::system, and
> invoking ruby in an external process, even though I'd really like my
> little code-snippet to be able to access, for instance, the Logger
> I've set up in my queue-system.


You can pretty easily inject variables into your binding. As I looked
at my code, I realized that I actually am not using the BindingFactory
idea (it was a prototype that I ended up not sticking with).

Instead, I have a Workspace class. It's got a method called #set_value
that takes a name and value and sets an instance variable and adds an
attr_reader inside the workspace's eigenclass.

Then, the tasks that I've got (I call them Command in my code) know how
to execute themselves inside a workspace, so I can just say

command.execute( workspace )

and it calls the proc inside that binding.

I'm working on getting my code released (gotta get the company to
agree), and until then I can't show too much, but I'm happy to talk
about it more if it sounds similar enough to what you're doing to help.

Ben

 
Reply With Quote
 
Hans Sjunnesson
Guest
Posts: n/a
 
      02-22-2007
On Feb 22, 8:56 pm, (E-Mail Removed) wrote:
> On Fri, 23 Feb 2007, Hans Sjunnesson wrote:
> >> Ben

>
> > Helpful - yes, in finding out that using eval might not be what I'm
> > after.
> > I thought, at first, that a binding housed the entirety of a running
> > ruby process' context.

>
> > I'm wanting to run ruby snippets like the below:

>
> > require 'rake'
> > default = task :default do
> > # do stuff
> > end
> > default.invoke

>
> > But for my problem, I might be better off using Kernel::system, and
> > invoking ruby in an external process, even though I'd really like my
> > little code-snippet to be able to access, for instance, the Logger
> > I've set up in my queue-system.
> > I might get away with that by modifying your BindingFactory to pass
> > objects into the created binding as local variables. But stuff like
> > rake modify the running context in more ways than setting local
> > variables.

>
> why don't you fork?
>
> -a
> --
> be kind whenever possible... it is always possible.
> - the dalai lama


Actually, that works perfectly. I was under the impression that
Kernel.fork wrapped native fork() and thus wasn't portable. But it
works well for what I need.


 
Reply With Quote
 
ara.t.howard@noaa.gov
Guest
Posts: n/a
 
      02-22-2007
On Fri, 23 Feb 2007, Hans Sjunnesson wrote:

>>
>> why don't you fork?
>>
>> -a
>> --
>> be kind whenever possible... it is always possible.
>> - the dalai lama

>
> Actually, that works perfectly. I was under the impression that
> Kernel.fork wrapped native fork() and thus wasn't portable. But it
> works well for what I need.
>


definitely not portable. then again, thread aren't so much either unless one
is __very__ careful with io and other blocking ops.

regards.

-a
--
be kind whenever possible... it is always possible.
- the dalai lama

 
Reply With Quote
 
Erik Veenstra
Guest
Posts: n/a
 
      02-24-2007
> The problem I'm having is that I need these jobs to evaluate
> in a clean environment, uncluttered by the previous jobs.


You could use an anonymous module to de_inspect a string:

a = "[1, 2, 3, 4]".de_inspect

gegroet,
Erik V. - http://www.erikveen.dds.nl/

----------------------------------------------------------------

class String
def de_inspect
Thread.new do
$SAFE = 4

eval(self, Module.new.module_eval{binding})
end.value
end
end

class String
def de_inspect_unsafe
eval(self, Module.new.module_eval{binding})
end
end

----------------------------------------------------------------


 
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
PLEASE HELP restore to previous date CdLSRN Computer Support 8 08-27-2007 02:36 AM
System Restore won't restore Jimi Computer Support 6 05-17-2006 01:28 AM
System restore will no longer restore Larry Hale Computer Support 2 03-16-2006 06:14 PM
Can't Restore Comp. from any Restore Point cgott Computer Information 3 10-01-2005 01:22 AM
Re: System Restore won't restore WinXP Pro NEMISIES Computer Support 0 06-27-2003 12:22 AM



Advertisments