7

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.

4

5 回答 5

7

@DaveNewton 对我说了一些话,很明显,基本上我正在为我的应用程序寻找一些简单的 DSL,这就是我最终使用的——它非常简单,但如果它对其他人有用:

# /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
于 2012-08-29T15:41:18.253 回答
1

与其他现有的 Ruby 规则引擎相比,Ruleby 似乎是维护最积极的:

但是,Wongi 引擎看起来很有前途,可能会成为您所需要的。

于 2012-08-28T18:46:08.780 回答
1

正如 Stratus3D 所建议的那样,也许看看 Wongi。乍一看,它看起来不错,并且有很好的介绍。在接下来的几周里,我将在一个更复杂的测试用例上对其进行测试。

另一方面,Rools 似乎没有维护(rubyforge 页面已死,我发现的所有分叉似乎也已死)。

于 2015-02-06T08:31:27.430 回答
0

不要忘记 wongi-engine gem ( https://github.com/ulfurinn/wongi-engine )。它基于 Rete 算法 ( http://en.wikipedia.org/wiki/Rete_algorithm/ ) 并且具有类似于您正在寻找的语法。

于 2013-12-05T21:50:00.753 回答
0

我已经断断续续地玩了几个星期的 Ruleby,它使用起来并不太复杂,尽管我增加的复杂性是使用大量的 case 语句以编程方式将规则加载到引擎中。

一旦您了解诸如事实之类的东西在引擎中是持久的,并且每次后续运行不仅评估您刚刚输入的事实,而且还评估您之前断言的事实,它就非常直截了当。不喜欢其中一些是如何黑盒的,尽管当我遇到运行时错误时,排除故障绝对是一件痛苦的事(因为我目前正在处理一个部分)。

于 2012-09-26T22:03:43.707 回答