Is there a better way

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.

···

--
Posted via http://www.ruby-forum.com/.

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

Hope that helps.

James Edward Gray II

···

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

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

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.

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.

···

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

--
Posted via http://www.ruby-forum.com/\.

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.

···

--
      vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

} 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

···

On Mon, Jun 12, 2006 at 05:03:43AM +0900, James McCarthy wrote:

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.

···

--
      vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407