vsql_parser 0.2

Sign up to get free protection for your applications and to get access to all the features.
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: