Class: RuleEngine::Base
- Inherits:
-
Object
- Object
- RuleEngine::Base
- Defined in:
- lib/cirrocumulus/rules/engine.rb
Overview
Core class for Cirrocumulus Rule Engine. All the magic about asserting/retracting facts and pattern-matching is performed here.
Class Method Summary collapse
-
.rule(name, facts, options = {}, &block) ⇒ Object
DSL-method for defining rules.
Instance Method Summary collapse
-
#assert(fact, options = {}, silent = false) ⇒ Object
Asserts new fact.
- #dump_kb ⇒ Object
- #dump_ruleset ⇒ Object
-
#execute ⇒ Object
Executes all associated with current KB rules.
-
#initialize ⇒ Base
constructor
A new instance of Base.
- #match(pattern) ⇒ Object
- #query(fact) ⇒ Object
-
#replace(pattern, values, options = {}) ⇒ Object
Replaces fact value.
-
#retract(fact, silent = false) ⇒ Object
Retracts an existing fact.
-
#start ⇒ Object
Starts this rule engine instance.
- #tick ⇒ Object
- #transaction ⇒ Object
Constructor Details
Class Method Details
.rule(name, facts, options = {}, &block) ⇒ Object
DSL-method for defining rules.
52 53 54 |
# File 'lib/cirrocumulus/rules/engine.rb', line 52 def self.rule(name, facts, = {}, &block) current_ruleset << RuleDescription.new(name, facts, , block) end |
Instance Method Details
#assert(fact, options = {}, silent = false) ⇒ Object
Asserts new fact. If ‘silent’ is set to true, does not perform any associated rules
-
Returns :
-
nothing
-
90 91 92 93 94 95 96 97 |
# File 'lib/cirrocumulus/rules/engine.rb', line 90 def assert(fact, = {}, silent = false) silent = unless .is_a?(Hash) = {} unless .is_a?(Hash) @mutex.synchronize do assert_nonblocking(fact, , silent) end end |
#dump_kb ⇒ Object
63 64 65 66 67 68 69 70 71 |
# File 'lib/cirrocumulus/rules/engine.rb', line 63 def dump_kb() log "Dumping current knowledge base:\n" @facts.each_with_index do |fact,i| log "%d) %s (at %s)" % [i, fact.inspect, @fact_times[fact]] end log "Empty" if @facts.empty? end |
#dump_ruleset ⇒ Object
73 74 75 76 77 78 79 80 |
# File 'lib/cirrocumulus/rules/engine.rb', line 73 def dump_ruleset() log "Dumping current ruleset:\n" self.class.current_ruleset.each_with_index do |rule,i| log "%d) %s" % [i, rule[:name]] end log "Empty ruleset" if self.class.current_ruleset.empty? end |
#execute ⇒ Object
Executes all associated with current KB rules. Normally, this shouldn’t be called by the programmer.
195 196 197 |
# File 'lib/cirrocumulus/rules/engine.rb', line 195 def execute() process() end |
#match(pattern) ⇒ Object
159 160 161 162 163 164 165 166 |
# File 'lib/cirrocumulus/rules/engine.rb', line 159 def match(pattern) res = [] find_matches_for_condition(pattern).each do |fact| res << bind_parameters(pattern, fact.data, {}) end res end |
#query(fact) ⇒ Object
155 156 157 |
# File 'lib/cirrocumulus/rules/engine.rb', line 155 def query(fact) find_matches_for_condition(fact).map {|data| data.data} end |
#replace(pattern, values, options = {}) ⇒ Object
Replaces fact value. If fact was not found - asserts it
-
Returns :
-
nothing
-
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/cirrocumulus/rules/engine.rb', line 113 def replace(pattern, values, = {}) @mutex.synchronize do data = match(pattern) if data.empty? new_fact = pattern.clone pattern.each_with_index do |item,i| if item.is_a?(Symbol) && item.to_s.upcase == item.to_s new_fact[i] = values.is_a?(Hash) ? values[item] : values end end assert_nonblocking(new_fact, , false) else data.each do |match_data| old_fact = pattern.clone new_fact = pattern.clone pattern.each_with_index do |item,i| if match_data.include? item old_fact[i] = match_data[item] new_fact[i] = values.is_a?(Hash) ? values[item] : values end end facts_are_same = true old_fact.each_with_index do |item, idx| new_item = new_fact[idx] facts_are_same = false if new_item != item end unless facts_are_same debug "replace #{pattern.inspect} for #{values.inspect}" retract_nonblocking(old_fact, true) assert_nonblocking(new_fact, {}, false) end end end end end |
#retract(fact, silent = false) ⇒ Object
Retracts an existing fact. If ‘silent’ is set to true, does not perform any associated rules
-
Returns :
-
nothing
-
103 104 105 106 107 |
# File 'lib/cirrocumulus/rules/engine.rb', line 103 def retract(fact, silent = false) @mutex.synchronize do retract_nonblocking(fact, silent) end end |
#start ⇒ Object
Starts this rule engine instance.
169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/cirrocumulus/rules/engine.rb', line 169 def start() @worker_thread = Thread.new do engine = nil while true do engine = Thread.current[:engine] if engine.nil? engine.tick() if engine @queue.run_queued_rules() sleep 0.1 end end @worker_thread[:engine] = self end |
#tick ⇒ Object
183 184 185 186 187 188 189 190 191 192 |
# File 'lib/cirrocumulus/rules/engine.rb', line 183 def tick() @mutex.synchronize do to_retract = [] @facts.each {|fact| to_retract << fact if fact.timed_out? } to_retract.each {|fact| retract_nonblocking(fact.data, true) } process() unless to_retract.empty? end rescue Exception => ex p ex end |
#transaction ⇒ Object
82 83 84 |
# File 'lib/cirrocumulus/rules/engine.rb', line 82 def transaction end |