Jon*_*han 7 ruby dsl ruby-on-rails
我觉得我要在这里重新发明轮子,所以在我这样做之前......
我需要处理大量数据,处理数据的"规则"会随着时间的推移而发展,所以我认为实现一个简单的规则引擎是有序的.
注意我不是在寻找一个自然语言解析器,我希望所有的规则都是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
Run Code Online (Sandbox Code Playgroud)
我想知道是否有任何现有的模式或宝石可以帮助解决这个问题.看起来最接近的是规则,但似乎没有积极维护,并且似乎对我的问题的解决方案太复杂.
谢谢!
请注意,这是一个类似的问题:Ruby和Rules Engines,但不同之处在于,我不关心自然语言处理和规则存储.
@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
Run Code Online (Sandbox Code Playgroud)