msfl 1.0.0 → 1.1.0

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: 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