Is there a better way


#1

Is there an neater way to achieve this without using that clunky eval
and inline substitution?

def test_confirmation(object, test_attribute, test_values = {},
attributes = {})
instance = eval("#{object}.new(attributes)")
test_values.each do |value|
instance.send("#{test_attribute}=", value)
instance.send("#{test_attribute}_confirmation=", value)
assert !instance.save
assert instance.errors.invalid?(test_attribute)
end
end

Just feels a little clunky and wanted some pointers to improve my ruby.
Any thoughts would be useful.


#2

On Jun 11, 2006, at 3:03 PM, James McCarthy wrote:

instance = eval("#{object}.new(attributes)")

instance = Object.const_get(object).new(attributes)

Hope that helps.

James Edward G. II


#3

On Jun 11, 2006, at 4:03 PM, James McCarthy wrote:

  assert instance.errors.invalid?(test_attribute)
end

end

Just feels a little clunky and wanted some pointers to improve my
ruby.
Any thoughts would be useful.

You can pass classes as arguments to functions:
test_confirmation(SomeClass, …)

instance = object.new(attributes)

If the problem is you have to get a string, use const_get
e.g.
Object.const_get(object).new(attributes)

The only problem with this is that it doesn’t work for nested
constants (e.g. Net::HTTP). So to generalize that you do

instance = object.split(/::/).inject(Object) { |base, child|
base.const_get(child) }.new(attributes)

the #send s seem fine to me, much better than just straight eval’ing
the stuff.


#4

Joel VanderWerf wrote:

             object.send(:new, attributes)

Duh. Of course, as Logan said, you can just object.new(attributes). And
unlike me he was not lazy and wrote out the inject solution.


#5

James McCarthy wrote:

Is there an neater way to achieve this without using that clunky eval
and inline substitution?

def test_confirmation(object, test_attribute, test_values = {},
attributes = {})
instance = eval("#{object}.new(attributes)")

If object is supposed to be a class:

             object.send(:new, attributes)

If object is a string that names a class you will have to use const_get
to avoid eval. Check the archives for a good way to do that using
inject.

test_values.each do |value|
  instance.send("#{test_attribute}=", value)
  instance.send("#{test_attribute}_confirmation=", value)

AFAIK there is no better way to call setter methods, if the name of the
method is a parameter. If you only need to set the instance vars, you
can use #instance_variable_set, but that’s not the same thing as calling
the accessor method.

HTH.


#6

On Mon, Jun 12, 2006 at 05:03:43AM +0900, James McCarthy wrote:
} Is there an neater way to achieve this without using that clunky eval
} and inline substitution?
}
} def test_confirmation(object, test_attribute, test_values = {},
} attributes = {})
} instance = eval("#{object}.new(attributes)")
} test_values.each do |value|
} instance.send("#{test_attribute}=", value)
} instance.send("#{test_attribute}_confirmation=", value)
} assert !instance.save
} assert instance.errors.invalid?(test_attribute)
} end
} end
}
} Just feels a little clunky and wanted some pointers to improve my
ruby.
} Any thoughts would be useful.

Take a look at
http://redcorundum.blogspot.com/2006/05/kernelqualifiedconstget.html

–Greg