msfl_visitors 1.3.0.dev.f → 1.3.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: ec528af7457f8551d7febd5d497337a2b805ac8b
4
- data.tar.gz: 5e3de6c175ad703eb72b351c30cb3e7a025d9c82
3
+ metadata.gz: ff27f36c62e1d5dc9848c0779ee2a997fa390479
4
+ data.tar.gz: e8fcbac337f97ad9d34366c1e32804a8b51c44e3
5
5
  SHA512:
6
- metadata.gz: a78faedefd14402aba98cbdcd9e4c8ff976c43fc80aa5a9370cf17d6cc1d3ddc0350e47e4d4c3ced60669253fc7840ff0fe54ece4d6a46641f8a55b1449667c8
7
- data.tar.gz: c05b7c376734ef110bb67a02f16c2e4bc167da846e07a30b00c6197900655b85da0c3adf6b671384f3b55da9e8ca19ff8bda38ff6c53599c021752344be4d89c
6
+ metadata.gz: c3b37837e8ce9c138a42db0196c42aef3905d367bdc1d310184543578ea2626e824b97de9f1b523b744d478beaee5dbf07512811bd509e5807c4c67bcf86dce6
7
+ data.tar.gz: 466355a1f210564a0ad16c52f513d6f3f0853e1999e02b284bb9715d99710386e86f81a6224ab2f7e56dfefad3fd051d583e343ee568eb1fbbe11c65efd12b36
data/Gemfile CHANGED
@@ -1,6 +1,3 @@
1
- source 'https://rubygems.org'
2
- gem 'simplecov', :require => false, :group => :test # MIT https://github.com/colszowka/simplecov/blob/master/MIT-LICENSE
3
- gem 'yard' # MIT https://github.com/lsegal/yard/blob/master/LICENSE + Ruby license for one file from the Ruby source lib/parser/ruby/legacy/ruby_lex.rb
4
- gem 'rspec' # MIT https://github.com/rspec/rspec/blob/master/License.txt
5
- gem 'byebug'
6
- gem 'msfl', "~> 1.2", ">=1.2.2"
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/Gemfile.lock CHANGED
@@ -1,6 +1,13 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ msfl_visitors (1.3.0)
5
+ msfl (~> 1.2, >= 1.2.1)
6
+
1
7
  GEM
2
8
  remote: https://rubygems.org/
3
9
  specs:
10
+ builder (3.2.3)
4
11
  byebug (4.0.5)
5
12
  columnize (= 0.9.0)
6
13
  columnize (0.9.0)
@@ -9,6 +16,7 @@ GEM
9
16
  json (1.8.2)
10
17
  msfl (1.2.2)
11
18
  json (~> 1.7)
19
+ rake (10.4.2)
12
20
  rspec (3.2.0)
13
21
  rspec-core (~> 3.2.0)
14
22
  rspec-expectations (~> 3.2.0)
@@ -22,6 +30,9 @@ GEM
22
30
  diff-lcs (>= 1.2.0, < 2.0)
23
31
  rspec-support (~> 3.2.0)
24
32
  rspec-support (3.2.2)
33
+ rspec_junit_formatter (0.2.3)
34
+ builder (< 4)
35
+ rspec-core (>= 2, < 4, != 2.12.0)
25
36
  simplecov (0.10.0)
26
37
  docile (~> 1.1.0)
27
38
  json (~> 1.8)
@@ -33,8 +44,10 @@ PLATFORMS
33
44
  ruby
34
45
 
35
46
  DEPENDENCIES
36
- byebug
37
- msfl (~> 1.2, >= 1.2.2)
38
- rspec
39
- simplecov
40
- yard
47
+ byebug (~> 4.0)
48
+ msfl_visitors!
49
+ rake (~> 10.3)
50
+ rspec (~> 3.2)
51
+ rspec_junit_formatter (~> 0.2)
52
+ simplecov (~> 0.10)
53
+ yard (~> 0.8)
data/circle.yml CHANGED
@@ -6,4 +6,9 @@ machine:
6
6
  # Version of ruby to use
7
7
  ruby:
8
8
  version:
9
- 2.1.3
9
+ 2.1.9
10
+
11
+ test:
12
+ override:
13
+ - mkdir -p $CIRCLE_TEST_REPORTS/rspec
14
+ - bundle exec rspec --format RspecJunitFormatter --out $CIRCLE_TEST_REPORTS/rspec/rspec.xml spec --format progress
data/lib/msfl_visitors.rb CHANGED
@@ -15,17 +15,5 @@ module MSFLVisitors
15
15
  ast = parser.parse nmsfl
16
16
  visitor.visit_tree ast
17
17
  end
18
-
19
- def get_arel(dataset, msfl, visitor = MSFLVisitors::Visitor.new)
20
- visitor.mode = :arel
21
- unless dataset.is_a? MSFL::Datasets::Base
22
- raise ArgumentError, "The first argument to MSFLVisitors.get_arel must be a descendant of MSFL::Datasets::Base."
23
- end
24
- parser = MSFLVisitors::Parsers::MSFLParser.new dataset
25
- converter = MSFL::Converters::Operator.new
26
- nmsfl = converter.run_conversions msfl
27
- ast = parser.parse nmsfl
28
- visitor.visit_tree ast, arel_table: dataset.arel_table
29
- end
30
18
  end
31
19
  end
@@ -22,6 +22,7 @@ require_relative 'nodes/less_than_equal'
22
22
  require_relative 'nodes/match'
23
23
  require_relative 'nodes/named_value'
24
24
  require_relative 'nodes/number'
25
+ require_relative 'nodes/or'
25
26
  require_relative 'nodes/partial'
26
27
  require_relative 'nodes/query_string'
27
28
  require_relative 'nodes/range_value'
@@ -0,0 +1,22 @@
1
+ require_relative 'iterator'
2
+ require_relative 'value'
3
+ module MSFLVisitors
4
+ module Nodes
5
+ class Or < Iterator
6
+
7
+ def initialize(set)
8
+ super
9
+ unless valid_set_children?
10
+ fail ArgumentError, "Members of child Set node of Or node must be expressions, not values, only containment Set nodes have values as children."
11
+ end
12
+ end
13
+
14
+ private
15
+ def valid_set_children?
16
+ set.each do |child|
17
+ return false if child.is_a?(Value)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -4,6 +4,7 @@ module MSFLVisitors
4
4
  class MSFLParser
5
5
  OPERATORS_TO_NODE_CLASS = {
6
6
  and: Nodes::And,
7
+ or: Nodes::Or,
7
8
  gt: Nodes::GreaterThan,
8
9
  gte: Nodes::GreaterThanEqual,
9
10
  eq: Nodes::Equal,
@@ -25,10 +26,10 @@ module MSFLVisitors
25
26
  MSFLVisitors::Nodes::Number.new obj
26
27
 
27
28
  when Hash
28
- parse_Hash obj, lhs
29
+ parse_hash obj, lhs
29
30
 
30
31
  when MSFL::Types::Set
31
- parse_Set obj, lhs
32
+ parse_set obj, lhs
32
33
 
33
34
  when Symbol, String, NilClass
34
35
  MSFLVisitors::Nodes::Word.new obj.to_s
@@ -47,7 +48,7 @@ module MSFLVisitors
47
48
 
48
49
  attr_accessor :dataset
49
50
 
50
- def parse_Hash(obj, lhs = false)
51
+ def parse_hash(obj, lhs = false)
51
52
  nodes = Array.new
52
53
  obj.each do |k, v|
53
54
  nodes << hash_dispatch(k, v, lhs)
@@ -61,7 +62,7 @@ module MSFLVisitors
61
62
  end
62
63
  end
63
64
 
64
- def parse_Set(obj, lhs = false)
65
+ def parse_set(obj, lhs = false)
65
66
  nodes = MSFL::Types::Set.new([])
66
67
  obj.each do |item|
67
68
  nodes << parse(item)
@@ -19,15 +19,11 @@ module MSFLVisitors
19
19
  def composable_expr_for(regex_as_literal_string)
20
20
  regex_as_literal_string[3..-4]
21
21
  end
22
-
23
- def coerce_value_to_unquoted(value)
24
- return value[1..-2] if value[0] == "\""
25
- end
26
22
  end
27
23
 
28
24
  class Visitor
29
25
 
30
- attr_accessor :clauses, :current_clause, :arel_table
26
+ attr_accessor :clauses, :current_clause
31
27
  attr_writer :mode
32
28
 
33
29
  def initialize
@@ -39,8 +35,6 @@ module MSFLVisitors
39
35
  def visit(node)
40
36
  if mode == :es_term
41
37
  get_visitor.visit(node)
42
- elsif mode == :arel
43
- get_visitor.visit(node)
44
38
  else
45
39
  case node
46
40
  when Nodes::Partial
@@ -60,8 +54,6 @@ module MSFLVisitors
60
54
  TermFilterVisitor.new(self)
61
55
  when :es_term
62
56
  ESTermFilterVisitor.new(self)
63
- when :arel
64
- ArelFilterVisitor.new(self, arel_table)
65
57
  else
66
58
  AggregationsVisitor.new(self)
67
59
  end
@@ -74,11 +66,8 @@ module MSFLVisitors
74
66
  result
75
67
  end
76
68
 
77
- def visit_tree(root, arel_table: nil)
78
- return [{clause: root.accept(self)}].concat(clauses).reject { |c| c[:clause] == "" } unless mode == :arel
79
- raise ArgumentError unless arel_table
80
- @arel_table = arel_table.name
81
- "#{root.accept(self)}"
69
+ def visit_tree(root)
70
+ [{clause: root.accept(self)}].concat(clauses).reject { |c| c[:clause] == "" }
82
71
  end
83
72
 
84
73
  private
@@ -102,7 +91,10 @@ module MSFLVisitors
102
91
  Nodes::Match => '=~',
103
92
  }
104
93
 
105
-
94
+ ITERATOR_OPERATORS = {
95
+ Nodes::And => "&",
96
+ Nodes::Or => "|"
97
+ }
106
98
 
107
99
  def visit(node)
108
100
  case node
@@ -144,11 +136,11 @@ module MSFLVisitors
144
136
  node.contents.map { |n| "( " + n.accept(visitor) + " )" }.join(" & ")
145
137
  end
146
138
 
147
- when Nodes::And
139
+ when Nodes::Iterator
148
140
  if node.set.contents.count == 1
149
141
  node.set.contents.first.accept(visitor)
150
142
  else
151
- node.set.contents.map { |n| "( " + n.accept(visitor) + " )" }.join(" & ")
143
+ node.set.contents.map { |n| "( " + n.accept(visitor) + " )" }.join(" #{ITERATOR_OPERATORS[node.class]} ")
152
144
  end
153
145
 
154
146
  when Nodes::Foreign
@@ -182,6 +174,11 @@ module MSFLVisitors
182
174
  Nodes::QueryString => :query_string,
183
175
  }
184
176
 
177
+ ITERATOR_OPERATORS = {
178
+ Nodes::And => :and,
179
+ Nodes::Or => :or,
180
+ }
181
+
185
182
  def visit(node)
186
183
  case node
187
184
  when Nodes::Partial
@@ -240,8 +237,8 @@ module MSFLVisitors
240
237
  else
241
238
  { and: node.contents.map { |n| n.accept(visitor) } }
242
239
  end
243
- when Nodes::And
244
- { and: node.set.accept(visitor) }
240
+ when Nodes::Iterator
241
+ { ITERATOR_OPERATORS[node.class] => node.set.accept(visitor) }
245
242
 
246
243
  when Nodes::Foreign
247
244
  { foreign: Hash[[[:type, node.left.accept(visitor)], [:filter, node.right.accept(visitor)]]] }
@@ -256,87 +253,6 @@ module MSFLVisitors
256
253
  attr_reader :visitor
257
254
  end
258
255
 
259
- class ArelFilterVisitor
260
- include VisitorHelpers
261
-
262
- attr_accessor :arel_table
263
-
264
- def initialize(visitor, arel_table)
265
- @visitor = visitor
266
- @arel_table = arel_table
267
- end
268
-
269
- BINARY_OPERATORS = {
270
- Nodes::Containment => 'in',
271
- Nodes::GreaterThan => 'gt',
272
- Nodes::GreaterThanEqual => 'gte',
273
- Nodes::Equal => 'eq',
274
- Nodes::LessThan => 'lt',
275
- Nodes::LessThanEqual => 'lte',
276
- Nodes::Match => '=~',
277
- }
278
-
279
-
280
-
281
- def visit(node)
282
- case node
283
- when Nodes::Field
284
- "#{node.value.to_sym}"
285
- when Nodes::Regex
286
- regex_escape node.value.to_s
287
- when Nodes::Word
288
- "\"#{node.value}\""
289
- when Nodes::Date, Nodes::Time
290
- "\"#{node.value.iso8601}\""
291
- when Nodes::Number, Nodes::Boolean
292
- node.value
293
-
294
- when Nodes::QueryString
295
- %(#{node.left.accept(visitor)} LIKE '%#{coerce_value_to_unquoted node.right.accept(visitor)}%')
296
-
297
- when Nodes::Match
298
- if node.right.is_a? Nodes::Set
299
- escaped_str_frags = node.right.contents.map { |right_child| composable_expr_for(MSFLVisitors::Nodes::Regex.new(right_child.value.to_s).accept(visitor).inspect) }
300
- escaped_str = "(" + escaped_str_frags.join('|') + ")"
301
- "#{node.left.accept(visitor)} #{BINARY_OPERATORS[node.class]} " + %r[.*#{escaped_str}.*].inspect
302
- else
303
- "#{node.left.accept(visitor)} #{BINARY_OPERATORS[node.class]} " + MSFLVisitors::Nodes::Regex.new(node.right.value.to_s).accept(visitor).inspect
304
- end
305
- when Nodes::Containment,
306
- Nodes::GreaterThan,
307
- Nodes::GreaterThanEqual,
308
- Nodes::Equal,
309
- Nodes::LessThan,
310
- Nodes::LessThanEqual
311
- %(#{arel_table}[:#{node.left.accept(visitor)}].#{BINARY_OPERATORS[node.class]}(#{node.right.accept(visitor)}))
312
- when Nodes::Set
313
- "[" + node.contents.map { |n| n.accept(visitor) }.join(", ") + "]"
314
- when Nodes::Filter
315
- node.contents.reduce("") { |res, n|
316
- next(n.accept(visitor)) unless res.length > 0
317
- res + ".and(#{n.accept(visitor)})"
318
- }
319
- when Nodes::And
320
- node.set.contents.reduce("") { |res, n|
321
- next(n.accept(visitor)) unless res.length > 0
322
- res + ".and(#{n.accept(visitor)})"
323
- }
324
- when Nodes::Foreign
325
- "#{node.left.accept visitor}.filter { #{node.right.accept visitor} }"
326
-
327
- when Nodes::Dataset
328
- "has_child( :#{node.value} )"
329
-
330
- else
331
- fail ArgumentError, "ArelFilter cannot visit: #{node.class.name}"
332
- end
333
- end
334
-
335
- private
336
-
337
- attr_reader :visitor
338
- end
339
-
340
256
  # ESTermFilterVisitor is not currently used and so not all node types are implemented
341
257
  class ESTermFilterVisitor
342
258
  def initialize(visitor)
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'msfl_visitors'
3
- s.version = '1.3.0.dev.f'
4
- s.date = '2016-09-30'
3
+ s.version = '1.3.0'
4
+ s.date = '2017-04-06'
5
5
  s.summary = "Convert MSFL to other forms"
6
6
  s.description = "Visitor pattern approach to converting MSFL to other forms."
7
7
  s.authors = ["Courtland Caldwell"]
@@ -16,5 +16,6 @@ Gem::Specification.new do |s|
16
16
  s.add_development_dependency "yard", "~> 0.8"
17
17
  s.add_development_dependency "rspec", "~> 3.2"
18
18
  s.add_development_dependency "byebug", "~> 4.0"
19
+ s.add_development_dependency "rspec_junit_formatter", "~> 0.2" # MIT https://github.com/sj26/rspec_junit_formatter/blob/master/LICENSE
19
20
  s.license = "MIT"
20
21
  end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe MSFLVisitors::Nodes::Or do
4
+
5
+ context "when creating an instance of #{described_class}" do
6
+
7
+ subject { described_class.new node }
8
+
9
+ context "when passed as Set node as the argument to the constructor" do
10
+
11
+ let(:node) { MSFLVisitors::Nodes::Set.new [MSFLVisitors::Nodes::Number.new(1)] }
12
+
13
+ context "when the Set contains any nodes which inherit from Value" do
14
+
15
+ it "raises an ArgumentError" do
16
+ expect { subject }.to raise_error ArgumentError
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -731,6 +731,181 @@ describe MSFLVisitors::Visitor do
731
731
  end
732
732
  end
733
733
 
734
+ describe "an Or node" do
735
+
736
+ let(:first_field) { MSFLVisitors::Nodes::Field.new "first_field" }
737
+
738
+ let(:first_value) { MSFLVisitors::Nodes::Word.new "first_word" }
739
+
740
+ let(:first) { MSFLVisitors::Nodes::Equal.new first_field, first_value }
741
+
742
+ let(:second_field) { MSFLVisitors::Nodes::Field.new "second_field" }
743
+
744
+ let(:second_value) { MSFLVisitors::Nodes::Word.new "second_word" }
745
+
746
+ let(:second) { MSFLVisitors::Nodes::Equal.new second_field, second_value }
747
+
748
+ let(:third_field) { MSFLVisitors::Nodes::Field.new "third_field" }
749
+
750
+ let(:third_value) { MSFLVisitors::Nodes::Word.new "third_word" }
751
+
752
+ let(:third) { MSFLVisitors::Nodes::Equal.new third_field, third_value }
753
+
754
+ let(:node) { MSFLVisitors::Nodes::Or.new set_node }
755
+
756
+ context "when the Or node has zero items" do
757
+
758
+ let(:set_node) { MSFLVisitors::Nodes::Set.new [] }
759
+
760
+ context "when using the TermFilter visitor" do
761
+
762
+ it "is empty" do
763
+ expect(result).to be_empty
764
+ end
765
+ end
766
+
767
+ context "when using the Aggregations visitor" do
768
+
769
+ before { visitor.mode = :aggregations }
770
+
771
+ it "returns: { and: [] }" do
772
+ expect(result).to eq({ or: [] })
773
+ end
774
+ end
775
+ end
776
+
777
+ context "when the node has one item" do
778
+
779
+ let(:set_node) { MSFLVisitors::Nodes::Set.new [first] }
780
+
781
+ context "when using the TermFilter visitor" do
782
+
783
+ it "returns: the item without adding parentheses" do
784
+ expect(result).to eq 'first_field == "first_word"'
785
+ end
786
+ end
787
+
788
+ context "when using the Aggregations visitor" do
789
+
790
+ before { visitor.mode = :aggregations }
791
+
792
+ it "returns: { or: [{ agg_field_name: :first_field, operator: :eq, test_value: \"first_word\" }]}" do
793
+ expect(result).to eq({ or: [{ agg_field_name: :first_field, operator: :eq, test_value: "first_word" }]})
794
+ end
795
+ end
796
+ end
797
+
798
+ context "when the node has two items" do
799
+
800
+ let(:set_node) { MSFLVisitors::Nodes::Set.new [first, second] }
801
+
802
+ context "when using the TermFilter visitor" do
803
+
804
+ it "returns: '( first_field == \"first_word\" ) | ( second_field == \"second_word\" )'" do
805
+ expect(result).to eq '( first_field == "first_word" ) | ( second_field == "second_word" )'
806
+ end
807
+ end
808
+
809
+ context "when using the Aggregations visitor" do
810
+
811
+ before { visitor.mode = :aggregations }
812
+
813
+ it "returns: {
814
+ or: [{ agg_field_name: :first_field, operator: :eq, test_value: \"first_word\" },
815
+ { agg_field_name: :second_field, operator: :eq, test_value: \"second_word\" }
816
+ ]}" do
817
+ expect(result).to eq({
818
+ or: [{ agg_field_name: :first_field, operator: :eq, test_value: "first_word" },
819
+ { agg_field_name: :second_field, operator: :eq, test_value: "second_word" }
820
+ ]})
821
+ end
822
+ end
823
+ end
824
+
825
+ context "when the node has three items" do
826
+
827
+ let(:set_node) { MSFLVisitors::Nodes::Set.new [first, second, third] }
828
+
829
+ context "when using the TermFilter visitor" do
830
+
831
+ it "returns: '( first_field == \"first_word\" ) | ( second_field == \"second_word\" ) | ( third_field == \"third_word\" )'" do
832
+ expect(result).to eq '( first_field == "first_word" ) | ( second_field == "second_word" ) | ( third_field == "third_word" )'
833
+ end
834
+ end
835
+
836
+ context "when using the Aggregations visitor" do
837
+
838
+ before { visitor.mode = :aggregations }
839
+
840
+ it "returns: {
841
+ or: [{ agg_field_name: :first_field, operator: :eq, test_value: \"first_word\" },
842
+ { agg_field_name: :second_field, operator: :eq, test_value: \"second_word\"},
843
+ {agg_field_name: :third_field, operator: :eq, test_value: \"third_word\"}
844
+ ]}" do
845
+ expect(result).to eq({
846
+ or: [{ agg_field_name: :first_field, operator: :eq, test_value: "first_word" },
847
+ { agg_field_name: :second_field, operator: :eq, test_value: "second_word"},
848
+ {agg_field_name: :third_field, operator: :eq, test_value: "third_word"}
849
+ ]})
850
+ end
851
+ end
852
+ end
853
+
854
+ context "when one of the node's items is a containment node" do
855
+
856
+ let(:node) do
857
+ MSFLVisitors::Nodes::Or.new(
858
+ MSFLVisitors::Nodes::Set.new(
859
+ [
860
+ MSFLVisitors::Nodes::Filter.new(
861
+ [
862
+ MSFLVisitors::Nodes::Containment.new(
863
+ MSFLVisitors::Nodes::Field.new(:make),
864
+ MSFLVisitors::Nodes::Set.new(
865
+ [
866
+ MSFLVisitors::Nodes::Word.new("Honda"),
867
+ MSFLVisitors::Nodes::Word.new("Chevy"),
868
+ MSFLVisitors::Nodes::Word.new("Volvo")
869
+ ]
870
+ )
871
+ )
872
+ ]
873
+ ),
874
+ MSFLVisitors::Nodes::Filter.new(
875
+ [
876
+ MSFLVisitors::Nodes::GreaterThanEqual.new(
877
+ MSFLVisitors::Nodes::Field.new(:value),
878
+ MSFLVisitors::Nodes::Number.new(1000)
879
+ )
880
+ ]
881
+ )
882
+ ]
883
+ )
884
+ )
885
+ end
886
+
887
+ context "when using the TermFilter visitor" do
888
+
889
+ it "returns: '( make == [ \"Honda\" , \"Chevy\" , \"Volvo\" ] ) | ( value >= 1000 )'" do
890
+ expect(result).to eq '( make == [ "Honda" , "Chevy" , "Volvo" ] ) | ( value >= 1000 )'
891
+ end
892
+ end
893
+
894
+ context "when using the Aggregations visitor" do
895
+
896
+ before { visitor.mode = :aggregations }
897
+
898
+ it "returns: { or: [{ agg_field_name: :make, operator: :in, test_value: [\"Honda\", \"Chevy\", \"Volvo\"] }, { agg_field_name: :value, operator: :gte, test_value: 1000 } }] }" do
899
+ expected = { or: [
900
+ { agg_field_name: :make, operator: :in, test_value: ["Honda", "Chevy", "Volvo"] },
901
+ { agg_field_name: :value, operator: :gte, test_value: 1000}
902
+ ]}
903
+ expect(result).to eq expected
904
+ end
905
+ end
906
+ end
907
+ end
908
+
734
909
  describe "value nodes" do
735
910
  describe "a Boolean node" do
736
911
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: msfl_visitors
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0.dev.f
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Courtland Caldwell
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-09-30 00:00:00.000000000 Z
11
+ date: 2017-04-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: msfl
@@ -100,6 +100,20 @@ dependencies:
100
100
  - - "~>"
101
101
  - !ruby/object:Gem::Version
102
102
  version: '4.0'
103
+ - !ruby/object:Gem::Dependency
104
+ name: rspec_junit_formatter
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '0.2'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: '0.2'
103
117
  description: Visitor pattern approach to converting MSFL to other forms.
104
118
  email: courtland@mattermark.com
105
119
  executables: []
@@ -138,6 +152,7 @@ files:
138
152
  - lib/msfl_visitors/nodes/match.rb
139
153
  - lib/msfl_visitors/nodes/named_value.rb
140
154
  - lib/msfl_visitors/nodes/number.rb
155
+ - lib/msfl_visitors/nodes/or.rb
141
156
  - lib/msfl_visitors/nodes/partial.rb
142
157
  - lib/msfl_visitors/nodes/query_string.rb
143
158
  - lib/msfl_visitors/nodes/range_value.rb
@@ -152,9 +167,9 @@ files:
152
167
  - simplecov_custom_profiles.rb
153
168
  - spec/msfl_visitors/nodes/and_spec.rb
154
169
  - spec/msfl_visitors/nodes/iterator_spec.rb
170
+ - spec/msfl_visitors/nodes/or_spec.rb
155
171
  - spec/msfl_visitors/parsers/msfl_parser_spec.rb
156
172
  - spec/msfl_visitors/visitor_spec.rb
157
- - spec/msfl_visitors/visitors/arel_filter_spec.rb
158
173
  - spec/msfl_visitors/visitors/chewy_term_filter_spec.rb
159
174
  - spec/msfl_visitors/visitors/es_term_filter_spec.rb
160
175
  - spec/msfl_visitors_spec.rb
@@ -174,9 +189,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
174
189
  version: '0'
175
190
  required_rubygems_version: !ruby/object:Gem::Requirement
176
191
  requirements:
177
- - - ">"
192
+ - - ">="
178
193
  - !ruby/object:Gem::Version
179
- version: 1.3.1
194
+ version: '0'
180
195
  requirements: []
181
196
  rubyforge_project:
182
197
  rubygems_version: 2.4.3
@@ -186,11 +201,10 @@ summary: Convert MSFL to other forms
186
201
  test_files:
187
202
  - spec/msfl_visitors/nodes/and_spec.rb
188
203
  - spec/msfl_visitors/nodes/iterator_spec.rb
204
+ - spec/msfl_visitors/nodes/or_spec.rb
189
205
  - spec/msfl_visitors/parsers/msfl_parser_spec.rb
190
206
  - spec/msfl_visitors/visitor_spec.rb
191
- - spec/msfl_visitors/visitors/arel_filter_spec.rb
192
207
  - spec/msfl_visitors/visitors/chewy_term_filter_spec.rb
193
208
  - spec/msfl_visitors/visitors/es_term_filter_spec.rb
194
209
  - spec/msfl_visitors_spec.rb
195
210
  - spec/spec_helper.rb
196
- has_rdoc:
@@ -1,451 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe MSFLVisitors::Visitor do
4
-
5
- let(:node) { fail ArgumentError, "You must define the node variable in each scope." }
6
-
7
- let(:visitor) { described_class.new }
8
-
9
- let(:left) { MSFLVisitors::Nodes::Field.new "lhs" }
10
-
11
- let(:right) { MSFLVisitors::Nodes::Word.new "rhs" }
12
-
13
- subject(:result) { node.accept visitor }
14
-
15
- context "when using the ArelFilter visitor" do
16
-
17
- before {
18
- visitor.mode = :arel
19
- visitor.arel_table = :cars
20
- }
21
-
22
- context "when visiting" do
23
-
24
- describe "an unsupported node" do
25
-
26
- class UnsupportedNode
27
-
28
- def accept(visitor)
29
- visitor.visit self
30
- end
31
- end
32
-
33
- let(:node) { UnsupportedNode.new }
34
-
35
- it "raises an ArgumentError" do
36
- expect { subject }.to raise_error ArgumentError
37
- end
38
- end
39
-
40
- # describe "a Partial node" do
41
- #
42
- # let(:node) { MSFLVisitors::Nodes::Partial.new given_node, named_value }
43
- #
44
- # let(:given_node) { MSFLVisitors::Nodes::Given.new [given_equal_node] }
45
- #
46
- # let(:given_equal_node) { MSFLVisitors::Nodes::Equal.new given_field_node, given_value_node }
47
- #
48
- # let(:given_field_node) { MSFLVisitors::Nodes::Field.new :make }
49
- #
50
- # let(:given_value_node) { MSFLVisitors::Nodes::Word.new "Toyota" }
51
- #
52
- #
53
- # let(:named_value) { MSFLVisitors::Nodes::NamedValue.new MSFLVisitors::Nodes::Word.new("partial"), explicit_filter_node }
54
- #
55
- # let(:explicit_filter_node) { MSFLVisitors::Nodes::ExplicitFilter.new [greater_than_node] }
56
- #
57
- # let(:greater_than_node) { MSFLVisitors::Nodes::GreaterThan.new field_node, value_node }
58
- #
59
- # let(:field_node) { MSFLVisitors::Nodes::Field.new :age }
60
- #
61
- # let(:value_node) { MSFLVisitors::Nodes::Number.new 10 }
62
- #
63
- #
64
- # subject { visitor.visit_tree node }
65
- #
66
- # it "results in the appropriate clause" do
67
- # exp = [{
68
- # clause: {
69
- # given: {
70
- # filter: {
71
- # term: { make: "Toyota" }
72
- # },
73
- # aggs: {
74
- # partial: {
75
- # filter: { range: { age: { gt: 10 }}}
76
- # }
77
- # }
78
- # }
79
- # }
80
- # }]
81
- # expect(subject).to eq exp
82
- # end
83
- # end
84
- #
85
- # describe "a Given node" do
86
- #
87
- # let(:node) { MSFLVisitors::Nodes::Given.new [given_equal_node] }
88
- #
89
- # let(:given_equal_node) { MSFLVisitors::Nodes::Equal.new given_field_node, given_value_node }
90
- #
91
- # let(:given_field_node) { MSFLVisitors::Nodes::Field.new :make }
92
- #
93
- # let(:given_value_node) { MSFLVisitors::Nodes::Word.new "Toyota" }
94
- #
95
- #
96
- # it "results in: [:filter, { term: { make: \"Toyota\" } }]" do
97
- # expect(subject).to eq([:filter, { term: { make: "Toyota" } }])
98
- # end
99
- # end
100
- #
101
- # describe "a Foreign node" do
102
- #
103
- # let(:node) { MSFLVisitors::Nodes::Foreign.new dataset_node, filter_node }
104
- #
105
- # let(:dataset_node) { MSFLVisitors::Nodes::Dataset.new "person" }
106
- #
107
- # let(:filter_node) { MSFLVisitors::Nodes::ExplicitFilter.new [equal_node] }
108
- #
109
- # let(:equal_node) { MSFLVisitors::Nodes::Equal.new left, right }
110
- #
111
- # let(:left) { MSFLVisitors::Nodes::Field.new :age }
112
- #
113
- # let(:right) { MSFLVisitors::Nodes::Number.new 25 }
114
- #
115
- # it "results in: { has_child: { type: \"person\", filter: { term: { age: 25 } } } }" do
116
- # expect(subject).to eq({ has_child: { type: "person", filter: { term: { age: 25 } } } })
117
- # end
118
- # end
119
-
120
- describe "a Containment node" do
121
-
122
- let(:node) { MSFLVisitors::Nodes::Containment.new field, values }
123
-
124
- let(:values) { MSFLVisitors::Nodes::Set.new(MSFL::Types::Set.new([item_one, item_two, item_three])) }
125
-
126
- let(:item_one) { MSFLVisitors::Nodes::Word.new "item_one" }
127
-
128
- let(:item_two) { MSFLVisitors::Nodes::Word.new "item_two" }
129
-
130
- let(:item_three) { MSFLVisitors::Nodes::Word.new "item_three" }
131
-
132
- let(:field) { left }
133
-
134
- it %(results in: 'cars[:lhs].in(["item_one", "item_two", "item_three"])') do
135
- expect(subject).to eq(%(cars[:lhs].in(["item_one", "item_two", "item_three"])))
136
- end
137
- end
138
-
139
- describe "a Set node" do
140
-
141
- let(:node) { MSFLVisitors::Nodes::Set.new values }
142
-
143
- let(:values) { MSFL::Types::Set.new([item_one, item_two]) }
144
-
145
- let(:item_one) { MSFLVisitors::Nodes::Word.new "item_one" }
146
-
147
- let(:item_two) { MSFLVisitors::Nodes::Word.new "item_two" }
148
-
149
- it %(results in: '["item_one", "item_two"]') do
150
- expect(result).to eq %(["item_one", "item_two"])
151
- end
152
- end
153
-
154
- describe "an Equal node" do
155
-
156
- let(:node) { MSFLVisitors::Nodes::Equal.new left, right }
157
-
158
- it %(results in: 'cars[:lhs].eq("rhs")') do
159
- expect(result).to eq(%(cars[:lhs].eq("rhs")))
160
- end
161
- end
162
-
163
- #
164
- # Models::Investor.arel_table.project(Arel.sql('*')).where(send MSFLVisitors.get_arel(MSFL::Datasets::Investor.new, { linkedin_id: { gt: 200 } })).to_a
165
- #
166
- describe "a GreaterThan node" do
167
-
168
- let(:node) { MSFLVisitors::Nodes::GreaterThan.new left, right }
169
-
170
- let(:right) { MSFLVisitors::Nodes::Number.new 1000 }
171
-
172
- it %(results in: 'cars[:lhs].gt(1000)') do
173
- expect(result).to eq(%(cars[:lhs].gt(1000)))
174
- end
175
- end
176
-
177
- describe "a GreaterThanEqual node" do
178
-
179
- let(:node) { MSFLVisitors::Nodes::GreaterThanEqual.new left, right }
180
-
181
- let(:right) { MSFLVisitors::Nodes::Number.new 10.52 }
182
-
183
- it %(results in: 'cars[:lhs].gte(10.52)') do
184
- expect(result).to eq(%(cars[:lhs].gte(10.52)))
185
- end
186
- end
187
-
188
- describe "a LessThan node" do
189
-
190
- let(:node) { MSFLVisitors::Nodes::LessThan.new left, right }
191
-
192
- let(:right) { MSFLVisitors::Nodes::Number.new 133.7 }
193
-
194
- it %(returns: 'cars[:lhs].lt(133.7)') do
195
- expect(result).to eq(%(cars[:lhs].lt(133.7)))
196
- end
197
- end
198
-
199
- describe "a LessThanEqual node" do
200
-
201
- let(:node) { MSFLVisitors::Nodes::LessThanEqual.new left, right }
202
-
203
- let(:right) { MSFLVisitors::Nodes::Date.new Date.today }
204
-
205
- it %(returns: 'cars[:lhs].lte(#{Date.today})') do
206
- expect(result).to eq(%(cars[:lhs].lte("#{Date.today}")))
207
- end
208
- end
209
-
210
- describe "a QueryString node" do
211
-
212
- let(:node) { MSFLVisitors::Nodes::QueryString.new left, right }
213
-
214
- let(:right) { MSFLVisitors::Nodes::Word.new "happy" }
215
-
216
- it %(returns: "lhs LIKE '%happy%'") do
217
- expect(result).to eq(%(lhs LIKE '%happy%'))
218
- end
219
- end
220
-
221
- describe "a Filter node" do
222
-
223
- let(:node) { MSFLVisitors::Nodes::Filter.new filtered_nodes }
224
-
225
- let(:filtered_nodes) do
226
- [
227
- MSFLVisitors::Nodes::GreaterThanEqual.new(
228
- MSFLVisitors::Nodes::Field.new(:value),
229
- MSFLVisitors::Nodes::Number.new(1000))
230
- ]
231
- end
232
-
233
- it %(returns: 'cars[:value].gte(1000)') do
234
- expect(result).to eq(%(cars[:value].gte(1000)))
235
- end
236
-
237
- context "when the filter has multiple children" do
238
-
239
- let(:filtered_nodes) do
240
- [
241
- MSFLVisitors::Nodes::Equal.new(
242
- MSFLVisitors::Nodes::Field.new(:make),
243
- MSFLVisitors::Nodes::Word.new("Chevy")
244
- ),
245
- MSFLVisitors::Nodes::GreaterThanEqual.new(
246
- MSFLVisitors::Nodes::Field.new(:value),
247
- MSFLVisitors::Nodes::Number.new(1000))
248
- ]
249
- end
250
-
251
- it %(returns: 'cars[:make].eq("Chevy").and(cars[:value].gte(1000))') do
252
- expect(result).to eq(%(cars[:make].eq("Chevy").and(cars[:value].gte(1000))))
253
- end
254
- end
255
- end
256
-
257
- describe "an And node" do
258
-
259
- let(:first_field) { MSFLVisitors::Nodes::Field.new "first_field" }
260
-
261
- let(:first_value) { MSFLVisitors::Nodes::Word.new "first_word" }
262
-
263
- let(:first) { MSFLVisitors::Nodes::Equal.new(first_field, first_value) }
264
-
265
- let(:second_field) { MSFLVisitors::Nodes::Field.new "second_field" }
266
-
267
- let(:second_value) { MSFLVisitors::Nodes::Word.new "second_word" }
268
-
269
- let(:second) { MSFLVisitors::Nodes::Equal.new(second_field, second_value) }
270
-
271
- let(:third_field) { MSFLVisitors::Nodes::Field.new "third_field" }
272
-
273
- let(:third_value) { MSFLVisitors::Nodes::Word.new "third_word" }
274
-
275
- let(:third) { MSFLVisitors::Nodes::Equal.new(third_field, third_value) }
276
-
277
- let(:node) { MSFLVisitors::Nodes::And.new(set_node) }
278
-
279
- context "when the And node has zero items" do
280
-
281
- let(:set_node) { MSFLVisitors::Nodes::Set.new [] }
282
-
283
- it %(returns: '') do
284
- expect(result).to eq('')
285
- end
286
- end
287
-
288
- context "when the node has one item" do
289
-
290
- let(:set_node) { MSFLVisitors::Nodes::Set.new [first] }
291
-
292
- it %(returns: 'cars[:first_field].eq("first_word")') do
293
- expect(result).to eq(%(cars[:first_field].eq("first_word")))
294
- end
295
- end
296
-
297
- context "when the node has two items" do
298
-
299
- let(:set_node) { MSFLVisitors::Nodes::Set.new [first, second] }
300
-
301
- it %(returns: 'cars[:first_field].eq("first_word").and(cars[:second_field].eq("second_word"))') do
302
- expect(result).to eq(%(cars[:first_field].eq("first_word").and(cars[:second_field].eq("second_word"))))
303
- end
304
- end
305
-
306
- context "when the node has three items" do
307
-
308
- let(:set_node) { MSFLVisitors::Nodes::Set.new [first, second, third] }
309
-
310
- it %(returns: 'cars[:first_field].eq("first_word").and(cars[:second_field].eq("second_word")).and(cars[:third_field].eq("third_word"))') do
311
- expect(result).to eq(%(cars[:first_field].eq("first_word").and(cars[:second_field].eq("second_word")).and(cars[:third_field].eq("third_word"))))
312
- end
313
- end
314
-
315
- context "when one of the node's items is a containment node" do
316
-
317
- let(:node) do
318
- MSFLVisitors::Nodes::And.new(
319
- MSFLVisitors::Nodes::Set.new(
320
- [
321
- MSFLVisitors::Nodes::Filter.new(
322
- [
323
- MSFLVisitors::Nodes::Containment.new(
324
- MSFLVisitors::Nodes::Field.new(:make),
325
- MSFLVisitors::Nodes::Set.new(
326
- [
327
- MSFLVisitors::Nodes::Word.new("Honda"),
328
- MSFLVisitors::Nodes::Word.new("Chevy"),
329
- MSFLVisitors::Nodes::Word.new("Volvo")
330
- ]
331
- )
332
- )
333
- ]
334
- ),
335
- MSFLVisitors::Nodes::Filter.new(
336
- [
337
- MSFLVisitors::Nodes::GreaterThanEqual.new(
338
- MSFLVisitors::Nodes::Field.new(:value),
339
- MSFLVisitors::Nodes::Number.new(1000)
340
- )
341
- ]
342
- )
343
- ]
344
- )
345
- )
346
- end
347
- it %(returns: 'cars[:make].in(["Honda", "Chevy", "Volvo"]).and(cars[:value].gte(1000))') do
348
- expected = %(cars[:make].in(["Honda", "Chevy", "Volvo"]).and(cars[:value].gte(1000)))
349
- expect(result).to eq expected
350
- end
351
- end
352
- end
353
-
354
- describe "value nodes" do
355
- describe "a Boolean node" do
356
-
357
- let(:node) { MSFLVisitors::Nodes::Boolean.new value }
358
-
359
- subject(:result) { node.accept visitor }
360
-
361
- context "with a value of true" do
362
-
363
- let(:value) { true }
364
-
365
- it "returns: true" do
366
- expect(result).to eq true
367
- end
368
- end
369
-
370
- context "with a value of false" do
371
-
372
- let(:value) { false }
373
-
374
- it "returns: false" do
375
- expect(result).to eq false
376
- end
377
- end
378
- end
379
-
380
- describe "a Word node" do
381
-
382
- let(:word) { "node_content" }
383
-
384
- let(:node) { MSFLVisitors::Nodes::Word.new word }
385
-
386
- it "returns: the literal string" do
387
- expect(result).to eq "\"#{word}\""
388
- end
389
- end
390
- end
391
-
392
- describe "range value nodes" do
393
-
394
- subject(:result) { node.accept visitor }
395
-
396
- describe "a Date node" do
397
-
398
- let(:today) { Date.today }
399
-
400
- let(:node) { MSFLVisitors::Nodes::Date.new today }
401
-
402
- it "returns: the date using iso8601 formatting" do
403
- expect(result).to eq "\"#{today.iso8601}\""
404
- end
405
- end
406
-
407
- describe "a Time node" do
408
-
409
- let(:now) { Time.now }
410
-
411
- let(:node) { MSFLVisitors::Nodes::Time.new now }
412
-
413
- it "returns: the date using iso8601 formatting" do
414
- expect(result).to eq "\"#{now.iso8601}\""
415
- end
416
- end
417
-
418
- describe "a DateTime node" do
419
-
420
- let(:now) { DateTime.now }
421
-
422
- let(:node) { MSFLVisitors::Nodes::DateTime.new now }
423
-
424
- it "returns: the date and time using iso8601 formatting" do
425
- expect(result).to eq "\"#{now.iso8601}\""
426
- end
427
- end
428
-
429
- describe "a Number node" do
430
-
431
- let(:number) { 123 }
432
-
433
- let(:node) { MSFLVisitors::Nodes::Number.new number }
434
-
435
- it "returns: 123" do
436
- expect(result).to eq number
437
- end
438
-
439
- context "when the number is a float" do
440
-
441
- let(:number) { 123.456 }
442
-
443
- it "returns: the number with the same precision" do
444
- expect(result).to eq number
445
- end
446
- end
447
- end
448
- end
449
- end
450
- end
451
- end