array_logic 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|