【问题标题】:ruby rules engine红宝石规则引擎
【发布时间】:2012-08-28 15:11:06
【问题描述】:

我觉得我要在这里重新发明轮子了,所以在我这样做之前......

我有大量需要处理的数据,处理这些数据的“规则”会随着时间的推移而发展,所以我认为实现一个简单的规则引擎是有必要的。

注意我不是在寻找自然语言解析器,我希望所有规则都是 ruby​​ procs。

我可以想象语法看起来像:

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

我想知道是否有任何现有的模式或宝石可以帮助解决这个问题。似乎最接近的一个是ruleby,但似乎没有得到积极维护,而且对于我的问题来说似乎太复杂了。

谢谢!


请注意,这是与Ruby & Rules Engines 类似的问题,但不同之处在于,我不关心自然语言处理和规则存储。

【问题讨论】:

  • 没有更多细节很难提供帮助;到目前为止,您似乎有一个“规则应该触发”块和一个“规则操作”块。最多看起来像一个简单的 DSL,即使你忽略了一个瘦 DSL 包装器,也有一些相当清晰的 Ruby。
  • 你可能想看看 gem state_machine
  • @DaveNewton,我认为你完全正确。下面是我想出的解决方案。感谢您将我推向正确的方向

标签: ruby-on-rails ruby dsl


【解决方案1】:

@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

【讨论】:

  • 酷;感谢您的跟进。希望一切顺利——我已经完成了一些非常简单的“规则引擎”,比如这样,对于很多事情来说,它们已经足够了。
【解决方案2】:

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

但是,Wongi Engine 看起来很有希望,可能会成为您所需要的。

【讨论】:

  • 从外观上看,Ruby 规则并没有发生太多变化。
  • 顺便说一句,我把 ruby​​-rules 代码搬到了这里 github.com/michaelneale/Ruby-Rules,因为 codehaus 已经不复存在了(我已经好几年没碰过它了,与其他人相比它是基本的)。
【解决方案3】:

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

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

【讨论】:

    【解决方案4】:

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

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

    【讨论】:

      【解决方案5】:

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

      【讨论】:

        猜你喜欢
        • 2011-04-18
        • 2019-08-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多