piggly-nsd 2.3.3

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.
Files changed (96) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +170 -0
  3. data/Rakefile +33 -0
  4. data/bin/piggly +8 -0
  5. data/lib/piggly/command/base.rb +148 -0
  6. data/lib/piggly/command/report.rb +162 -0
  7. data/lib/piggly/command/trace.rb +90 -0
  8. data/lib/piggly/command/untrace.rb +78 -0
  9. data/lib/piggly/command.rb +8 -0
  10. data/lib/piggly/compiler/cache_dir.rb +119 -0
  11. data/lib/piggly/compiler/coverage_report.rb +63 -0
  12. data/lib/piggly/compiler/trace_compiler.rb +117 -0
  13. data/lib/piggly/compiler.rb +7 -0
  14. data/lib/piggly/config.rb +80 -0
  15. data/lib/piggly/dumper/index.rb +121 -0
  16. data/lib/piggly/dumper/qualified_name.rb +36 -0
  17. data/lib/piggly/dumper/qualified_type.rb +141 -0
  18. data/lib/piggly/dumper/reified_procedure.rb +172 -0
  19. data/lib/piggly/dumper/skeleton_procedure.rb +112 -0
  20. data/lib/piggly/dumper.rb +9 -0
  21. data/lib/piggly/installer.rb +137 -0
  22. data/lib/piggly/parser/grammar.tt +748 -0
  23. data/lib/piggly/parser/nodes.rb +378 -0
  24. data/lib/piggly/parser/traversal.rb +50 -0
  25. data/lib/piggly/parser/treetop_ruby19_patch.rb +21 -0
  26. data/lib/piggly/parser.rb +69 -0
  27. data/lib/piggly/profile.rb +108 -0
  28. data/lib/piggly/reporter/base.rb +106 -0
  29. data/lib/piggly/reporter/html_dsl.rb +63 -0
  30. data/lib/piggly/reporter/index.rb +114 -0
  31. data/lib/piggly/reporter/procedure.rb +129 -0
  32. data/lib/piggly/reporter/resources/highlight.js +38 -0
  33. data/lib/piggly/reporter/resources/piggly.css +515 -0
  34. data/lib/piggly/reporter/resources/sortable.js +493 -0
  35. data/lib/piggly/reporter.rb +8 -0
  36. data/lib/piggly/tags.rb +280 -0
  37. data/lib/piggly/task.rb +215 -0
  38. data/lib/piggly/util/blankslate.rb +114 -0
  39. data/lib/piggly/util/cacheable.rb +19 -0
  40. data/lib/piggly/util/enumerable.rb +44 -0
  41. data/lib/piggly/util/file.rb +17 -0
  42. data/lib/piggly/util/process_queue.rb +96 -0
  43. data/lib/piggly/util/thunk.rb +39 -0
  44. data/lib/piggly/util.rb +9 -0
  45. data/lib/piggly/version.rb +15 -0
  46. data/lib/piggly.rb +20 -0
  47. data/spec/examples/compiler/cacheable_spec.rb +190 -0
  48. data/spec/examples/compiler/report_spec.rb +25 -0
  49. data/spec/examples/compiler/trace_spec.rb +123 -0
  50. data/spec/examples/config_spec.rb +63 -0
  51. data/spec/examples/dumper/index_spec.rb +199 -0
  52. data/spec/examples/dumper/procedure_spec.rb +116 -0
  53. data/spec/examples/grammar/expression_spec.rb +302 -0
  54. data/spec/examples/grammar/statements/assignment_spec.rb +70 -0
  55. data/spec/examples/grammar/statements/declaration_spec.rb +21 -0
  56. data/spec/examples/grammar/statements/exception_spec.rb +78 -0
  57. data/spec/examples/grammar/statements/if_spec.rb +191 -0
  58. data/spec/examples/grammar/statements/loop_spec.rb +41 -0
  59. data/spec/examples/grammar/statements/sql_spec.rb +71 -0
  60. data/spec/examples/grammar/tokens/comment_spec.rb +58 -0
  61. data/spec/examples/grammar/tokens/datatype_spec.rb +58 -0
  62. data/spec/examples/grammar/tokens/identifier_spec.rb +74 -0
  63. data/spec/examples/grammar/tokens/keyword_spec.rb +44 -0
  64. data/spec/examples/grammar/tokens/label_spec.rb +40 -0
  65. data/spec/examples/grammar/tokens/literal_spec.rb +30 -0
  66. data/spec/examples/grammar/tokens/lval_spec.rb +50 -0
  67. data/spec/examples/grammar/tokens/number_spec.rb +34 -0
  68. data/spec/examples/grammar/tokens/sqlkeywords_spec.rb +45 -0
  69. data/spec/examples/grammar/tokens/string_spec.rb +54 -0
  70. data/spec/examples/grammar/tokens/whitespace_spec.rb +40 -0
  71. data/spec/examples/installer_spec.rb +59 -0
  72. data/spec/examples/parser/nodes_spec.rb +73 -0
  73. data/spec/examples/parser/traversal_spec.rb +14 -0
  74. data/spec/examples/parser_spec.rb +118 -0
  75. data/spec/examples/profile_spec.rb +153 -0
  76. data/spec/examples/reporter/html/dsl_spec.rb +0 -0
  77. data/spec/examples/reporter/html/index_spec.rb +0 -0
  78. data/spec/examples/reporter/html_spec.rb +1 -0
  79. data/spec/examples/reporter_spec.rb +0 -0
  80. data/spec/examples/tags_spec.rb +285 -0
  81. data/spec/examples/task_spec.rb +0 -0
  82. data/spec/examples/util/cacheable_spec.rb +41 -0
  83. data/spec/examples/util/enumerable_spec.rb +64 -0
  84. data/spec/examples/util/file_spec.rb +40 -0
  85. data/spec/examples/util/process_queue_spec.rb +16 -0
  86. data/spec/examples/util/thunk_spec.rb +59 -0
  87. data/spec/examples/version_spec.rb +0 -0
  88. data/spec/issues/007_spec.rb +25 -0
  89. data/spec/issues/008_spec.rb +73 -0
  90. data/spec/issues/018_spec.rb +25 -0
  91. data/spec/issues/028_spec.rb +48 -0
  92. data/spec/issues/032_spec.rb +98 -0
  93. data/spec/issues/036_spec.rb +41 -0
  94. data/spec/spec_helper.rb +312 -0
  95. data/spec/spec_suite.rb +5 -0
  96. metadata +162 -0
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ module Piggly
4
+
5
+ describe Parser, "statements" do
6
+ include GrammarHelper
7
+
8
+ describe "single variable declarations" do
9
+ it "parse successfully" do
10
+ node = parse(:stmtDeclare, "declare t text;")
11
+ node.count{|e| e.identifier? }.should == 1
12
+ node.count{|e| e.datatype? }.should == 1
13
+ end
14
+
15
+ it "allows an initial assignment" do
16
+ node = parse(:stmtDeclare, "declare a text := 10;")
17
+ end
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,78 @@
1
+ require 'spec_helper'
2
+
3
+ module Piggly
4
+ describe Parser, "control structures" do
5
+ include GrammarHelper
6
+
7
+ describe "exceptions" do
8
+ describe "raise" do
9
+ it "parses successfully" do
10
+ node, rest = parse_some(:statement, "RAISE EXCEPTION 'message';")
11
+ node.should be_statement
12
+ rest.should == ''
13
+ end
14
+
15
+ it "handles exception" do
16
+ node = parse(:statement, "RAISE EXCEPTION 'message';")
17
+ node.count{|e| e.is_a?(Parser::Nodes::Throw) }.should == 1
18
+ node.count{|e| e.is_a?(Parser::Nodes::Raise) }.should == 0
19
+ end
20
+
21
+ it "handles events" do
22
+ %w(WARNING LOG INFO NOTICE DEBUG).each do |event|
23
+ node = parse(:statement, "RAISE #{event} 'message';")
24
+ node.count{|e| e.is_a?(Parser::Nodes::Throw) }.should == 0
25
+ node.count{|e| e.is_a?(Parser::Nodes::Raise) }.should == 1
26
+ end
27
+ end
28
+
29
+ it "doesn't require a message" do
30
+ node = parse(:statement, "RAISE EXCEPTION;")
31
+ node.count{|e| e.is_a?(Parser::Nodes::Throw) }.should == 1
32
+ node.count{|e| e.is_a?(Parser::Nodes::Raise) }.should == 0
33
+ end
34
+
35
+ it "doesn't require a message" do
36
+ %w(WARNING LOG INFO NOTICE DEBUG).each do |event|
37
+ node = parse(:statement, "RAISE #{event};")
38
+ node.count{|e| e.is_a?(Parser::Nodes::Throw) }.should == 0
39
+ node.count{|e| e.is_a?(Parser::Nodes::Raise) }.should == 1
40
+ end
41
+ end
42
+
43
+ it "has default level of EXCEPTION" do
44
+ node = parse(:statement, "RAISE 'message';")
45
+ node.count{|e| e.is_a?(Parser::Nodes::Throw) }.should == 1
46
+ node.count{|e| e.is_a?(Parser::Nodes::Raise) }.should == 0
47
+ end
48
+
49
+ it "doesn't require a level or message" do
50
+ node = parse(:statement, "RAISE;")
51
+ node.count{|e| e.is_a?(Parser::Nodes::Throw) }.should == 1
52
+ node.count{|e| e.is_a?(Parser::Nodes::Raise) }.should == 0
53
+ end
54
+ end
55
+
56
+ describe "catch" do
57
+ before do
58
+ @text = 'BEGIN a := 10; EXCEPTION WHEN cond THEN b := 10; WHEN cond THEN b := 20; END;'
59
+ end
60
+
61
+ it "parses successfully" do
62
+ node, rest = parse_some(:statement, @text)
63
+ node.should be_statement
64
+ rest.should == ''
65
+ end
66
+
67
+ it "has Catch node" do
68
+ node = parse(:statement, @text)
69
+ catches = node.select{|e| e.is_a?(Parser::Nodes::Catch) }
70
+ catches.size.should == 2
71
+
72
+ catches[0].count{|e| e.named?(:cond) and e.expression? }.should == 1
73
+ catches[1].count{|e| e.named?(:cond) and e.expression? }.should == 1
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,191 @@
1
+ require 'spec_helper'
2
+
3
+ module Piggly
4
+
5
+ describe Parser, "control structures" do
6
+ include GrammarHelper
7
+
8
+ describe "if statements" do
9
+ describe "if .. then .. end if" do
10
+ it "must end with a semicolon" do
11
+ expect{ parse(:statement, 'IF cond THEN a := 10; END IF') }.to raise_error(Piggly::Parser::Failure)
12
+ expect{ parse_some(:stmtIf, 'IF cond THEN a := 10; END IF') }.to raise_error(Piggly::Parser::Failure)
13
+ end
14
+
15
+ it "parses successfully" do
16
+ node, rest = parse_some(:statement, 'IF cond THEN a := 10; END IF;')
17
+ node.should be_statement
18
+ rest.should == ''
19
+ end
20
+
21
+ it "does not have an Else node" do
22
+ node = parse(:statement, 'IF cond THEN a := 10; END IF;')
23
+ node.count{|e| e.else? }.should == 0
24
+ node.count{|e| e.named?(:else) and not e.empty? }.should == 0
25
+ end
26
+
27
+ it "has a 'cond' Expression" do
28
+ node = parse(:statement, 'IF cond THEN a := 10; END IF;')
29
+ node.count{|e| e.named?(:cond) }.should == 1
30
+ node.find{|e| e.named?(:cond) }.should be_expression
31
+ end
32
+
33
+ it "can have missing body" do
34
+ node = parse(:statement, 'IF cond THEN END IF;')
35
+ node.should be_statement
36
+ node.count{|e| e.if? }.should == 1
37
+ node.count{|e| e.named?(:cond) }.should == 1
38
+ end
39
+
40
+ it "can have comment body" do
41
+ node = parse(:statement, 'IF cond THEN /* removed */ END IF;')
42
+ node.should be_statement
43
+ node.count{|e| e.if? }.should == 1
44
+ node.count{|e| e.comment? }.should == 1
45
+ node.find{|e| e.comment? }.source_text.should == '/* removed */'
46
+ end
47
+
48
+ it "can have single statement body" do
49
+ node = parse(:statement, 'IF cond THEN a := 10; END IF;')
50
+ node.count{|e| e.if? }.should == 1
51
+ node.count{|e| e.assignment? }.should == 1
52
+ end
53
+
54
+ it "can have multiple statement body" do
55
+ node = parse(:statement, 'IF cond THEN a := 10; b := 10; END IF;')
56
+ node.count{|e| e.if? }.should == 1
57
+ node.count{|e| e.assignment? }.should == 2
58
+ end
59
+
60
+ it "can contain comments" do
61
+ node = parse(:statement, "IF cond /* comment */ THEN -- foo\n NULL; /* foo */ END IF;")
62
+ node.should be_statement
63
+ node.count{|e| e.comment? }.should == 3
64
+ end
65
+ end
66
+
67
+ describe "if .. then .. else .. end if" do
68
+ it "parses successfully" do
69
+ node, rest = parse_some(:statement, 'IF cond THEN a := 10; ELSE a := 20; END IF;')
70
+ node.should be_statement
71
+ rest.should == ''
72
+ end
73
+
74
+ it "has an Else node named 'else'" do
75
+ node = parse(:statement, 'IF cond THEN a := 10; ELSE a := 20; END IF;')
76
+ node.count{|e| e.named?(:else) and e.else? }.should == 1
77
+ node.find{|e| e.named?(:else) }.source_text.should == 'ELSE a := 20; '
78
+ end
79
+
80
+ it "can have missing else body" do
81
+ node = parse(:statement, 'IF cond THEN a := 10; ELSE END IF;')
82
+ node.count{|e| e.if? }.should == 1
83
+ node.count{|e| e.assignment? }.should == 1
84
+ end
85
+
86
+ it "can have comment body" do
87
+ node = parse(:statement, 'IF cond THEN a := 10; ELSE /* removed */ END IF;')
88
+ node.count{|e| e.if? }.should == 1
89
+ node.count{|e| e.comment? }.should == 1
90
+ node.count{|e| e.assignment? }.should == 1
91
+ end
92
+
93
+ it "can have single statement body" do
94
+ node = parse(:statement, 'IF cond THEN a := 10; ELSE a := 20; END IF;')
95
+ node.count{|e| e.if? }.should == 1
96
+ node.count{|e| e.assignment? }.should == 2
97
+ end
98
+
99
+ it "can have multiple statement body" do
100
+ node = parse(:statement, 'IF cond THEN a := 10; ELSE a := 20; b := 30; END IF;')
101
+ node.count{|e| e.if? }.should == 1
102
+ node.count{|e| e.assignment? }.should == 3
103
+ end
104
+ end
105
+
106
+ describe "if .. then .. elsif .. then .. end if" do
107
+ it "parses successfully" do
108
+ node, rest = parse_some(:statement, 'IF cond THEN a := 10; ELSIF cond THEN a := 20; END IF;')
109
+ node.should be_statement
110
+ rest.should == ''
111
+ end
112
+
113
+ it "can have comment body" do
114
+ node = parse(:statement, 'IF cond THEN a := 10; ELSIF cond THEN /* removed */ END IF;')
115
+ node.count{|e| e.if? }.should == 2
116
+ node.count{|e| e.comment? }.should == 1
117
+ node.count{|e| e.assignment? }.should == 1
118
+ end
119
+
120
+ it "can having missing body" do
121
+ node = parse(:statement, 'IF cond THEN a := 10; ELSIF cond THEN END IF;')
122
+ node.count{|e| e.if? }.should == 2
123
+ node.count{|e| e.assignment? }.should == 1
124
+ end
125
+
126
+ it "can have single statement body" do
127
+ node = parse(:statement, 'IF cond THEN a := 10; ELSIF cond THEN a := 20; END IF;')
128
+ node.count{|e| e.if? }.should == 2
129
+ node.count{|e| e.assignment? }.should == 2
130
+ end
131
+
132
+ it "can have multiple statement body" do
133
+ node = parse(:statement, 'IF cond THEN a := 10; ELSIF cond THEN a := 20; b := 30; END IF;')
134
+ node.count{|e| e.if? }.should == 2
135
+ node.count{|e| e.assignment? }.should == 3
136
+ end
137
+
138
+ it "can have many elsif branches" do
139
+ node = parse(:statement, <<-SQL.strip)
140
+ IF cond THEN a := 10;
141
+ ELSIF cond THEN a := 20;
142
+ ELSIF cond THEN a := 30;
143
+ ELSIF cond THEN a := 40;
144
+ ELSIF cond THEN a := 50;
145
+ ELSIF cond THEN a := 60;
146
+ END IF;
147
+ SQL
148
+
149
+ node.count{|e| e.named?(:cond) }.should == 6
150
+ node.count{|e| e.if? }.should == 6
151
+ node.count{|e| e.if? and e.named?(:else) }.should == 5
152
+ end
153
+
154
+ it "has no Else nodes" do
155
+ node = parse(:statement, 'IF cond THEN a := 10; ELSIF cond THEN a := 20; END IF;')
156
+ node.count{|e| e.else? }.should == 0
157
+ end
158
+ end
159
+
160
+ describe "if .. then .. elsif .. then .. else .. endif" do
161
+ before do
162
+ @text = 'IF cond THEN a := 10; ELSIF cond THEN a := 20; ELSE a := 30; END IF;'
163
+ end
164
+
165
+ it "parses successfully" do
166
+ node, rest = parse_some(:statement, @text)
167
+ node.should be_statement
168
+ rest.should == ''
169
+ end
170
+
171
+ it "has an If node named 'else'" do
172
+ node = parse(:statement, @text)
173
+ node.count{|e| e.named?(:else) and e.if? }.should == 1
174
+ node.find{|e| e.named?(:else) and e.if? }.source_text.should == 'ELSIF cond THEN a := 20; ELSE a := 30; '
175
+ end
176
+
177
+ it "has an Else node named 'else'" do
178
+ node = parse(:statement, @text)
179
+ node.count{|e| e.named?(:else) and e.else? }.should == 1
180
+ node.find{|e| e.named?(:else) and e.else? }.source_text.should == 'ELSE a := 30; '
181
+ end
182
+
183
+ it "has two If nodes" do
184
+ node = parse(:statement, @text)
185
+ node.count{|e| e.if? }.should == 2
186
+ end
187
+ end
188
+ end
189
+
190
+ end
191
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ module Piggly
4
+ describe Parser, "control structures" do
5
+ include GrammarHelper
6
+
7
+ describe "loops" do
8
+ describe "for loops" do
9
+ it "can loop over integers" do
10
+ node = parse(:stmtForLoop, 'FOR x IN 0 .. 100 LOOP a := x; END LOOP;')
11
+ node.should be_statement
12
+
13
+ cond = node.find{|e| e.named?(:cond) }
14
+ cond.source_text.should == '0 .. 100 '
15
+ cond.should be_expression
16
+ end
17
+
18
+ it "can loop over query results" do
19
+ node = parse(:stmtForLoop, 'FOR x IN SELECT * FROM table LOOP a := x; END LOOP;')
20
+ node.should be_statement
21
+
22
+ cond = node.find{|e| e.named?(:cond) }
23
+ cond.source_text.should == 'SELECT * FROM table '
24
+ cond.should be_sql
25
+ end
26
+ end
27
+
28
+ describe "while loops" do
29
+ end
30
+
31
+ describe "unconditional loops" do
32
+ end
33
+
34
+ describe "continue" do
35
+ end
36
+
37
+ describe "break" do
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,71 @@
1
+ require 'spec_helper'
2
+
3
+ module Piggly
4
+ describe Parser, "statements" do
5
+ include GrammarHelper
6
+
7
+ describe "SQL statements" do
8
+ it "parse successfully" do
9
+ node, rest = parse_some(:statement, 'SELECT id FROM users;')
10
+ node.should be_statement
11
+ node.count{|e| e.sql? }.should == 1
12
+ node.find{|e| e.sql? }.source_text.should == 'SELECT id FROM users;'
13
+ rest.should == ''
14
+ end
15
+
16
+ it "must end with a semicolon" do
17
+ expect{ parse(:statement, 'SELECT id FROM users') }.to raise_error(Piggly::Parser::Failure)
18
+ expect{ parse_some(:statement, 'SELECT id FROM users') }.to raise_error(Piggly::Parser::Failure)
19
+ end
20
+
21
+ it "can contain comments" do
22
+ node = parse(:statement, <<-SQL.strip)
23
+ SELECT INTO user u.id, /* u.name */, p.fist_name, p.last_name
24
+ FROM users u
25
+ INNER JOIN people p ON p.id = u.person_id
26
+ WHERE u.disabled -- can't login
27
+ AND u.id = 100;
28
+ SQL
29
+ sql = node.find{|e| e.sql? }
30
+ sql.count{|e| e.comment? }.should == 2
31
+ end
32
+
33
+ it "can be followed by comments" do
34
+ node, rest = parse_some(:statement, 'SELECT id FROM users; -- comment')
35
+ node.find{|e| e.sql? }.source_text == 'SELECT id FROM users;'
36
+ node.tail.source_text.should == ' -- comment'
37
+ rest.should == ''
38
+ end
39
+
40
+ it "can be followed by whitespace" do
41
+ node, rest = parse_some(:statement, "SELECT id FROM users; \n")
42
+ node.find{|e| e.sql? }.source_text == 'SELECT id FROM users;'
43
+ node.tail.source_text.should == " \n"
44
+ rest.should == ''
45
+ end
46
+
47
+ it "can contain strings" do
48
+ node, rest = parse_some(:statement, <<-SQL.strip)
49
+ SELECT INTO user u.id, u.first_name, u.last_name
50
+ FROM users u
51
+ WHERE first_name ILIKE '%a%'
52
+ OR last_name ILIKE '%b%';
53
+ SQL
54
+ sql = node.find{|e| e.sql? }
55
+ sql.count{|e| e.string? }.should == 2
56
+ end
57
+
58
+ it "can contain strings and comments" do
59
+ node = parse(:statement, <<-SQL.strip)
60
+ a := (SELECT fk, count(*), 'not a statement;'
61
+ FROM dataset
62
+ WHERE id > 100 /* filter out 'reserved' range */
63
+ AND id < 900 -- shouldn't be a string
64
+ OR source_text <> 'alpha /* no comment */;'
65
+ GROUP BY /* pk ; 'abc' */ fk);
66
+ SQL
67
+ end
68
+
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+
3
+ module Piggly
4
+ describe Parser, "tokens" do
5
+ include GrammarHelper
6
+
7
+ describe "comments" do
8
+ it "can begin with -- and terminate at EOF" do
9
+ GrammarHelper::COMMENTS.map{|s| "-- #{s}" }.test_each do |s|
10
+ parse(:tComment, s).should be_comment
11
+ end
12
+ end
13
+
14
+ it "can begin with -- and terminate at line ending" do
15
+ GrammarHelper::COMMENTS.map{|s| "-- #{s}\n" }.test_each do |s|
16
+ parse(:tComment, s).should be_comment
17
+ end
18
+
19
+ GrammarHelper::COMMENTS.map{|s| "-- #{s}\n\n" }.test_each do |s|
20
+ node, rest = parse_some(:tComment, s)
21
+ node.should be_comment
22
+ rest.should == "\n"
23
+ end
24
+
25
+ GrammarHelper::COMMENTS.map{|s| "-- #{s}\nremaining cruft\n" }.test_each do |s|
26
+ node, rest = parse_some(:tComment, s)
27
+ node.should be_comment
28
+ rest.should == "remaining cruft\n"
29
+ end
30
+ end
31
+
32
+ it "can be /* c-style */" do
33
+ GrammarHelper::COMMENTS.map{|s| "/* #{s} */" }.test_each do |s|
34
+ parse(:tComment, s).should be_comment
35
+ end
36
+ end
37
+
38
+ it "terminates after */ marker" do
39
+ GrammarHelper::COMMENTS.map{|s| "/* #{s} */remaining cruft\n" }.test_each do |s|
40
+ node, rest = parse_some(:tComment, s)
41
+ node.should be_comment
42
+ rest.should == "remaining cruft\n"
43
+ end
44
+ end
45
+
46
+ it "cannot be nested" do
47
+ node, rest = parse_some(:tComment, "/* nested /*INLINE*/ comments */")
48
+ node.should be_comment
49
+ rest.should == " comments */"
50
+
51
+ node, rest = parse_some(:tComment, "-- nested -- line comments")
52
+ node.count{|e| e.comment? }.should == 1
53
+ rest.should == ''
54
+ end
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+
3
+ module Piggly
4
+ describe Parser, "tokens" do
5
+ include GrammarHelper
6
+
7
+ describe "data types" do
8
+ it "can consist of a single word" do
9
+ %w[int boolean char varchar text date timestamp record].test_each do |s|
10
+ parse(:tType, s).should be_datatype
11
+ end
12
+ end
13
+
14
+ it "can have parameterized types" do
15
+ ["numeric(10,2)", "decimal(12,4)", "char(1)", "varchar(100)"].test_each do |s|
16
+ parse(:tType, s).should be_datatype
17
+ end
18
+ end
19
+
20
+ it "can end in %ROWTYPE" do
21
+ %w[users%rowtype].test_each do |s|
22
+ parse(:tType, s).should be_datatype
23
+ end
24
+ end
25
+
26
+ it "can have namespace notation" do
27
+ %w[public.users namespace.relation%rowtype].test_each do |s|
28
+ parse(:tType, s).should be_datatype
29
+ end
30
+ end
31
+
32
+ it "can consist of several words" do
33
+ ["timestamp with time zone", "character varying"].test_each do |s|
34
+ parse(:tType, s).should be_datatype
35
+ end
36
+ end
37
+
38
+ it "can specify arrays" do
39
+ ["integer[]", "varchar(10)[]", "numeric(10,2)[]", "timestamp without time zone[]"].test_each do |s|
40
+ parse(:tType, s).should be_datatype
41
+ end
42
+ end
43
+
44
+ it "can specify multi-dimensional" do
45
+ ["integer[][]", "char(1)[][]", "character varying[][]"].test_each do |s|
46
+ parse(:tType, s).should be_datatype
47
+ end
48
+ end
49
+
50
+ it "are terminated by symbol outside of parentheses" do
51
+ node, rest = parse_some(:tType, "character varying, ")
52
+ node.should be_datatype
53
+ rest.should == ', '
54
+ end
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,74 @@
1
+ require 'spec_helper'
2
+
3
+ module Piggly
4
+ describe Parser, "tokens" do
5
+ include GrammarHelper
6
+
7
+ describe "identifiers" do
8
+ it "cannot be a keyword" do
9
+ GrammarHelper::KEYWORDS.test_each do |s|
10
+ expect{ parse(:tIdentifier, s); puts s }.to raise_error(Piggly::Parser::Failure)
11
+ end
12
+ end
13
+
14
+ it "can be quoted keyword" do
15
+ GrammarHelper::KEYWORDS.map{|s| '"' + s + '"' }.test_each do |s|
16
+ parse(:tIdentifier, s).should be_identifier
17
+ end
18
+ end
19
+
20
+ it "can begin with a keyword" do
21
+ GrammarHelper::KEYWORDS.select{|s| s =~ /^[a-z]/i }.map{|s| "#{s}xyz" }.test_each do |s|
22
+ parse(:tIdentifier, s).should be_identifier
23
+ end
24
+
25
+ GrammarHelper::KEYWORDS.select{|s| s =~ /^[a-z]/i }.map{|s| "#{s}_xyz" }.test_each do |s|
26
+ parse(:tIdentifier, s).should be_identifier
27
+ end
28
+ end
29
+
30
+ it "can end with a keyword" do
31
+ GrammarHelper::KEYWORDS.select{|s| s =~ /^[a-z]/i }.map{|s| "xyz#{s}" }.test_each do |s|
32
+ parse(:tIdentifier, s).should be_identifier
33
+ end
34
+
35
+ GrammarHelper::KEYWORDS.select{|s| s =~ /^[a-z]/i }.map{|s| "xyz_#{s}" }.test_each do |s|
36
+ parse(:tIdentifier, s).should be_identifier
37
+ end
38
+ end
39
+
40
+ it "is terminated by an operator" do
41
+ GrammarHelper::KEYWORDS.select{|s| s !~ /^[a-z]/i }.test_each do |op|
42
+ node, rest = parse_some(:tIdentifier, "xyv#{op}")
43
+ node.should be_identifier
44
+ rest.should == op
45
+ end
46
+ end
47
+
48
+ it "is terminated by an operator" do
49
+ GrammarHelper::KEYWORDS.select{|s| s !~ /^[a-z]/i }.test_each do |op|
50
+ node, rest = parse_some(:tIdentifier, "xyv_#{op}")
51
+ node.should be_identifier
52
+ rest.should == op
53
+ end
54
+ end
55
+
56
+ it "can be one single character" do
57
+ %w[_ a b c d e f g h i j k l m n o p q r s t u v w x y z].test_each do |s|
58
+ parse(:tIdentifier, s).should be_identifier
59
+ end
60
+ end
61
+
62
+ it "can contain underscores" do
63
+ %w[_abc abc_ ab_c a_bc ab_cd ab_c_d a_bc_d ab_c_d a_b_c_d a__b__c__d].test_each do |s|
64
+ parse(:tIdentifier, s).should be_identifier
65
+ end
66
+ end
67
+
68
+ it "can contain numbers" do
69
+ parse(:tIdentifier, 'foo9000').should be_identifier
70
+ end
71
+ end
72
+
73
+ end
74
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ module Piggly
4
+ describe Parser, "tokens" do
5
+ include GrammarHelper
6
+
7
+ describe "keywords" do
8
+ it "parse successfully" do
9
+ GrammarHelper::KEYWORDS.test_each do |k|
10
+ parse(:keyword, k).should be_keyword
11
+ end
12
+ end
13
+
14
+ it "cannot have trailing characters" do
15
+ GrammarHelper::KEYWORDS.each do |k|
16
+ expect{ parse(:keyword, "#{k}abc") }.to raise_error(Piggly::Parser::Failure)
17
+ end
18
+ end
19
+
20
+ it "cannot have preceeding characters" do
21
+ GrammarHelper::KEYWORDS.each do |k|
22
+ expect{ parse(:keyword, "#{k}abc") }.to raise_error(Piggly::Parser::Failure)
23
+ end
24
+ end
25
+
26
+ it "are terminated by symbols" do
27
+ GrammarHelper::KEYWORDS.test_each do |k|
28
+ node, rest = parse_some(:keyword, "#{k}+")
29
+ node.should be_keyword
30
+ rest.should == '+'
31
+ end
32
+ end
33
+
34
+ it "are terminated by spaces" do
35
+ GrammarHelper::KEYWORDS.test_each do |k|
36
+ node, rest = parse_some(:keyword, "#{k} ")
37
+ node.should be_keyword
38
+ rest.should == ' '
39
+ end
40
+ end
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ module Piggly
4
+ describe Parser, "tokens" do
5
+ include GrammarHelper
6
+
7
+ describe "labels" do
8
+ it "must be enclosed in << and >>" do
9
+ ['', 'a', 'abc', '<< a', 'a >>'].test_each do |s|
10
+ expect{ parse(:tLabelDefinition, s) }.to raise_error(Piggly::Parser::Failure)
11
+ end
12
+ end
13
+
14
+ it "can have space padding" do
15
+ %w[a abc _].map{|s| "<< #{s} >>" }.test_each do |s|
16
+ parse(:tLabelDefinition, s).should be_label
17
+ end
18
+ end
19
+
20
+ it "can have no space padding" do
21
+ %w[a abc _].map{|s| "<<#{s}>>" }.test_each do |s|
22
+ parse(:tLabelDefinition, s).should be_label
23
+ end
24
+ end
25
+
26
+ it "cannot be multiple unquoted words" do
27
+ ["<< a b >>", "<< ab cd >>"].test_each do |s|
28
+ expect{ parse(:tLabelDefinition, s) }.to raise_error(Piggly::Parser::Failure)
29
+ end
30
+ end
31
+
32
+ it "can be enclosed in double quotes" do
33
+ ['<< "a" >>', '<< "a b" >>', '<< "ab cd" >>'].test_each do |s|
34
+ parse(:tLabelDefinition, s).should be_label
35
+ end
36
+ end
37
+ end
38
+
39
+ end
40
+ end