Monday, March 17, 2008
Move eval from Run-time to Parse-time
You need to use eval, but want to limit the number of times eval is necessary.
becomes
Motivation
Mechanics
The following Person class uses eval to define the logic the readers rely upon for returning a default value if no value has previously been set.
The above example executes without issue, but it relies upon eval each time a reader is called. If multiple calls to eval are determined to be problematic the solution is to expand the eval to include defining the method itself.
options.each_pair do |attribute, default_value|
define_method attribute do
eval "@ ||= "
end
end
end
attr_with_default :emails => "[]", :employee_number => "EmployeeNumberGenerator.next"
endbecomes
options.each_pair do |attribute, default_value|
eval "def
@ ||=
end"
end
end
attr_with_default :emails => "[]", :employee_number => "EmployeeNumberGenerator.next"
endMotivation
premature optimization is the root of all evil -- Knuth, DonaldI'll never advocate for premature optimization, but this refactoring can be helpful when you determine that eval is a source of performance pain. The Kernel#eval method can be the right solution in some cases; but it is almost always more expensive (in terms of performance) than it's alternatives. In the cases where eval is necessary, it's often better to move an eval call from run-time to parse-time.
Mechanics
- Expand the scope of the string being eval'd.
- Test
The following Person class uses eval to define the logic the readers rely upon for returning a default value if no value has previously been set.
options.each_pair do |attribute, default_value|
define_method attribute do
eval "@ ||= "
end
end
end
attr_with_default :emails => "[]", :employee_number => "EmployeeNumberGenerator.next"
endThe above example executes without issue, but it relies upon eval each time a reader is called. If multiple calls to eval are determined to be problematic the solution is to expand the eval to include defining the method itself.
options.each_pair do |attribute, default_value|
eval "def
@ ||=
end"
end
end
attr_with_default :emails => "[]", :employee_number => "EmployeeNumberGenerator.next"
endLabels: eval, refactoring, ruby
Thursday, February 15, 2007
Ruby Evaluation options article on InfoQ
Yesterday, I published a fairly long article on InfoQ about Evaluation Options in Ruby. The article covers eval, instance_eval, class_eval and provides examples of using each of them.
Feedback welcome.
Feedback welcome.
Labels: class_eval, eval, InfoQ, instance_eval, ruby


