rools 0.2 → 0.3

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,5 +1,12 @@
1
1
  = Rools CHANGELOG
2
2
 
3
+ == Rools - 0.3
4
+ * facts can now have a defined namespace
5
+ * fixed csv_test
6
+ * added load_xml_rules_as_string and load_rb_rules_as_string
7
+ * 100% test coverage
8
+ * Applied doc patch from John Mettraux
9
+
3
10
  == Rools - 0.2 released 2007/05/22
4
11
  * specifications have been created using RSpec
5
12
  * fix bug #10985 regarding the support of rule extension
data/RAKEFILE CHANGED
@@ -144,20 +144,30 @@ end
144
144
  task :upload_website => [:doc] do
145
145
  sh """
146
146
  rsync -azv -e ssh \
147
+ --exclude='.svn' --delete-excluded \
147
148
  html/ \
148
- ENV['RUBYFORGE_USER']:ENV['RUBYFORGE_PROJECT']
149
+ cappelaere@rubyforge.org:/var/www/gforge-projects/rools \
149
150
  """
150
151
  sh """
151
152
  rsync -azv -e ssh \
152
153
  --exclude='.svn' --delete-excluded \
153
154
  doc/res/defs \
154
- ENV['RUBYFORGE_USER']:ENV['RUBYFORGE_PROJECT']
155
+ cappelaere@rubyforge.org:/var/www/gforge-projects/rools \
155
156
  """
156
157
  sh """
157
158
  rsync -azv -e ssh \
158
159
  --exclude='.svn' --delete-excluded \
159
160
  examples \
160
- ENV['RUBYFORGE_USER']:ENV['RUBYFORGE_PROJECT']
161
+ cappelaere@rubyforge.org:/var/www/gforge-projects/rools \
162
+ """
163
+ end
164
+
165
+ task :upload_html do
166
+ sh """
167
+ rsync -azv -e ssh \
168
+ --exclude='.svn' \
169
+ html \
170
+ cappelaere@rubyforge.org:/var/www/gforge-projects/rools \
161
171
  """
162
172
  end
163
173
 
data/README CHANGED
@@ -1,4 +1,4 @@
1
- :nodoc: YOU SHOULD NOT BE VIEWING THIS FILE DIRECTLY. PLEASE USE: gem_server
1
+
2
2
  = Rools -- A pure ruby rules-engine
3
3
 
4
4
  Rools is a rules engine for abstracting business logic and program-flow. It's ideally suited to processing applications where the business logic undergoes frequent modification.
@@ -25,15 +25,15 @@ module Rools
25
25
  raise ArgumentError.new('The "rule" parameter must respond to an :assert method') unless rule.respond_to?(:assert)
26
26
  @rule = rule
27
27
  @proc = b
28
- @working_object = nil
28
+ #@working_object = nil
29
29
  end
30
30
 
31
31
  # Call the bound block and set the working object so that it
32
32
  # can be referred to by method_missing
33
33
  def call(obj)
34
- @working_object = obj
34
+ #@working_object = obj
35
35
  status = instance_eval(&@proc)
36
- @working_object = nil
36
+ #@working_object = nil
37
37
  return status
38
38
  end
39
39
 
@@ -45,22 +45,20 @@ module Rools
45
45
  # Parameterless method calls by the attached block are assumed to
46
46
  # be references to the working object
47
47
  def method_missing(sym, *args)
48
- #puts "method missing: #{sym}"
48
+ # puts "method missing: #{sym} args:#{args.inspect}"
49
49
  # check if it is a fact first
50
- begin
50
+ #begin
51
51
  facts = @rule.rule_set.get_facts
52
52
  if facts.has_key?( sym.to_s )
53
53
  #puts "return fact #{facts[sym.to_s].value}"
54
54
  return facts[sym.to_s].value
55
- #else
56
- #puts "#{sym} not in facts"
55
+ else
56
+ raise Exception, "symbol: #{sym} not found in facts"
57
57
  end
58
- rescue Exception => e
59
- #logger.error "miss exception #{e} #{e.backtrace.join("\n")}" if logger
60
- #puts "miss exception #{e} #{e.backtrace.join("\n")}"
61
- end
62
- #return @working_object if @working_object && args.size == 0
63
- #return nil
58
+ #rescue Exception => e
59
+ # puts "miss exception #{e} #{e.backtrace.join("\n")}"
60
+ # return nil
61
+ #end
64
62
  end
65
63
 
66
64
  # Stops the current assertion. Does not indicate failure.
@@ -60,8 +60,16 @@ module Rools
60
60
  # To verify that the asserted object is an Employee, that inherits from
61
61
  # Person, and responds to :department
62
62
  def parameters(*matches)
63
- logger.debug( "Adding parameters: #{matches}") if logger
64
- @parameters += matches
63
+ logger.debug( "Adding parameters: #{matches.inspect}") if logger
64
+ # @parameters += matches
65
+ @parameters << matches
66
+ end
67
+
68
+ #
69
+ # returns parameters of rule
70
+ #
71
+ def get_parameters
72
+ @parameters
65
73
  end
66
74
 
67
75
  # parameters is aliased to aid in readability if you decide
@@ -70,25 +78,31 @@ module Rools
70
78
 
71
79
  # Checks to see if this Rule's parameters match the asserted object
72
80
  def parameters_match?(obj)
73
- @parameters.each do |p|
74
- logger.debug( "#{self} match p:#{p} obj:#{obj} sym:#{Symbol}") if logger
75
- if p.is_a?(Symbol)
76
- #return false unless obj.respond_to?(p)
77
- return true if obj.respond_to?(p)
78
- else
79
- logger.debug( "#{self} is_a p:#{p} obj:#{obj} #{obj.is_a?(p)}") if logger
80
- #return false unless obj.is_a?(p)
81
- return true if obj.is_a?(p)
82
- end
83
- end
84
-
85
81
  # if parameters are not specified, let's assume that the rule is always relevant
86
82
  if @parameters.size == 0
87
83
  logger.debug "no parameters defined for rule: #{self}" if logger
88
84
  return true
89
85
  end
90
86
 
91
- logger.debug( "no parameter match") if logger
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
+
92
106
  return false
93
107
  end
94
108
 
@@ -98,7 +112,7 @@ module Rools
98
112
  begin
99
113
  @conditions.each { |c| return false unless c.call(obj) }
100
114
  rescue StandardError => e
101
- logger.error( "rule StandardError #{e} #{e.backtrace.join("\n")}") if logger
115
+ logger.error( "conditions_match? StandardError #{e} #{e.backtrace.join("\n")}") if logger
102
116
  raise RuleCheckError.new(self, e)
103
117
  end
104
118
 
@@ -118,10 +132,10 @@ module Rools
118
132
  @consequences.each do |c|
119
133
  c.call(obj)
120
134
  end
121
- rescue StandardError => e
135
+ rescue Exception => e
122
136
  # discontinue the Rools::RuleSet#assert if any consequence fails
123
137
  logger.error( "rule RuleConsequenceError #{e.to_s} #{e.backtrace.join("\n")}") if logger
124
- raise RuleConsequenceError.new(rule, e)
138
+ raise RuleConsequenceError.new(self, e)
125
139
  end
126
140
  end
127
141
 
@@ -61,8 +61,17 @@ module Rools
61
61
  #
62
62
  def load_xml( fileName )
63
63
  begin
64
- file = File.new( fileName )
65
- doc = REXML::Document.new file
64
+ str = IO.read(fileName)
65
+ load_xml_rules_as_string(str)
66
+ rescue Exception => e
67
+ raise RuleLoadingError, "loading xml file"
68
+ end
69
+ end
70
+
71
+ # load xml rules as a string
72
+ def load_xml_rules_as_string( str )
73
+ begin
74
+ doc = REXML::Document.new str
66
75
  doc.elements.each( "rule-set") { |rs|
67
76
  facts = rs.elements.each( "facts") { |f|
68
77
  facts( f.attributes["name"] ) do f.text.strip end
@@ -100,10 +109,20 @@ module Rools
100
109
  end
101
110
 
102
111
  #
103
- # Ruby File format
112
+ # Ruby File format loading
104
113
  #
105
114
  def load_rb( file )
106
- instance_eval(File::open(file).read)
115
+ begin
116
+ str = IO.read(file)
117
+ load_rb_rules_as_string(str)
118
+ rescue Exception => e
119
+ raise RuleLoadingError, "loading ruby file"
120
+ end
121
+ end
122
+
123
+ # load ruby rules as a string
124
+ def load_rb_rules_as_string( str )
125
+ instance_eval(str)
107
126
  end
108
127
 
109
128
  #
@@ -136,25 +155,28 @@ module Rools
136
155
  # facts can be created in a similar manner to rules
137
156
  # all names are converted to strings and downcased.
138
157
  # Facts name is equivalent to a Class Name
158
+ #
139
159
  # ==Example
140
- # require 'rools'
141
- #
142
- # rules = Rools::RuleSet.new do
143
- #
144
- # facts 'Countries' do
145
- # ["China", "USSR", "France", "Great Britain", "USA"]
146
- # end
147
- #
148
- # rule 'Is it on Security Council?' do
149
- # parameter String
150
- # condition { countries.include?(string) }
151
- # consequence { puts "Yes, #{string} is in the country list"}
152
- # end
153
- # end
160
+ #
161
+ # require 'rools'
162
+ #
163
+ # rules = Rools::RuleSet.new do
164
+ #
165
+ # facts 'Countries' do
166
+ # ["China", "USSR", "France", "Great Britain", "USA"]
167
+ # end
168
+ #
169
+ # rule 'Is it on Security Council?' do
170
+ # parameter String
171
+ # condition { countries.include?(string) }
172
+ # consequence { puts "Yes, #{string} is in the country list"}
173
+ # end
174
+ # end
154
175
  #
155
- # rules.assert 'France'
176
+ # rules.assert 'France'
156
177
  #
157
178
  def facts(name, &b)
179
+ name.gsub!(/:/, '_')
158
180
  name.to_s.downcase!
159
181
  @facts[name] = Facts.new(self, name, b)
160
182
  logger.debug( "created facts: #{name}") if logger
@@ -163,11 +185,11 @@ module Rools
163
185
  # A single fact can be an single object of a particular class type
164
186
  # or a collection of objects of a particular type
165
187
  def fact( obj )
166
- begin
188
+ #begin
167
189
  # check if facts already exist for that class
168
190
  # if so, we need to add it to the existing list
169
191
  cls = obj.class.to_s.downcase
170
-
192
+ cls.gsub!(/:/, '_')
171
193
  if @facts.key? cls
172
194
  logger.debug( "adding to facts: #{cls}") if logger
173
195
  @facts[cls].fact_value << obj
@@ -178,9 +200,9 @@ module Rools
178
200
  proc = Proc.new { arr }
179
201
  @facts[cls] = Facts.new(self, cls, proc )
180
202
  end
181
- rescue Exception=> e
182
- logger.error e if logger
183
- end
203
+ #rescue Exception=> e
204
+ # logger.error e if logger
205
+ #end
184
206
  end
185
207
 
186
208
  # Delete all existing facts
@@ -289,7 +311,7 @@ module Rools
289
311
  get_relevant_rules()
290
312
  logger.debug("no relevant rules") if logger && @relevant_rules.size==0
291
313
 
292
- begin #rescue
314
+ #begin #rescue
293
315
 
294
316
  # loop through the available_rules, evaluating each one,
295
317
  # until there are no more matching rules available
@@ -331,23 +353,22 @@ module Rools
331
353
  break
332
354
  end # if rule.conditions_match?(obj)
333
355
 
356
+ rescue RuleConsequenceError
357
+ fail
334
358
  rescue RuleCheckError => e
335
- #puts "evaluate RuleCheckError: #{e.to_s}"
336
- logger.error( "RuleCheckError") if logger
337
- @relevant_rules.delete(e.rule)
338
- @status = fail
359
+ fail
339
360
  end # begin/rescue
340
361
 
341
362
  end # available_rules.each
342
363
 
343
364
  end while(matches && @assert)
344
365
 
345
- rescue RuleConsequenceError => rce
366
+ #rescue RuleConsequenceError => rce
346
367
  # RuleConsequenceErrors are allowed to break out of the current assertion,
347
368
  # then the inner error is bubbled-up to the asserting code.
348
- @status = fail
349
- raise rce.inner_error
350
- end
369
+ # @status = FAIL
370
+ # raise rce.inner_error
371
+ #end
351
372
 
352
373
  @assert = false
353
374
 
@@ -355,4 +376,4 @@ module Rools
355
376
  end
356
377
 
357
378
  end # class RuleSet
358
- end # module Rools
379
+ end # module Rools
@@ -1,4 +1,4 @@
1
1
  module Rools
2
- ROOLS_VERSION = '0.2'
3
- ROOLS_COVERAGE = 95.1
2
+ ROOLS_VERSION = '0.3'
3
+ ROOLS_COVERAGE = 100.0
4
4
  end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.2
3
3
  specification_version: 1
4
4
  name: rools
5
5
  version: !ruby/object:Gem::Version
6
- version: "0.2"
7
- date: 2007-05-22 00:00:00 -04:00
6
+ version: "0.3"
7
+ date: 2007-07-18 00:00:00 -04:00
8
8
  summary: A Rules Engine written in Ruby
9
9
  require_paths:
10
10
  - lib