Inspecting a caller environment?

Hi all,
having to design a usable environment for non
extremely-computer-literate users, I’d like them to fire
up irb with some default options via an alias and write:

foo = ‘life’
bar = ‘the universe’
baz = ‘everything’
calculate
==> 42

Here, the calculate() method would (in my dreams) inspect
the caller’s environment, find out the values of foo, bar
and baz, and use them in its calculation. Of course, in
the real thing the parameters would be a few more, and
some of them could be omitted. Is there a decent way to
accomplish this?

Thanks,
Luigi

P.S. Of course I will accept suggestions for an altogether
different way of enabling people to use my code. But
the above seems an interesting problem in its own right,
and now I got curious :slight_smile:
P.P.S. RTFM answers are welcome as well, when coupled with
the relevant reference (I did skim through the pickaxe
book, but without luck—the reflection thing only
seems to apply to the current frame…)

“Luigi Ballabio” luigi.ballabio@fastwebnet.it schrieb im Newsbeitrag
news:pan.2003.06.24.14.18.21.963302@fastwebnet.it…

Hi all,
having to design a usable environment for non
extremely-computer-literate users, I’d like them to fire
up irb with some default options via an alias and write:

foo = ‘life’
bar = ‘the universe’
baz = ‘everything’
calculate
==> 42

Here, the calculate() method would (in my dreams) inspect
the caller’s environment, find out the values of foo, bar
and baz, and use them in its calculation. Of course, in
the real thing the parameters would be a few more, and
some of them could be omitted. Is there a decent way to
accomplish this?

If you can guess the variable names you can do:

b = eval ‘x’

A simple solution to your problem is to use instance variables like this:

irb(main):001:0> @foo = ‘life’
“life”
irb(main):002:0> @bar = ‘the universe’
“the universe”
irb(main):003:0> @baz = ‘everything’
“everything”
irb(main):004:0>
irb(main):005:0* instance_variables
[“@bar”, “@foo”, “@baz”]
irb(main):006:0> instance_variables.map{|var| eval var}
[“the universe”, “life”, “everything”]
irb(main):007:0>

Regards

robert

This should produce exactly the result you are looking for:

require ‘readline’

def create_binding
return binding
end

$b = create_binding

def calculate
foo = eval ‘foo’, $b
bar = eval ‘bar’, $b
baz = eval ‘baz’, $b
if foo == ‘life’ and bar == ‘the universe’ and baz == ‘everything’
puts " ==> 42"
end
end

while line = Readline.readline('Foo> ') do
eval line, $b
end

You may need to modify the code slightly if you do not have Readline
available on your platform.

See also [ruby-talk:22963].

Paul

···

On Tue, Jun 24, 2003 at 11:31:09PM +0900, Luigi Ballabio wrote:

foo = ‘life’
bar = ‘the universe’
baz = ‘everything’
calculate
==> 42

“Luigi Ballabio” luigi.ballabio@fastwebnet.it schrieb im Newsbeitrag
news:pan.2003.06.24.14.18.21.963302@fastwebnet.it…

Hi all,
having to design a usable environment for non
extremely-computer-literate users, I’d like them to fire
up irb with some default options via an alias and write:

foo = ‘life’
bar = ‘the universe’
baz = ‘everything’
calculate
==> 42

If you can guess the variable names you can do:

b = eval ‘x’

Hmm, not if calculate is defined in another module, I think…

A simple solution to your problem is to use instance variables like this:

irb(main):001:0> @foo = ‘life’
“life”
irb(main):002:0> @bar = ‘the universe’
“the universe”
irb(main):003:0> @baz = ‘everything’
“everything”
irb(main):004:0>
irb(main):005:0* instance_variables
[“@bar”, “@foo”, “@baz”]
irb(main):006:0> instance_variables.map{|var| eval var}
[“the universe”, “life”, “everything”]
irb(main):007:0>

I like this one! Again, the eval part won’t work if calculate is
defined elsewhere, but I do know the variable names, so I can just
use them…

Thanks,
Luigi

···

On Wed, 25 Jun 2003 00:09:31 +0900, Robert Klemme wrote:

“Luigi Ballabio” luigi.ballabio@fastwebnet.it schrieb im Newsbeitrag
news:pan.2003.06.24.17.07.18.904137@fastwebnet.it…

“Luigi Ballabio” luigi.ballabio@fastwebnet.it schrieb im Newsbeitrag
news:pan.2003.06.24.14.18.21.963302@fastwebnet.it…

Hi all,
having to design a usable environment for non
extremely-computer-literate users, I’d like them to fire
up irb with some default options via an alias and write:

foo = ‘life’
bar = ‘the universe’
baz = ‘everything’
calculate
==> 42

If you can guess the variable names you can do:

b = eval ‘x’

Hmm, not if calculate is defined in another module, I think…

You can access local variables under certain circumstances, i.e., if you
get a binding from that environment:

irb(main):001:0> def bind()
irb(main):002:1> foo = “value of foo”
irb(main):003:1> binding
irb(main):004:1> end
nil
irb(main):005:0>
irb(main):006:0* b = bind
#Binding:0x2ab2aa0
irb(main):007:0>
irb(main):008:0* eval “foo”, b
“value of foo”
irb(main):009:0>

However, i guess you are right, because it will be difficult to get a
binding from the prompt’s context.

A simple solution to your problem is to use instance variables like
this:

irb(main):001:0> @foo = ‘life’
“life”
irb(main):002:0> @bar = ‘the universe’
“the universe”
irb(main):003:0> @baz = ‘everything’
“everything”
irb(main):004:0>
irb(main):005:0* instance_variables
[“@bar”, “@foo”, “@baz”]
irb(main):006:0> instance_variables.map{|var| eval var}
[“the universe”, “life”, “everything”]
irb(main):007:0>

I like this one! Again, the eval part won’t work if calculate is
defined elsewhere, but I do know the variable names, so I can just
use them…

No, that definitely works anywhere. You just need to get the object
reference of the instance that has the variables:

irb(main):001:0> class Foo
irb(main):002:1> # instances can have arbitrary variables
irb(main):003:1* def set(name, var)
irb(main):004:2> instance_eval “@#{name} = var”
irb(main):005:2> end
irb(main):006:1> end
nil
irb(main):007:0>
irb(main):008:0* f = Foo.new
#Foo:0x2aadcd0
irb(main):009:0>
irb(main):010:0* f.instance_variables

irb(main):011:0> f.instance_variables.each {|v| puts “#{v} =
#{f.instance_eval(
v ).inspect}” }

irb(main):012:0>
irb(main):013:0* f.set “foo”, “xx”
“xx”
irb(main):014:0> f.instance_variables
[“@foo”]
irb(main):015:0> f.instance_variables.each {|v| puts “#{v} =
#{f.instance_eval(
v ).inspect}” }
@foo = “xx”
[“@foo”]
irb(main):016:0>
irb(main):017:0* f.set “bar”, “baz”
“baz”
irb(main):018:0> f.instance_variables
[“@bar”, “@foo”]
irb(main):019:0> f.instance_variables.each {|v| puts “#{v} =
#{f.instance_eval(
v ).inspect}” }
@bar = “baz”
@foo = “xx”
[“@bar”, “@foo”]
irb(main):020:0>

Regards

robert
···

On Wed, 25 Jun 2003 00:09:31 +0900, Robert Klemme wrote: