module Rulz module Evaluator class Base def initialize(receiver, *args) @receiver = receiver @args = args || [] end def it @receiver end alias :its :it end class Condition < Evaluator::Base def initialize(receiver, name, *args) @condition = Rulz::Condition.find(receiver.class, name) super(receiver, *args) end def condition(name, *args) Rulz::Evaluator::Condition.new(@receiver, name, *args).evaluate end def opposite_of(name, *args) not condition(name, *args) end def evaluate instance_exec(*@args, &@condition.proc) end end class AttributeCondition < Evaluator::Base def initialize(receiver, attribute, name, *args) @attribute = attribute @condition = Rulz::Attribute::Condition.find(receiver.class, attribute, name) super(receiver, *args) define_singleton_method attribute do @receiver.send(attribute) end end def condition(name, *args) Rulz::Evaluator::AttributeCondition.new(@receiver, @attribute, name, *args).evaluate end def opposite_of(name, *args) not condition(name, *args) end def evaluate instance_exec(*@args, &@condition.proc) end end class Action < Evaluator::Base def initialize(receiver, name, *args) @action = Rulz::Action.find(receiver.class, name) super(receiver, *args) end def evaluate instance_exec(*@args, &@action.proc) end def action(name, *args) Rulz::Evaluator::Action.new(@receiver, name, *args).evaluate end end class Rule < Evaluator::Base def initialize(receiver, proc) @receiver = receiver @proc = proc end def evaluate instance_eval(&@proc) end def where(condition, *args, &block) if condition.is_a? String @receiver.instance_eval(&block) if Rulz::Evaluator::Condition.new(@receiver, condition, *args).evaluate elsif condition.is_a? Proc @receiver.instance_eval(&block) if condition.call(*args) elsif condition.is_a? Array split_condition = condition.inject([[]]) do |results, element| if ["AND", "OR"].include? element results << {"AND" => "&&", "OR" => "||"}[element] results << [] elsif element.is_a?(Hash) results.pop if results.last.respond_to?(:empty?) && results.last.empty? results << element else results.last << element end results end split_condition.map! do |element| if element.is_a?(Array) Rulz::Evaluator::Condition.new(@receiver, *element).evaluate elsif element.is_a?(Hash) attribute, element = *element.first Rulz::Evaluator::AttributeCondition.new(@receiver, attribute, *element).evaluate else element end end @receiver.instance_eval(&block) if eval(split_condition.join(" ")) elsif condition.is_a? Hash attribute, condition = *condition.first @receiver.instance_eval(&block) if Rulz::Evaluator::AttributeCondition.new(@receiver, attribute, *condition).evaluate else raise ArgumentError, "Invalid condition" end end end end end