I have an array of tags per item like so:
item1 = ['new', 'expensive']
item2 = ['expensive', 'lame']
I also have a boolean expression as a string based on possible tags:
buy_it = "(new || expensive) && !lame"
How can I determine if an 开发者_开发技巧item matches the buying criteria based on the tags associated with it? My original thought was to do a gsub on all words in buy_it to become 'true' or 'false' based on them existing in the itemx tags array and then exec the resulting string to get a boolean result.
But since the Ruby community is usually more creative than me, is there a better solution?
EDIT:
Just to clarify, buy_it in my example is dynamic, users can change the criteria for buying something at run-time.
Along the lines of your gsub
idea, instead of substituting each word for true/false every time, why not substitute each "query" into an expression that can be re-used, e.g. the example buy_it
:
buy_it = "(new || expensive) && !lame"
buy_it_expr = buy_it.gsub(/(\w+)/, 'tags.include?("\1")')
puts buy_it_expr
=> (tags.include?("new") || tags.include?("expensive")) && !tags.include?("lame")
It could be evaluated into a Proc
and used like this:
buy_it_proc = eval "Proc.new { |tags| #{buy_it_expr} }"
buy_it_proc.call(item1)
=> true
buy_it_proc.call(item2)
=> false
Of course, care must be taken that the expression does not contain malicious code. (One solution might be to strip all but the allowed operator characters from the string and of course be wary of exceptions during eval.)
A hash is a good candidate here.
items = {'ipad' => ['new', 'expensive'], 'kindle' => ['expensive', 'lame']}
items.each do |name,tags|
if tags.include?('new' || 'expensive') && !tags.include?('lame')
puts "buy #{name}."
else
puts "#{name} isn't worth it."
end
end
精彩评论