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.
- data/README.rdoc +68 -2
- data/Rakefile +1 -1
- data/lib/array_logic.rb +0 -1
- data/lib/array_logic/rule.rb +24 -1
- data/lib/array_logic/version.rb +5 -1
- data/test/array_logic/rule_test.rb +109 -1
- data/test/array_logic/test_case.rb +1 -0
- data/{lib → test}/array_logic/thing.rb +8 -0
- data/test/array_logic/thing_test.rb +10 -0
- metadata +4 -3
data/README.rdoc
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
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
|
-
|
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 = "
|
12
|
+
rdoc.title = "ArrayLogic Docs"
|
13
13
|
rdoc.rdoc_dir = 'doc/rdoc' # rdoc output folder
|
14
14
|
rdoc.options << '--line-numbers'
|
15
15
|
end
|
data/lib/array_logic.rb
CHANGED
data/lib/array_logic/rule.rb
CHANGED
@@ -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 => [
|
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
|
|
data/lib/array_logic/version.rb
CHANGED
@@ -1,10 +1,14 @@
|
|
1
1
|
module ArrayLogic
|
2
|
-
VERSION = "0.
|
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
|
@@ -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.
|
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-
|
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
|