msfl 1.1.1 → 1.1.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.
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