msfl_visitors 0.1.0.rc3 → 0.3.0.dev
Sign up to get free protection for your applications and to get access to all the features.
- 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
|