array_logic 0.2.1 → 0.2.2

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.
@@ -52,7 +52,11 @@ module ArrayLogic
52
52
 
53
53
  private
54
54
  def logic
55
- eval(expression)
55
+ begin
56
+ eval(expression)
57
+ rescue SyntaxError
58
+ raise "Unable to determine logic from this expression : #{expression}"
59
+ end
56
60
  end
57
61
 
58
62
  def match_ids(ids)
@@ -82,9 +86,9 @@ module ArrayLogic
82
86
  end
83
87
 
84
88
  def rule_processing_steps
85
- replace_item(function_pattern, value_of_function_called_on_id_objects)
86
89
  add_space_around_puctuation_characters
87
90
  make_everything_lower_case
91
+ replace_item(function_pattern, build_logic_from_function_statement)
88
92
  replace_logic_words_with_operators
89
93
  replace_item(thing_id_pattern, ids_include_this_id)
90
94
  replace_item(number_in_set_pattern, comparison_of_number_with_true_count)
@@ -117,34 +121,29 @@ module ArrayLogic
117
121
  end
118
122
 
119
123
  def function_pattern
120
- /(#{array_functions.keys.join('|')})\(\s*\:(\w+[\?\!]?)\s*\)\s*((==|[\<\>\!]=?)\s*\d+(\.\d+)?)/
124
+ function_name_pattern = array_functions.keys.join('|')
125
+ instance_function_pattern = '\w+[\?\!]?' # e.g. 'id', 'this!', 'that?', 'foo_bar'
126
+ comparison_pattern ='(==|[\<\>]=?|!=)\s*\d+(\.\d+)?' # e.g. '== 4.3', '> 4'
127
+ /(#{function_name_pattern})\(\s*\:(#{instance_function_pattern})\s*\)\s*(#{comparison_pattern})/
121
128
  end
122
129
 
123
130
  def array_functions
124
131
  {
125
- :sum => 'inject(:+)',
126
- :average => 'reduce(:+) / size.to_f',
132
+ :sum => 'reduce(0){|sum,x| x.respond_to?(:to_f) ? sum + x.to_f : sum }',
133
+ :average => 'reduce(0){|sum,x| x.respond_to?(:to_f) ? sum + x.to_f : sum } / size',
127
134
  :count => 'compact.size'
128
135
  }
129
136
  end
130
137
 
131
- def value_of_function_called_on_id_objects
138
+ def build_logic_from_function_statement
132
139
  lambda do |string|
133
- all, array_function, function, operator = function_pattern.match(string).to_a
134
- values = things.collect &function.to_sym
135
- numbers_booleans_or_nils?(values)
140
+ array_function, instance_function, comparison = function_pattern.match(string).to_a[1, 3]
141
+ values = things.collect &instance_function.to_sym
136
142
  result = values.instance_eval(array_functions[array_function.to_sym])
137
- "( #{result} #{operator} )"
143
+ "( #{result} #{comparison} )"
138
144
  end
139
145
  end
140
146
 
141
- def numbers_booleans_or_nils?(values)
142
- errors = values.reject{|v| v.nil? || v.is_a?(Numeric) || !!v == v}
143
- unless errors.empty?
144
- raise "Values must be numbers or nils. The problem is here: #{errors.join(", ")}"
145
- end
146
- end
147
-
148
147
  def processed_rule
149
148
  @processed_rule ||= rule.clone
150
149
  end
@@ -200,13 +199,13 @@ module ArrayLogic
200
199
  def allowed_characters
201
200
  {
202
201
  :brackets => ['\(', '\)'],
203
- :in_pattern => ['\d+\s+in'],
202
+ :in_pattern => '\d+\s+in',
204
203
  :ids => [thing_id_pattern],
205
204
  :logic_words => %w{and or not},
206
205
  :logic_chrs => ['&&', '\|\|', '!'],
207
- :commas => ['\,'],
208
- :white_space => ['\s'],
209
- :function_pattern => [function_pattern]
206
+ :commas => '\,',
207
+ :white_space => '\s',
208
+ :function_pattern => function_pattern
210
209
  }
211
210
  end
212
211
 
@@ -1,24 +1,29 @@
1
1
  module ArrayLogic
2
- VERSION = "0.2.1"
2
+ VERSION = "0.2.2"
3
3
  end
4
4
 
5
5
  # History
6
6
  # =======
7
7
  #
8
+ # Version 0.2.2
9
+ # -------------
10
+ # Refactor to allow functions to be more flexible. That's is, to handle unexpected
11
+ # input, rather than just rejecting it.
12
+ #
8
13
  # Version 0.2.1
9
- # =============
14
+ # -------------
10
15
  # Improved handling of errors in functions and add != operator
11
16
  #
12
17
  # Version 0.2.0
13
- # =============
18
+ # -------------
14
19
  # Adds functions: sum, count and average
15
20
  #
16
21
  # Version 0.1.2
17
- # =============
22
+ # -------------
18
23
  # Refactor to tidy up code and make private, rule methods that don't need exposing
19
24
  #
20
25
  #
21
26
  # Version 0.1.1
22
- # =============
27
+ # -------------
23
28
  # Working version. No history before this point
24
29
  #
@@ -298,10 +298,12 @@ module ArrayLogic
298
298
  end
299
299
 
300
300
  def test_function_with_object_method_that_does_not_return_number
301
- @rule.rule = 'sum(:methods) == 1'
302
- assert_raise RuntimeError do
303
- @rule.match(get_things([1, 2]))
304
- end
301
+ @rule.rule = 'average(:methods) == 0'
302
+ assert @rule.match(get_things([1, 2]))
303
+ @rule.rule = 'sum(:methods) == 0'
304
+ assert @rule.match(get_things([1, 2]))
305
+ @rule.rule = 'count(:methods) == 2'
306
+ assert @rule.match(get_things([1, 2]))
305
307
  end
306
308
 
307
309
  def test_match_without_rule
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.2.1
4
+ version: 0.2.2
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-03-27 00:00:00.000000000 Z
12
+ date: 2013-03-28 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.