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,285 @@
1
+ require 'spec_helper'
2
+
3
+ module Piggly
4
+
5
+ describe Tags::AbstractTag do
6
+ end
7
+
8
+ describe Tags::EvaluationTag do
9
+ end
10
+
11
+ describe Tags::BlockTag do
12
+ end
13
+
14
+ describe Tags::UnconditionalBranchTag do
15
+ end
16
+
17
+ describe Tags::ConditionalLoopTag do
18
+ end
19
+
20
+ describe Tags::UnconditionalLoopTag do
21
+ before do
22
+ @tag = Tags::UnconditionalLoopTag.new('for-loop')
23
+ end
24
+
25
+ it "starts with state 00 (0b0000)" do
26
+ # - terminates normally
27
+ # - pass through
28
+ # - iterate only once
29
+ # - iterate more than once
30
+ @tag.state.should == 0b0000
31
+ end
32
+
33
+ it "detects state 01 (0b0001)" do
34
+ # - terminates normally
35
+ # - pass through
36
+ # - iterate only once
37
+ # + iterate more than once
38
+
39
+ # two iterations
40
+ @tag.ping('t')
41
+ @tag.ping('t')
42
+ @tag.ping('f')
43
+
44
+ @tag.state.should == 0b0001
45
+ end
46
+
47
+ it "detects state 02 (0b0010)" do
48
+ # - terminates normally
49
+ # - pass through
50
+ # + iterate only once
51
+ # - iterate more than once
52
+
53
+ # one iteration
54
+ @tag.ping('t')
55
+ @tag.ping('f')
56
+
57
+ @tag.state.should == 0b0010
58
+ end
59
+
60
+ it "detects state 03 (0b0011)" do
61
+ # - terminates normally
62
+ # - pass through
63
+ # + iterate only once
64
+ # + iterate more than once
65
+
66
+ # one iteration
67
+ @tag.ping('t')
68
+ @tag.ping('f')
69
+
70
+ # two iterations
71
+ @tag.ping('t')
72
+ @tag.ping('t')
73
+ @tag.ping('f')
74
+
75
+ @tag.state.should == 0b0011
76
+ end
77
+
78
+ it "detects state 04 (0b0100)" do
79
+ # - terminates normally
80
+ # + pass through
81
+ # - iterate only once
82
+ # - iterate more than once
83
+
84
+ # zero iterations
85
+ @tag.ping('f')
86
+
87
+ @tag.state.should == 0b0100
88
+ end
89
+
90
+ it "detects state 05 (0b0101)" do
91
+ # - terminates normally
92
+ # + pass through
93
+ # - iterate only once
94
+ # + iterate more than once
95
+
96
+ # zero iterations
97
+ @tag.ping('f')
98
+
99
+ # two iterations
100
+ @tag.ping('t')
101
+ @tag.ping('t')
102
+ @tag.ping('f')
103
+
104
+ @tag.state.should == 0b0101
105
+ end
106
+
107
+ it "detects state 06 (0b0110)" do
108
+ # - terminates normally
109
+ # + pass through
110
+ # + iterate only once
111
+ # - iterate more than once
112
+
113
+ # zero iterations
114
+ @tag.ping('f')
115
+
116
+ # one iteration
117
+ @tag.ping('t')
118
+ @tag.ping('f')
119
+
120
+ @tag.state.should == 0b0110
121
+ end
122
+
123
+ it "detects state 07 (0b0111)" do
124
+ # - terminates normally
125
+ # + pass through
126
+ # + iterate only once
127
+ # + iterate more than once
128
+
129
+ # zero iterations
130
+ @tag.ping('f')
131
+
132
+ # one iteration
133
+ @tag.ping('t')
134
+ @tag.ping('f')
135
+
136
+ # two iterations
137
+ @tag.ping('t')
138
+ @tag.ping('t')
139
+ @tag.ping('f')
140
+
141
+ @tag.state.should == 0b0111
142
+ end
143
+
144
+ it "detects state 08 (0b1000)" do
145
+ # + terminates normally
146
+ # - pass through
147
+ # - iterate only once
148
+ # - iterate more than once
149
+
150
+ # TODO invalid
151
+ @tag.ping('@')
152
+
153
+ @tag.state.should == 0b1000
154
+ end
155
+
156
+ it "detects state 09 (0b1001)" do
157
+ # + terminates normally
158
+ # - pass through
159
+ # - iterate only once
160
+ # + iterate more than once
161
+
162
+ # iterate twice
163
+ @tag.ping('t')
164
+ @tag.ping('@')
165
+ @tag.ping('t')
166
+ @tag.ping('@')
167
+ @tag.ping('f')
168
+
169
+ @tag.state.should == 0b1001
170
+ end
171
+
172
+ it "detects state 10 (0b1010)" do
173
+ # + terminates normally
174
+ # - pass through
175
+ # + iterate only once
176
+ # - iterate more than once
177
+
178
+ # iterate once
179
+ @tag.ping('t')
180
+ @tag.ping('@')
181
+ @tag.ping('f')
182
+
183
+ @tag.state.should == 0b1010
184
+ end
185
+
186
+ it "detects state 11 (0b1011)" do
187
+ # + terminates normally
188
+ # - pass through
189
+ # + iterate only once
190
+ # + iterate more than once
191
+
192
+ # iterate once
193
+ @tag.ping('t')
194
+ @tag.ping('@')
195
+ @tag.ping('f')
196
+
197
+ # iterate twice
198
+ @tag.ping('t')
199
+ @tag.ping('@')
200
+ @tag.ping('t')
201
+ @tag.ping('@')
202
+ @tag.ping('f')
203
+
204
+ @tag.state.should == 0b1011
205
+ end
206
+
207
+ it "detects state 12 (0b1100)" do
208
+ # + terminates normally
209
+ # + pass through
210
+ # - iterate only once
211
+ # - iterate more than once
212
+
213
+ # TODO invalid
214
+ @tag.ping('@')
215
+ @tag.ping('f')
216
+
217
+ @tag.state.should == 0b1100
218
+ end
219
+
220
+ it "detects state 13 (0b1101)" do
221
+ # + terminates normally
222
+ # + pass through
223
+ # - iterate only once
224
+ # + iterate more than once
225
+
226
+ # iterate twice
227
+ @tag.ping('t')
228
+ @tag.ping('@')
229
+ @tag.ping('t')
230
+ @tag.ping('@')
231
+ @tag.ping('f')
232
+
233
+ # pass through
234
+ @tag.ping('f')
235
+
236
+ @tag.state.should == 0b1101
237
+ end
238
+
239
+ it "detects state 14 (0b1110)" do
240
+ # + terminates normally
241
+ # + pass through
242
+ # + iterate only once
243
+ # - iterate more than once
244
+
245
+ # pass through
246
+ @tag.ping('f')
247
+
248
+ # iterate once
249
+ @tag.ping('t')
250
+ @tag.ping('@')
251
+ @tag.ping('f')
252
+
253
+ @tag.state.should == 0b1110
254
+ end
255
+
256
+ it "detects state 15 (0b1111)" do
257
+ # + terminates normally
258
+ # + pass through
259
+ # + iterate only once
260
+ # + iterate more than once
261
+
262
+ # pass through
263
+ @tag.ping('f')
264
+
265
+ # iterate once
266
+ @tag.ping('t')
267
+ @tag.ping('@')
268
+ @tag.ping('f')
269
+
270
+ # iterate twice
271
+ @tag.ping('t')
272
+ @tag.ping('@')
273
+ @tag.ping('t')
274
+ @tag.ping('@')
275
+ @tag.ping('f')
276
+
277
+ @tag.state.should == 0b1111
278
+ end
279
+
280
+ end
281
+
282
+ describe Tags::ConditionalBranchTag do
283
+ end
284
+
285
+ end
File without changes
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ module Piggly
4
+
5
+ =begin
6
+ describe Util::Cacheable do
7
+
8
+ class ExampleClass; include Piggly::Util::Cacheable; end
9
+ class ExampleCacheClass; include Piggly::Util::Cacheable; end
10
+ class PigglyExampleClassHTML; include Piggly::Util::Cacheable; end
11
+ class PigglyExampleHTMLClass; include Piggly::Util::Cacheable; end
12
+ class HTMLPiggly; include Piggly::Util::Cacheable; end
13
+ class ExampleRedefined
14
+ include Piggly::Util::Cacheable
15
+ def self.cache_path(file)
16
+ 'redefined'
17
+ end
18
+ end
19
+
20
+ before do
21
+ Config.stub(:cache_root).and_return('/')
22
+ end
23
+
24
+ it "installs class methods" do
25
+ ExampleClass.should respond_to(:cache_path)
26
+ end
27
+
28
+ it "uses class name as cache subdirectory" do
29
+ FileUtils.should_receive(:makedirs).at_least(:once)
30
+
31
+ ExampleClass.cache_path('a.ext').should =~ %r(/Example/a.ext$)
32
+ ExampleCacheClass.cache_path('a.ext').should =~ %r(/ExampleCache/a.ext$)
33
+ PigglyExampleClassHTML.cache_path('a.ext').should =~ %r(/PigglyExampleClassHTML/a.ext$)
34
+ PigglyExampleHTMLClass.cache_path('a.ext').should =~ %r(/PigglyExampleHTML/a.ext$)
35
+ HTMLPiggly.cache_path('a.ext').should =~ %r(/HTML/a.ext$)
36
+ ExampleRedefined.cache_path('a.ext').should == 'redefined'
37
+ end
38
+ end
39
+ =end
40
+
41
+ end
@@ -0,0 +1,64 @@
1
+ require 'spec_helper'
2
+
3
+ module Piggly::Util
4
+
5
+ describe Enumerable do
6
+ before do
7
+ @hash = {:a => '%', :b => '#'}
8
+ @array = %w(a b c d)
9
+ @range = 'w'..'z'
10
+ @empty = []
11
+ end
12
+
13
+ describe "count" do
14
+ it "should default to `size' when no block is given" do
15
+ Enumerable.count(@hash).should == 2
16
+ end
17
+
18
+ it "should count items that satisfied block" do
19
+ Enumerable.count(@hash){ true }.should == @hash.size
20
+ Enumerable.count(@array){ false }.should == 0
21
+ Enumerable.count(@empty){ true }.should == @empty.size
22
+ Enumerable.count(@range){|c| c < 'z' }.should == 3
23
+ end
24
+ end
25
+
26
+ describe "sum" do
27
+ it "should append when no block is given" do
28
+ Enumerable.sum(@range).should == 'wxyz'
29
+ Enumerable.sum(@array).should == 'abcd'
30
+ Enumerable.sum(@empty).should == 0
31
+ end
32
+
33
+ it "should use block return value" do
34
+ Enumerable.sum(@range){ 100 }.should == 400
35
+ Enumerable.sum(@empty){ 100 }.should == 0
36
+ end
37
+ end
38
+
39
+ describe "group_by" do
40
+ it "should return a Hash" do
41
+ Enumerable.group_by(@array){ nil }.should be_a(Hash)
42
+ end
43
+
44
+ it "should collect elements into subcollections" do
45
+ Enumerable.group_by(@array){ :a }.should == { :a => @array }
46
+ Enumerable.group_by(@array){|x| x <= 'b'}.should == { true => %w(a b), false => %w(c d) }
47
+ Enumerable.group_by(@range){|x| x.to_i }.should == { 0 => %w(w x y z) }
48
+ Enumerable.group_by(@empty){ false }.should == {}
49
+ end
50
+ end
51
+
52
+ describe "index_by" do
53
+ it "should return a Hash" do
54
+ Enumerable.index_by(@array){ nil }.should be_a(Hash)
55
+ end
56
+
57
+ it "should collect only one element per group" do
58
+ Enumerable.index_by(@array){ nil }.should == { nil => 'd' }
59
+ Enumerable.index_by(@range){|x| x }.should == { 'w' => 'w', 'x' => 'x', 'y' => 'y', 'z' => 'z' }
60
+ end
61
+ end
62
+ end
63
+
64
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ module Piggly::Util
4
+
5
+ describe File, "cache invalidation" do
6
+ before do
7
+ mtime = Hash['a' => 1, 'b' => 2, 'c' => 3]
8
+ allow(::File).to receive(:mtime) { |f| mtime.fetch(f) }
9
+ allow(::File).to receive(:exist?) { |f| mtime.include?(f) }
10
+ end
11
+
12
+ it "invalidates non-existant cache file" do
13
+ expect(File.stale?('d', 'a')).to eq(true)
14
+ expect(File.stale?('d', 'a', 'b')).to eq(true)
15
+ end
16
+
17
+ it "performs validation using file mtimes" do
18
+ expect(File.stale?('c', 'b')).not_to be_truthy
19
+ expect(File.stale?('c', 'a')).not_to be_truthy
20
+ expect(File.stale?('c', 'b', 'a')).not_to be_truthy
21
+ expect(File.stale?('c', 'a', 'b')).not_to be_truthy
22
+
23
+ expect(File.stale?('b', 'a')).not_to be_truthy
24
+ expect(File.stale?('b', 'c')).to be_truthy
25
+ expect(File.stale?('b', 'a', 'c')).to be_truthy
26
+ expect(File.stale?('b', 'c', 'a')).to be_truthy
27
+
28
+ expect(File.stale?('a', 'b')).to be_truthy
29
+ expect(File.stale?('a', 'c')).to be_truthy
30
+ expect(File.stale?('a', 'b', 'c')).to be_truthy
31
+ expect(File.stale?('a', 'c', 'b')).to be_truthy
32
+ end
33
+
34
+ it "assumes sources exist" do
35
+ expect{ File.stale?('a', 'd') }.to raise_error(StandardError)
36
+ expect{ File.stale?('c', 'a', 'x') }.to raise_error(StandardError)
37
+ end
38
+ end
39
+
40
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ module Piggly
4
+
5
+ describe Util::ProcessQueue do
6
+ context "when empty" do
7
+ end
8
+
9
+ context "when less than @max items pending" do
10
+ end
11
+
12
+ context "when more than @max items pending" do
13
+ end
14
+ end
15
+
16
+ end
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+
3
+ module Piggly
4
+
5
+ describe Util::Thunk do
6
+
7
+ context "not already evaluated" do
8
+ before do
9
+ @work = double('computation')
10
+ @thunk = Util::Thunk.new { @work.evaluate }
11
+ end
12
+
13
+ it "responds to thunk? without evaluating" do
14
+ expect(@work).not_to receive(:evaluate)
15
+ expect(@thunk.thunk?).to be_truthy
16
+ end
17
+
18
+ it "evaluates when force! is explicitly called" do
19
+ expect(@work).to receive(:evaluate).and_return(@work)
20
+ expect(@thunk.force!).to eq(@work)
21
+ end
22
+
23
+ it "evaluates when some other method is called" do
24
+ expect(@work).to receive(:evaluate).and_return(@work)
25
+ expect(@work).to receive(:something).and_return(@work)
26
+ expect(@thunk.something).to eq(@work)
27
+ end
28
+ end
29
+
30
+ context "previously evaluated" do
31
+ before do
32
+ @work = double('computation')
33
+ allow(@work).to receive(:evaluate).and_return(@work)
34
+
35
+ @thunk = Util::Thunk.new { @work.evaluate }
36
+ @thunk.force!
37
+ end
38
+
39
+ it "responds to thunk? without evaluating" do
40
+ expect(@work).not_to receive(:evaluate)
41
+ expect(@thunk.thunk?).to be_truthy
42
+ end
43
+
44
+ it "should not re-evaluate when force! is called" do
45
+ expect(@work).not_to receive(:evaluate)
46
+ @thunk.force!
47
+ end
48
+
49
+ it "should not re-evaluate when some other method is called" do
50
+ expect(@work).not_to receive(:evaluate)
51
+ expect(@work).to receive(:something).and_return(@work)
52
+ expect(@thunk.something).to eq(@work)
53
+ end
54
+ end
55
+
56
+ end
57
+
58
+ end
59
+
File without changes
@@ -0,0 +1,25 @@
1
+ require "spec_helper"
2
+
3
+ module Piggly
4
+ describe "github issue #7" do
5
+ include GrammarHelper
6
+
7
+ it "can loop over dynamic query results" do
8
+ node = parse(:stmtForLoop, "FOR r IN EXECUTE 'SELECT * FROM pg_user;' LOOP END LOOP;")
9
+ node.should be_statement
10
+
11
+ cond = node.find{|e| e.named?(:cond) }
12
+ cond.source_text.should == "EXECUTE 'SELECT * FROM pg_user;' "
13
+ cond.should be_sql
14
+ end
15
+
16
+ it "can loop over dynamic query results when query contains the word 'LOOP'" do
17
+ node = parse(:stmtForLoop, "FOR r IN EXECUTE 'SELECT * FROM pg_user.LOOP;' LOOP END LOOP;")
18
+ node.should be_statement
19
+
20
+ cond = node.find{|e| e.named?(:cond) }
21
+ cond.source_text.should == "EXECUTE 'SELECT * FROM pg_user.LOOP;' "
22
+ cond.should be_sql
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,73 @@
1
+ require "spec_helper"
2
+
3
+ module Piggly
4
+
5
+ describe "github issue #8" do
6
+ include GrammarHelper
7
+
8
+ context "with declare" do
9
+ it "doesn't require a space before the := symbol" do
10
+ node, rest = parse_some(:stmtDeclare, "declare a text:= 10; begin")
11
+ # node.count{|e| e.assignment? }.should == 1
12
+ rest.should == "begin"
13
+ end
14
+
15
+ it "doesn't require a space after the := symbol" do
16
+ node, rest = parse_some(:stmtDeclare, "declare a text :=10;")
17
+ rest.should == ""
18
+ # node.count{|e| e.assignment? }.should == 1
19
+ end
20
+
21
+ it "doesn't require a space after the := symbol" do
22
+ node, rest = parse_some(:stmtDeclare, "declare a text :=10; begin")
23
+ # node.count{|e| e.assignment? }.should == 1
24
+ rest.should == "begin"
25
+ end
26
+
27
+ it "allows escaped strings" do
28
+ node, rest = parse_some(:stmtDeclare, "declare a text :=E'\\001abc'; begin")
29
+ # node.count{|e| e.assignment? }.should == 1
30
+ rest.should == "begin"
31
+ end
32
+
33
+ it "allows escaped octal characters" do
34
+ node, rest = parse_some(:stmtDeclare, "declare a text :=E'\\001abc'; begin")
35
+ # node.count{|e| e.assignment? }.should == 1
36
+ rest.should == "begin"
37
+ end
38
+ end
39
+
40
+ context "without declare" do
41
+ it "doesn't require a space before the := symbol" do
42
+ node, rest = parse_some(:statement, "a:= 10; begin")
43
+ node.count{|e| e.assignment? }.should == 1
44
+ rest.should == "begin"
45
+ end
46
+
47
+ it "doesn't require a space after the := symbol" do
48
+ node = parse(:statement, "a :=10;")
49
+ node.should be_statement
50
+ node.count{|e| e.assignment? }.should == 1
51
+ end
52
+
53
+ it "doesn't require a space after the := symbol" do
54
+ node, rest = parse_some(:statement, "a :=10; begin")
55
+ node.count{|e| e.assignment? }.should == 1
56
+ rest.should == "begin"
57
+ end
58
+
59
+ it "allows escaped strings" do
60
+ node, rest = parse_some(:statement, "a :=E'\\001abc'; begin")
61
+ node.count{|e| e.assignment? }.should == 1
62
+ rest.should == "begin"
63
+ end
64
+
65
+ it "allows escaped octal characters" do
66
+ node, rest = parse_some(:statement, "a :=E'\\001abc'; begin")
67
+ node.count{|e| e.assignment? }.should == 1
68
+ rest.should == "begin"
69
+ end
70
+ end
71
+
72
+ end
73
+ end
@@ -0,0 +1,25 @@
1
+ require "spec_helper"
2
+
3
+ module Piggly
4
+ describe "github issue #18" do
5
+ include GrammarHelper
6
+
7
+ it "can parse the example" do
8
+ body = <<-SQL
9
+ DECLARE
10
+ schema TEXT = 'pg_catalog';
11
+ r RECORD;
12
+ BEGIN
13
+ FOR r IN EXECUTE 'SELECT * FROM ' || quote_ident(schema) || 'pg_user;'
14
+ LOOP
15
+ -- do nothing
16
+ END LOOP;
17
+ END;
18
+ SQL
19
+
20
+ node = parse(:start, body)
21
+ node.count{|e| e.for? }.should == 1
22
+ node.count{|e| e.comment? }.should == 1
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,48 @@
1
+ require "spec_helper"
2
+
3
+ module Piggly
4
+ describe "github issue #28" do
5
+ include GrammarHelper
6
+
7
+ it "can parse a GET STACKED DIAGNOSTICS statement" do
8
+ body = 'GET STACKED DIAGNOSTICS text_var1 = MESSAGE_TEXT, text_var2 = PG_EXCEPTION_DETAIL, text_var3 = PG_EXCEPTION_HINT;'
9
+
10
+ node = parse(:statement, body)
11
+ node.should be_statement
12
+ end
13
+
14
+ it "can parse a procedure with GET STACKED DIAGNOSTICS" do
15
+ body = <<-SQL
16
+ DECLARE
17
+ text_var1 text;
18
+ text_var2 text;
19
+ text_var3 text;
20
+ BEGIN
21
+ RETURN 1/0;
22
+ EXCEPTION WHEN SQLSTATE '22012' THEN
23
+ GET STACKED DIAGNOSTICS text_var1 = MESSAGE_TEXT,
24
+ text_var2 = PG_EXCEPTION_DETAIL,
25
+ text_var3 = PG_EXCEPTION_HINT;
26
+ END
27
+ SQL
28
+
29
+ node = parse(:start, body.strip)
30
+ node.count{|e| e.branch? }.should == 1 # catch
31
+ node.find{|e| e.branch? }.body.source_text.strip.should =~ /^GET.+HINT;/m
32
+ end
33
+
34
+ it "can parse WITH <> AS <> SELECT <> SQL query" do
35
+ body = <<-SQL
36
+ DECLARE
37
+ BEGIN
38
+ WITH n AS (SELECT first_name FROM users where id > 1000)
39
+ SELECT * FROM people WHERE people.first_name = n.first_name;
40
+ RETURN 1;
41
+ END
42
+ SQL
43
+
44
+ node = parse(:start, body.strip.downcase)
45
+ node.count{|e| e.sql? }.should == 1
46
+ end
47
+ end
48
+ end