Ruby: Parse, replace, and evaluate a string formula
Posted
by
Swartz
on Stack Overflow
See other posts from Stack Overflow
or by Swartz
Published on 2011-02-02T22:53:55Z
Indexed on
2011/02/02
23:25 UTC
Read the original article
Hit count: 237
I'm creating a simple Ruby on Rails survey application for a friend's psychological survey project. So we have surveys, each survey has a bunch of questions, and each question has one of the options participants can choose from. Nothing exciting.
One of the interesting aspects is that each answer option has a score value associated with it. And so for each survey a total score needs to be calculated based on these values.
Now my idea is instead of hard-coding calculations is to allow user add a formula by which the total survey score will be calculated. Example formulas:
"Q1 + Q2 + Q3"
"(Q1 + Q2 + Q3) / 3"
"(10 - Q1) + Q2 + (Q3 * 2)"
So just basic math (with some extra parenthesis for clarity). The idea is to keep the formulas very simple such that anyone with basic math can enter them without resolving to some fancy syntax.
My idea is to take any given formula and replace placeholders such as Q1, Q2, etc with the score values based on what the participant chooses. And then eval() the newly formed string. Something like this:
f = "(Q1 + Q2 + Q3) / 2" # some crazy formula for this survey
values = {:Q1 => 1, :Q2 => 2, :Q3 => 2} # values for substitution
result = f.gsub(/(Q\d+)/) {|m| values[$1.to_sym] } # string to be eval()-ed
eval(result)
So my questions are:
Is there a better way to do this? I'm open to any suggestions.
How to handle formulas where not all placeholders were successfully replaced (e.g. one question wasn't answered)? Ex: {:Q3 => 2} wasn't in values hash? My idea is to rescue eval()... any thoughts?
How to get proper result? Should be 2.5, but due to integer arithmetic, it will truncate to 2. I can't expect people who provide the correct formula (e.g. / 2.0 ) to understand this nuance.
I do not expect this, but how to best protect eval() from abuse (e.g. bad formula, manipulated values coming in)?
Thank you!
© Stack Overflow or respective owner