msfl_visitors 0.0.1
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 +7 -0
- data/.gitignore +20 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +40 -0
- data/LICENSE +22 -0
- data/README.md +64 -0
- data/Rakefile +10 -0
- data/circle.yml +9 -0
- data/lib/msfl_visitors.rb +7 -0
- data/lib/msfl_visitors/ast.rb +15 -0
- data/lib/msfl_visitors/nodes.rb +26 -0
- data/lib/msfl_visitors/nodes/and.rb +13 -0
- data/lib/msfl_visitors/nodes/base.rb +7 -0
- data/lib/msfl_visitors/nodes/binary.rb +26 -0
- data/lib/msfl_visitors/nodes/boolean.rb +7 -0
- data/lib/msfl_visitors/nodes/comparison.rb +7 -0
- data/lib/msfl_visitors/nodes/constant_value.rb +11 -0
- data/lib/msfl_visitors/nodes/date.rb +7 -0
- data/lib/msfl_visitors/nodes/date_time.rb +7 -0
- data/lib/msfl_visitors/nodes/equal.rb +7 -0
- data/lib/msfl_visitors/nodes/filter.rb +23 -0
- data/lib/msfl_visitors/nodes/greater_than.rb +7 -0
- data/lib/msfl_visitors/nodes/greater_than_equal.rb +7 -0
- data/lib/msfl_visitors/nodes/grouping/close.rb +9 -0
- data/lib/msfl_visitors/nodes/grouping/grouping.rb +24 -0
- data/lib/msfl_visitors/nodes/grouping/open.rb +9 -0
- data/lib/msfl_visitors/nodes/less_than.rb +7 -0
- data/lib/msfl_visitors/nodes/less_than_equal.rb +7 -0
- data/lib/msfl_visitors/nodes/number.rb +7 -0
- data/lib/msfl_visitors/nodes/range_value.rb +7 -0
- data/lib/msfl_visitors/nodes/time.rb +7 -0
- data/lib/msfl_visitors/nodes/value.rb +22 -0
- data/lib/msfl_visitors/nodes/word.rb +7 -0
- data/lib/msfl_visitors/parsers/msfl_parser.rb +78 -0
- data/lib/msfl_visitors/visitors/base.rb +15 -0
- data/lib/msfl_visitors/visitors/chewy_term_filter.rb +70 -0
- data/msfl_visitors.gemspec +20 -0
- data/simplecov_custom_profiles.rb +5 -0
- data/spec/parsers/parse_msfl_spec.rb +22 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/visitors/chewy_term_filter/visit_binary_spec.rb +26 -0
- data/spec/visitors/chewy_term_filter/visit_comparison_spec.rb +61 -0
- data/spec/visitors/chewy_term_filter/visit_range_value_spec.rb +63 -0
- data/spec/visitors/chewy_term_filter/visit_value_spec.rb +44 -0
- metadata +183 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 095f9e51f9996a5555813581c265dbf5633b2272
|
|
4
|
+
data.tar.gz: 59c199f8df4b4f53bfe8b332d430c3e3e502476e
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: a41e25d060824497a403ffa1f0f7b65a2856322e1dbc45819409e441559e1c9704bd024c92d37cf1bf861d8d06726609354906c90dd8e7432a9a3e3425c7c592
|
|
7
|
+
data.tar.gz: c602d663fdcc0864218ae9825362cc3c4917c26b7cbbbf959f33419704d4135d9ff9c81f80a6aa7a756ecb26364dfa50d99b9942e38e7889f482345ad6fccd46
|
data/.gitignore
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
### Ruby template
|
|
2
|
+
*.gem
|
|
3
|
+
*.rbc
|
|
4
|
+
/coverage/
|
|
5
|
+
/spec/reports/
|
|
6
|
+
|
|
7
|
+
## Documentation cache and generated files:
|
|
8
|
+
/.yardoc/
|
|
9
|
+
/_yardoc/
|
|
10
|
+
/doc/
|
|
11
|
+
/rdoc/
|
|
12
|
+
|
|
13
|
+
## Environment normalisation:
|
|
14
|
+
/.bundle/
|
|
15
|
+
/lib/bundler/man/
|
|
16
|
+
.idea/
|
|
17
|
+
|
|
18
|
+
## Gemfile for development
|
|
19
|
+
#Gemfile
|
|
20
|
+
#Gemfile.lock
|
data/Gemfile
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
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.1"
|
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
GEM
|
|
2
|
+
remote: https://rubygems.org/
|
|
3
|
+
specs:
|
|
4
|
+
byebug (4.0.5)
|
|
5
|
+
columnize (= 0.9.0)
|
|
6
|
+
columnize (0.9.0)
|
|
7
|
+
diff-lcs (1.2.5)
|
|
8
|
+
docile (1.1.5)
|
|
9
|
+
json (1.8.2)
|
|
10
|
+
msfl (1.1.6)
|
|
11
|
+
json (~> 1.7)
|
|
12
|
+
rspec (3.2.0)
|
|
13
|
+
rspec-core (~> 3.2.0)
|
|
14
|
+
rspec-expectations (~> 3.2.0)
|
|
15
|
+
rspec-mocks (~> 3.2.0)
|
|
16
|
+
rspec-core (3.2.3)
|
|
17
|
+
rspec-support (~> 3.2.0)
|
|
18
|
+
rspec-expectations (3.2.1)
|
|
19
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
20
|
+
rspec-support (~> 3.2.0)
|
|
21
|
+
rspec-mocks (3.2.1)
|
|
22
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
23
|
+
rspec-support (~> 3.2.0)
|
|
24
|
+
rspec-support (3.2.2)
|
|
25
|
+
simplecov (0.10.0)
|
|
26
|
+
docile (~> 1.1.0)
|
|
27
|
+
json (~> 1.8)
|
|
28
|
+
simplecov-html (~> 0.10.0)
|
|
29
|
+
simplecov-html (0.10.0)
|
|
30
|
+
yard (0.8.7.6)
|
|
31
|
+
|
|
32
|
+
PLATFORMS
|
|
33
|
+
ruby
|
|
34
|
+
|
|
35
|
+
DEPENDENCIES
|
|
36
|
+
byebug
|
|
37
|
+
msfl (~> 1.1)
|
|
38
|
+
rspec
|
|
39
|
+
simplecov
|
|
40
|
+
yard
|
data/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2015 Referly
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
data/README.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
[](https://circleci.com/gh/Referly/msfl-visitors)
|
|
2
|
+
|
|
3
|
+
# msfl_visitors
|
|
4
|
+
A visitor pattern based approach for converting MSFL to other forms
|
|
5
|
+
|
|
6
|
+
## Usage
|
|
7
|
+
|
|
8
|
+
```ruby
|
|
9
|
+
# This is not actually working code yet! @todo revisit once Matt's refactor branch is merged.
|
|
10
|
+
require 'msfl_visitor'
|
|
11
|
+
|
|
12
|
+
filter = { make: "Toyota" }
|
|
13
|
+
|
|
14
|
+
collector = String.new
|
|
15
|
+
|
|
16
|
+
renderer = MSFLVisitors::Renderers::Chewy::TermFilter.new
|
|
17
|
+
|
|
18
|
+
visitor = MSFLVisitors::Visitor.new collector, renderer
|
|
19
|
+
|
|
20
|
+
MSFLVisitors::AST.new(filter).accept(visitor)
|
|
21
|
+
|
|
22
|
+
=> 'make == "Toyota"'
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Architecture
|
|
27
|
+
|
|
28
|
+
msfl_visitors is designed to consume normalized Mattermark Semantic Filter Language (NMSFL).
|
|
29
|
+
msfl_visitors implements a parser (parsers/msfl_parser) that converts NMSFL into an AST.
|
|
30
|
+
msfl_visitors implements a visitor that traverses the ast and produces the well formed output.
|
|
31
|
+
The behavior of the visitor is controlled through composition at construction. It accepts a collector and a renderer.
|
|
32
|
+
|
|
33
|
+
## MSFLParser
|
|
34
|
+
|
|
35
|
+
The parser accepts a Hash containing NMSFL and produces an AST.
|
|
36
|
+
The parser uses a simplified version of the visitor pattern to traverse the NMSFL and produce the AST.
|
|
37
|
+
|
|
38
|
+
Typically one does not interact with the parser directly, instead a consumer of this gem should interact with the AST.
|
|
39
|
+
|
|
40
|
+
## AST
|
|
41
|
+
|
|
42
|
+
The abstract syntax tree that represents a certain query filter. In the version of the visitor pattern herein
|
|
43
|
+
adopted, each node of the AST is responsible for managing its state and traversal of itself and children.
|
|
44
|
+
|
|
45
|
+
A consumer of this gem creates a new AST instance passing in a Hash of NMSFL. The AST will leverage the MSFL parser
|
|
46
|
+
to construct itself. The AST object is a Node as it implements the #accept(visitor) method.
|
|
47
|
+
|
|
48
|
+
## visitor
|
|
49
|
+
|
|
50
|
+
Unlike the classical visitor pattern double dispatch is not strictly achieved through type matching in the visitor.
|
|
51
|
+
Instead the visitor is just a single service that is composed of a collector and a renderer.
|
|
52
|
+
The double dispatch is codified inside of a renderer, which like the visitors in the classic pattern can produce
|
|
53
|
+
multiple output DSLs.
|
|
54
|
+
|
|
55
|
+
## collector
|
|
56
|
+
|
|
57
|
+
During traversal the output from each node needs to be stored or buffered somewhere. The collector serves this role.
|
|
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 (<<)
|
|
60
|
+
|
|
61
|
+
## renderer
|
|
62
|
+
|
|
63
|
+
The logic for rendering the AST nodes into the output DSL is codified in a renderer. The two principle renderers at
|
|
64
|
+
this time are Chewy::TermFilter and Chewy:QueryStringFilter
|
data/Rakefile
ADDED
data/circle.yml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
require_relative 'msfl_visitors/ast'
|
|
2
|
+
require_relative 'msfl_visitors/visitors/base'
|
|
3
|
+
require_relative 'msfl_visitors/nodes'
|
|
4
|
+
require_relative 'msfl_visitors/visitors/chewy_term_filter'
|
|
5
|
+
require_relative 'msfl_visitors/parsers/msfl_parser'
|
|
6
|
+
module MSFLVisitors
|
|
7
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module MSFLVisitors
|
|
2
|
+
class AST
|
|
3
|
+
|
|
4
|
+
attr_accessor :root
|
|
5
|
+
|
|
6
|
+
def initialize(msfl)
|
|
7
|
+
self.root = MSFLVisitors::Parsers::MSFLParser.parse msfl
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# Use this method to walk the AST with a particular visitor
|
|
11
|
+
def accept(visitor)
|
|
12
|
+
root.accept visitor
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Using alphabetical order to keep these organized
|
|
2
|
+
require_relative 'nodes/and'
|
|
3
|
+
require_relative 'nodes/base'
|
|
4
|
+
require_relative 'nodes/binary'
|
|
5
|
+
require_relative 'nodes/boolean'
|
|
6
|
+
require_relative 'nodes/comparison'
|
|
7
|
+
require_relative 'nodes/constant_value'
|
|
8
|
+
require_relative 'nodes/date'
|
|
9
|
+
require_relative 'nodes/date_time'
|
|
10
|
+
require_relative 'nodes/equal'
|
|
11
|
+
require_relative 'nodes/filter'
|
|
12
|
+
require_relative 'nodes/greater_than'
|
|
13
|
+
require_relative 'nodes/greater_than_equal'
|
|
14
|
+
require_relative 'nodes/grouping/close'
|
|
15
|
+
require_relative 'nodes/grouping/grouping'
|
|
16
|
+
require_relative 'nodes/grouping/open'
|
|
17
|
+
require_relative 'nodes/less_than'
|
|
18
|
+
require_relative 'nodes/less_than_equal'
|
|
19
|
+
require_relative 'nodes/number'
|
|
20
|
+
require_relative 'nodes/range_value'
|
|
21
|
+
require_relative 'nodes/time'
|
|
22
|
+
require_relative 'nodes/value'
|
|
23
|
+
require_relative 'nodes/word'
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require_relative 'binary'
|
|
2
|
+
module MSFLVisitors
|
|
3
|
+
module Nodes
|
|
4
|
+
class And < Binary
|
|
5
|
+
|
|
6
|
+
def accept(visitor)
|
|
7
|
+
MSFLVisitors::Nodes::Grouping::Grouping.new(left).accept visitor
|
|
8
|
+
visitor.visit self
|
|
9
|
+
MSFLVisitors::Nodes::Grouping::Grouping.new(right).accept visitor
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require_relative 'base'
|
|
2
|
+
module MSFLVisitors
|
|
3
|
+
module Nodes
|
|
4
|
+
class Binary < Base
|
|
5
|
+
|
|
6
|
+
attr_accessor :left, :right
|
|
7
|
+
|
|
8
|
+
def accept(visitor)
|
|
9
|
+
visitor.visit left
|
|
10
|
+
visitor.visit self
|
|
11
|
+
visitor.visit right
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def initialize(left, right)
|
|
15
|
+
self.left = left
|
|
16
|
+
self.right = right
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def ==(other)
|
|
20
|
+
self.class == other.class &&
|
|
21
|
+
self.left == other.left &&
|
|
22
|
+
self.right == other.right
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require_relative 'base'
|
|
2
|
+
module MSFLVisitors
|
|
3
|
+
module Nodes
|
|
4
|
+
class Filter < Base
|
|
5
|
+
|
|
6
|
+
attr_accessor :contents
|
|
7
|
+
|
|
8
|
+
def accept(visitor)
|
|
9
|
+
contents.accept visitor
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# @param nodes [Array<MSFL::Nodes::Base>] the nodes that the filter surrounds
|
|
13
|
+
def initialize(nodes)
|
|
14
|
+
self.contents = nodes
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def ==(other)
|
|
18
|
+
self.class == other.class &&
|
|
19
|
+
contents == other.contents
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require_relative '../base'
|
|
2
|
+
require_relative 'close'
|
|
3
|
+
require_relative 'open'
|
|
4
|
+
module MSFLVisitors
|
|
5
|
+
module Nodes
|
|
6
|
+
module Grouping
|
|
7
|
+
class Grouping < Base
|
|
8
|
+
|
|
9
|
+
attr_accessor :contents
|
|
10
|
+
|
|
11
|
+
def accept(visitor)
|
|
12
|
+
Open.new.accept visitor
|
|
13
|
+
contents.accept visitor
|
|
14
|
+
Close.new.accept visitor
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# @param node [MSFL::Nodes::Base] the node that the grouping surrounds
|
|
18
|
+
def initialize(node)
|
|
19
|
+
self.contents = node
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require_relative 'base'
|
|
2
|
+
module MSFLVisitors
|
|
3
|
+
module Nodes
|
|
4
|
+
class Value < Base
|
|
5
|
+
|
|
6
|
+
attr_accessor :value
|
|
7
|
+
|
|
8
|
+
def accept(visitor)
|
|
9
|
+
visitor.visit self
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def initialize(expr)
|
|
13
|
+
self.value = expr
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def ==(other)
|
|
17
|
+
self.class == other.class &&
|
|
18
|
+
value == other.value
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
require 'msfl'
|
|
2
|
+
module MSFLVisitors
|
|
3
|
+
module Parsers
|
|
4
|
+
class MSFLParser
|
|
5
|
+
include MSFL::Validators::Definitions::HashKey
|
|
6
|
+
|
|
7
|
+
def parse(obj, lhs = false)
|
|
8
|
+
# send("parse_#{obj.class.to_s.gsub('::', '_')}", obj, lhs)
|
|
9
|
+
case obj
|
|
10
|
+
|
|
11
|
+
when Float, Fixnum
|
|
12
|
+
MSFLVisitors::Nodes::Number.new obj
|
|
13
|
+
|
|
14
|
+
when Hash
|
|
15
|
+
parse_Hash obj, lhs
|
|
16
|
+
|
|
17
|
+
when MSFL::Types::Set
|
|
18
|
+
parse_Set obj, lhs
|
|
19
|
+
|
|
20
|
+
when Symbol, String, NilClass
|
|
21
|
+
MSFLVisitors::Nodes::Word.new obj.to_s
|
|
22
|
+
|
|
23
|
+
else
|
|
24
|
+
fail ArgumentError, "Invalid NMSFL, unable to parse."
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def parse_Hash(obj, lhs = false)
|
|
34
|
+
nodes = Array.new
|
|
35
|
+
obj.each do |k, v|
|
|
36
|
+
nodes << hash_dispatch(k, v, lhs)
|
|
37
|
+
end
|
|
38
|
+
MSFLVisitors::Nodes::Filter.new nodes
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def parse_Set(obj, lhs = false)
|
|
42
|
+
fail NoMethodError, "#parse_Set is not yet implemented."
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def hash_dispatch(key, value, lhs = false)
|
|
46
|
+
if hash_key_operators.include? key
|
|
47
|
+
# Detect the node type, forward the lhs if it was passed in (essentially when the operator is a binary op)
|
|
48
|
+
args = [lhs, parse(value)] if lhs
|
|
49
|
+
args ||= [parse(value)]
|
|
50
|
+
Object.const_get("MSFLVisitors::Nodes::#{key.to_s.capitalize}").new(*args)
|
|
51
|
+
else
|
|
52
|
+
# the key is a field
|
|
53
|
+
# there are three possible scenarios when they key is a field
|
|
54
|
+
# 1. the implicit equality scenario, where the right side is a value
|
|
55
|
+
# { make: "toyota" }
|
|
56
|
+
#
|
|
57
|
+
# 2. the explicit comparison scenario
|
|
58
|
+
# { value: { gte: 2000 } }
|
|
59
|
+
#
|
|
60
|
+
# 3. the containment scenario
|
|
61
|
+
# { model: { in: ["Corolla", "Civic", "Mustang"] } }
|
|
62
|
+
#
|
|
63
|
+
# 2 & 3 are just hashes and can be parsed using the same method
|
|
64
|
+
lhs = MSFLVisitors::Nodes::Word.new key
|
|
65
|
+
|
|
66
|
+
# the node type generated by parsing value can use the lhs node when appropriate and otherwise ignore it
|
|
67
|
+
# although I can't think of a situation when it would ignore it.
|
|
68
|
+
rhs = parse value, lhs
|
|
69
|
+
if rhs.is_a? MSFLVisitors::Nodes::Value
|
|
70
|
+
MSFLVisitors::Nodes::Equal.new lhs, rhs
|
|
71
|
+
else
|
|
72
|
+
rhs
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module MSFLVisitors
|
|
2
|
+
module Visitors
|
|
3
|
+
class Base
|
|
4
|
+
attr_accessor :collector
|
|
5
|
+
|
|
6
|
+
def visit(obj)
|
|
7
|
+
send("visit_#{obj.class.to_s.gsub('::', '_')}", obj, collector)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def initialize(collector)
|
|
11
|
+
self.collector = collector
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
module MSFLVisitors
|
|
2
|
+
module Visitors
|
|
3
|
+
class ChewyTermFilter < Base
|
|
4
|
+
|
|
5
|
+
# Instead of using string interpolation only supported operators are enabled
|
|
6
|
+
BINARY_OPERATORS = { eq: "==", gt: ">", gte: ">=", lt: "<", lte: "<=", and: "&" }
|
|
7
|
+
|
|
8
|
+
def visit_MSFLVisitors_Nodes_And(obj, collector)
|
|
9
|
+
binary_helper :and, collector
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def visit_MSFLVisitors_Nodes_Boolean(obj, collector)
|
|
13
|
+
collector << obj.value
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def visit_MSFLVisitors_Nodes_Date(obj, collector)
|
|
17
|
+
collector << obj.value.iso8601
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def visit_MSFLVisitors_Nodes_DateTime(obj, collector)
|
|
21
|
+
collector << obj.value.iso8601
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def visit_MSFLVisitors_Nodes_Equal(obj, collector)
|
|
25
|
+
binary_helper :eq, collector
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def visit_MSFLVisitors_Nodes_GreaterThan(obj, collector)
|
|
29
|
+
binary_helper :gt, collector
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def visit_MSFLVisitors_Nodes_GreaterThanEqual(obj, collector)
|
|
33
|
+
binary_helper :gte, collector
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def visit_MSFLVisitors_Nodes_Grouping_Close(obj, collector)
|
|
37
|
+
collector << " )"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def visit_MSFLVisitors_Nodes_Grouping_Open(obj, collector)
|
|
41
|
+
collector << "( "
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def visit_MSFLVisitors_Nodes_LessThan(obj, collector)
|
|
45
|
+
binary_helper :lt, collector
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def visit_MSFLVisitors_Nodes_LessThanEqual(obj, collector)
|
|
49
|
+
binary_helper :lte, collector
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def visit_MSFLVisitors_Nodes_Number(obj, collector)
|
|
53
|
+
collector << obj.value
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def visit_MSFLVisitors_Nodes_Time(obj, collector)
|
|
57
|
+
collector << obj.value.iso8601
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def visit_MSFLVisitors_Nodes_Word(obj, collector)
|
|
61
|
+
collector << "#{obj.value.to_s}"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
def binary_helper(operator, collector)
|
|
66
|
+
collector << " #{BINARY_OPERATORS.fetch(operator.to_sym)} "
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Gem::Specification.new do |s|
|
|
2
|
+
s.name = 'msfl_visitors'
|
|
3
|
+
s.version = '0.0.1'
|
|
4
|
+
s.date = '2015-05-01'
|
|
5
|
+
s.summary = "Convert MSFL to other forms"
|
|
6
|
+
s.description = "Visitor pattern approach to converting MSFL to other forms."
|
|
7
|
+
s.authors = ["Courtland Caldwell"]
|
|
8
|
+
s.email = 'courtland@mattermark.com'
|
|
9
|
+
s.files = `git ls-files`.split("\n")
|
|
10
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
11
|
+
s.homepage =
|
|
12
|
+
'https://github.com/Referly/msfl_visitors'
|
|
13
|
+
s.add_runtime_dependency "msfl", "~> 1.1", '>= 1.1.6'
|
|
14
|
+
s.add_development_dependency "rake", "~> 10.3"
|
|
15
|
+
s.add_development_dependency "simplecov", "~> 0.10"
|
|
16
|
+
s.add_development_dependency "yard", "~> 0.8"
|
|
17
|
+
s.add_development_dependency "rspec", "~> 3.2"
|
|
18
|
+
s.add_development_dependency "byebug", "~> 4.0"
|
|
19
|
+
s.license = "MIT"
|
|
20
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# This is a working file until I split these up
|
|
2
|
+
require 'spec_helper'
|
|
3
|
+
|
|
4
|
+
describe MSFLVisitors::Parsers::MSFLParser do
|
|
5
|
+
|
|
6
|
+
describe "parsing a trivial filter" do
|
|
7
|
+
|
|
8
|
+
subject { described_class.new.parse msfl }
|
|
9
|
+
|
|
10
|
+
let(:msfl) { { make: "Ferrari" } }
|
|
11
|
+
|
|
12
|
+
let(:expected) { MSFLVisitors::Nodes::Filter.new [ MSFLVisitors::Nodes::Equal.new(left, right) ] }
|
|
13
|
+
|
|
14
|
+
let(:left) { MSFLVisitors::Nodes::Word.new :make }
|
|
15
|
+
|
|
16
|
+
let(:right) { MSFLVisitors::Nodes::Word.new "Ferrari" }
|
|
17
|
+
|
|
18
|
+
it "is the expected AST" do
|
|
19
|
+
expect(subject).to eq expected
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe MSFLVisitors::Visitors::ChewyTermFilter do
|
|
4
|
+
|
|
5
|
+
subject { node.accept visitor }
|
|
6
|
+
|
|
7
|
+
let(:node) { fail ArgumentError, "You must define the node variable in each scope." }
|
|
8
|
+
|
|
9
|
+
let(:visitor) { described_class.new collector }
|
|
10
|
+
|
|
11
|
+
let(:collector) { String.new }
|
|
12
|
+
|
|
13
|
+
let(:left) { MSFLVisitors::Nodes::Word.new "lhs" }
|
|
14
|
+
|
|
15
|
+
let(:right) { MSFLVisitors::Nodes::Word.new "rhs" }
|
|
16
|
+
|
|
17
|
+
describe "visiting an And node" do
|
|
18
|
+
|
|
19
|
+
let(:node) { MSFLVisitors::Nodes::And.new left, right }
|
|
20
|
+
|
|
21
|
+
it "matches ( left ) & ( right )" do
|
|
22
|
+
expect(subject).to match "( lhs ) & ( rhs )"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe MSFLVisitors::Visitors::ChewyTermFilter do
|
|
4
|
+
|
|
5
|
+
subject { node.accept visitor }
|
|
6
|
+
|
|
7
|
+
let(:node) { fail ArgumentError, "You must define the node variable in each scope." }
|
|
8
|
+
|
|
9
|
+
let(:visitor) { described_class.new collector }
|
|
10
|
+
|
|
11
|
+
let(:collector) { String.new }
|
|
12
|
+
|
|
13
|
+
let(:left) { MSFLVisitors::Nodes::Word.new "lhs" }
|
|
14
|
+
|
|
15
|
+
let(:right) { MSFLVisitors::Nodes::Word.new "rhs" }
|
|
16
|
+
|
|
17
|
+
describe "visiting an Equal node" do
|
|
18
|
+
|
|
19
|
+
let(:node) { MSFLVisitors::Nodes::Equal.new left, right }
|
|
20
|
+
|
|
21
|
+
it "matches left == right" do
|
|
22
|
+
expect(subject).to match "lhs == rhs"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
describe "visiting a GreaterThan node" do
|
|
27
|
+
|
|
28
|
+
let(:node) { MSFLVisitors::Nodes::GreaterThan.new left, right }
|
|
29
|
+
|
|
30
|
+
it "matches left > right" do
|
|
31
|
+
expect(subject).to match "lhs > rhs"
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
describe "visiting a GreaterThanEqual node" do
|
|
36
|
+
|
|
37
|
+
let(:node) { MSFLVisitors::Nodes::GreaterThanEqual.new left, right }
|
|
38
|
+
|
|
39
|
+
it "matches left >= right" do
|
|
40
|
+
expect(subject).to match "lhs >= rhs"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
describe "visiting a LessThan node" do
|
|
45
|
+
|
|
46
|
+
let(:node) { MSFLVisitors::Nodes::LessThan.new left, right }
|
|
47
|
+
|
|
48
|
+
it "matches left < right" do
|
|
49
|
+
expect(subject).to match "lhs < rhs"
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
describe "visiting a LessThanEqual node" do
|
|
54
|
+
|
|
55
|
+
let(:node) { MSFLVisitors::Nodes::LessThanEqual.new left, right }
|
|
56
|
+
|
|
57
|
+
it "matches left <= right" do
|
|
58
|
+
expect(subject).to match "lhs <= rhs"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe MSFLVisitors::Visitors::ChewyTermFilter do
|
|
4
|
+
|
|
5
|
+
subject { node.accept visitor }
|
|
6
|
+
|
|
7
|
+
let(:node) { fail ArgumentError, "You must define the node variable in each scope." }
|
|
8
|
+
|
|
9
|
+
let(:visitor) { described_class.new collector }
|
|
10
|
+
|
|
11
|
+
let(:collector) { Array.new }
|
|
12
|
+
|
|
13
|
+
describe "visiting a Date node" do
|
|
14
|
+
|
|
15
|
+
let(:node) { MSFLVisitors::Nodes::Date.new Date.today }
|
|
16
|
+
|
|
17
|
+
it "is today's date using iso8601 formatting" do
|
|
18
|
+
expect(subject.first).to eq Date.today.iso8601
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
describe "visiting a DateTime node" do
|
|
23
|
+
|
|
24
|
+
let(:now) { DateTime.now }
|
|
25
|
+
|
|
26
|
+
let(:node) { MSFLVisitors::Nodes::DateTime.new now }
|
|
27
|
+
|
|
28
|
+
it "is the current date and time using iso8601 formatting" do
|
|
29
|
+
expect(subject.first).to eq now.iso8601
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe "visiting a Number node" do
|
|
34
|
+
|
|
35
|
+
let(:node) { MSFLVisitors::Nodes::Number.new number }
|
|
36
|
+
|
|
37
|
+
let(:number) { 123 }
|
|
38
|
+
|
|
39
|
+
it "is the number" do
|
|
40
|
+
expect(subject.first).to eq number
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
context "when the number is a float" do
|
|
44
|
+
|
|
45
|
+
let(:number) { 123.456 }
|
|
46
|
+
|
|
47
|
+
it "is the number with the same precision" do
|
|
48
|
+
expect(subject.first).to eq number
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
describe "visiting a Time node" do
|
|
54
|
+
|
|
55
|
+
let(:node) { MSFLVisitors::Nodes::Time.new current_time }
|
|
56
|
+
|
|
57
|
+
let(:current_time) { Time.now }
|
|
58
|
+
|
|
59
|
+
it "is the current time using iso8601 formatting" do
|
|
60
|
+
expect(subject.first).to eq current_time.iso8601
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe MSFLVisitors::Visitors::ChewyTermFilter do
|
|
4
|
+
|
|
5
|
+
subject { node.accept visitor }
|
|
6
|
+
|
|
7
|
+
let(:node) { fail ArgumentError, "You must define the node variable in each scope." }
|
|
8
|
+
|
|
9
|
+
let(:visitor) { described_class.new collector }
|
|
10
|
+
|
|
11
|
+
let(:collector) { Array.new }
|
|
12
|
+
|
|
13
|
+
describe "visiting a Boolean node" do
|
|
14
|
+
|
|
15
|
+
let(:node) { MSFLVisitors::Nodes::Boolean.new value }
|
|
16
|
+
|
|
17
|
+
context "when the node has a value of true" do
|
|
18
|
+
|
|
19
|
+
let(:value) { true }
|
|
20
|
+
|
|
21
|
+
it "is true" do
|
|
22
|
+
expect(subject.first).to be true
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
context "when the node has a value of false" do
|
|
27
|
+
|
|
28
|
+
let(:value) { false }
|
|
29
|
+
|
|
30
|
+
it "is false" do
|
|
31
|
+
expect(subject.first).to be false
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
describe "visiting a Word node" do
|
|
37
|
+
|
|
38
|
+
let(:node) { MSFLVisitors::Nodes::Word.new "node_content" }
|
|
39
|
+
|
|
40
|
+
it "is a literal string" do
|
|
41
|
+
expect(subject.first).to match /node_content/
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: msfl_visitors
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Courtland Caldwell
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2015-05-01 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: msfl
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '1.1'
|
|
20
|
+
- - ">="
|
|
21
|
+
- !ruby/object:Gem::Version
|
|
22
|
+
version: 1.1.6
|
|
23
|
+
type: :runtime
|
|
24
|
+
prerelease: false
|
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
26
|
+
requirements:
|
|
27
|
+
- - "~>"
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '1.1'
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: 1.1.6
|
|
33
|
+
- !ruby/object:Gem::Dependency
|
|
34
|
+
name: rake
|
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '10.3'
|
|
40
|
+
type: :development
|
|
41
|
+
prerelease: false
|
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '10.3'
|
|
47
|
+
- !ruby/object:Gem::Dependency
|
|
48
|
+
name: simplecov
|
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0.10'
|
|
54
|
+
type: :development
|
|
55
|
+
prerelease: false
|
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - "~>"
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '0.10'
|
|
61
|
+
- !ruby/object:Gem::Dependency
|
|
62
|
+
name: yard
|
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - "~>"
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '0.8'
|
|
68
|
+
type: :development
|
|
69
|
+
prerelease: false
|
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - "~>"
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '0.8'
|
|
75
|
+
- !ruby/object:Gem::Dependency
|
|
76
|
+
name: rspec
|
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - "~>"
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '3.2'
|
|
82
|
+
type: :development
|
|
83
|
+
prerelease: false
|
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - "~>"
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '3.2'
|
|
89
|
+
- !ruby/object:Gem::Dependency
|
|
90
|
+
name: byebug
|
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - "~>"
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: '4.0'
|
|
96
|
+
type: :development
|
|
97
|
+
prerelease: false
|
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
99
|
+
requirements:
|
|
100
|
+
- - "~>"
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
version: '4.0'
|
|
103
|
+
description: Visitor pattern approach to converting MSFL to other forms.
|
|
104
|
+
email: courtland@mattermark.com
|
|
105
|
+
executables: []
|
|
106
|
+
extensions: []
|
|
107
|
+
extra_rdoc_files: []
|
|
108
|
+
files:
|
|
109
|
+
- ".gitignore"
|
|
110
|
+
- Gemfile
|
|
111
|
+
- Gemfile.lock
|
|
112
|
+
- LICENSE
|
|
113
|
+
- README.md
|
|
114
|
+
- Rakefile
|
|
115
|
+
- circle.yml
|
|
116
|
+
- lib/msfl_visitors.rb
|
|
117
|
+
- lib/msfl_visitors/ast.rb
|
|
118
|
+
- lib/msfl_visitors/nodes.rb
|
|
119
|
+
- lib/msfl_visitors/nodes/and.rb
|
|
120
|
+
- lib/msfl_visitors/nodes/base.rb
|
|
121
|
+
- lib/msfl_visitors/nodes/binary.rb
|
|
122
|
+
- lib/msfl_visitors/nodes/boolean.rb
|
|
123
|
+
- lib/msfl_visitors/nodes/comparison.rb
|
|
124
|
+
- lib/msfl_visitors/nodes/constant_value.rb
|
|
125
|
+
- lib/msfl_visitors/nodes/date.rb
|
|
126
|
+
- lib/msfl_visitors/nodes/date_time.rb
|
|
127
|
+
- lib/msfl_visitors/nodes/equal.rb
|
|
128
|
+
- lib/msfl_visitors/nodes/filter.rb
|
|
129
|
+
- lib/msfl_visitors/nodes/greater_than.rb
|
|
130
|
+
- lib/msfl_visitors/nodes/greater_than_equal.rb
|
|
131
|
+
- lib/msfl_visitors/nodes/grouping/close.rb
|
|
132
|
+
- lib/msfl_visitors/nodes/grouping/grouping.rb
|
|
133
|
+
- lib/msfl_visitors/nodes/grouping/open.rb
|
|
134
|
+
- lib/msfl_visitors/nodes/less_than.rb
|
|
135
|
+
- lib/msfl_visitors/nodes/less_than_equal.rb
|
|
136
|
+
- lib/msfl_visitors/nodes/number.rb
|
|
137
|
+
- lib/msfl_visitors/nodes/range_value.rb
|
|
138
|
+
- lib/msfl_visitors/nodes/time.rb
|
|
139
|
+
- lib/msfl_visitors/nodes/value.rb
|
|
140
|
+
- lib/msfl_visitors/nodes/word.rb
|
|
141
|
+
- lib/msfl_visitors/parsers/msfl_parser.rb
|
|
142
|
+
- lib/msfl_visitors/visitors/base.rb
|
|
143
|
+
- lib/msfl_visitors/visitors/chewy_term_filter.rb
|
|
144
|
+
- msfl_visitors.gemspec
|
|
145
|
+
- simplecov_custom_profiles.rb
|
|
146
|
+
- spec/parsers/parse_msfl_spec.rb
|
|
147
|
+
- spec/spec_helper.rb
|
|
148
|
+
- spec/visitors/chewy_term_filter/visit_binary_spec.rb
|
|
149
|
+
- spec/visitors/chewy_term_filter/visit_comparison_spec.rb
|
|
150
|
+
- spec/visitors/chewy_term_filter/visit_range_value_spec.rb
|
|
151
|
+
- spec/visitors/chewy_term_filter/visit_value_spec.rb
|
|
152
|
+
homepage: https://github.com/Referly/msfl_visitors
|
|
153
|
+
licenses:
|
|
154
|
+
- MIT
|
|
155
|
+
metadata: {}
|
|
156
|
+
post_install_message:
|
|
157
|
+
rdoc_options: []
|
|
158
|
+
require_paths:
|
|
159
|
+
- lib
|
|
160
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
161
|
+
requirements:
|
|
162
|
+
- - ">="
|
|
163
|
+
- !ruby/object:Gem::Version
|
|
164
|
+
version: '0'
|
|
165
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
166
|
+
requirements:
|
|
167
|
+
- - ">="
|
|
168
|
+
- !ruby/object:Gem::Version
|
|
169
|
+
version: '0'
|
|
170
|
+
requirements: []
|
|
171
|
+
rubyforge_project:
|
|
172
|
+
rubygems_version: 2.2.2
|
|
173
|
+
signing_key:
|
|
174
|
+
specification_version: 4
|
|
175
|
+
summary: Convert MSFL to other forms
|
|
176
|
+
test_files:
|
|
177
|
+
- spec/parsers/parse_msfl_spec.rb
|
|
178
|
+
- spec/spec_helper.rb
|
|
179
|
+
- spec/visitors/chewy_term_filter/visit_binary_spec.rb
|
|
180
|
+
- spec/visitors/chewy_term_filter/visit_comparison_spec.rb
|
|
181
|
+
- spec/visitors/chewy_term_filter/visit_range_value_spec.rb
|
|
182
|
+
- spec/visitors/chewy_term_filter/visit_value_spec.rb
|
|
183
|
+
has_rdoc:
|