array_logic 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- == array_logic
1
+ = ArrayLogic
2
2
 
3
3
  A system that allows me to define the logic for comparing arrays of objects.
4
4
 
@@ -39,7 +39,7 @@ and *blockers*:
39
39
 
40
40
  See test/array_logic/rule_test for more examples
41
41
 
42
- === Combinations that match
42
+ == Combinations that match
43
43
 
44
44
  Two methods allow you to determine sample combinations that match the current
45
45
  rule.
@@ -57,3 +57,69 @@ and so would [1,2,3]. However, arrays that only contain 1 or 2 would not match
57
57
  Run example.rb to see some more examples
58
58
 
59
59
  ruby /lib/example.rb
60
+
61
+ == Functions
62
+
63
+ Version 0.2 introduces the concept of functions to ArrayLogic. The function
64
+ syntax is:
65
+
66
+ <function>(<object_method as symbol>) <operator> <number>
67
+
68
+ where:
69
+
70
+ [function] One of the functions listed below
71
+ [object_method] A method that can be called on all of the objects in the array
72
+ [operator] one of: <, <=, >, >=, ==
73
+ [number] a number to compare with the result
74
+
75
+ Using this array as an example:
76
+
77
+ answers = [Answer.find(1), Answer.find(5), Answer.find(6)]
78
+
79
+ === sum
80
+
81
+ Sums the values returned by the object_method and compares them with the number
82
+
83
+ rule = ArrayLogic::Rule.new 'sum(:id) == 12'
84
+ rule.match(answers) --> true
85
+
86
+ rule = ArrayLogic::Rule.new 'sum(:id) > 12'
87
+ rule.match(answers) --> false
88
+
89
+ rule = ArrayLogic::Rule.new 'sum(:id) >= 12'
90
+ rule.match(answers) --> true
91
+
92
+ === average
93
+
94
+ Averages the values returned by the object_method and compares them with the number
95
+
96
+ rule = ArrayLogic::Rule.new 'average(:id) == 4'
97
+ rule.match(answers) --> true
98
+
99
+ rule = ArrayLogic::Rule.new 'average(:id) < 4'
100
+ rule.match(answers) --> false
101
+
102
+ rule = ArrayLogic::Rule.new 'average(:id) <= 4'
103
+ rule.match(answers) --> true
104
+
105
+ === count
106
+
107
+ Counts the number of items not returning nil.
108
+
109
+ rule = ArrayLogic::Rule.new 'count(:id) == 3'
110
+ rule.match(answers) --> true
111
+
112
+ If answer has a method :is_odd? that returned nil if the :id is even:
113
+
114
+ rule = ArrayLogic::Rule.new 'count(:is_odd?) == 2'
115
+ rule.match(answers) --> true
116
+
117
+ === Combining functions with other rules
118
+
119
+ functions can be combined with other rules:
120
+
121
+ rule = ArrayLogic::Rule.new 'sum(:id) == 12 and a6'
122
+ rule.match(answers) --> true
123
+
124
+ rule = ArrayLogic::Rule.new '(sum(:id) == 12) and not a6'
125
+ rule.match(answers) --> false
data/Rakefile CHANGED
@@ -9,7 +9,7 @@ Rake::RDocTask.new do |rdoc|
9
9
  files =['README.rdoc', 'MIT-LICENSE', 'lib/**/*.rb']
10
10
  rdoc.rdoc_files.add(files)
11
11
  rdoc.main = "README.rdoc" # page to start on
12
- rdoc.title = "Dibber Docs"
12
+ rdoc.title = "ArrayLogic Docs"
13
13
  rdoc.rdoc_dir = 'doc/rdoc' # rdoc output folder
14
14
  rdoc.options << '--line-numbers'
15
15
  end
@@ -1,4 +1,3 @@
1
- require_relative('array_logic/thing')
2
1
  require_relative('array_logic/rule')
3
2
  module ArrayLogic
4
3
 
@@ -82,6 +82,7 @@ module ArrayLogic
82
82
  end
83
83
 
84
84
  def rule_processing_steps
85
+ replace_item(function_pattern, value_of_function_called_on_id_objects)
85
86
  add_space_around_puctuation_characters
86
87
  make_everything_lower_case
87
88
  replace_logic_words_with_operators
@@ -114,6 +115,27 @@ module ArrayLogic
114
115
  def ids_include_this_id
115
116
  lambda {|s| thing_ids.include?(s[/\d+/].to_i)}
116
117
  end
118
+
119
+ def function_pattern
120
+ /(#{array_functions.keys.join('|')})\(\s*\:(\w+[\?\!]?)\s*\)\s*((==|[\<\>]=?)\s*\d+(\.\d+)?)/
121
+ end
122
+
123
+ def array_functions
124
+ {
125
+ :sum => 'inject(:+)',
126
+ :average => 'reduce(:+) / size.to_f',
127
+ :count => 'compact.size'
128
+ }
129
+ end
130
+
131
+ def value_of_function_called_on_id_objects
132
+ lambda do |string|
133
+ all, array_function, function, operator = function_pattern.match(string).to_a
134
+ values = things.collect &function.to_sym
135
+ result = values.instance_eval(array_functions[array_function.to_sym])
136
+ "( #{result} #{operator} )"
137
+ end
138
+ end
117
139
 
118
140
  def processed_rule
119
141
  @processed_rule ||= rule.clone
@@ -171,11 +193,12 @@ module ArrayLogic
171
193
  {
172
194
  :brackets => ['\(', '\)'],
173
195
  :in_pattern => ['\d+\s+in'],
174
- :ids => ['\w\d+'],
196
+ :ids => [thing_id_pattern],
175
197
  :logic_words => %w{and or not},
176
198
  :logic_chrs => ['&&', '\|\|', '!'],
177
199
  :commas => ['\,'],
178
200
  :white_space => ['\s'],
201
+ :function_pattern => [function_pattern]
179
202
  }
180
203
  end
181
204
 
@@ -1,10 +1,14 @@
1
1
  module ArrayLogic
2
- VERSION = "0.1.2"
2
+ VERSION = "0.2.0"
3
3
  end
4
4
 
5
5
  # History
6
6
  # =======
7
7
  #
8
+ # Version 0.2.0
9
+ # =============
10
+ # Adds functions: sum, count and average
11
+ #
8
12
  # Version 0.1.2
9
13
  # =============
10
14
  # Refactor to tidy up code and make private, rule methods that don't need exposing
@@ -144,7 +144,115 @@ module ArrayLogic
144
144
  assert_thing_match([1, 2, 3], @rule)
145
145
  assert_no_thing_match([3], @rule)
146
146
  assert_thing_match([4], @rule)
147
- end
147
+ end
148
+
149
+ def test_cost
150
+ assert_equal(2, Thing.new(1).cost)
151
+ end
152
+
153
+ def test_sum
154
+ @rule.rule = 'sum(:cost) == 2'
155
+ assert_no_thing_match([1, 2], @rule)
156
+ assert_no_thing_match([1, 2, 3], @rule)
157
+ assert_thing_match([3], @rule)
158
+ assert_thing_match([4], @rule)
159
+ end
160
+
161
+ def test_sum_greater_than
162
+ @rule.rule = 'sum(:cost) > 2'
163
+ assert_thing_match([1, 2], @rule)
164
+ assert_thing_match([1, 2, 3], @rule)
165
+ assert_no_thing_match([3], @rule)
166
+ assert_no_thing_match([4], @rule)
167
+ end
168
+
169
+ def test_sum_less_than
170
+ @rule.rule = 'sum(:cost) < 3'
171
+ assert_no_thing_match([1, 2], @rule)
172
+ assert_no_thing_match([1, 2, 3], @rule)
173
+ assert_thing_match([3], @rule)
174
+ assert_thing_match([4], @rule)
175
+ end
176
+
177
+ def test_average
178
+ @rule.rule = 'average(:id) == 2'
179
+ assert_no_thing_match([1, 2], @rule)
180
+ assert_thing_match([1, 2, 3], @rule)
181
+ assert_no_thing_match([3], @rule)
182
+ assert_no_thing_match([4], @rule)
183
+ end
184
+
185
+ def test_average_with_decimal
186
+ @rule.rule = 'average(:id) == 1.5'
187
+ assert_thing_match([1, 2], @rule)
188
+ assert_no_thing_match([1, 2, 3], @rule)
189
+ assert_no_thing_match([3], @rule)
190
+ assert_no_thing_match([4], @rule)
191
+ end
192
+
193
+ def test_average_greater_than
194
+ @rule.rule = 'average(:id) > 2'
195
+ assert_no_thing_match([1, 2], @rule)
196
+ assert_no_thing_match([1, 2, 3], @rule)
197
+ assert_thing_match([3], @rule)
198
+ assert_thing_match([4], @rule)
199
+ end
200
+
201
+ def test_average_less_than
202
+ @rule.rule = 'average(:id) <= 2'
203
+ assert_thing_match([1, 2], @rule)
204
+ assert_thing_match([1, 2, 3], @rule)
205
+ assert_no_thing_match([3], @rule)
206
+ assert_no_thing_match([4], @rule)
207
+ end
208
+
209
+ def test_count
210
+ @rule.rule = 'count(:id) == 2'
211
+ assert_thing_match([1, 2], @rule)
212
+ assert_no_thing_match([1, 2, 3], @rule)
213
+ assert_no_thing_match([3], @rule)
214
+ assert_no_thing_match([4], @rule)
215
+ end
216
+
217
+ def test_count_greater_than
218
+ @rule.rule = 'count(:id) > 2'
219
+ assert_no_thing_match([1, 2], @rule)
220
+ assert_thing_match([1, 2, 3], @rule)
221
+ assert_no_thing_match([3], @rule)
222
+ assert_no_thing_match([4], @rule)
223
+ end
224
+
225
+ def test_count_less_than
226
+ @rule.rule = 'count(:id) <= 2'
227
+ assert_thing_match([1, 2], @rule)
228
+ assert_no_thing_match([1, 2, 3], @rule)
229
+ assert_thing_match([3], @rule)
230
+ assert_thing_match([4], @rule)
231
+ end
232
+
233
+ def test_count_with_method_that_can_return_nil
234
+ @rule.rule = 'count(:id_odd?) == 1'
235
+ assert_thing_match([1, 2], @rule)
236
+ assert_no_thing_match([1, 2, 3], @rule)
237
+ assert_thing_match([3], @rule)
238
+ assert_no_thing_match([4], @rule)
239
+ end
240
+
241
+ def test_function_with_other_rule
242
+ @rule.rule = 'sum(:id) >= 3 and t3'
243
+ assert_no_thing_match([1, 2], @rule)
244
+ assert_thing_match([1, 2, 3], @rule)
245
+ assert_thing_match([3], @rule)
246
+ assert_no_thing_match([4], @rule)
247
+ end
248
+
249
+ def test_function_with_other_rule_with_brackets
250
+ @rule.rule = '(sum(:id) >= 3) and t3'
251
+ assert_no_thing_match([1, 2], @rule)
252
+ assert_thing_match([1, 2, 3], @rule)
253
+ assert_thing_match([3], @rule)
254
+ assert_no_thing_match([4], @rule)
255
+ end
148
256
 
149
257
  def test_match_without_rule
150
258
  assert_raise RuntimeError do
@@ -1,5 +1,6 @@
1
1
  require 'test/unit'
2
2
  require_relative '../../lib/array_logic'
3
+ require_relative 'thing'
3
4
 
4
5
  module ArrayLogic
5
6
  class TestCase < Test::Unit::TestCase
@@ -8,6 +8,14 @@ module ArrayLogic
8
8
  @id = number
9
9
  end
10
10
 
11
+ def cost
12
+ 2
13
+ end
14
+
15
+ def id_odd?
16
+ return true if id % 2 != 0
17
+ end
18
+
11
19
  def self.make(number)
12
20
  things = Hash.new
13
21
  (1..number).each{|n| things[n] = new(n)}
@@ -10,5 +10,15 @@ module ArrayLogic
10
10
  assert_equal((1..number).to_a, things.values.collect(&:id))
11
11
  assert_equal((1..number).to_a, things.keys)
12
12
  end
13
+
14
+ def test_cost
15
+ thing = Thing.new(1)
16
+ assert_equal(2, thing.cost)
17
+ end
18
+
19
+ def test_id_odd
20
+ things = Thing.make(4)
21
+ assert_equal([true, nil, true, nil], things.values.collect(&:id_odd?))
22
+ end
13
23
  end
14
24
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: array_logic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-02-22 00:00:00.000000000 Z
12
+ date: 2013-03-26 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Allow a user to define a set of rules, and then test to see if an array
15
15
  of object match those rules.
@@ -20,13 +20,13 @@ extensions: []
20
20
  extra_rdoc_files: []
21
21
  files:
22
22
  - lib/array_logic/version.rb
23
- - lib/array_logic/thing.rb
24
23
  - lib/array_logic/rule.rb
25
24
  - lib/array_logic.rb
26
25
  - lib/example.rb
27
26
  - MIT-LICENSE
28
27
  - Rakefile
29
28
  - README.rdoc
29
+ - test/array_logic/thing.rb
30
30
  - test/array_logic/test_case.rb
31
31
  - test/array_logic/rule_test.rb
32
32
  - test/array_logic/thing_test.rb
@@ -55,6 +55,7 @@ signing_key:
55
55
  specification_version: 3
56
56
  summary: Matches arrays of objects against logical rules.
57
57
  test_files:
58
+ - test/array_logic/thing.rb
58
59
  - test/array_logic/test_case.rb
59
60
  - test/array_logic/rule_test.rb
60
61
  - test/array_logic/thing_test.rb