vsql_parser 0.2

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.
data/MIT_LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 LeadTune
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/lib/formatter.rb ADDED
@@ -0,0 +1,81 @@
1
+ require_relative "./vsql_node_extensions"
2
+
3
+ module VSql
4
+ module Formatter
5
+ extend self
6
+
7
+ def indent(value, amount = 2, first_line = false)
8
+ spacer = (" " * amount)
9
+ (first_line ? spacer : "") + value.gsub("\n", "\n#{spacer}")
10
+ end
11
+
12
+ def eager_indent(value, amount = 2)
13
+ indent(value, amount, true)
14
+ end
15
+
16
+ def quote_alias_if_needed(a)
17
+ if a.match(/[^a-z0-9_]/)
18
+ '"' + a + '"'
19
+ else
20
+ a
21
+ end
22
+ end
23
+
24
+ DEFAULT_FORMATTER = lambda { |n|
25
+ n.pieces.map { |p|
26
+ p.is_a?(String) ? p : format_node(p)
27
+ }.join
28
+ }
29
+
30
+ NODE_FORMATTERS = {
31
+ SelectExpression => lambda { |n|
32
+ formatted_expr = format_node(n.elements[0])
33
+ if n.alias_node
34
+ expr_alias = n.alias_node.text_value
35
+ [formatted_expr, " AS ", quote_alias_if_needed(expr_alias)].join
36
+ else
37
+ formatted_expr
38
+ end
39
+ },
40
+ SelectStatement => lambda { |n|
41
+ statements = n.match(SelectExpression, Query)
42
+ "\nSELECT\n" + eager_indent(statements.map { |s| format_node(s) }.join(",\n"))
43
+ },
44
+ LimitStatement => lambda { |n|
45
+ "\nLIMIT" + n.elements[1..-1].map(&:text_value).join
46
+ },
47
+ WhereStatement => lambda { |n|
48
+ exprs = n.elements.select {|e| e.is_a?(Expression) }
49
+ "\nWHERE " + indent(exprs.map {|e| DEFAULT_FORMATTER[e] }.join)
50
+ },
51
+ FromStatement => lambda { |n|
52
+ expressions = n.match(FromExpression, Query)
53
+ "\nFROM " + indent(expressions.map {|e| format_node(e) }.join("\n"))
54
+ },
55
+ JoinStatement => lambda { |n|
56
+ join_keyword = n.match(JoinKeyword, Query)[0]
57
+ from, criteria = n.elements.select {|e| e.is_a?(Expression) }
58
+ ["\n",
59
+ join_keyword.text_value.upcase,
60
+ " ",
61
+ indent(format_node(from)),
62
+ " ON ",
63
+ indent(format_node(criteria))].join
64
+ },
65
+ OrderByStatement => lambda { |n|
66
+ exprs = n.elements.select {|e| e.is_a?(OrderByExpression) }
67
+ "\nORDER BY " + indent(exprs.map {|e| DEFAULT_FORMATTER[e] }.join)
68
+ }
69
+ }
70
+
71
+ FORMATTERS = Hash.new(DEFAULT_FORMATTER).update(NODE_FORMATTERS)
72
+
73
+ def format_node(node)
74
+ FORMATTERS[node.class][node]
75
+ end
76
+
77
+ def format(node)
78
+ format_node(node).split("\n").map(&:rstrip).join("\n").strip + "\n"
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,63 @@
1
+ # In file parser.rb
2
+ require_relative './vsql_parser.rb'
3
+
4
+ module TestChamber
5
+ module Helpers
6
+ NORMAL_COLOR ||= 37
7
+ def colorize(color, output)
8
+ "\e[0;#{color}m#{output}\e[0;#{NORMAL_COLOR}m"
9
+ end
10
+ end
11
+
12
+ include Helpers
13
+ extend self
14
+
15
+ def pparse(sql, output_errors = true)
16
+ parse(sql, output_errors).tap { |q| q.prune! }
17
+ end
18
+
19
+ def parse(sql, output_errors = true)
20
+ parser = ::VSqlParser.parser
21
+ VSqlParser.parse(sql).tap do |tree|
22
+ # If the AST is nil then there was an error during parsing
23
+ # we need to report a simple error message to help the user
24
+ if tree.nil?
25
+ output_error(sql, parser) if output_errors
26
+ raise Exception, parser.failure_reason
27
+ end
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def output_error(sql, parser)
34
+ fail_index = parser.max_terminal_failure_index
35
+ STDERR.flush
36
+ STDOUT.flush
37
+ STDERR.puts( "\n" +
38
+ ((fail_index > 0) ? colorize(42, sql[0..(fail_index - 1)]) : "") +
39
+ colorize(41, sql[(fail_index)..-1]) +
40
+ "\n\n")
41
+
42
+ STDERR.flush
43
+ end
44
+
45
+ def clean_tree(root_node)
46
+ return if(root_node.elements.nil?)
47
+ root_node.elements.delete_if{|node| node.class.name == "Treetop::Runtime::SyntaxNode" }
48
+ root_node.elements.each {|node| self.clean_tree(node) }
49
+ end
50
+
51
+ def reload
52
+ Object.send(:remove_const, :SqlParser) rescue nil
53
+ Object.send(:remove_const, :Sql) rescue nil
54
+ Object.send(:remove_const, :VSql) rescue nil
55
+ TestChamber.send(:remove_const, :PARSER) rescue nil
56
+
57
+ load(File.join(VSQLPARSER_BASE_PATH, 'vsql_node_extensions.rb'))
58
+ load(File.join(VSQLPARSER_BASE_PATH, 'formatter.rb'))
59
+ Treetop.load(File.join(VSQLPARSER_BASE_PATH, 'vsql_parser.treetop'))
60
+ VSqlParser.extend(VSqlParserHelpers)
61
+ load(__FILE__)
62
+ end
63
+ end
@@ -0,0 +1,246 @@
1
+ module ScanHelpers
2
+ extend self
3
+ require 'strscan'
4
+ def gsub_replacements(string, pattern, replacement)
5
+ pattern = Regexp.new(Regexp.escape(pattern)) if pattern.is_a?(String)
6
+ [].tap do |matches|
7
+ scanner = StringScanner.new(string)
8
+ until scanner.eos?
9
+ return matches unless scanner.scan_until(pattern)
10
+ matches.push([(scanner.pos - scanner.matched_size)..(scanner.pos - 1),
11
+ replacement.size - scanner.matched_size,
12
+ replacement])
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ module Replaceability
19
+ def index_of(str)
20
+ e.text_value.index(str) + e.interval.first
21
+ end
22
+
23
+ def adjust_intervals!(idx, delta)
24
+ case
25
+ when @interval.include?(idx)
26
+ @interval = (@interval.first)...[@interval.first, @interval.last + delta].max
27
+ when @interval.first > idx
28
+ @interval = (@interval.first + delta)...(@interval.last + delta)
29
+ end
30
+ elements && elements.each { |e| e.adjust_intervals!(idx, delta) }
31
+ true
32
+ end
33
+
34
+ def gsub!(pattern, replacement)
35
+ ScanHelpers.gsub_replacements(text_value, pattern, replacement).reverse.each do |(range, delta, rep_str)|
36
+ end_idx = (@interval.min + range.max)
37
+ @input[(@interval.min + range.min)..end_idx] = rep_str
38
+ root.adjust_intervals!(end_idx, delta)
39
+ end
40
+ end
41
+ end
42
+
43
+ class Treetop::Runtime::SyntaxNode
44
+ def _pieces_with_gaps(cursor, elements, results = [])
45
+ return [cursor, results] if elements.nil? || elements.empty?
46
+ element, interval, next_elements = elements[0], elements[0].interval, elements[1..-1]
47
+ next_results = [*results,
48
+ *(input[cursor...interval.first] if cursor != elements.first.interval.first),
49
+ element]
50
+ _pieces_with_gaps(interval.last,
51
+ next_elements,
52
+ next_results)
53
+ end
54
+
55
+ def pieces
56
+ last_pos, pieces = _pieces_with_gaps(interval.first, elements)
57
+ if last_pos != interval.last
58
+ [input[last_pos...(interval.last)], *pieces]
59
+ else
60
+ pieces
61
+ end
62
+ end
63
+
64
+ def match(klass = Treetop::Runtime::SyntaxNode, skip = nil)
65
+ VSql::Helpers.find_elements(self, klass, skip)
66
+ end
67
+
68
+ def find(klass)
69
+ match(klass).first
70
+ end
71
+
72
+ def delete!
73
+ parent.elements.delete(self)
74
+ end
75
+
76
+ def vanilla?
77
+ (self.class == Treetop::Runtime::SyntaxNode) &&
78
+ (parent && parent.class == Treetop::Runtime::SyntaxNode || text_value.length == 0) &&
79
+ (elements.nil? || elements.all?(&:vanilla?))
80
+ end
81
+
82
+ def prune_if!(&block)
83
+ delete! if yield(self)
84
+ end
85
+
86
+ def prune!
87
+ es = match(Treetop::Runtime::SyntaxNode)
88
+ es.reverse.each do |e|
89
+ e.prune_if!(&:vanilla?)
90
+ end
91
+ self
92
+ end
93
+
94
+ def root
95
+ parent ? parent.root : self
96
+ end
97
+
98
+ def match_nearest(klass)
99
+ case
100
+ when parent.nil?
101
+ nil
102
+ when parent.is_a?(klass)
103
+ parent
104
+ else
105
+ parent.match_nearest(klass)
106
+ end
107
+ end
108
+
109
+ include Replaceability
110
+ end
111
+
112
+ module VSql
113
+ module Helpers
114
+ def self.find_elements(node, klass, skip_klass = nil)
115
+ results = []
116
+ return results unless node.elements
117
+ node.elements.each do |e|
118
+ case
119
+ when e.is_a?(klass)
120
+ results << e
121
+ results.concat(find_elements(e, klass, skip_klass))
122
+ when skip_klass && e.is_a?(skip_klass)
123
+ next
124
+ else
125
+ results.concat(find_elements(e, klass, skip_klass))
126
+ end
127
+ end
128
+ results
129
+ end
130
+ end
131
+
132
+ class VSqlSyntaxNode < Treetop::Runtime::SyntaxNode
133
+ end
134
+
135
+ class Operator < VSqlSyntaxNode
136
+ end
137
+
138
+ class Statement < VSqlSyntaxNode
139
+ end
140
+
141
+ class SelectStatement < Statement
142
+ def expressions
143
+ Helpers.find_elements(self, SelectExpression)
144
+ end
145
+ end
146
+
147
+ class SelectExpression < VSqlSyntaxNode
148
+ def expression_sql
149
+ end
150
+
151
+ def alias_node
152
+ @alias_node ||= Helpers.find_elements(self, Alias, Query).first
153
+ end
154
+
155
+ def root_nodes
156
+ elements[0].elements.select { |e| ! e.text_value.empty? }
157
+ end
158
+
159
+ def name
160
+ case
161
+ when alias_node
162
+ alias_node.text_value
163
+ when root_nodes.length == 1 && root_nodes.first.is_a?(Function)
164
+ root_nodes.first.name
165
+ when root_nodes.length == 1 && root_nodes.first.is_a?(FieldRef)
166
+ element =
167
+ Helpers.find_elements(self, FieldGlob).last ||
168
+ Helpers.find_elements(self, Name).last
169
+ element.text_value
170
+ else "?column?"
171
+ end
172
+ end
173
+ end
174
+
175
+ class NameExpression < VSqlSyntaxNode
176
+ end
177
+
178
+ class FromStatement < Statement
179
+ end
180
+
181
+ class FromExpression < VSqlSyntaxNode
182
+ end
183
+
184
+ class JoinStatement < Statement
185
+ end
186
+
187
+ class JoinKeyword < VSqlSyntaxNode
188
+ end
189
+
190
+ class WhereStatement < Statement
191
+ end
192
+
193
+ class OrderByStatement < Statement
194
+ end
195
+
196
+ class LimitStatement < Statement
197
+ end
198
+
199
+ class OrderByExpression < VSqlSyntaxNode
200
+ end
201
+
202
+ class Name < VSqlSyntaxNode
203
+ end
204
+
205
+ class FieldRef < VSqlSyntaxNode
206
+ end
207
+
208
+ class TablePart < VSqlSyntaxNode
209
+ end
210
+
211
+ class FieldGlob < VSqlSyntaxNode
212
+ end
213
+
214
+ class Alias < VSqlSyntaxNode
215
+ end
216
+
217
+ class Function < VSqlSyntaxNode
218
+ def name
219
+ elements[0].text_value
220
+ end
221
+ end
222
+
223
+ class Entity < VSqlSyntaxNode
224
+ # def to_array
225
+ # return self.elements[0].to_array
226
+ # end
227
+ end
228
+
229
+ class Expression < VSqlSyntaxNode
230
+ end
231
+
232
+ class QuotedEntity < Entity
233
+ end
234
+
235
+ class Query < VSqlSyntaxNode
236
+ # def to_array
237
+ # return self.elements.map {|x| x.to_array}
238
+ # end
239
+ # def select_statement
240
+ # elements.detect { |e| e.is_a?(SelectStatement) }
241
+ # end
242
+ end
243
+
244
+ class SubQuery < VSqlSyntaxNode
245
+ end
246
+ end
@@ -0,0 +1,25 @@
1
+ # In file parser.rb
2
+ require 'treetop'
3
+ require_relative './vsql_node_extensions.rb'
4
+ require_relative './formatter.rb'
5
+
6
+ VSQLPARSER_BASE_PATH ||= File.expand_path(File.dirname(__FILE__))
7
+
8
+ module VSqlParserHelpers
9
+ def parser
10
+ @parser ||= VSqlParser.new
11
+ end
12
+
13
+ def parse(sql)
14
+ d_sql = sql.downcase
15
+ parser.parse(d_sql).tap do
16
+ d_sql.replace(sql)
17
+ end
18
+ end
19
+ end
20
+
21
+ # Find out what our base path is
22
+ Treetop.load(File.join(VSQLPARSER_BASE_PATH, 'vsql_parser.treetop')) # <- This creates the VSqlParser class
23
+
24
+ VSqlParser.extend(VSqlParserHelpers)
25
+
@@ -0,0 +1,237 @@
1
+ grammar VSql
2
+
3
+ rule query
4
+ space*
5
+ select_statement
6
+ (space from_statement (space join_statement)*
7
+ (space where_statement)?
8
+ (space group_by_statement)?
9
+ (space having_statement)?
10
+ (space window_statement)*
11
+ (space order_by_statement)?
12
+ (space limit_statement)?
13
+ )?
14
+ (space* 'union' space query)?
15
+ (space / ';')*
16
+ <Query>
17
+ end
18
+
19
+ rule select_statement
20
+ 'select' space (distinct_predicate space)? select_expressions <SelectStatement>
21
+ end
22
+
23
+ rule join_keyword
24
+ ('left' / 'outer' / 'inner' / 'right' / 'full' / space)* 'join' <JoinKeyword>
25
+ end
26
+
27
+ rule join_statement
28
+ join_keyword space expression (space alias)? space 'on' space expression <JoinStatement>
29
+ end
30
+
31
+ rule where_statement
32
+ 'where' space expression <WhereStatement>
33
+ end
34
+
35
+ rule having_statement
36
+ 'having' space expression
37
+ end
38
+
39
+ rule window_statement
40
+ 'window' space name_expression space 'as' space window
41
+ end
42
+
43
+ rule group_by_statement
44
+ 'group by' space expression (expression_separator expression)* <Statement>
45
+ end
46
+
47
+ rule order_by_statement
48
+ 'order by' space order_by_expression (expression_separator order_by_expression)* <OrderByStatement>
49
+ end
50
+
51
+ rule limit_statement
52
+ 'limit' space [0-9]+ <LimitStatement>
53
+ end
54
+
55
+ rule select_expressions
56
+ select_expression (expression_separator select_expression)* <Entity>
57
+ end
58
+
59
+ rule expression_separator
60
+ space* ',' space* <Entity>
61
+ end
62
+
63
+ rule order_by_expression
64
+ expression (space ('desc' / 'asc'))? <OrderByExpression>
65
+ end
66
+
67
+ rule select_expression
68
+ expression (space alias)? <SelectExpression>
69
+ end
70
+
71
+ rule alias
72
+ ('as' space)?
73
+ (
74
+ '"' ([^\"]+ <Alias>) '"'
75
+ /
76
+ !(keyword word_boundary) [\w]+ <Alias>
77
+ )
78
+ end
79
+
80
+ rule expression
81
+ prefix_modifier?
82
+ (
83
+ '(' query ')' <Query>
84
+ /
85
+ '(' space? expression space? ')' <Entity>
86
+ /
87
+ sub_expression)
88
+ (space? inline_window)?
89
+ ('::' [\w]+)? # cast
90
+ (space? set_operator space? (set))*
91
+ (space? operator space? expression)? <Expression>
92
+ end
93
+
94
+ rule prefix_modifier
95
+ 'not' space
96
+ /
97
+ '-' space?
98
+ end
99
+
100
+ rule inline_window
101
+ 'over' space (window / name_expression)
102
+ end
103
+
104
+ # poorman window parsing right now... we'll need to beef this up if we use windows with parentheses
105
+ rule window
106
+ '(' [^\)]* ')'
107
+ end
108
+
109
+ rule set
110
+ set_literal
111
+ /
112
+ '(' query ')'
113
+ end
114
+
115
+ rule distinct_predicate
116
+ 'distinct' / 'all'
117
+ end
118
+
119
+ rule set_literal
120
+ '(' space? primitive_literal (space? ',' space? primitive_literal)* space? ')'
121
+ end
122
+
123
+ rule primitive_literal
124
+ interval_literal / numeric_literal / string_literal / date_literal
125
+ end
126
+
127
+ rule interval_literal
128
+ 'interval' space "'" [\w ]+ "'"
129
+ end
130
+
131
+ rule date_literal
132
+ '{d' space+ "'" [^\'\}]+ "'}"
133
+ end
134
+
135
+ rule numeric_literal
136
+ [0-9]+ ("." [0-9]+)?
137
+ end
138
+
139
+ rule sub_expression
140
+ case_statement
141
+ /
142
+ function
143
+ /
144
+ primitive_literal
145
+ /
146
+ field_reference
147
+ end
148
+
149
+ rule set_operator
150
+ 'not in' / 'in' &space
151
+ end
152
+
153
+ rule operator
154
+ [+\-/=\|><!]+
155
+ /
156
+ ('is not' / 'is' / 'like' / 'between' / 'and' / 'or') &space
157
+ end
158
+
159
+ rule case_statement
160
+ 'case'
161
+ (space !('when') expression)?
162
+ (space 'when' space expression space 'then' space expression)*
163
+ (space 'else' space expression)?
164
+ space 'end' <Entity>
165
+
166
+ end
167
+
168
+ rule function
169
+ [\w]+ space* '(' (distinct_predicate space)? (expression / ',' / space)* ')' <Function>
170
+ end
171
+
172
+ rule string_literal
173
+ "'" [^\']+ "'"
174
+ end
175
+
176
+ rule name_expression
177
+ '"' ([^\"]+ <Name>) '"' <NameExpression>
178
+ /
179
+ ([\w]+ <Name>) <NameExpression>
180
+ end
181
+
182
+ rule field_glob
183
+ '*' <FieldGlob>
184
+ end
185
+
186
+ rule field_reference
187
+ (name_expression "." ' '* <TablePart>)? (name_expression / field_glob) <FieldRef>
188
+ end
189
+
190
+ rule from_statement
191
+ 'from' space+ from_expression (expression_separator from_expression)* <FromStatement>
192
+ end
193
+
194
+ rule from_expression
195
+ ( name_expression
196
+ /
197
+ '(' query ')' <SubQuery>) (space alias)? <FromExpression>
198
+ end
199
+
200
+ # matches at least one space. Handles comments, too.
201
+ rule space
202
+ ([\s]+ / ('--' (!"\n" .)+ ))+
203
+ end
204
+
205
+ rule word_boundary
206
+ ![\w]
207
+ end
208
+
209
+ rule keyword
210
+ # 'select' / 'from' / 'inner' / 'outer' / 'full' / 'left' / 'right' / 'join' / 'on' / 'where' / 'group by' / 'order by' / 'having' / 'limit' / 'union'
211
+ (
212
+ 'all' / 'analyse' / 'analyze' / 'and' / 'any' / 'array' / 'asc' / 'as' /
213
+ 'binary' / 'both' /
214
+ 'case' / 'cast' / 'check' / 'column' / 'constraint' / 'correlation' / 'create' / 'current_database' / 'current_date' / 'current_schema' / 'current_timestamp' / 'current_time' / 'current_user' /
215
+ 'default' / 'deferrable' / 'desc' / 'distinct' / 'do' /
216
+ 'else' / 'encoded' / 'end' / 'except' /
217
+ 'false' / 'foreign' / 'for' / 'from' /
218
+ 'grant' / 'grouped' / 'group' /
219
+ 'having' /
220
+ 'initially' / 'intersect' / 'intervalym' / 'interval' / 'into' / 'in' /
221
+ 'join' /
222
+ 'ksafe' /
223
+ 'leading' / 'left' / 'limit' / 'localtimestamp' / 'localtime'
224
+ 'match' /
225
+ 'new' / 'not' / 'nullsequal' / 'null' /
226
+ 'offset' / 'off' / 'old' / 'only' / 'on' / 'order' / 'or' /
227
+ 'pinned' / 'placing' / 'primary' / 'projection' /
228
+ 'references' /
229
+ 'schema' / 'segmented' / 'select' / 'session_user' / 'some' / 'sysdate' /
230
+ 'table' / 'then' / 'timeseries' / 'to' / 'trailing' / 'true' /
231
+ 'unbounded' / 'union' / 'unique' / 'unsegmented' / 'user' / 'using' /
232
+ 'when' / 'where' / 'window' / 'within' / 'with'
233
+ )
234
+ word_boundary
235
+ end
236
+
237
+ end
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vsql_parser
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.2'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Tim Harper
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-09-04 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: treetop
16
+ requirement: &70201796873120 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.4'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70201796873120
25
+ - !ruby/object:Gem::Dependency
26
+ name: ruby-debug19
27
+ requirement: &70201796872740 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70201796872740
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ requirement: &70201796872140 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - =
42
+ - !ruby/object:Gem::Version
43
+ version: 2.10.0
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70201796872140
47
+ - !ruby/object:Gem::Dependency
48
+ name: pry
49
+ requirement: &70201796871700 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70201796871700
58
+ description: Provides treetop grammar for Vertica SQL. (Most likely works with Postgres
59
+ SQL as well)
60
+ email:
61
+ - tim@redbrainlabs.com
62
+ executables: []
63
+ extensions: []
64
+ extra_rdoc_files: []
65
+ files:
66
+ - lib/formatter.rb
67
+ - lib/test_chamber.rb
68
+ - lib/vsql_node_extensions.rb
69
+ - lib/vsql_parser.rb
70
+ - lib/vsql_parser.treetop
71
+ - MIT_LICENSE
72
+ homepage:
73
+ licenses: []
74
+ post_install_message:
75
+ rdoc_options: []
76
+ require_paths:
77
+ - lib
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ none: false
80
+ requirements:
81
+ - - ! '>='
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ! '>='
88
+ - !ruby/object:Gem::Version
89
+ version: 1.3.6
90
+ requirements: []
91
+ rubyforge_project:
92
+ rubygems_version: 1.8.7
93
+ signing_key:
94
+ specification_version: 3
95
+ summary: Vertica SQL Parser
96
+ test_files: []
97
+ has_rdoc: