Skip to content

Instantly share code, notes, and snippets.

@mperham
Last active August 29, 2015 14:02
Show Gist options
  • Save mperham/7d763bdc42465caf17c7 to your computer and use it in GitHub Desktop.
Save mperham/7d763bdc42465caf17c7 to your computer and use it in GitHub Desktop.
Rule execution

I want to build a system which uses rules. These rules will change hourly (i.e. "this rule is effective from 2pm to 6pm"). The rules must support arbitrarily complex logic on just 2-3 pre-defined variables and result in a boolean:

item.a > 10 && item.b == 0 || item.category == FOOTWEAR

These rules will be executed hundreds of times per second so I can't afford the overhead of plain old eval. I want to reload the current effective ruleset from the database hourly, precompile each rule's logic string and execute it via the quickest method possible. It might look something like this:

class Rule
  def applies?(item)
    precompiled_logic.execute(item, TOPLEVEL_BINDING)
  end
end

How can I do this? I'm using Ruby 2.1.

@avit
Copy link

avit commented May 30, 2014

What about something simple like this:

RULES = {}

new_rule_str = "item.a > 10 && item.b == 0 || item.category == FOOTWEAR"
key = Digest::MD5.hexdigest(new_rule_str) # can be rule.id or something.

RULES[key] = eval("->(item) { #{new_rule_str} }")

# ...

RULES[key][item]

This precompiles the lambda on first run, then just calls it with the "item" parameter for every subsequent run.

@avit
Copy link

avit commented May 30, 2014

I think I'm on the same page with @joeyAghion

@mperham
Copy link
Author

mperham commented May 30, 2014

Ah, great idea, guys. Thanks so much!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment