I feel like that I am about to reinvent the wheel here, so before I do that ...
I have a large set of data that I need to process, and the 'rules' that process the data will evolve over time, so I thought that implementing a simple rules engine would be in order.
Note I am not looking for a natural language parser, I want all of the rules to be ruby procs.
I could imagine the syntax to look something like:
engine = SimpleRulesEngine.new
rule = engine.add_rule(priority: 10) do |row|
  row.name != 'George'
end
rule.action do |row|
  puts "Yikes, name is not George!, it was #{row.name}"
  row.update_attribute :name, 'George'
end
engine.process collection
I was wondering if there was any existing patterns or gems out there that would help with this. The one that seems closest is ruleby, but does not seem to be actively maintained, and seems too complex of a solution for my problem.
Thanks!
Note this is a similar question to : Ruby & Rules Engines, but different in that, I do not care about natural language processing, and rule storage.
By comparison to the other existing Ruby rules engines, Ruleby seems like the most actively maintained:
However, the Wongi Engine looks promising and may become what you need.
@DaveNewton talked some sence into me, and it is clear that basically I was looking for some simple DSL for my app, this is what I ended up using -- its very simple, but incase it is useful for someone else:
# /lib/simple_rules_engine
# To use, just include it in any file where you need some rules engine love ...
# then defile rules like so:
#
# rule :name_of_rule,
#       priority: 10,
#       validate: lambda {|o| # do something with o}
#       fail: lambda {|o| o.fail!}} 
# 
# then to run the engine
# process_rules(your_data_set)
#   
module SimpleRulesEngine
  extend ActiveSupport::Concern
  included do
    class_attribute :rules
    self.rules = []
  end
  module ClassMethods
    # rule :name_of_rule,
    #       priority: 10,
    #       validate: lambda {|o| # do something with o}
    #       fail: lambda {|o| o.fail!}}
    def rule(name,options={})
      self.rules << SimpleRulesEngine::Rule.new(name,options)
    end
    def process_rules(collection)
      collection.each do |row|
        rules.sort_by(&:priority).each do |rule|
          rule.run(row)
        end
        row.valid!
      end
    end
  end
  ## Helper Classes
  class Rule
    attr_accessor :priority
    attr_accessor :name
    # proc to test
    attr_accessor :validate
    # if valid
    attr_accessor :success
    # if invalid
    attr_accessor :fail
    NO_OP = lambda {|o| true }
    def initialize(name, options={})
      self.name = name
      self.priority = options[:priority] || 10
      self.validate = options[:validate] || NO_OP
      self.fail = options[:fail] || NO_OP
      self.success = options[:success] || NO_OP
    end
    def run(data)
      if validate.call(data)
        success.call(data)
      else
        fail.call(data)
      end
    end
  end
end
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With