msfl 1.0.0 → 1.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 563d3ef0c03cf0f730fce20bca483a0821114b07
4
- data.tar.gz: 55d9c65bd08ff2112be042f643cb5db0e02ffbc0
3
+ metadata.gz: 51e5ed15234f2119cf9a96d709f7cb15505f6e75
4
+ data.tar.gz: b31ccaeae664a0d09c359322875a892d55808e71
5
5
  SHA512:
6
- metadata.gz: d9c693af109604a14129e16660d56ef5430b7039a4ada968a1d66c78cdf5be537154d7d7fcd87b577d626619ce81260aa715fa19a790d8a1636f4827946d0d25
7
- data.tar.gz: ca8a5143b80148cd2f37527c87400ce72abb527833299645af6ed592c9d861a73167f3adb094f19b8780bb05fddb280622d74218a2bf3869b21aa90aff39d2d2
6
+ metadata.gz: 6b8cdc31ca60efdbb600107dfd98c10580eac574c3677c2a24b34fdbf7933de5c488d719340a3a8d048c9b4be520b06ad456df80f7413c803f8cae607f24c391
7
+ data.tar.gz: 1a41e178d9b1230eeb16503b4411bc85a6daebc8260df764aea726c7880ee1fb11f608e316654bbfc64a433b46ee4e1675dfb2d15b114cd97d903f1a13258ab9
@@ -4,6 +4,7 @@ require_relative 'msfl/validators'
4
4
  require_relative 'msfl/configuration'
5
5
  require_relative 'msfl/datasets'
6
6
  require_relative 'msfl/sinatra'
7
+ require_relative 'msfl/converters'
7
8
 
8
9
  module MSFL
9
10
  class << self
@@ -0,0 +1 @@
1
+ require_relative 'converters/operator'
@@ -0,0 +1,115 @@
1
+ module MSFL
2
+ module Converters
3
+ class Operator
4
+ include MSFL::Validators::Definitions::HashKey
5
+
6
+ # Recursively converts all between operators to equivalent anded gte / lte
7
+ # it currently creates the converted operators into the implied AND format
8
+ #
9
+ # @param obj [Object] the object to recurse through to convert all betweens to gte / ltes
10
+ # @return [Object] the object with betweens converted to anded gte / ltes
11
+ def between_to_gte_lte_recursively(obj)
12
+ result = obj
13
+ if obj.is_a? Hash
14
+ obj.each do |k, v|
15
+ if v.is_a?(Hash) && v.has_key?(:between) && v[:between].has_key?(:start) && v[:between].has_key?(:end)
16
+ lower_bound = between_to_gte_lte_recursively v[:between][:start]
17
+ upper_bound = between_to_gte_lte_recursively v[:between][:end]
18
+ result[k] = { gte: lower_bound, lte: upper_bound }
19
+ else
20
+ result[k] = between_to_gte_lte_recursively v
21
+ end
22
+ end
23
+ 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
28
+ elsif obj.is_a? Array
29
+ 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
+ end
31
+ result
32
+ end
33
+
34
+ # Convert a Hash containing an implict and into an explicit and
35
+ #
36
+ # TYPE 1 ---
37
+ # { make: "chevy", year: 2010 }
38
+ # => { and: [ { make: "chevy" }, { year: 2010 }] }
39
+ # TYPE 2 ---
40
+ # { year: { gte: 2010, lte: 2012 } }
41
+ # => { and: [ { year: { gte: 2010 } }, { year: { lte: 2012 } } ] }
42
+ #
43
+ # TYPE 3 ---
44
+ # { make: "chevy", year: { gte: 2010, lte: 2012 } }
45
+ # => { and: [ { make: "chevy" }, { and: [ { year: { gte: 2010 } }, { year: { lte: 2012 } } ] } ] }
46
+ #
47
+ # @param obj [Object] the Hash that is an implicit and
48
+ # @return [Hash] the resulting explicit hash
49
+ def implicit_and_to_explicit_recursively(obj, parent_key = nil)
50
+ if obj.is_a? Hash
51
+ first_key = obj.keys.first
52
+ if hash_key_operators.include?(first_key)
53
+ # the first key an operator
54
+ raise ArgumentError, "#implicit_and_to_explicit requires that all or none of a hash's keys be operators" unless all_operators?(obj.keys)
55
+ # all keys are operators
56
+ raise ArgumentError, "#implicit_and_to_explicit requires that parent_key be specified when converting operators" if parent_key.nil?
57
+ # parent key is non nil
58
+ and_array = []
59
+ obj.each do |k, v|
60
+ and_array << { parent_key => { k => implicit_and_to_explicit_recursively(v, k) } }
61
+ end
62
+ else
63
+ # the first key is not an operator
64
+ # if there is only one key just assign the result of calling this method recursively on the value to the result for the key
65
+ if obj.keys.count == 1
66
+ if obj[first_key].is_a?(Hash)
67
+ result = implicit_and_to_explicit_recursively obj[first_key], first_key
68
+ end
69
+ else
70
+ raise ArgumentError, "#implicit_and_to_explicit requires that all or none of a hash's keys be operators" if any_operators?(obj.keys)
71
+ # none of the keys are operators
72
+ and_array = []
73
+ obj.each do |k, v|
74
+ if v.is_a? Hash
75
+ and_array << implicit_and_to_explicit_recursively(v, k)
76
+ else
77
+ and_array << { k => v }
78
+ end
79
+ end
80
+ end
81
+ end
82
+ result ||= { and: MSFL::Types::Set.new(and_array) }
83
+ elsif obj.is_a? MSFL::Types::Set
84
+ result = Types::Set.new
85
+ obj.each do |v|
86
+ result << implicit_and_to_explicit_recursively(v)
87
+ end
88
+ elsif obj.is_a? Array
89
+ 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"
90
+ end
91
+ result ||= obj
92
+ end
93
+
94
+ private
95
+ # Use this method for converting implicit and hashes to explicit ones when the keys are operators
96
+ def implicit_to_explicit_for_ops(hash)
97
+ and_array = []
98
+ field = hash.keys.first
99
+ if hash[field].is_a? Hash
100
+ hash[field].each do |k, v|
101
+ and_array << { field => { k => v } }
102
+ end
103
+ end
104
+ { and: MSFL::Types::Set.new(and_array) }
105
+ end
106
+
107
+ # Use this method for converting implicit and hashes to explicit ones when the keys are properties
108
+ def implicit_to_explicit_for_field(hash)
109
+ and_array = []
110
+ hash.each { |key, value| and_array << { key => value } }
111
+ { and: MSFL::Types::Set.new(and_array) }
112
+ end
113
+ end
114
+ end
115
+ end
@@ -13,7 +13,6 @@ module MSFL
13
13
  obj = ::JSON.parse(json_to_parse)
14
14
  obj = arrays_to_sets obj
15
15
  obj = convert_keys_to_symbols obj
16
- obj = convert_between_to_gte_lte obj
17
16
  obj
18
17
  end
19
18
 
@@ -57,34 +56,6 @@ module MSFL
57
56
  end
58
57
  result
59
58
  end
60
-
61
- # Recursively converts all between operators to equivalent anded gte / lte
62
- # it currently creates the converted operators in the implied AND format
63
- #
64
- # @param obj [Object] the object to recurse through to convert all betweens to gte / ltes
65
- # @return [Object] the object with betweens converted to anded gte / ltes
66
- def self.convert_between_to_gte_lte(obj)
67
- result = obj
68
- if obj.is_a? Hash
69
- obj.each do |k, v|
70
- if v.is_a?(Hash) && v.has_key?(:between) && v[:between].has_key?(:start) && v[:between].has_key?(:end)
71
- lower_bound = convert_between_to_gte_lte v[:between][:start]
72
- upper_bound = convert_between_to_gte_lte v[:between][:end]
73
- result[k] = { gte: lower_bound, lte: upper_bound }
74
- else
75
- result[k] = convert_between_to_gte_lte v
76
- end
77
- end
78
- elsif obj.is_a? Types::Set
79
- result = Types::Set.new
80
- obj.each do |v|
81
- result << convert_between_to_gte_lte(v)
82
- end
83
- elsif obj.is_a? Array
84
- raise ArgumentError, ".convert_between_to_gte_lte requires its argument to have been preprocessed by .arrays_to_sets and .convert_keys_to_symbols"
85
- end
86
- result
87
- end
88
59
  end
89
60
  end
90
61
  end
@@ -30,6 +30,28 @@ module MSFL
30
30
  :neg, # logical negation
31
31
  ]
32
32
  end
33
+
34
+ # Returns true if all elements of arr are operators, false otherwise
35
+ #
36
+ # @param arr [Array<Symbol>] the Array of Symbols to be checked against the operators list
37
+ # @return [Bool] true if all of the elements of arr are operators
38
+ def all_operators?(arr)
39
+ arr.each do |e|
40
+ return false unless hash_key_operators.include?(e)
41
+ end
42
+ true
43
+ end
44
+
45
+ # Returns true if any of the elements in arr are operators, otherwise false
46
+ #
47
+ # @param arr [Array] the array of elements to check for the presence of operators
48
+ # @return [Bool] true if any of the elements of arr are operators
49
+ def any_operators?(arr)
50
+ arr.each do |e|
51
+ return true if hash_key_operators.include?(e)
52
+ end
53
+ false
54
+ end
33
55
  end
34
56
  end
35
57
  end
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'msfl'
3
- s.version = '1.0.0'
3
+ s.version = '1.1.0'
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."
@@ -0,0 +1,193 @@
1
+ require 'spec_helper'
2
+
3
+ describe "MSFL::Converters::Operator" do
4
+
5
+ describe "#implicit_and_to_explicit" do
6
+
7
+ subject(:mut) { test_instance.implicit_and_to_explicit_recursively arg }
8
+
9
+ let(:test_instance) { MSFL::Converters::Operator.new }
10
+
11
+ let(:arg) { raise ArgumentError, "You are expected to define the arg variable" }
12
+
13
+ let(:expected) { raise ArgumentError, "You are expected to define the expected value" }
14
+
15
+ context "when the implicit AND exists on a Hash whose keys are fields" do
16
+
17
+ # TYPE 1 --- { make: "chevy", year: 2010 } => { and: [ { make: "chevy" }, { year: 2010 }] }
18
+ let(:arg) { { make: "chevy", year: 2010 } }
19
+
20
+ let(:expected) { { and: MSFL::Types::Set.new([
21
+ { make: "chevy" },
22
+ { year: 2010 }
23
+ ])}}
24
+
25
+ it "converts the implicit AND to an explicit AND" do
26
+ expect(mut).to eq expected
27
+ end
28
+ end
29
+
30
+ context "when the implicit AND exists on a Hash whose value is a Hash with multiple operator keys" do
31
+
32
+ # TYPE 2 --- { year: { gte: 2010, lte: 2012 } } => { and: [ { year: { gte: 2010 } }, { year: { lte: 2012 } } ] }
33
+ let(:arg) { { year: { gte: 2010, lte: 2012 } } }
34
+
35
+ let(:expected) { { and: MSFL::Types::Set.new([
36
+ { year: { gte: 2010 } },
37
+ { year: { lte: 2012 } }
38
+ ])}}
39
+
40
+ it "converts the implicit AND to an explicit AND" do
41
+ expect(mut).to eq expected
42
+ end
43
+ end
44
+
45
+ context "when the implicit AND exists on a Hash whose keys are fields" do
46
+
47
+ context "when the implicit AND exists on a Hash whose value is a Hash with multiple operator keys" do
48
+
49
+ # TYPE 3 --- { make: "chevy", year: { gte: 2010, lte: 2012 } } => { and: [ { make: "chevy" }, { and: [ { year: { gte: 2010 } }, { year: { lte: 2012 } } ] } ] }
50
+ let(:arg) { { make: "chevy", year: { gte: 2010, lte: 2012 } } }
51
+
52
+ let(:expected) do
53
+ { and: MSFL::Types::Set.new([
54
+ { make: "chevy" },
55
+ { and: MSFL::Types::Set.new([
56
+ { year: { gte: 2010 } },
57
+ { year: { lte: 2012 } }
58
+ ])}
59
+ ])}
60
+ end
61
+
62
+ it "converts both of the implicit ANDs to explicit ANDs" do
63
+ expect(mut).to eq expected
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ describe "#between_to_gte_lte_recursively" do
70
+
71
+ subject(:mut) { test_instance.between_to_gte_lte_recursively arg }
72
+
73
+ let(:test_instance) { MSFL::Converters::Operator.new }
74
+
75
+ let(:arg) { Object.new }
76
+
77
+ let(:deep_nest) do
78
+ {
79
+ cat: 1221,
80
+ dog: "fur",
81
+ lol: MSFL::Types::Set.new([ { hat: { between: { start: 1, end: 5 } } } ]),
82
+ :"1337" => 1337.1337, noob: MSFL::Types::Set.new([ MSFL::Types::Set.new([123]), { :"123" => 456, onetwo: 34 } ]) }
83
+ end
84
+
85
+ context "when the argument is a type other than MSFL::Types::Set, Hash, or Array" do
86
+
87
+ [55, 60.9, "five", :fourty, nil].each do |item|
88
+ context "when the argument is a #{item.class}" do
89
+
90
+ let(:arg) { item }
91
+
92
+ it "is equal to the argument" do
93
+ expect(mut).to eq arg
94
+ end
95
+ end
96
+ end
97
+ end
98
+
99
+ context "when the argument is a Hash" do
100
+
101
+ let(:arg) { { foo: { between: { start: "2015-01-01", end: "2015-04-01" } } } }
102
+
103
+ let(:expected) { { foo: { gte: "2015-01-01", lte: "2015-04-01" } } }
104
+
105
+ it "converts between clauses into anded gte / lte clauses" do
106
+ expect(mut).to eq expected
107
+ end
108
+
109
+ context "when the between clause is below the second level" do
110
+
111
+ let(:arg) do
112
+ {
113
+ and: MSFL::Types::Set.new([
114
+ { foo: { between: { start: -500, end: 12 } } },
115
+ { bar: { dog: "cat" } },
116
+ ])
117
+ }
118
+ end
119
+
120
+ let(:expected) do
121
+ {
122
+ and: MSFL::Types::Set.new([
123
+ { foo: { gte: -500, lte: 12 } },
124
+ { bar: { dog: "cat" } }
125
+ ])
126
+ }
127
+ end
128
+
129
+ it "recursively converts between clauses into anded gte / lte clauses" do
130
+ expect(mut).to eq expected
131
+ end
132
+ end
133
+ end
134
+
135
+ context "when the argument is a MSFL::Types::Set" do
136
+
137
+ let(:arg) { MSFL::Types::Set.new([ { foo: { between: { start: 1, end: 5 } } } ])}
138
+
139
+ let(:expected) { MSFL::Types::Set.new([ { foo: { gte: 1, lte: 5 } } ]) }
140
+
141
+ it "recursively converts between clauses into anded gte / lte clauses" do
142
+ expect(mut).to eq expected
143
+ end
144
+
145
+ context "when the between clause is below the second level" do
146
+
147
+ let(:arg) { MSFL::Types::Set.new([ { and: MSFL::Types::Set.new([{foo: { between: { start: 1, end: 5 } } }, {bar: 123}]) } ])}
148
+
149
+ let(:expected) { MSFL::Types::Set.new([ { and: MSFL::Types::Set.new([{ foo: { gte: 1, lte: 5} }, { bar: 123} ]) }]) }
150
+
151
+ it "recursively converts between clauses into anded gte / lte clauses" do
152
+ expect(mut).to eq expected
153
+ end
154
+ end
155
+ end
156
+
157
+ context "when the argument contains an Array" do
158
+
159
+ let(:arg) { [ { foo: { between: { start: 1, end: 5 } } } ] }
160
+
161
+ it "raises an ArgumentError" do
162
+ expect { mut }.to raise_error ArgumentError
163
+ end
164
+ end
165
+
166
+ context "when the argument is deeply nested and contains many types" do
167
+
168
+ let(:arg) { MSFL::Types::Set.new([deep_nest]) }
169
+
170
+ let(:expected) do
171
+ MSFL::Types::Set.new([
172
+ {
173
+ cat: 1221,
174
+ dog: "fur",
175
+ lol: MSFL::Types::Set.new(
176
+ [
177
+ { hat: { gte: 1, lte: 5} }
178
+ ]),
179
+ :"1337" => 1337.1337,
180
+ noob: MSFL::Types::Set.new(
181
+ [
182
+ MSFL::Types::Set.new([123]),
183
+ { :"123" => 456, onetwo: 34 }
184
+ ])
185
+ }])
186
+ end
187
+
188
+ it "recursively converts between clauses into anded gte / lte clauses" do
189
+ expect(mut).to eq expected
190
+ end
191
+ end
192
+ end
193
+ end
@@ -36,129 +36,6 @@ describe "MSFL::Parsers::JSON" do
36
36
 
37
37
  end
38
38
 
39
- describe ".convert_between_to_gte_lte" do
40
-
41
- subject(:mut) { MSFL::Parsers::JSON.convert_between_to_gte_lte arg }
42
-
43
- let(:arg) { Object.new }
44
-
45
- let(:deep_nest) do
46
- {
47
- cat: 1221,
48
- dog: "fur",
49
- lol: MSFL::Types::Set.new([ { hat: { between: { start: 1, end: 5 } } } ]),
50
- :"1337" => 1337.1337, noob: MSFL::Types::Set.new([ MSFL::Types::Set.new([123]), { :"123" => 456, onetwo: 34 } ]) }
51
- end
52
-
53
- context "when the argument is a type other than MSFL::Types::Set, Hash, or Array" do
54
-
55
- [55, 60.9, "five", :fourty, nil].each do |item|
56
- context "when the argument is a #{item.class}" do
57
-
58
- let(:arg) { item }
59
-
60
- it "is equal to the argument" do
61
- expect(mut).to eq arg
62
- end
63
- end
64
- end
65
- end
66
-
67
- context "when the argument is a Hash" do
68
-
69
- let(:arg) { { foo: { between: { start: "2015-01-01", end: "2015-04-01" } } } }
70
-
71
- let(:expected) { { foo: { gte: "2015-01-01", lte: "2015-04-01" } } }
72
-
73
- it "converts between clauses into anded gte / lte clauses" do
74
- expect(mut).to eq expected
75
- end
76
-
77
- context "when the between clause is below the second level" do
78
-
79
- let(:arg) do
80
- {
81
- and: MSFL::Types::Set.new([
82
- { foo: { between: { start: -500, end: 12 } } },
83
- { bar: { dog: "cat" } },
84
- ])
85
- }
86
- end
87
-
88
- let(:expected) do
89
- {
90
- and: MSFL::Types::Set.new([
91
- { foo: { gte: -500, lte: 12 } },
92
- { bar: { dog: "cat" } }
93
- ])
94
- }
95
- end
96
-
97
- it "recursively converts between clauses into anded gte / lte clauses" do
98
- expect(mut).to eq expected
99
- end
100
- end
101
- end
102
-
103
- context "when the argument is a MSFL::Types::Set" do
104
-
105
- let(:arg) { MSFL::Types::Set.new([ { foo: { between: { start: 1, end: 5 } } } ])}
106
-
107
- let(:expected) { MSFL::Types::Set.new([ { foo: { gte: 1, lte: 5 } } ]) }
108
-
109
- it "recursively converts between clauses into anded gte / lte clauses" do
110
- expect(mut).to eq expected
111
- end
112
-
113
- context "when the between clause is below the second level" do
114
-
115
- let(:arg) { MSFL::Types::Set.new([ { and: MSFL::Types::Set.new([{foo: { between: { start: 1, end: 5 } } }, {bar: 123}]) } ])}
116
-
117
- let(:expected) { MSFL::Types::Set.new([ { and: MSFL::Types::Set.new([{ foo: { gte: 1, lte: 5} }, { bar: 123} ]) }]) }
118
-
119
- it "recursively converts between clauses into anded gte / lte clauses" do
120
- expect(mut).to eq expected
121
- end
122
- end
123
- end
124
-
125
- context "when the argument contains an Array" do
126
-
127
- let(:arg) { [ { foo: { between: { start: 1, end: 5 } } } ] }
128
-
129
- it "raises an ArgumentError" do
130
- expect { mut }.to raise_error ArgumentError
131
- end
132
- end
133
-
134
- context "when the argument is deeply nested and contains many types" do
135
-
136
- let(:arg) { MSFL::Types::Set.new([deep_nest]) }
137
-
138
- let(:expected) do
139
- MSFL::Types::Set.new([
140
- {
141
- cat: 1221,
142
- dog: "fur",
143
- lol: MSFL::Types::Set.new(
144
- [
145
- { hat: { gte: 1, lte: 5} }
146
- ]),
147
- :"1337" => 1337.1337,
148
- noob: MSFL::Types::Set.new(
149
- [
150
- MSFL::Types::Set.new([123]),
151
- { :"123" => 456, onetwo: 34 }
152
- ])
153
- }])
154
- end
155
-
156
- it "recursively converts between clauses into anded gte / lte clauses" do
157
- expect(mut).to eq expected
158
- end
159
- end
160
- end
161
-
162
39
  describe ".arrays_to_sets" do
163
40
 
164
41
  subject(:mut) { MSFL::Parsers::JSON.arrays_to_sets 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.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Courtland Caldwell
@@ -110,6 +110,8 @@ files:
110
110
  - circle.yml
111
111
  - lib/msfl.rb
112
112
  - lib/msfl/configuration.rb
113
+ - lib/msfl/converters.rb
114
+ - lib/msfl/converters/operator.rb
113
115
  - lib/msfl/datasets.rb
114
116
  - lib/msfl/datasets/base.rb
115
117
  - lib/msfl/datasets/car.rb
@@ -125,6 +127,7 @@ files:
125
127
  - lib/msfl/validators/semantic.rb
126
128
  - msfl.gemspec
127
129
  - simplecov_custom_profiles.rb
130
+ - spec/msfl/converters/operator_spec.rb
128
131
  - spec/msfl/datasets/base_spec.rb
129
132
  - spec/msfl/parsers/json_spec.rb
130
133
  - spec/msfl/shared_examples.rb
@@ -158,6 +161,7 @@ signing_key:
158
161
  specification_version: 4
159
162
  summary: MSFL in Ruby
160
163
  test_files:
164
+ - spec/msfl/converters/operator_spec.rb
161
165
  - spec/msfl/datasets/base_spec.rb
162
166
  - spec/msfl/parsers/json_spec.rb
163
167
  - spec/msfl/shared_examples.rb