msfl_visitors 0.1.0.rc3 → 0.3.0.dev
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 +4 -4
- data/Gemfile +1 -1
- data/Gemfile.lock +2 -2
- data/README.md +9 -17
- data/lib/msfl_visitors/nodes/and.rb +0 -17
- data/lib/msfl_visitors/nodes/base.rb +3 -1
- data/lib/msfl_visitors/nodes/binary.rb +0 -7
- data/lib/msfl_visitors/nodes/dataset.rb +7 -0
- data/lib/msfl_visitors/nodes/equal.rb +17 -0
- data/lib/msfl_visitors/nodes/explicit_filter.rb +7 -0
- data/lib/msfl_visitors/nodes/filter.rb +16 -15
- data/lib/msfl_visitors/nodes/foreign.rb +7 -0
- data/lib/msfl_visitors/nodes/given.rb +7 -0
- data/lib/msfl_visitors/nodes/iterator.rb +7 -1
- data/lib/msfl_visitors/nodes/named_value.rb +16 -0
- data/lib/msfl_visitors/nodes/partial.rb +7 -0
- data/lib/msfl_visitors/nodes/set.rb +23 -0
- data/lib/msfl_visitors/nodes.rb +7 -9
- data/lib/msfl_visitors/parsers/msfl_parser.rb +33 -4
- data/lib/msfl_visitors/visitor.rb +165 -6
- data/lib/msfl_visitors.rb +0 -2
- data/msfl_visitors.gemspec +3 -3
- data/spec/nodes/iterator_spec.rb +21 -3
- data/spec/parsers/msfl_parser_spec.rb +61 -4
- data/spec/spec_helper.rb +5 -1
- data/spec/visitors/chewy_term_filter_spec.rb +460 -53
- metadata +11 -24
- data/lib/msfl_visitors/collectors/chewy/term_filter.rb +0 -19
- data/lib/msfl_visitors/collectors.rb +0 -1
- data/lib/msfl_visitors/nodes/binary_and.rb +0 -7
- data/lib/msfl_visitors/nodes/constant_value.rb +0 -11
- data/lib/msfl_visitors/nodes/grouping/close.rb +0 -9
- data/lib/msfl_visitors/nodes/grouping/grouping.rb +0 -24
- data/lib/msfl_visitors/nodes/grouping/open.rb +0 -9
- data/lib/msfl_visitors/nodes/set/close.rb +0 -9
- data/lib/msfl_visitors/nodes/set/delimiter.rb +0 -9
- data/lib/msfl_visitors/nodes/set/open.rb +0 -9
- data/lib/msfl_visitors/nodes/set/set.rb +0 -43
- data/lib/msfl_visitors/renderers/chewy/term_filter.rb +0 -59
- data/spec/renderers/chewy/term_filter_spec.rb +0 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 172130f160936dc67e1d5658a17276f9e1bd6b9d
|
4
|
+
data.tar.gz: b86ec5deb1e85c048e418a39a3d5fa003bd36c6a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 86d580b40f4198b2a7f62370be7c0cae80d4c374ea4e29ee04b477ab1efb1a77b889b00e38400a83e2c6d4f6e0981b24f29dbbe7285cc9bd7babcb5a676ee310
|
7
|
+
data.tar.gz: f336cc01362a4f87ccc8a0265c7588c517ecb1b117a735fe293b4518a661d295b29ee1b3a1f5c81630ba7976821c5a5a0c377840f5a1df2f00d7d33ffcf84d62
|
data/Gemfile
CHANGED
@@ -3,4 +3,4 @@ gem 'simplecov', :require => false, :group => :test # MIT https://gith
|
|
3
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
4
|
gem 'rspec' # MIT https://github.com/rspec/rspec/blob/master/License.txt
|
5
5
|
gem 'byebug'
|
6
|
-
gem 'msfl', "
|
6
|
+
gem 'msfl', "1.2.0.dev4"
|
data/Gemfile.lock
CHANGED
@@ -7,7 +7,7 @@ GEM
|
|
7
7
|
diff-lcs (1.2.5)
|
8
8
|
docile (1.1.5)
|
9
9
|
json (1.8.2)
|
10
|
-
msfl (1.
|
10
|
+
msfl (1.2.0.dev4)
|
11
11
|
json (~> 1.7)
|
12
12
|
rspec (3.2.0)
|
13
13
|
rspec-core (~> 3.2.0)
|
@@ -34,7 +34,7 @@ PLATFORMS
|
|
34
34
|
|
35
35
|
DEPENDENCIES
|
36
36
|
byebug
|
37
|
-
msfl (
|
37
|
+
msfl (= 1.2.0.dev4)
|
38
38
|
rspec
|
39
39
|
simplecov
|
40
40
|
yard
|
data/README.md
CHANGED
@@ -5,23 +5,18 @@ A visitor pattern based approach for converting MSFL to other forms
|
|
5
5
|
|
6
6
|
## Usage
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
require 'msfl_visitor'
|
8
|
+
```ruby
|
9
|
+
require 'msfl_visitor'
|
11
10
|
|
12
|
-
|
11
|
+
filter = { make: "Toyota" }
|
13
12
|
|
14
|
-
|
13
|
+
visitor = MSFLVisitors::Visitor.new
|
15
14
|
|
16
|
-
|
15
|
+
visitor.visit_tree MSFLVisitors::AST.new(filter)
|
17
16
|
|
18
|
-
|
17
|
+
=> [{clause: 'make == "Toyota"'}]
|
19
18
|
|
20
|
-
|
21
|
-
|
22
|
-
=> 'make == "Toyota"'
|
23
|
-
|
24
|
-
```
|
19
|
+
```
|
25
20
|
|
26
21
|
## Architecture
|
27
22
|
|
@@ -54,11 +49,8 @@ multiple output DSLs.
|
|
54
49
|
|
55
50
|
## collector
|
56
51
|
|
57
|
-
|
58
|
-
It can be as simple as a String or an Array, or it can be more elaborate. Ultimately it must respond to the shovel
|
59
|
-
operator (<<)
|
52
|
+
Removed as of 0.3
|
60
53
|
|
61
54
|
## renderer
|
62
55
|
|
63
|
-
|
64
|
-
this time are Chewy::TermFilter and Chewy:QueryStringFilter
|
56
|
+
Removed as of 0.3
|
@@ -2,23 +2,6 @@ require_relative 'iterator'
|
|
2
2
|
module MSFLVisitors
|
3
3
|
module Nodes
|
4
4
|
class And < Iterator
|
5
|
-
|
6
|
-
def accept(visitor)
|
7
|
-
nodes = Array.new
|
8
|
-
if set.count > 1
|
9
|
-
set.each do |item|
|
10
|
-
nodes << MSFLVisitors::Nodes::Grouping::Grouping.new(item)
|
11
|
-
nodes << BinaryAnd.new
|
12
|
-
end
|
13
|
-
nodes.pop
|
14
|
-
elsif set.count == 1
|
15
|
-
nodes << set.first
|
16
|
-
end
|
17
|
-
|
18
|
-
nodes.each do |node|
|
19
|
-
node.accept visitor
|
20
|
-
end
|
21
|
-
end
|
22
5
|
end
|
23
6
|
end
|
24
7
|
end
|
@@ -2,15 +2,8 @@ require_relative 'base'
|
|
2
2
|
module MSFLVisitors
|
3
3
|
module Nodes
|
4
4
|
class Binary < Base
|
5
|
-
|
6
5
|
attr_accessor :left, :right
|
7
6
|
|
8
|
-
def accept(visitor)
|
9
|
-
left.accept visitor
|
10
|
-
visitor.visit self
|
11
|
-
right.accept visitor
|
12
|
-
end
|
13
|
-
|
14
7
|
def initialize(left, right)
|
15
8
|
self.left = left
|
16
9
|
self.right = right
|
@@ -2,6 +2,23 @@ require_relative 'comparison'
|
|
2
2
|
module MSFLVisitors
|
3
3
|
module Nodes
|
4
4
|
class Equal < Comparison
|
5
|
+
|
6
|
+
def accept(visitor)
|
7
|
+
visitor.visit self
|
8
|
+
#
|
9
|
+
# case visitor.current_visitor
|
10
|
+
# when Visitors::Chewy::TermFilter
|
11
|
+
# super
|
12
|
+
#
|
13
|
+
# when Visitors::Chewy::Aggregations
|
14
|
+
# @value = { left.accept(visitor) => right.accept(visitor) }
|
15
|
+
# visitor.visit(self)
|
16
|
+
#
|
17
|
+
# else
|
18
|
+
# fail ArgumentError, "Unknown current visitor type."
|
19
|
+
# end
|
20
|
+
end
|
21
|
+
|
5
22
|
end
|
6
23
|
end
|
7
24
|
end
|
@@ -1,20 +1,21 @@
|
|
1
|
-
require_relative '
|
1
|
+
require_relative 'base'
|
2
2
|
module MSFLVisitors
|
3
3
|
module Nodes
|
4
|
-
class Filter <
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
4
|
+
class Filter < Base
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
attr_accessor :contents
|
8
|
+
|
9
|
+
def_delegators :contents, :count, :first, :each
|
10
|
+
|
11
|
+
# @param nodes [Array<MSFL::Nodes::Base>] the nodes that the filter surrounds
|
12
|
+
def initialize(nodes)
|
13
|
+
self.contents = Array(nodes)
|
14
|
+
end
|
15
|
+
|
16
|
+
def ==(other)
|
17
|
+
self.class == other.class &&
|
18
|
+
contents == other.contents
|
18
19
|
end
|
19
20
|
end
|
20
21
|
end
|
@@ -5,8 +5,14 @@ module MSFLVisitors
|
|
5
5
|
|
6
6
|
attr_accessor :set
|
7
7
|
|
8
|
-
#
|
8
|
+
# Be extra defensive, because even after adding previous comment I still tend to make the mistake of
|
9
|
+
# passing in an array.
|
10
|
+
#
|
11
|
+
# @param set [MSFLVisitors::Nodes::Set] a set node that allows its elements to be iterated over
|
9
12
|
def initialize(set)
|
13
|
+
unless set.is_a? MSFLVisitors::Nodes::Set
|
14
|
+
fail ArgumentError, "Argument to Iterator initialize must be instance of MSFLVisitors::Nodes::Set"
|
15
|
+
end
|
10
16
|
self.set = set
|
11
17
|
end
|
12
18
|
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
module MSFLVisitors
|
3
|
+
module Nodes
|
4
|
+
class Set < Base
|
5
|
+
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
attr_accessor :contents
|
9
|
+
|
10
|
+
def_delegators :contents, :count, :first, :each
|
11
|
+
|
12
|
+
# @param nodes [Array<MSFL::Nodes::Base>] the nodes that the filter surrounds
|
13
|
+
def initialize(nodes)
|
14
|
+
self.contents = Array(nodes)
|
15
|
+
end
|
16
|
+
|
17
|
+
def ==(other)
|
18
|
+
self.class == other.class &&
|
19
|
+
contents == other.contents
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/msfl_visitors/nodes.rb
CHANGED
@@ -2,30 +2,28 @@
|
|
2
2
|
require_relative 'nodes/and'
|
3
3
|
require_relative 'nodes/base'
|
4
4
|
require_relative 'nodes/binary'
|
5
|
-
require_relative 'nodes/binary_and'
|
6
5
|
require_relative 'nodes/boolean'
|
7
6
|
require_relative 'nodes/comparison'
|
8
|
-
require_relative 'nodes/constant_value'
|
9
7
|
require_relative 'nodes/containment'
|
8
|
+
require_relative 'nodes/dataset'
|
10
9
|
require_relative 'nodes/date'
|
11
10
|
require_relative 'nodes/date_time'
|
12
11
|
require_relative 'nodes/equal'
|
12
|
+
require_relative 'nodes/explicit_filter'
|
13
13
|
require_relative 'nodes/field'
|
14
14
|
require_relative 'nodes/filter'
|
15
|
+
require_relative 'nodes/foreign'
|
16
|
+
require_relative 'nodes/given'
|
15
17
|
require_relative 'nodes/iterator'
|
16
18
|
require_relative 'nodes/greater_than'
|
17
19
|
require_relative 'nodes/greater_than_equal'
|
18
|
-
require_relative 'nodes/grouping/close'
|
19
|
-
require_relative 'nodes/grouping/grouping'
|
20
|
-
require_relative 'nodes/grouping/open'
|
21
20
|
require_relative 'nodes/less_than'
|
22
21
|
require_relative 'nodes/less_than_equal'
|
22
|
+
require_relative 'nodes/named_value'
|
23
23
|
require_relative 'nodes/number'
|
24
|
+
require_relative 'nodes/partial'
|
24
25
|
require_relative 'nodes/range_value'
|
25
|
-
require_relative 'nodes/set
|
26
|
-
require_relative 'nodes/set/delimiter'
|
27
|
-
require_relative 'nodes/set/set'
|
28
|
-
require_relative 'nodes/set/open'
|
26
|
+
require_relative 'nodes/set'
|
29
27
|
require_relative 'nodes/time'
|
30
28
|
require_relative 'nodes/value'
|
31
29
|
require_relative 'nodes/word'
|
@@ -10,6 +10,11 @@ module MSFLVisitors
|
|
10
10
|
lt: Nodes::LessThan,
|
11
11
|
lte: Nodes::LessThanEqual,
|
12
12
|
in: Nodes::Containment,
|
13
|
+
foreign: Nodes::Foreign,
|
14
|
+
dataset: Nodes::Dataset,
|
15
|
+
filter: Nodes::ExplicitFilter,
|
16
|
+
given: Nodes::Given,
|
17
|
+
partial: Nodes::Partial,
|
13
18
|
|
14
19
|
}
|
15
20
|
|
@@ -34,10 +39,14 @@ module MSFLVisitors
|
|
34
39
|
end
|
35
40
|
|
36
41
|
|
37
|
-
|
42
|
+
def initialize(dataset = nil)
|
43
|
+
@dataset = dataset
|
44
|
+
end
|
38
45
|
|
39
46
|
private
|
40
47
|
|
48
|
+
attr_accessor :dataset
|
49
|
+
|
41
50
|
def parse_Hash(obj, lhs = false)
|
42
51
|
nodes = Array.new
|
43
52
|
obj.each do |k, v|
|
@@ -57,14 +66,34 @@ module MSFLVisitors
|
|
57
66
|
obj.each do |item|
|
58
67
|
nodes << parse(item)
|
59
68
|
end
|
60
|
-
MSFLVisitors::Nodes::Set
|
69
|
+
MSFLVisitors::Nodes::Set.new nodes
|
61
70
|
end
|
62
71
|
|
72
|
+
# A key/value pair needs to be parsed and handled while iterating across the Hash that the key/value pair belong to
|
73
|
+
# lhs is for when the field is a parent of the actual operator node
|
74
|
+
# ex. { year: { gte: 2010 } } needs to be converted to (gte(year, 2010)) -- infix operators to RPN
|
63
75
|
def hash_dispatch(key, value, lhs = false)
|
64
76
|
if OPERATORS_TO_NODE_CLASS.include? key
|
65
77
|
# Detect the node type, forward the lhs if it was passed in (essentially when the operator is a binary op)
|
66
|
-
|
67
|
-
|
78
|
+
case key
|
79
|
+
when :foreign
|
80
|
+
args = [hash_dispatch(:dataset, value[:dataset]), hash_dispatch(:filter, value[:filter])]
|
81
|
+
|
82
|
+
when :partial
|
83
|
+
args = [hash_dispatch(:given, value[:given]), hash_dispatch(:filter, value[:filter])]
|
84
|
+
|
85
|
+
when :dataset
|
86
|
+
args = [value]
|
87
|
+
when :filter, :given
|
88
|
+
# Explicit Filter
|
89
|
+
# ex { foreign: { dataset: "person", filter: { age: 25 } } }
|
90
|
+
# ex { partial: { given: { make: "Toyota" }, filter: { avg_age: 10 } } }
|
91
|
+
args = value.map { |k,v| hash_dispatch(k,v) }
|
92
|
+
else
|
93
|
+
# fall back to a Filter Node
|
94
|
+
args = [lhs, parse(value)] if lhs
|
95
|
+
args ||= [parse(value)]
|
96
|
+
end
|
68
97
|
OPERATORS_TO_NODE_CLASS[key].new(*args)
|
69
98
|
else
|
70
99
|
# the key is a field
|
@@ -1,16 +1,175 @@
|
|
1
|
+
require 'forwardable'
|
1
2
|
module MSFLVisitors
|
2
3
|
class Visitor
|
3
|
-
|
4
|
-
|
5
|
-
|
4
|
+
|
5
|
+
attr_accessor :clauses, :current_clause
|
6
|
+
attr_writer :mode
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
self.mode = :term # or :aggregations
|
10
|
+
self.clauses = Array.new
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
def visit(node)
|
15
|
+
case node
|
16
|
+
when Nodes::Partial
|
17
|
+
in_aggregation_mode do
|
18
|
+
clauses << { clause: get_visitor.visit(node), method_to_execute: :aggregations }
|
19
|
+
""
|
20
|
+
end
|
21
|
+
else
|
22
|
+
get_visitor.visit(node)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def get_visitor
|
27
|
+
(mode == :term ? TermFilterVisitor : AggregationsVisitor).new(self)
|
6
28
|
end
|
7
29
|
|
8
|
-
def
|
9
|
-
|
30
|
+
def in_aggregation_mode
|
31
|
+
self.mode = :aggregations
|
32
|
+
result = yield if block_given?
|
33
|
+
self.mode = :term
|
34
|
+
result
|
35
|
+
end
|
36
|
+
|
37
|
+
def visit_tree(root)
|
38
|
+
[{clause: root.accept(self)}].concat(clauses).reject { |c| c[:clause] == "" }
|
10
39
|
end
|
11
40
|
|
12
41
|
private
|
13
42
|
|
14
|
-
attr_reader :
|
43
|
+
attr_reader :mode
|
44
|
+
|
45
|
+
class TermFilterVisitor
|
46
|
+
def initialize(visitor)
|
47
|
+
@visitor = visitor
|
48
|
+
end
|
49
|
+
|
50
|
+
BINARY_OPERATORS = {
|
51
|
+
Nodes::Containment => '==',
|
52
|
+
Nodes::GreaterThan => '>',
|
53
|
+
Nodes::GreaterThanEqual => '>=',
|
54
|
+
Nodes::Equal => '==',
|
55
|
+
Nodes::LessThan => '<',
|
56
|
+
Nodes::LessThanEqual => '<=',
|
57
|
+
}
|
58
|
+
|
59
|
+
def visit(node)
|
60
|
+
case node
|
61
|
+
when Nodes::Field
|
62
|
+
node.value.to_s
|
63
|
+
when Nodes::Word
|
64
|
+
"\"#{node.value}\""
|
65
|
+
when Nodes::Date, Nodes::Time
|
66
|
+
"\"#{node.value.iso8601}\""
|
67
|
+
when Nodes::Number, Nodes::Boolean
|
68
|
+
node.value
|
69
|
+
when Nodes::Containment,
|
70
|
+
Nodes::GreaterThan,
|
71
|
+
Nodes::GreaterThanEqual,
|
72
|
+
Nodes::Equal,
|
73
|
+
Nodes::LessThan,
|
74
|
+
Nodes::LessThanEqual
|
75
|
+
"#{node.left.accept(visitor)} #{BINARY_OPERATORS[node.class]} #{node.right.accept(visitor)}"
|
76
|
+
when Nodes::Set
|
77
|
+
"[ " + node.contents.map { |n| n.accept(visitor) }.join(" , ") + " ]"
|
78
|
+
when Nodes::Filter
|
79
|
+
if node.contents.count == 1
|
80
|
+
node.contents.first.accept(visitor)
|
81
|
+
else
|
82
|
+
node.contents.map { |n| "( " + n.accept(visitor) + " )" }.join(" & ")
|
83
|
+
end
|
84
|
+
|
85
|
+
when Nodes::And
|
86
|
+
if node.set.contents.count == 1
|
87
|
+
node.set.contents.first.accept(visitor)
|
88
|
+
else
|
89
|
+
node.set.contents.map { |n| "( " + n.accept(visitor) + " )" }.join(" & ")
|
90
|
+
end
|
91
|
+
|
92
|
+
when Nodes::Foreign
|
93
|
+
"#{node.left.accept visitor}.filter { #{node.right.accept visitor} }"
|
94
|
+
|
95
|
+
when Nodes::Dataset
|
96
|
+
"has_child( :#{node.value} )"
|
97
|
+
|
98
|
+
else
|
99
|
+
fail ArgumentError, "TERMFILTER cannot visit: #{node.class.name}"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
attr_reader :visitor
|
106
|
+
end
|
107
|
+
|
108
|
+
class AggregationsVisitor
|
109
|
+
def initialize(visitor)
|
110
|
+
@visitor = visitor
|
111
|
+
end
|
112
|
+
|
113
|
+
RANGE_OPERATORS = {
|
114
|
+
Nodes::GreaterThan => :gt,
|
115
|
+
Nodes::GreaterThanEqual => :gte,
|
116
|
+
Nodes::LessThan => :lt,
|
117
|
+
Nodes::LessThanEqual => :lte,
|
118
|
+
}
|
119
|
+
|
120
|
+
def visit(node)
|
121
|
+
case node
|
122
|
+
when Nodes::Partial
|
123
|
+
{ given: Hash[[node.left.accept(visitor), node.right.accept(visitor)]] }
|
124
|
+
|
125
|
+
when Nodes::Equal
|
126
|
+
{ term: { node.left.accept(visitor) => node.right.accept(visitor) } }
|
127
|
+
# [{ clause: }]
|
128
|
+
when Nodes::Field
|
129
|
+
node.value.to_sym
|
130
|
+
when Nodes::Date, Nodes::Time
|
131
|
+
node.value.iso8601
|
132
|
+
when Nodes::Word,
|
133
|
+
Nodes::Number,
|
134
|
+
Nodes::Boolean,
|
135
|
+
Nodes::Dataset
|
136
|
+
node.value
|
137
|
+
when Nodes::GreaterThan,
|
138
|
+
Nodes::GreaterThanEqual,
|
139
|
+
Nodes::LessThan,
|
140
|
+
Nodes::LessThanEqual
|
141
|
+
{ range: { node.left.accept(visitor) => { RANGE_OPERATORS[node.class] => node.right.accept(visitor) } } }
|
142
|
+
when Nodes::Given
|
143
|
+
[:filter, node.contents.first.accept(visitor)]
|
144
|
+
when Nodes::ExplicitFilter
|
145
|
+
[:filter, node.contents.map { |n| n.accept(visitor) }.reduce({}) { |hsh, x| hsh.merge!(x); hsh } ]
|
146
|
+
when Nodes::NamedValue
|
147
|
+
[:aggs, {node.name.accept(visitor).to_sym => Hash[[node.value.accept(visitor)]]}]
|
148
|
+
when Nodes::Containment
|
149
|
+
{ terms: {node.left.accept(visitor).to_sym => node.right.accept(visitor)} }
|
150
|
+
when Nodes::Set
|
151
|
+
node.contents.map { |n| n.accept(visitor) }
|
152
|
+
when Nodes::Filter
|
153
|
+
if node.contents.count == 1
|
154
|
+
node.contents.first.accept visitor
|
155
|
+
else
|
156
|
+
{ and: node.contents.map { |n| n.accept(visitor) } }
|
157
|
+
end
|
158
|
+
when Nodes::And
|
159
|
+
{ and: node.set.accept(visitor) }
|
160
|
+
|
161
|
+
when Nodes::Foreign
|
162
|
+
{ has_child: Hash[[[:type, node.left.accept(visitor)], node.right.accept(visitor)]] }
|
163
|
+
|
164
|
+
else
|
165
|
+
fail ArgumentError, "AGGREGATIONS cannot visit: #{node.class.name}"
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
private
|
170
|
+
|
171
|
+
attr_reader :visitor
|
172
|
+
end
|
15
173
|
end
|
16
174
|
end
|
175
|
+
|
data/lib/msfl_visitors.rb
CHANGED
@@ -1,9 +1,7 @@
|
|
1
1
|
require_relative 'msfl_visitors/ast'
|
2
2
|
require_relative 'msfl_visitors/nodes'
|
3
3
|
require_relative 'msfl_visitors/visitor'
|
4
|
-
require_relative 'msfl_visitors/renderers/chewy/term_filter'
|
5
4
|
require_relative 'msfl_visitors/parsers/msfl_parser'
|
6
|
-
require_relative 'msfl_visitors/collectors'
|
7
5
|
|
8
6
|
module MSFLVisitors
|
9
7
|
end
|
data/msfl_visitors.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'msfl_visitors'
|
3
|
-
s.version = '0.
|
4
|
-
s.date = '2015-05-
|
3
|
+
s.version = '0.3.0.dev'
|
4
|
+
s.date = '2015-05-15'
|
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"]
|
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
|
|
10
10
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
11
11
|
s.homepage =
|
12
12
|
'https://github.com/Referly/msfl_visitors'
|
13
|
-
s.add_runtime_dependency "msfl", "~> 1.
|
13
|
+
s.add_runtime_dependency "msfl", "~> 1.2"
|
14
14
|
s.add_development_dependency "rake", "~> 10.3"
|
15
15
|
s.add_development_dependency "simplecov", "~> 0.10"
|
16
16
|
s.add_development_dependency "yard", "~> 0.8"
|
data/spec/nodes/iterator_spec.rb
CHANGED
@@ -2,15 +2,33 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe MSFLVisitors::Nodes::Iterator do
|
4
4
|
|
5
|
+
describe ".new" do
|
6
|
+
|
7
|
+
subject { described_class.new arg }
|
8
|
+
|
9
|
+
context "when the argument is not a MSFLVisitors::Nodes::Set instance" do
|
10
|
+
|
11
|
+
let(:arg) { double('Not a Set node') }
|
12
|
+
|
13
|
+
it "raises an ArgumentError" do
|
14
|
+
expect { subject }.to raise_error ArgumentError
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
5
19
|
describe "#==" do
|
6
20
|
|
7
21
|
let(:one) { MSFLVisitors::Nodes::Number.new(1) }
|
8
22
|
|
9
23
|
let(:two) { MSFLVisitors::Nodes::Number.new(2) }
|
10
24
|
|
11
|
-
let(:left) { MSFLVisitors::Nodes::Iterator.new
|
25
|
+
let(:left) { MSFLVisitors::Nodes::Iterator.new left_set }
|
26
|
+
|
27
|
+
let(:left_set) { MSFLVisitors::Nodes::Set.new [one, two] }
|
28
|
+
|
29
|
+
let(:right) { MSFLVisitors::Nodes::Iterator.new right_set }
|
12
30
|
|
13
|
-
let(:
|
31
|
+
let(:right_set) { MSFLVisitors::Nodes::Set.new [one, two] }
|
14
32
|
|
15
33
|
subject { left == right }
|
16
34
|
|
@@ -23,7 +41,7 @@ describe MSFLVisitors::Nodes::Iterator do
|
|
23
41
|
|
24
42
|
context "when lhs#items is not equal to rhs#items" do
|
25
43
|
|
26
|
-
let(:
|
44
|
+
let(:right_set) { MSFLVisitors::Nodes::Set.new [one] }
|
27
45
|
|
28
46
|
it { is_expected.to be false }
|
29
47
|
end
|