msfl 1.1.1 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8b2132d5eaec0ac5b4a2055174d6f40685580f40
4
- data.tar.gz: 0ff98ee3c34b4225a43c8e9433b0c08b87e2521f
3
+ metadata.gz: e60cd25d855a736231fddc1f1d893df5a1b45296
4
+ data.tar.gz: cd75be374c724735b63103dcd8c9f5d2b021d480
5
5
  SHA512:
6
- metadata.gz: cdacb790d452b5343363f7b8e420f4a37aabd3e5e16f2005031545f79389c06f528c42601ef8f537350a993cfce5b1af745b5607142c041af50df784930091ba
7
- data.tar.gz: 5c429cf64452914f271a8ad7513627e009c1d8ea33c1a5f9768277df9f2c660f62c02615a4823bb434fed98c1c9478383e8337495646b8f93579390cc54f8fd0
6
+ metadata.gz: 888ff6048f6f675f75f1f518ef928ce66d1d0fe40f651d6597738050b0845064392533d0f0c28bfebf7cc2ce1495df0d27f3014414bbbe1e133063d42202052d
7
+ data.tar.gz: 6c0e6b5f896bb6061abcfdd9e572cc0c90d804bee82127d09f6ace0b7278403288c48fa63ca0374408cbefcbc9dd31639ded8297df9a68f51d75bb4995449471
@@ -3,6 +3,58 @@ module MSFL
3
3
  class Operator
4
4
  include MSFL::Validators::Definitions::HashKey
5
5
 
6
+ # Order is respected by run_conversions
7
+ # in otherwords run_conversions executes conversions in the order they occur
8
+ # in CONVERSIONS, not in the order in which they are passed into the method
9
+ #
10
+ # conversion order is context-free
11
+ CONVERSIONS = [
12
+ :implicit_between_to_explicit_recursively,
13
+ :between_to_gte_lte_recursively,
14
+ :implicit_and_to_explict_recursively
15
+ ]
16
+
17
+ # Runs conversions on an object
18
+ # It respects the order of CONVERSIONS, not the order of elements in conversions_to_run
19
+ #
20
+ # @param obj [Object] the object to run the conversions on
21
+ # @param conversions_to_run [Array<Symbol>] an array of the conversions that should be run, duplicates are ignored
22
+ # @return [Object] the object with the conversions applied
23
+ def run_conversions(obj, conversions_to_run = nil)
24
+ conversions_to_run ||= CONVERSIONS
25
+ unless all_conversions?(conversions_to_run)
26
+ raise ArgumentError, "#run_conversions second argument is optional, if specified it must be an Array of Symbols"
27
+ end
28
+
29
+ CONVERSIONS.each do |conv|
30
+ # In the order that items are in CONVERSIONS run all of the conversions_to_run
31
+ obj = send(conv, obj) if conversions_to_run.include?(conv)
32
+ end
33
+ end
34
+
35
+
36
+
37
+ # { year: { start: 2001, end: 2005 } }
38
+ # => { year: { between: { start: 2001, end: 2015 } } }
39
+ def implicit_between_to_explicit_recursively(obj)
40
+ if obj.is_a? Hash
41
+ # if the hash has two keys :start and :end, nest it inside a between and recurse on the values
42
+ if obj.has_key?(:start) && obj.has_key?(:end)
43
+ result = { between: { start: implicit_between_to_explicit_recursively(obj[:start]), end: implicit_between_to_explicit_recursively(obj[:end]) } }
44
+ else
45
+ result = Hash.new
46
+ obj.each do |k, v|
47
+ result[k] = implicit_between_to_explicit_recursively(v)
48
+ end
49
+ end
50
+ elsif obj.is_a? Types::Set
51
+ result = recurse_through_set :implicit_between_to_explicit_recursively, obj
52
+ elsif obj.is_a? Array
53
+ raise ArgumentError, "#implicit_between_to_explicit_recursively requires that it does not contain any Arrays - its argument should preprocessed by .arrays_to_sets and .convert_keys_to_symbols"
54
+ end
55
+ result ||= obj
56
+ end
57
+
6
58
  # Recursively converts all between operators to equivalent anded gte / lte
7
59
  # it currently creates the converted operators into the implied AND format
8
60
  #
@@ -21,10 +73,7 @@ module MSFL
21
73
  end
22
74
  end
23
75
  elsif obj.is_a? Types::Set
24
- result = Types::Set.new
25
- obj.each do |v|
26
- result << between_to_gte_lte_recursively(v)
27
- end
76
+ result = recurse_through_set :between_to_gte_lte_recursively, obj
28
77
  elsif obj.is_a? Array
29
78
  raise ArgumentError, "#between_to_gte_lte requires that it does not contain any Arrays - its argument should preprocessed by .arrays_to_sets and .convert_keys_to_symbols"
30
79
  end
@@ -62,13 +111,8 @@ module MSFL
62
111
  elsif obj[first_key].is_a? MSFL::Types::Set
63
112
  # This situation occurs when there are nested logical operators
64
113
  # obj is a hash, with one key that is not a binary operator which has a value that is a MSFL::Types::Set
65
- result = { }
66
- and_array = MSFL::Types::Set.new
67
- obj[first_key].each do |v|
68
- # byebug
69
- and_array << implicit_and_to_explicit_recursively(v)
70
- end
71
- result[first_key] = and_array
114
+ result = Hash.new
115
+ result[first_key] = recurse_through_set :implicit_and_to_explicit_recursively, obj[first_key]
72
116
  elsif obj[first_key].is_a? Array
73
117
  raise ArgumentError, "#implicit_and_to_explicit requires that it does not contain any Arrays - its argument should preprocessed by .arrays_to_sets and .convert_keys_to_symbols"
74
118
  end
@@ -110,7 +154,6 @@ module MSFL
110
154
  # the first key an operator
111
155
  raise ArgumentError, "#implicit_and_to_explicit requires that all or none of a hash's keys be operators" unless all_operators?(hash.keys)
112
156
  # all keys are operators
113
-
114
157
  first_key = hash.keys.first
115
158
  if hash.keys.count == 1
116
159
  # There's only one key so there cannot be an implied AND at this level
@@ -122,7 +165,6 @@ module MSFL
122
165
  else
123
166
  { first_key => implicit_and_to_explicit_recursively(hash[first_key]) }
124
167
  end
125
-
126
168
  else
127
169
  raise ArgumentError, "#implicit_and_to_explicit requires that parent_key be specified when converting operators" if parent_key.nil?
128
170
  # parent key is non nil
@@ -135,12 +177,28 @@ module MSFL
135
177
  end
136
178
 
137
179
  def i_to_e_set(set, parent_key = nil)
180
+ recurse_through_set :implicit_and_to_explicit_recursively, set
181
+ end
182
+
183
+ def recurse_through_set(method, set)
138
184
  result = MSFL::Types::Set.new
139
185
  set.each do |v|
140
- result << implicit_and_to_explicit_recursively(v)
186
+ result << send(method, v)
141
187
  end
142
188
  result
143
189
  end
190
+
191
+ # Returns true if the argument is an Array of Symbols, otherwise false
192
+ #
193
+ # @param obj [Obj] the object to check
194
+ # @return [Bool] true if the argument is an Array of Symbols
195
+ def all_conversions?(obj)
196
+ return false unless obj.is_a?(Array)
197
+ obj.each do |v|
198
+ return false unless v.is_a?(Symbol)
199
+ end
200
+ true
201
+ end
144
202
  end
145
203
  end
146
204
  end
data/msfl.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'msfl'
3
- s.version = '1.1.1'
3
+ s.version = '1.1.2'
4
4
  s.date = '2015-04-01'
5
5
  s.summary = "MSFL in Ruby"
6
6
  s.description = "Serializers, validators, and other tasty goodness for the Mattermark Semantic Filter Language in Ruby."
@@ -2,6 +2,208 @@ require 'spec_helper'
2
2
 
3
3
  describe "MSFL::Converters::Operator" do
4
4
 
5
+ describe "#run_conversions" do
6
+
7
+ subject { test_instance.run_conversions obj, conversions_to_run }
8
+
9
+ let(:klass) do
10
+ class OpTestConverter < MSFL::Converters::Operator
11
+ end
12
+ OpTestConverter
13
+ end
14
+
15
+ let(:test_instance) { klass.new }
16
+
17
+ let(:obj) { Object.new }
18
+
19
+ let(:conversions_to_run) { nil }
20
+
21
+ context "when the conversions_to_run argument is nil" do
22
+
23
+ let(:test_instance) do
24
+ t_i = klass.new
25
+
26
+ allow(t_i).to receive(:implicit_between_to_explicit_recursively)
27
+ expect(t_i).to receive(:implicit_between_to_explicit_recursively).once
28
+
29
+ allow(t_i).to receive(:between_to_gte_lte_recursively)
30
+ expect(t_i).to receive(:between_to_gte_lte_recursively).once
31
+
32
+ allow(t_i).to receive(:implicit_and_to_explict_recursively)
33
+ expect(t_i).to receive(:implicit_and_to_explict_recursively).once
34
+ t_i
35
+ end
36
+
37
+ it "runs all conversions in CONVERSIONS" do
38
+ subject
39
+ end
40
+ end
41
+
42
+ context "when conversions_to_run is an array of symbols" do
43
+
44
+ let(:conversions_to_run) { [:implicit_and_to_explict_recursively, :between_to_gte_lte_recursively]}
45
+
46
+ it "runs all elements in CONVERSIONS that are in conversions_to_run" do
47
+ allow(test_instance).to receive :implicit_and_to_explict_recursively
48
+ expect(test_instance).to receive(:implicit_and_to_explict_recursively)
49
+
50
+ allow(test_instance).to receive :between_to_gte_lte_recursively
51
+ expect(test_instance).to receive(:between_to_gte_lte_recursively)
52
+
53
+ allow(test_instance).to receive :implicit_between_to_explicit_recursively
54
+ expect(test_instance).to receive(:implicit_between_to_explicit_recursively).never
55
+
56
+ subject
57
+ end
58
+
59
+ it "runs the indicated conversions exactly once" do
60
+
61
+ allow(test_instance).to receive :implicit_and_to_explict_recursively
62
+ expect(test_instance).to receive(:implicit_and_to_explict_recursively).once
63
+
64
+ allow(test_instance).to receive :between_to_gte_lte_recursively
65
+ expect(test_instance).to receive(:between_to_gte_lte_recursively).once
66
+
67
+ subject
68
+ end
69
+
70
+ it "runs the indicated conversions in the order they appear in CONVERSIONS" do
71
+
72
+ allow(test_instance).to receive :between_to_gte_lte_recursively
73
+ expect(test_instance).to receive(:between_to_gte_lte_recursively).ordered
74
+
75
+ allow(test_instance).to receive :implicit_and_to_explict_recursively
76
+ expect(test_instance).to receive(:implicit_and_to_explict_recursively).ordered
77
+
78
+ subject
79
+ end
80
+ end
81
+
82
+
83
+ context "when conversions_to_run is not nil and not an array of symbols" do
84
+
85
+ let(:conversions_to_run) { "foo" }
86
+
87
+ it "raises an ArgumentError" do
88
+ expect { subject }.to raise_error ArgumentError
89
+ end
90
+ end
91
+ end
92
+
93
+ describe "#implicit_between_to_explicit_recursively" do
94
+
95
+ subject { test_instance.implicit_between_to_explicit_recursively arg }
96
+
97
+ let(:test_instance) { MSFL::Converters::Operator.new }
98
+
99
+ let(:arg) { raise ArgumentError, "You are expected to define the arg variable" }
100
+
101
+ let(:expected) { raise ArgumentError, "You are expected to define the expected value" }
102
+
103
+ context "when there is not an implicit BETWEEN" do
104
+
105
+ ["foo", { foo: "bar" }, 123, 56.12, :aaaah].each do |arg|
106
+
107
+ context "when the argument is #{arg}" do
108
+
109
+ let(:arg) { arg }
110
+
111
+ it "is the argument unchanged" do
112
+ expect(subject).to eq arg
113
+ end
114
+ end
115
+ end
116
+ end
117
+
118
+ context "when there is an implicit BETWEEN" do
119
+
120
+ context "when the implicit BETWEEN is at the highest possible level of the filter" do
121
+
122
+ let(:arg) { { year: { start: 2001, end: 2005 } } }
123
+
124
+ let(:expected) { { year: { between: { start: 2001, end: 2005 } } } }
125
+
126
+ it "is an explicit BETWEEN" do
127
+ expect(subject).to eq expected
128
+ end
129
+ end
130
+
131
+ context "when the implicit BETWEEN is inside of a MSFL::Types::Set" do
132
+
133
+ let(:arg) do
134
+ { and:
135
+ MSFL::Types::Set.new([
136
+ { make: "Honda"},
137
+ { year: { start: 2001, end: 2005 } }
138
+ ])
139
+ }
140
+ end
141
+
142
+ let(:expected) do
143
+ { and: MSFL::Types::Set.new([
144
+ { make: "Honda" },
145
+ { year: { between: { start: 2001, end: 2005 } } }
146
+ ])}
147
+ end
148
+
149
+ it "recursively converts the implicit BETWEEN to an explicit BETWEEN" do
150
+ expect(subject).to eq expected
151
+ end
152
+ end
153
+
154
+ # This can't actually happen in the current MSFL syntax (at least I don't think it can)
155
+ context "when the implicit BETWEEN is inside of another Hash" do
156
+
157
+ let(:arg) do
158
+ { foo: { bar: { start: "2015-01-01", end: "2015-03-01" } } }
159
+ end
160
+
161
+ let(:expected) do
162
+ { foo: { bar: { between: { start: "2015-01-01", end: "2015-03-01" } } } }
163
+ end
164
+
165
+ it "recursively converts the implicit BETWEEN to an explicit BETWEEN" do
166
+ expect(subject).to eq expected
167
+ end
168
+ end
169
+
170
+ context "when there are multiple implicit BETWEENs that are deeply nested" do
171
+
172
+ let(:deep_nest) do
173
+ {
174
+ cat: 1221,
175
+ dog: "fur",
176
+ lol: MSFL::Types::Set.new([ { hat: { start: 1, end: 5 } } ]),
177
+ :"1337" => 1337.1337,
178
+ noob: MSFL::Types::Set.new([
179
+ MSFL::Types::Set.new([123]),
180
+ { :"123" => 456, onetwo: { start: 3, end: 4 } } ]) }
181
+ end
182
+
183
+ let(:arg) { deep_nest }
184
+
185
+ let(:expected) do
186
+ {
187
+ cat: 1221,
188
+ dog: "fur",
189
+ lol: MSFL::Types::Set.new([
190
+ { hat: { between: { start: 1, end: 5 } } }
191
+ ]),
192
+ :"1337" => 1337.1337,
193
+ noob: MSFL::Types::Set.new([
194
+ MSFL::Types::Set.new([123]),
195
+ { :"123" => 456, onetwo: { between: { start: 3, end: 4 } } }
196
+ ])
197
+ }
198
+ end
199
+
200
+ it "recursively converts the implicit BETWEENs to an explicit BETWEENs" do
201
+ expect(subject).to eq expected
202
+ end
203
+ end
204
+ end
205
+ end
206
+
5
207
  describe "#implicit_and_to_explicit" do
6
208
 
7
209
  subject(:mut) { test_instance.implicit_and_to_explicit_recursively arg }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: msfl
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Courtland Caldwell