Accessing caller's binding?

I’m trying to make a function that is called like this:

cgi.export(%w(name email phone))

which would have the same effect as this:

name = cgi['name'][0]
email = cgi['email'][0]
phone = cgi['phone'][0]

Since there doesn’t seem to be a way to get the binding of the caller
automatically, I had to try stuff like:

cgi.export(%w(name email phone), binding())
# cgi.export uses the binding to eval

and

eval cgi.export(%w(name email phone))
# cgi.export returns code to set the variables

But I can’t get it to work. Apparently, it doesn’t seem to be possible
to create a variable in this fashion. Observe the following piece of
code, which looks like it should work but doesn’t:

$ ruby -e"eval ‘x = 3’; puts x"
-e:1: undefined local variable or method `x’ for #Object:0x401ddce0 (NameError)

Does anyone have ideas on how I could create such a function, or am I
trying to do the impossible? I want to minimize the amount of code
that has to be typed by the caller.

class CGI < Hash
def initialize
self[‘name’]=[‘fred’, nil]
self[‘email’]=[‘joe@pete.com’, nil]
self[‘phone’]=[‘000-0000’, nil]
end
def export(toWhom, names)
toWhom.instance_eval(“class <<self; attr_accessor :_mycgi; end”)
toWhom._mycgi = self
names.each { |name|
toWhom.instance_eval(“def self.#{name}; _mycgi[‘#{name}’][0];
end”)
}
end
end

class SomeOtherClass
def testMethod
cgi = CGI.new
cgi.export(self, %w(name email phone))
p name
p email
p phone
end
end

s = SomeOtherClass.new
s.testMethod

···

On Tuesday 09 July 2002 05:10 pm, Philip Mak wrote:

Observe the following piece of
code, which looks like it should work but doesn’t:

$ ruby -e"eval ‘x = 3’; puts x"
-e:1: undefined local variable or method `x’ for
#Object:0x401ddce0 (NameError)

Does anyone have ideas on how I could create such a function, or am
I trying to do the impossible? I want to minimize the amount of
code that has to be typed by the caller.


Ned Konz
http://bike-nomad.com
GPG key ID: BEEA7EFE

class CGI
def

end
def export(args)
args.each { |arg| self[arg][0] }
end
end

cgi = CGI.new

p defined? name # => nil
p defined? email # => nil
p defined? phone # => nil

name, email, phone = cgi.export %w(name email phone)

p name # => “name”
p email # => “email”
p phone # => “phone”

Not exactly what you want, but maybe close enough?

– Dossy

···

On 2002.07.10, Philip Mak pmak@animeglobe.com wrote:

I’m trying to make a function that is called like this:

cgi.export(%w(name email phone))

which would have the same effect as this:

name = cgi['name'][0]
email = cgi['email'][0]
phone = cgi['phone'][0]


Dossy Shiobara mail: dossy@panoptic.com
Panoptic Computer Network web: http://www.panoptic.com/
“He realized the fastest way to change is to laugh at your own
folly – then you can let go and quickly move on.” (p. 70)

See:

[ruby-talk:12422]
[ruby-talk:22963]
[ruby-talk:31781]

None of these options is particularly good. They will likely slow your
program down significantly.

BTW, this question seems to come up pretty often, both on irc and on
c.l.r. Should it be added to the FAQ?

Paul

···

On Wed, Jul 10, 2002 at 09:10:45AM +0900, Philip Mak wrote:

Does anyone have ideas on how I could create such a function, or am I
trying to do the impossible? I want to minimize the amount of code
that has to be typed by the caller.

Philip, if i understand you correctly:

my word! i have been trying to do something similar to this for a long
time, (you may have notice a couple of other threads) and never could
figure it out. but then the other day i figured how to create class
variables (@@x) and put them in modules using a module methods to set
them and including them into my classes. this allowed me to pass a
variable to vastly disperate objects. awsome.

but then i looked over your problem. and recalled trying to do the same
kind of thing when i first started my cgi app. why? probably like you, i
wanted to dynamiclly create objects corresponding to my cgi parameters.

and guess what? you got it:

module Mod
def Mod.export(params)
params.each do |param|
attr param.intern
end
end
end

Mod.export %w(name email phone)

class AKlass

include Mod

def initialize
@name = “me”
@email = “me.com
@phone = “555-5555”
end

def showem
p name
p email
p phone
end

end

a = AKlass.new
a.showem

shouldn’t be too far a cry to integrate in with cgi.

now, i’m thinking i should go back and redo my whole
shabang…ummm…nah, i opted for an cgi ↔ xml ↔ sql library i
wrote instead. it was a tough task, but works nicely.

~transami

···

On Tue, 2002-07-09 at 18:10, Philip Mak wrote:

I’m trying to make a function that is called like this:

cgi.export(%w(name email phone))

which would have the same effect as this:

name = cgi['name'][0]
email = cgi['email'][0]
phone = cgi['phone'][0]

Since there doesn’t seem to be a way to get the binding of the caller
automatically, I had to try stuff like:

cgi.export(%w(name email phone), binding())
# cgi.export uses the binding to eval

and

eval cgi.export(%w(name email phone))
# cgi.export returns code to set the variables

But I can’t get it to work. Apparently, it doesn’t seem to be possible
to create a variable in this fashion. Observe the following piece of
code, which looks like it should work but doesn’t:

$ ruby -e"eval ‘x = 3’; puts x"
-e:1: undefined local variable or method `x’ for #Object:0x401ddce0 (NameError)

Does anyone have ideas on how I could create such a function, or am I
trying to do the impossible? I want to minimize the amount of code
that has to be typed by the caller.


~transami

“They that can give up essential liberty to obtain a little
temporary safety deserve neither liberty nor safety.”
– Benjamin Franklin

-snip-

Thanks! That code solved the puzzle for me and taught me the
following:

  1. Use instance_eval, allowing me to pass ‘self’ instead of having
    to type ‘binding()’, or ‘eval’ a block of returned code (which
    is dangerous now that I think about it, if the variable names
    contain unsafe characters).

  2. Even if I can’t define a variable inside eval(), I can still
    define a function with the same name that returns the value I want.

The way #2 works seems a bit awkward, but it works.

So, here’s what I’m doing now:

class CGI
def export(target, vars)
vars.each do |var|
target.instance_eval(“def self.#{var}; $cgi[’#{var}’][0]; end”)
end
end
end

$cgi.export(self, %w(name phone email))

(I was able to remove the _mycgi stuff because in my application,
there’s a global variable called $cgi that is initialized to CGI.new
at the beginning of every new HTTP request.)

Thanks again.

···

On Wed, Jul 10, 2002 at 10:03:36AM +0900, Ned Konz wrote:

Well, then, you could do this:

class MyClass
def method_missing(sym, *args)
if $cgi.has_key?(sym) && args.size < 2
return $cgi[sym.to_s][ args[0] || 0 ]
end
super
end
end

which would look up methods as keys in $cgi, optionally passing
indexes:

name => $cgi[‘name’][0]
name(1) => $cgi[‘name’][1]

···

On Wednesday 10 July 2002 10:49 am, Philip Mak wrote:

(I was able to remove the _mycgi stuff because in my application,
there’s a global variable called $cgi that is initialized to
CGI.new at the beginning of every new HTTP request.)


Ned Konz
http://bike-nomad.com
GPG key ID: BEEA7EFE

Interesting. So then, all the variables would automatically be
declared if the web browser passed that variable, just like in PHP.

I think I'll stick with an explicit $cgi.export(self, %w(phone name
email)) though; I'm not quite comfortable with the idea of the web
browser being able to cause any variable to be set in my program. That
can make it easy to code security flaws.

Anyone coming from PHP would like this trick, though!

···

On Wed, Jul 10, 2002 at 11:03:09AM -0700, Ned Konz wrote:

Well, then, you could do this:

class MyClass
  def method_missing(sym, *args)
    if $cgi.has_key?(sym) && args.size < 2
      return $cgi[sym.to_s][ args[0] || 0 ]
    end
    super
  end
end