piggly 1.2.1 → 2.0.0
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/README.md +163 -0
- data/Rakefile +29 -15
- data/bin/piggly +4 -244
- data/lib/piggly.rb +19 -17
- data/lib/piggly/command.rb +9 -0
- data/lib/piggly/command/base.rb +148 -0
- data/lib/piggly/command/report.rb +162 -0
- data/lib/piggly/command/test.rb +157 -0
- data/lib/piggly/command/trace.rb +90 -0
- data/lib/piggly/command/untrace.rb +78 -0
- data/lib/piggly/compiler.rb +7 -5
- data/lib/piggly/compiler/cache_dir.rb +119 -0
- data/lib/piggly/compiler/coverage_report.rb +63 -0
- data/lib/piggly/compiler/trace_compiler.rb +105 -0
- data/lib/piggly/config.rb +47 -22
- data/lib/piggly/dumper.rb +9 -0
- data/lib/piggly/dumper/index.rb +121 -0
- data/lib/piggly/dumper/qualified_name.rb +36 -0
- data/lib/piggly/dumper/qualified_type.rb +81 -0
- data/lib/piggly/dumper/reified_procedure.rb +142 -0
- data/lib/piggly/dumper/skeleton_procedure.rb +102 -0
- data/lib/piggly/installer.rb +84 -42
- data/lib/piggly/parser.rb +43 -49
- data/lib/piggly/parser/grammar.tt +289 -313
- data/lib/piggly/parser/nodes.rb +270 -211
- data/lib/piggly/parser/traversal.rb +35 -33
- data/lib/piggly/parser/treetop_ruby19_patch.rb +1 -1
- data/lib/piggly/profile.rb +81 -60
- data/lib/piggly/reporter.rb +5 -18
- data/lib/piggly/reporter/base.rb +103 -0
- data/lib/piggly/reporter/html_dsl.rb +63 -0
- data/lib/piggly/reporter/index.rb +108 -0
- data/lib/piggly/reporter/procedure.rb +104 -0
- data/lib/piggly/reporter/resources/highlight.js +21 -0
- data/lib/piggly/reporter/{piggly.css → resources/piggly.css} +52 -12
- data/lib/piggly/reporter/{sortable.js → resources/sortable.js} +0 -0
- data/lib/piggly/tags.rb +280 -0
- data/lib/piggly/task.rb +191 -40
- data/lib/piggly/util.rb +8 -27
- data/lib/piggly/util/blankslate.rb +114 -0
- data/lib/piggly/util/cacheable.rb +19 -0
- data/lib/piggly/util/enumerable.rb +44 -0
- data/lib/piggly/util/file.rb +17 -0
- data/lib/piggly/util/process_queue.rb +96 -0
- data/lib/piggly/util/thunk.rb +39 -0
- data/lib/piggly/version.rb +8 -8
- data/spec/examples/compiler/cacheable_spec.rb +190 -0
- data/spec/examples/compiler/report_spec.rb +25 -0
- data/spec/{compiler → examples/compiler}/trace_spec.rb +7 -57
- data/spec/examples/config_spec.rb +61 -0
- data/spec/examples/dumper/index_spec.rb +197 -0
- data/spec/examples/dumper/procedure_spec.rb +116 -0
- data/spec/{grammar → examples/grammar}/expression_spec.rb +60 -60
- data/spec/{grammar → examples/grammar}/statements/assignment_spec.rb +15 -15
- data/spec/examples/grammar/statements/declaration_spec.rb +21 -0
- data/spec/{grammar → examples/grammar}/statements/exception_spec.rb +10 -10
- data/spec/{grammar → examples/grammar}/statements/if_spec.rb +47 -34
- data/spec/{grammar → examples/grammar}/statements/loop_spec.rb +5 -5
- data/spec/{grammar → examples/grammar}/statements/sql_spec.rb +11 -11
- data/spec/{grammar → examples/grammar}/tokens/comment_spec.rb +11 -11
- data/spec/{grammar → examples/grammar}/tokens/datatype_spec.rb +14 -8
- data/spec/{grammar → examples/grammar}/tokens/identifier_spec.rb +26 -10
- data/spec/{grammar → examples/grammar}/tokens/keyword_spec.rb +5 -5
- data/spec/{grammar → examples/grammar}/tokens/label_spec.rb +7 -7
- data/spec/{grammar → examples/grammar}/tokens/literal_spec.rb +1 -1
- data/spec/examples/grammar/tokens/lval_spec.rb +50 -0
- data/spec/{grammar → examples/grammar}/tokens/number_spec.rb +1 -1
- data/spec/{grammar → examples/grammar}/tokens/sqlkeywords_spec.rb +1 -1
- data/spec/{grammar → examples/grammar}/tokens/string_spec.rb +9 -9
- data/spec/{grammar → examples/grammar}/tokens/whitespace_spec.rb +1 -1
- data/spec/examples/installer_spec.rb +59 -0
- data/spec/examples/parser/nodes_spec.rb +73 -0
- data/spec/examples/parser/traversal_spec.rb +14 -0
- data/spec/examples/parser_spec.rb +115 -0
- data/spec/examples/profile_spec.rb +153 -0
- data/spec/{reporter/html_spec.rb → examples/reporter/html/dsl_spec.rb} +0 -0
- data/spec/examples/reporter/html/index_spec.rb +0 -0
- data/spec/examples/reporter/html_spec.rb +1 -0
- data/spec/examples/reporter_spec.rb +0 -0
- data/spec/{compiler → examples}/tags_spec.rb +10 -10
- data/spec/examples/task_spec.rb +0 -0
- data/spec/examples/util/cacheable_spec.rb +41 -0
- data/spec/examples/util/enumerable_spec.rb +64 -0
- data/spec/examples/util/file_spec.rb +40 -0
- data/spec/examples/util/process_queue_spec.rb +16 -0
- data/spec/examples/util/thunk_spec.rb +58 -0
- data/spec/examples/version_spec.rb +0 -0
- data/spec/issues/007_spec.rb +25 -0
- data/spec/issues/008_spec.rb +73 -0
- data/spec/issues/018_spec.rb +25 -0
- data/spec/spec_helper.rb +253 -9
- metadata +136 -93
- data/README.markdown +0 -116
- data/lib/piggly/compiler/cache.rb +0 -151
- data/lib/piggly/compiler/pretty.rb +0 -67
- data/lib/piggly/compiler/queue.rb +0 -46
- data/lib/piggly/compiler/tags.rb +0 -244
- data/lib/piggly/compiler/trace.rb +0 -91
- data/lib/piggly/filecache.rb +0 -40
- data/lib/piggly/parser/parser.rb +0 -11794
- data/lib/piggly/reporter/html.rb +0 -207
- data/spec/compiler/cache_spec.rb +0 -9
- data/spec/compiler/pretty_spec.rb +0 -9
- data/spec/compiler/queue_spec.rb +0 -3
- data/spec/compiler/rewrite_spec.rb +0 -3
- data/spec/config_spec.rb +0 -58
- data/spec/filecache_spec.rb +0 -70
- data/spec/fixtures/snippets.sql +0 -158
- data/spec/grammar/tokens/lval_spec.rb +0 -50
- data/spec/parser_spec.rb +0 -8
- data/spec/profile_spec.rb +0 -5
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Piggly
|
4
|
+
|
5
|
+
describe Config do
|
6
|
+
before do
|
7
|
+
@config = Config.new
|
8
|
+
end
|
9
|
+
|
10
|
+
it "has class accessors and mutators" do
|
11
|
+
@config.should respond_to(:cache_root)
|
12
|
+
@config.should respond_to(:cache_root=)
|
13
|
+
@config.should respond_to(:report_root)
|
14
|
+
@config.should respond_to(:report_root=)
|
15
|
+
@config.should respond_to(:trace_prefix)
|
16
|
+
@config.should respond_to(:trace_prefix=)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "has default values" do
|
20
|
+
@config.cache_root = nil
|
21
|
+
@config.cache_root.should_not be_nil
|
22
|
+
@config.cache_root.should =~ /cache$/
|
23
|
+
|
24
|
+
@config.report_root = nil
|
25
|
+
@config.report_root.should_not be_nil
|
26
|
+
@config.report_root.should =~ /reports$/
|
27
|
+
|
28
|
+
@config.trace_prefix = nil
|
29
|
+
@config.trace_prefix.should_not be_nil
|
30
|
+
@config.trace_prefix.should == 'PIGGLY'
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "path" do
|
34
|
+
it "doesn't reparent absolute paths" do
|
35
|
+
@config.path('/tmp', '/usr/bin/ps').should == '/usr/bin/ps'
|
36
|
+
@config.path('A:/data/tmp', 'C:/USER/tmp').should == 'C:/USER/tmp'
|
37
|
+
@config.path('/tmp/data', '../data.txt').should == '../data.txt'
|
38
|
+
end
|
39
|
+
|
40
|
+
it "reparents relative paths" do
|
41
|
+
@config.path('/tmp', 'note.txt').should == '/tmp/note.txt'
|
42
|
+
end
|
43
|
+
|
44
|
+
it "doesn't require path parameter" do
|
45
|
+
@config.path('/tmp').should == '/tmp'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "mkpath" do
|
50
|
+
it "creates root if doesn't exist" do
|
51
|
+
FileUtils.should_receive(:makedirs).with('x/y').once.and_return(true)
|
52
|
+
@config.mkpath('x/y', 'z')
|
53
|
+
end
|
54
|
+
|
55
|
+
it "throws an error on path components that exist as files" do
|
56
|
+
lambda { @config.mkpath('/etc/passwd/file') }.should raise_error(Errno::EEXIST)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,197 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
module Piggly
|
4
|
+
|
5
|
+
describe Dumper::Index do
|
6
|
+
before do
|
7
|
+
# make sure not to create directories all over the file system during the test
|
8
|
+
Config.stub(:mkpath).and_return{|root, file| File.join(root, file) }
|
9
|
+
|
10
|
+
@config = Config.new
|
11
|
+
@index = Dumper::Index.new(@config)
|
12
|
+
end
|
13
|
+
|
14
|
+
context "when cache file doesn't exist" do
|
15
|
+
it "is empty" do
|
16
|
+
File.should_receive(:exists?).with(@index.path).and_return(false)
|
17
|
+
@index.procedures.should be_empty
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context "when cache file exists" do
|
22
|
+
before do
|
23
|
+
File.stub(:exists?).with(@index.path).and_return(true)
|
24
|
+
end
|
25
|
+
|
26
|
+
context "when the cache index file is empty" do
|
27
|
+
it "is empty" do
|
28
|
+
File.should_receive(:read).with(@index.path).and_return([].to_yaml)
|
29
|
+
@index.procedures.should be_empty
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context "when the cache index file has two entries" do
|
34
|
+
before do
|
35
|
+
@first = Dumper::ReifiedProcedure.from_hash \
|
36
|
+
"oid" => "1000",
|
37
|
+
"name" => "iterate",
|
38
|
+
"source" => "FIRST PROCEDURE SOURCE CODE"
|
39
|
+
|
40
|
+
@second = Dumper::ReifiedProcedure.from_hash \
|
41
|
+
"oid" => "2000",
|
42
|
+
"name" => "login",
|
43
|
+
"source" => "SECOND PROCEDURE SOURCE CODE"
|
44
|
+
|
45
|
+
File.stub(:read).with(@first.source_path(@config)).
|
46
|
+
and_return(@first.source(@config))
|
47
|
+
|
48
|
+
File.stub(:read).with(@second.source_path(@config)).
|
49
|
+
and_return(@second.source(@config))
|
50
|
+
|
51
|
+
File.stub(:read).with(@index.path).
|
52
|
+
and_return(YAML.dump([@first, @second]))
|
53
|
+
end
|
54
|
+
|
55
|
+
it "has two procedures" do
|
56
|
+
@index.procedures.should have(2).things
|
57
|
+
end
|
58
|
+
|
59
|
+
it "is indexed by identifier" do
|
60
|
+
@index[@first.identifier].identifier.should == @first.identifier
|
61
|
+
@index[@second.identifier].identifier.should == @second.identifier
|
62
|
+
end
|
63
|
+
|
64
|
+
it "reads each procedure's source_path" do
|
65
|
+
@index[@first.identifier].source(@config).should == @first.source(@config)
|
66
|
+
@index[@second.identifier].source(@config).should == @second.source(@config)
|
67
|
+
end
|
68
|
+
|
69
|
+
context "when the procedures used to be identified using another method" do
|
70
|
+
it "renames each procedure using the current identifier"
|
71
|
+
it "updates the index with the current identified_using"
|
72
|
+
it "writes the updated index to disk"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "update" do
|
78
|
+
it "caches the source of new procedures"
|
79
|
+
it "updates the cached source of updated procedures"
|
80
|
+
it "purges the cached source of outdated procedures"
|
81
|
+
it "writes the cache index to disk"
|
82
|
+
it "does not write procedure source code within the cache index"
|
83
|
+
end
|
84
|
+
|
85
|
+
describe "label" do
|
86
|
+
def q(*ns)
|
87
|
+
Dumper::QualifiedName.new(*ns)
|
88
|
+
end
|
89
|
+
|
90
|
+
before do
|
91
|
+
@procedure = mock(:oid => 1,
|
92
|
+
:name => q("public", "foo"),
|
93
|
+
:type => q("private", "int"),
|
94
|
+
:arg_modes => ["in", "in"],
|
95
|
+
:arg_names => [],
|
96
|
+
:arg_types => [q("private", "int"), q("private", "varchar")])
|
97
|
+
end
|
98
|
+
|
99
|
+
context "when name is unique" do
|
100
|
+
context "and there is only one schema" do
|
101
|
+
before do
|
102
|
+
@index.stub(:procedures =>
|
103
|
+
[ @procedure,
|
104
|
+
mock(:oid => 2,
|
105
|
+
:name => q("public", "bar"),
|
106
|
+
:type => q("private", "int"),
|
107
|
+
:arg_modes => ["in"],
|
108
|
+
:arg_names => [],
|
109
|
+
:arg_types => []) ])
|
110
|
+
end
|
111
|
+
|
112
|
+
it "specifies schema.name" do
|
113
|
+
@index.label(@procedure).should == "foo"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context "and there is more than one schema" do
|
118
|
+
before do
|
119
|
+
@index.stub(:procedures =>
|
120
|
+
[ @procedure,
|
121
|
+
mock(:oid => 2,
|
122
|
+
:name => q("schema", "foo"),
|
123
|
+
:type => q("private", "int"),
|
124
|
+
:arg_modes => ["in"],
|
125
|
+
:arg_names => [],
|
126
|
+
:arg_types => []) ])
|
127
|
+
end
|
128
|
+
|
129
|
+
it "specifies schema.name" do
|
130
|
+
@index.label(@procedure).should == "public.foo"
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
context "when name is not unique" do
|
136
|
+
context "and schema.name is unique" do
|
137
|
+
before do
|
138
|
+
@index.stub(:procedures =>
|
139
|
+
[ @procedure,
|
140
|
+
mock(:oid => 2,
|
141
|
+
:name => q("schema", "foo"),
|
142
|
+
:type => q("private", "int"),
|
143
|
+
:arg_modes => ["in"],
|
144
|
+
:arg_names => [],
|
145
|
+
:arg_types => []) ])
|
146
|
+
end
|
147
|
+
|
148
|
+
it "specifies schema.name" do
|
149
|
+
@index.label(@procedure).should == "public.foo"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
context "and schema.name is not unique" do
|
154
|
+
context "but argument types are unique" do
|
155
|
+
before do
|
156
|
+
@index.stub(:procedures =>
|
157
|
+
[ @procedure,
|
158
|
+
mock(:oid => 2,
|
159
|
+
:name => q("public", "foo"),
|
160
|
+
:type => q("private", "int"),
|
161
|
+
:arg_modes => ["in"],
|
162
|
+
:arg_names => [],
|
163
|
+
:arg_types => []) ])
|
164
|
+
end
|
165
|
+
|
166
|
+
it "specifies schema.name(types)" do
|
167
|
+
@index.label(@procedure).should ==
|
168
|
+
"foo(private.int, private.varchar)"
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
context "and argument types are not unique" do
|
173
|
+
context "but argument modes are unique" do
|
174
|
+
before do
|
175
|
+
@index.stub(:procedures =>
|
176
|
+
[ @procedure,
|
177
|
+
mock(:oid => 2,
|
178
|
+
:name => q("public", "foo"),
|
179
|
+
:type => q("private", "int"),
|
180
|
+
:arg_modes => ["out", "out"],
|
181
|
+
:arg_names => [],
|
182
|
+
:arg_types => [q("private", "int"), q("private", "varchar")]) ])
|
183
|
+
end
|
184
|
+
|
185
|
+
it "specifies schema.name(types and modes)" do
|
186
|
+
@index.label(@procedure).should ==
|
187
|
+
"foo(in private.int, in private.varchar)"
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
end
|
196
|
+
|
197
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Piggly
|
4
|
+
|
5
|
+
describe Dumper::ReifiedProcedure do
|
6
|
+
describe "all" do
|
7
|
+
before do
|
8
|
+
# stub connection
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "from_hash" do
|
13
|
+
it "abbreviates known return types"
|
14
|
+
it "leaves alone unknown argument types"
|
15
|
+
|
16
|
+
it "abbreviates known return types"
|
17
|
+
it "leaves alone unknown argument types"
|
18
|
+
|
19
|
+
it "maps known volatilities"
|
20
|
+
it "leaves alone unknown volatilities"
|
21
|
+
|
22
|
+
it "maps known argument modes"
|
23
|
+
it "leaves alone unknown argument modes"
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "store_source" do
|
27
|
+
context "when source is already instrumented" do
|
28
|
+
it "raises an error"
|
29
|
+
end
|
30
|
+
|
31
|
+
context "when the procedure was identified using the current configuration setting" do
|
32
|
+
it "does not attempt to remove any files"
|
33
|
+
it "writes to the current location"
|
34
|
+
it "has the current identified_using property"
|
35
|
+
end
|
36
|
+
|
37
|
+
context "when the procedure was identified using some other configuration setting" do
|
38
|
+
it "removes any old report files"
|
39
|
+
it "removes any old trace cache files"
|
40
|
+
it "removes the old source cache files"
|
41
|
+
it "writes to the current location"
|
42
|
+
it "updates the identified_using property"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe Dumper::SkeletonProcedure do
|
48
|
+
describe "definition" do
|
49
|
+
it "specifies namespace and function name"
|
50
|
+
it "specifies source code between dollar-quoted string tags"
|
51
|
+
|
52
|
+
context "with argument modes" do
|
53
|
+
it "specifies argument modes"
|
54
|
+
end
|
55
|
+
|
56
|
+
context "without argument modes" do
|
57
|
+
it "doesn't specify argument modes"
|
58
|
+
end
|
59
|
+
|
60
|
+
context "with strict modifier" do
|
61
|
+
it "specifies STRICT token"
|
62
|
+
end
|
63
|
+
|
64
|
+
context "without strict modifier" do
|
65
|
+
it "doesn't specify STRICT token"
|
66
|
+
end
|
67
|
+
|
68
|
+
context "with security definer modifier" do
|
69
|
+
it "specifies SECURITY DEFINER token"
|
70
|
+
end
|
71
|
+
|
72
|
+
context "without security definer modifier" do
|
73
|
+
it "doesn't specify SECURITY DEFINER token"
|
74
|
+
end
|
75
|
+
|
76
|
+
context "with set-returning type" do
|
77
|
+
it "specifies SETOF token"
|
78
|
+
end
|
79
|
+
|
80
|
+
context "without non set-returning type" do
|
81
|
+
it "doesn't specify SETOF token"
|
82
|
+
end
|
83
|
+
|
84
|
+
context "with stable volatility" do
|
85
|
+
it "specifies STABLE token"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "source_path" do
|
90
|
+
it "has a .plpgsql extension"
|
91
|
+
it "is within the Dumper directory"
|
92
|
+
end
|
93
|
+
|
94
|
+
describe "purge_source" do
|
95
|
+
context "when the procedure was identified using the current configuration setting" do
|
96
|
+
it "removes any old report files"
|
97
|
+
it "removes any old trace cache files"
|
98
|
+
it "removes the old source cache files"
|
99
|
+
it "removes the current report files"
|
100
|
+
it "removes the current trace cache files"
|
101
|
+
it "removes the current source cache files"
|
102
|
+
it "doesn't attempt to remove any other files"
|
103
|
+
end
|
104
|
+
|
105
|
+
context "when the procedure was identified using some other configuration setting" do
|
106
|
+
it "removes the current report files"
|
107
|
+
it "removes the current trace cache files"
|
108
|
+
it "removes the current source cache files"
|
109
|
+
it "doesn't attempt to remove any other files"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe "equality operator"
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
module Piggly
|
4
4
|
describe Parser, "expressions" do
|
@@ -15,39 +15,39 @@ module Piggly
|
|
15
15
|
|
16
16
|
it "can be a blank expression" do
|
17
17
|
node, rest = parse_some(:expressionUntilSemiColon, ';')
|
18
|
-
node.should
|
18
|
+
node.should be_expression
|
19
19
|
node.source_text.should == ''
|
20
20
|
rest.should == ';'
|
21
21
|
end
|
22
22
|
|
23
23
|
it "can be a comment" do
|
24
24
|
node, rest = parse_some(:expressionUntilSemiColon, "/* comment */;")
|
25
|
-
node.should
|
26
|
-
node.count{|e| e.
|
25
|
+
node.should be_expression
|
26
|
+
node.count{|e| e.comment? }.should == 1
|
27
27
|
|
28
28
|
node, rest = parse_some(:expressionUntilSemiColon, "-- comment\n;")
|
29
|
-
node.should
|
30
|
-
node.count{|e| e.
|
29
|
+
node.should be_expression
|
30
|
+
node.count{|e| e.comment? }.should == 1
|
31
31
|
end
|
32
32
|
|
33
33
|
it "can be a string" do
|
34
34
|
node, rest = parse_some(:expressionUntilSemiColon, "'string';")
|
35
|
-
node.should
|
36
|
-
node.count{|e| e.
|
35
|
+
node.should be_expression
|
36
|
+
node.count{|e| e.string? }.should == 1
|
37
37
|
|
38
38
|
node, rest = parse_some(:expressionUntilSemiColon, "$$ string $$;")
|
39
|
-
node.should
|
40
|
-
node.count{|e| e.
|
39
|
+
node.should be_expression
|
40
|
+
node.count{|e| e.string? }.should == 1
|
41
41
|
end
|
42
42
|
|
43
43
|
it "can be an arithmetic expression" do
|
44
44
|
node, rest = parse_some(:expressionUntilSemiColon, "10 * (3 + x);")
|
45
|
-
node.should
|
45
|
+
node.should be_expression
|
46
46
|
end
|
47
47
|
|
48
48
|
it "can be an SQL statement" do
|
49
49
|
node, rest = parse_some(:expressionUntilSemiColon, "SELECT id FROM dataset;")
|
50
|
-
node.should
|
50
|
+
node.should be_expression
|
51
51
|
end
|
52
52
|
|
53
53
|
it "can be an expression with comments embedded" do
|
@@ -56,8 +56,8 @@ module Piggly
|
|
56
56
|
FROM "dataset" /* ; */ -- previous comments shouldn't terminate expression
|
57
57
|
WHERE value IS /*NOT*/ NULL;
|
58
58
|
SQL
|
59
|
-
node.should
|
60
|
-
node.count{|e| e.
|
59
|
+
node.should be_expression
|
60
|
+
node.count{|e| e.comment? }.should == 4
|
61
61
|
end
|
62
62
|
|
63
63
|
it "can be an expression with strings and comments embedded" do
|
@@ -68,9 +68,9 @@ module Piggly
|
|
68
68
|
AND length(value) > 10 -- 3. this comment in tail doesn't contain any 'string's
|
69
69
|
/* 4. farewell comment in tail */;
|
70
70
|
SQL
|
71
|
-
node.should
|
72
|
-
node.count{|e| e.
|
73
|
-
node.count{|e| e.
|
71
|
+
node.should be_expression
|
72
|
+
node.count{|e| e.comment? }.should == 4
|
73
|
+
node.count{|e| e.string? }.should == 1
|
74
74
|
end
|
75
75
|
|
76
76
|
it "can be an expression with strings embedded" do
|
@@ -81,19 +81,19 @@ module Piggly
|
|
81
81
|
AND value <> '; this should not terminate expression'
|
82
82
|
AND created_at = '2001-01-01';
|
83
83
|
SQL
|
84
|
-
node.should
|
85
|
-
node.count{|e| e.
|
84
|
+
node.should be_expression
|
85
|
+
node.count{|e| e.string? }.should == 2
|
86
86
|
end
|
87
87
|
|
88
|
-
it "
|
88
|
+
it "combines trailing whitespace into 'tail' node" do
|
89
89
|
node, rest = parse_some(:expressionUntilSemiColon, "a := x + y \t;")
|
90
|
-
node.should
|
90
|
+
node.should be_expression
|
91
91
|
node.tail.source_text.should == " \t"
|
92
92
|
end
|
93
93
|
|
94
|
-
it "
|
94
|
+
it "combines trailing comments into 'tail' node" do
|
95
95
|
node, rest = parse_some(:expressionUntilSemiColon, "a := x + y /* note -- comment */;")
|
96
|
-
node.should
|
96
|
+
node.should be_expression
|
97
97
|
node.tail.source_text.should == ' /* note -- comment */'
|
98
98
|
|
99
99
|
node, rest = parse_some(:expressionUntilSemiColon, <<-SQL)
|
@@ -103,7 +103,7 @@ module Piggly
|
|
103
103
|
AND length(value) > 10 -- 3. this comment in tail doesn't contain any 'string's
|
104
104
|
/* 4. farewell comment in tail */;
|
105
105
|
SQL
|
106
|
-
node.tail.count{|e| e.
|
106
|
+
node.tail.count{|e| e.comment? }.should == 2
|
107
107
|
end
|
108
108
|
end
|
109
109
|
|
@@ -127,22 +127,22 @@ module Piggly
|
|
127
127
|
|
128
128
|
it "can be a string" do
|
129
129
|
node, rest = parse_some(:expressionUntilThen, "'string' THEN")
|
130
|
-
node.should
|
131
|
-
node.count{|e| e.
|
130
|
+
node.should be_expression
|
131
|
+
node.count{|e| e.string? }.should == 1
|
132
132
|
|
133
133
|
node, rest = parse_some(:expressionUntilThen, "$$ string $$ THEN")
|
134
|
-
node.should
|
135
|
-
node.count{|e| e.
|
134
|
+
node.should be_expression
|
135
|
+
node.count{|e| e.string? }.should == 1
|
136
136
|
end
|
137
137
|
|
138
138
|
it "can be an arithmetic expression" do
|
139
139
|
node, rest = parse_some(:expressionUntilThen, "10 * (3 + x) THEN")
|
140
|
-
node.should
|
140
|
+
node.should be_expression
|
141
141
|
end
|
142
142
|
|
143
143
|
it "can be an SQL statement" do
|
144
144
|
node, rest = parse_some(:expressionUntilThen, "SELECT id FROM dataset THEN")
|
145
|
-
node.should
|
145
|
+
node.should be_expression
|
146
146
|
end
|
147
147
|
|
148
148
|
it "can be an expression with comments embedded" do
|
@@ -151,8 +151,8 @@ module Piggly
|
|
151
151
|
FROM "dataset" /* THEN */ -- previous comments shouldn't terminate expression
|
152
152
|
WHERE value IS /*NOT*/ NULL THEN
|
153
153
|
SQL
|
154
|
-
node.should
|
155
|
-
node.count{|e| e.
|
154
|
+
node.should be_expression
|
155
|
+
node.count{|e| e.comment? }.should == 4
|
156
156
|
end
|
157
157
|
|
158
158
|
it "can be an expression with strings and comments embedded" do
|
@@ -163,9 +163,9 @@ module Piggly
|
|
163
163
|
AND length(value) > 10 -- 3. this comment in tail doesn't contain any 'string's
|
164
164
|
/* 4. farewell comment in tail */ THEN
|
165
165
|
SQL
|
166
|
-
node.should
|
167
|
-
node.count{|e| e.
|
168
|
-
node.count{|e| e.
|
166
|
+
node.should be_expression
|
167
|
+
node.count{|e| e.comment? }.should == 4
|
168
|
+
node.count{|e| e.string? }.should == 1
|
169
169
|
end
|
170
170
|
|
171
171
|
it "can be an expression with strings embedded" do
|
@@ -176,19 +176,19 @@ module Piggly
|
|
176
176
|
AND value <> ' THEN this should not terminate expression'
|
177
177
|
AND created_at = '2001-01-01' THEN
|
178
178
|
SQL
|
179
|
-
node.should
|
180
|
-
node.count{|e| e.
|
179
|
+
node.should be_expression
|
180
|
+
node.count{|e| e.string? }.should == 2
|
181
181
|
end
|
182
182
|
|
183
|
-
it "
|
183
|
+
it "combines trailing whitespace into 'tail' node" do
|
184
184
|
node, rest = parse_some(:expressionUntilThen, "a := x + y \tTHEN")
|
185
|
-
node.should
|
185
|
+
node.should be_expression
|
186
186
|
node.tail.source_text.should == " \t"
|
187
187
|
end
|
188
188
|
|
189
|
-
it "
|
189
|
+
it "combines trailing comments into 'tail' node" do
|
190
190
|
node, rest = parse_some(:expressionUntilThen, "a := x + y /* note -- comment */THEN")
|
191
|
-
node.should
|
191
|
+
node.should be_expression
|
192
192
|
node.tail.source_text.should == ' /* note -- comment */'
|
193
193
|
|
194
194
|
node, rest = parse_some(:expressionUntilThen, <<-SQL)
|
@@ -198,7 +198,7 @@ module Piggly
|
|
198
198
|
AND length(value) > 10 -- 3. this comment in tail doesn't contain any 'string's
|
199
199
|
/* 4. farewell comment in tail */THEN
|
200
200
|
SQL
|
201
|
-
node.tail.count{|e| e.
|
201
|
+
node.tail.count{|e| e.comment? }.should == 2
|
202
202
|
end
|
203
203
|
end
|
204
204
|
|
@@ -222,22 +222,22 @@ module Piggly
|
|
222
222
|
|
223
223
|
it "can be a string" do
|
224
224
|
node, rest = parse_some(:expressionUntilLoop, "'string' LOOP")
|
225
|
-
node.should
|
226
|
-
node.count{|e| e.
|
225
|
+
node.should be_expression
|
226
|
+
node.count{|e| e.string? }.should == 1
|
227
227
|
|
228
228
|
node, rest = parse_some(:expressionUntilLoop, "$$ string $$ LOOP")
|
229
|
-
node.should
|
230
|
-
node.count{|e| e.
|
229
|
+
node.should be_expression
|
230
|
+
node.count{|e| e.string? }.should == 1
|
231
231
|
end
|
232
232
|
|
233
233
|
it "can be an arithmetic expression" do
|
234
234
|
node, rest = parse_some(:expressionUntilLoop, "10 * (3 + x) LOOP")
|
235
|
-
node.should
|
235
|
+
node.should be_expression
|
236
236
|
end
|
237
237
|
|
238
238
|
it "can be an SQL statement" do
|
239
239
|
node, rest = parse_some(:expressionUntilLoop, "SELECT id FROM dataset LOOP")
|
240
|
-
node.should
|
240
|
+
node.should be_expression
|
241
241
|
end
|
242
242
|
|
243
243
|
it "can be an expression with comments embedded" do
|
@@ -246,8 +246,8 @@ module Piggly
|
|
246
246
|
FROM "dataset" /* LOOP */ -- previous comments shouldn't terminate expression
|
247
247
|
WHERE value IS /*NOT*/ NULL LOOP
|
248
248
|
SQL
|
249
|
-
node.should
|
250
|
-
node.count{|e| e.
|
249
|
+
node.should be_expression
|
250
|
+
node.count{|e| e.comment? }.should == 4
|
251
251
|
end
|
252
252
|
|
253
253
|
it "can be an expression with strings and comments embedded" do
|
@@ -258,9 +258,9 @@ module Piggly
|
|
258
258
|
AND length(value) > 10 -- 3. this comment in tail doesn't contain any 'string's
|
259
259
|
/* 4. farewell comment in tail */ LOOP
|
260
260
|
SQL
|
261
|
-
node.should
|
262
|
-
node.count{|e| e.
|
263
|
-
node.count{|e| e.
|
261
|
+
node.should be_expression
|
262
|
+
node.count{|e| e.comment? }.should == 4
|
263
|
+
node.count{|e| e.string? }.should == 1
|
264
264
|
end
|
265
265
|
|
266
266
|
it "can be an expression with strings embedded" do
|
@@ -271,19 +271,19 @@ module Piggly
|
|
271
271
|
AND value <> ' LOOP this should not terminate expression'
|
272
272
|
AND created_at = '2001-01-01' LOOP
|
273
273
|
SQL
|
274
|
-
node.should
|
275
|
-
node.count{|e| e.
|
274
|
+
node.should be_expression
|
275
|
+
node.count{|e| e.string? }.should == 2
|
276
276
|
end
|
277
277
|
|
278
|
-
it "
|
278
|
+
it "combines trailing whitespace into 'tail' node" do
|
279
279
|
node, rest = parse_some(:expressionUntilLoop, "a := x + y \tLOOP")
|
280
|
-
node.should
|
280
|
+
node.should be_expression
|
281
281
|
node.tail.source_text.should == " \t"
|
282
282
|
end
|
283
283
|
|
284
|
-
it "
|
284
|
+
it "combines trailing comments into 'tail' node" do
|
285
285
|
node, rest = parse_some(:expressionUntilLoop, "a := x + y /* note -- comment */LOOP")
|
286
|
-
node.should
|
286
|
+
node.should be_expression
|
287
287
|
node.tail.source_text.should == ' /* note -- comment */'
|
288
288
|
|
289
289
|
node, rest = parse_some(:expressionUntilLoop, <<-SQL)
|
@@ -293,7 +293,7 @@ module Piggly
|
|
293
293
|
AND length(value) > 10 -- 3. this comment in tail doesn't contain any 'string's
|
294
294
|
/* 4. farewell comment in tail */LOOP
|
295
295
|
SQL
|
296
|
-
node.tail.count{|e| e.
|
296
|
+
node.tail.count{|e| e.comment? }.should == 2
|
297
297
|
end
|
298
298
|
end
|
299
299
|
|