| Class | Rools::Rule |
| In: |
lib/rools/rule.rb
|
| Parent: | Base |
| conditions | [R] | |
| consequences | [R] | |
| name | [R] | |
| parameters | [R] | |
| priority | [R] | |
| rule_set | [R] |
A Rule requires a Rools::RuleSet, a name, and an associated block which will be executed at initialization
# File lib/rools/rule.rb, line 13
13: def initialize(rule_set, name, priority, b)
14: @rule_set = rule_set
15: @name = name
16: @priority = priority
17: @conditions = []
18: @consequences = []
19: @parameters = []
20:
21: begin
22: instance_eval(&b) if b
23: rescue Exception => e
24: raise RuleCheckError.new( self, e)
25: end
26: end
Calls Rools::RuleSet#assert in the bound working-set
# File lib/rools/rule.rb, line 123
123: def assert(obj)
124: @rule_set.rule_assert(obj)
125: end
Execute each consequence. Any StandardErrors are caught and wrapped in Rools::RuleConsequenceError, then raised to break out of the current assertion.
# File lib/rools/rule.rb, line 130
130: def call(obj)
131: begin
132: @consequences.each do |c|
133: c.call(obj)
134: end
135: rescue Exception => e
136: # discontinue the Rools::RuleSet#assert if any consequence fails
137: logger.error( "rule RuleConsequenceError #{e.to_s} #{e.backtrace.join("\n")}") if logger
138: raise RuleConsequenceError.new(self, e)
139: end
140: end
Adds a condition to the Rule. For readability, it might be preferrable to use a new condition for every evaluation when possible.
condition { person.name == 'Fred' }
condition { person.age > 18 }
As opposed to:
condition { person.name == 'Fred' && person.age > 18 }
# File lib/rools/rule.rb, line 36
36: def condition(&b)
37: @conditions << DefaultParameterProc.new(self, b)
38: end
Checks to see if this Rule‘s conditions match the asserted object Any StandardErrors are caught and wrapped in RuleCheckErrors, then raised.
# File lib/rools/rule.rb, line 111
111: def conditions_match?(obj)
112: begin
113: @conditions.each { |c| return false unless c.call(obj) }
114: rescue StandardError => e
115: logger.error( "conditions_match? StandardError #{e} #{e.backtrace.join("\n")}") if logger
116: raise RuleCheckError.new(self, e)
117: end
118:
119: return true
120: end
Adds a consequence to the Rule
consequence { user.failed_logins += 1; user.save! }
# File lib/rools/rule.rb, line 43
43: def consequence(&b)
44: @consequences << DefaultParameterProc.new(self, b)
45: end
returns parameters of rule
# File lib/rools/rule.rb, line 71
71: def get_parameters
72: @parameters
73: end
Sets the parameters of the Rule
parameters Person, :name, :occupation
The arguments passed are evaluated with :is_a? for each constant-name passed, and :responds_to? for each symbol. So the above example would be the same as:
obj.is_a?(Person) &&
obj.responds_to?(:name) &&
obj.responds_to?(:occupation)
You can pass any combination of symbols or constants. You might want to refrain from referencing constants to aid in "duck-typing", or you might want to use parameters such as:
parameters Person, Employee, :department
To verify that the asserted object is an Employee, that inherits from Person, and responds to :department
# File lib/rools/rule.rb, line 62
62: def parameters(*matches)
63: logger.debug( "Adding parameters: #{matches.inspect}") if logger
64: # @parameters += matches
65: @parameters << matches
66: end
Checks to see if this Rule‘s parameters match the asserted object
# File lib/rools/rule.rb, line 80
80: def parameters_match?(obj)
81: # if parameters are not specified, let's assume that the rule is always relevant
82: if @parameters.size == 0
83: logger.debug "no parameters defined for rule: #{self}" if logger
84: return true
85: end
86:
87: @parameters.each do |params|
88: match = false
89:
90: params.each do |p|
91: logger.debug( "#{self} match p:#{p} obj:#{obj}") if logger
92:
93: if p.is_a?(Symbol)
94: if obj.respond_to?(p)
95: match = true
96: else
97: return false
98: end
99: elsif obj.is_a?(p)
100: match = true
101: end
102: end
103: return true if match
104: end
105:
106: return false
107: end