Hi,
as i mentioned before, i’m pretty new to ruby. So i’m trying to optimize
my code and learn the advantages of this nice language :).
What i’m trying this time is to pass a hash of parameters (passed by a
HTML form i.e.) to an new Object and then automatically assign the
values of this hash to the attributes of that object named like the keys
of that hash.
After a lot of research and even more trail & error i ended up with
this:
class Example
def initialize ( params = {} )
assign_params params unless params.nil?
end
def assign_params params
params.each { | key, value | eval “@#{key} = ‘#{value}’” }
end
end
At least, it works
Are there any suggestions for smarter or more efficient ways to
accomplish this? Escpecially the usage of eval() to assign variable
variables seems pretty workedaround to me.
Thy for any hint
D.
On 12/06/07, Daniel L. [email protected] wrote:
def assign_params params
params.each { | key, value | eval “@#{key} = ‘#{value}’” }
end
def assign_parmas(params)
params.each {|key,variable| instance_variable_set(“@{key}”,value)}
end
Farrel
Alle martedì 12 giugno 2007, Daniel L. ha scritto:
After a lot of research and even more trail & error i ended up with this:
end
At least, it works
Are there any suggestions for smarter or more efficient ways to
accomplish this? Escpecially the usage of eval() to assign variable
variables seems pretty workedaround to me.
Thy for any hint
D.
You can use instance_variable_set:
def assign_params params
params.each_pair{|k, v| instance_variable_set( “@#{k}”, v)}
end
I hope this helps
Stefano
Farrel L. wrote:
On 12/06/07, Daniel L. [email protected] wrote:
def assign_params params
params.each { | key, value | eval “@#{key} = ‘#{value}’” }
end
def assign_parmas(params)
params.each {|key,variable| instance_variable_set(“@{key}”,value)}
end
Thank you both!
Do you know if instance_variable_set() behaves different or is more
performant in any way than eval()?
Or is it just better readable code?
Daniel L. wrote:
Do you know if instance_variable_set() behaves different or is more
performant in any way than eval()?
Found the answer myself:
with instance_variable_set the variable remains it’s type (which is
actually much better!), the eval() version casts it to string.
Daniel L. [email protected] writes:
What i’m trying this time is to pass a hash of parameters (passed by a
HTML form i.e.) to an new Object and then automatically assign the
values of this hash to the attributes of that object named like the
keys of that hash.
Well, your initial attempt made all my internal security alarms go
“ACK!” - since a web user can pass pretty much arbitrary name/value
pairs in, that code lets a malicious user execute arbitrary ruby code
on your system by passing in a specially crafted name.
How are you intending to use this object? You might find something
like this more useful:
class HashAttrib
def initialize(parms={})
@parameters=parms
end
def method_missing(sym, *args)
return @parameters[sym.to_s] if args.empty?
if sym.to_s =~ /=$/ and args.size == 1 then
return @parameters[sym.to_s[0…-2]] = args[0]
end
return super.method_missing(sym, *args)
end
end
Then, here’s how you can use this class:
irb(main):013:0> a = HashAttrib.new(Hash[*%w{color red string 1 jump
yes}])
=> #<HashAttrib:0xb7c013b0 @parameters={“jump”=>“yes”, “color”=>“red”,
“string”=>“1”}>
irb(main):014:0> a.jump
=> “yes”
irb(main):015:0> a.color
=> “red”
irb(main):016:0> a.string
=> “1”
irb(main):017:0> a.colour
=> nil
irb(main):018:0> a.colour=a.color
=> “red”
irb(main):019:0> a.colour
=> “red”
Now, this doesn’t make the attributes (which is the word you seem to
be using for instance variables) equal to what’s in the hash, really,
it just fakes attributes by turning a.whatever into a hash lookup for
“whatever” in @parameters.
You might want to consider also adding an attr_accessor declaration
for “parameters” to HashAttrib to let you get at the underlying hash.
Alle martedì 12 giugno 2007, Daniel L. ha scritto:
Do you know if instance_variable_set() behaves different or is more
performant in any way than eval()?
Or is it just better readable code?
Here’s a small benchmark to test performances:
require ‘benchmark’
$h = {}
n.times{|i| $h["@v_#{i}"] = i}
class C
def initialize
$h.each_pair{|k, v| instance_variable_set(k,v)}
end
end
class D
def initialize
$h.each_pair{|k, v| eval “@#{k} = ‘#{v}’”}
end
end
Benchmark.bm(‘instance_variable_set:’.size) do |x|
x.report(‘instance_variable_set:’){C.new}
x.report(‘eval:’){D.new}
end
The results are:
-
n = 500:
user system total real
instance_variable_set: 0.010000 0.000000 0.010000 ( 0.015151)
eval: 0.030000 0.010000 0.040000 ( 0.032303)
-
n = 1000:
user system total real
instance_variable_set: 0.020000 0.000000 0.020000 ( 0.027947)
eval: 0.060000 0.000000 0.060000 ( 0.072785)
It’s clear that instance_variable_set is more performant. I’m not sure,
but I
think this happens because with eval, the interpreter also needs to
parse the
string you pass to eval.
Stefano
On 12.06.2007 15:12, Daniel L. wrote:
Thank you both!
Do you know if instance_variable_set() behaves different or is more
performant in any way than eval()?
Eval does not accidentally rhyme on evil. There are serious security
implications of using eval - sometimes the interpreter may actually
prevent evaling a string.
Btw the solution with instance_eval walways works but you might not get
at those values unless you also have attr accessors defined.
Here’s something else that you can do:
irb(main):001:0> require ‘ostruct’
=> true
irb(main):002:0> o=OpenStruct.new(:foo=>1, :bar=>2)
=> #
irb(main):003:0> o.foo
=> 1
irb(main):004:0> o.bar
=> 2
I.e. use OpenStruct. You could as well leave parameters in the Hash…
Kind regards
robert
Daniel M. wrote:
Daniel L. [email protected] writes:
[…]
def assign_params params
params.each { | key, value | eval “@#{key} = ‘#{value}’” }
end
[…]
Well, your initial attempt made all my internal security alarms go
“ACK!” - since a web user can pass pretty much arbitrary name/value
pairs in, that code lets a malicious user execute arbitrary ruby code
on your system by passing in a specially crafted name.
basically i’ll agree.
But using the method instance_variable_set() should also fix this issue,
right? Code may be passed but won’t be interpreted any more, as far as i
see it now.