msfl_visitors 1.3.0.dev.f → 1.3.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: 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