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.
Files changed (112) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +163 -0
  3. data/Rakefile +29 -15
  4. data/bin/piggly +4 -244
  5. data/lib/piggly.rb +19 -17
  6. data/lib/piggly/command.rb +9 -0
  7. data/lib/piggly/command/base.rb +148 -0
  8. data/lib/piggly/command/report.rb +162 -0
  9. data/lib/piggly/command/test.rb +157 -0
  10. data/lib/piggly/command/trace.rb +90 -0
  11. data/lib/piggly/command/untrace.rb +78 -0
  12. data/lib/piggly/compiler.rb +7 -5
  13. data/lib/piggly/compiler/cache_dir.rb +119 -0
  14. data/lib/piggly/compiler/coverage_report.rb +63 -0
  15. data/lib/piggly/compiler/trace_compiler.rb +105 -0
  16. data/lib/piggly/config.rb +47 -22
  17. data/lib/piggly/dumper.rb +9 -0
  18. data/lib/piggly/dumper/index.rb +121 -0
  19. data/lib/piggly/dumper/qualified_name.rb +36 -0
  20. data/lib/piggly/dumper/qualified_type.rb +81 -0
  21. data/lib/piggly/dumper/reified_procedure.rb +142 -0
  22. data/lib/piggly/dumper/skeleton_procedure.rb +102 -0
  23. data/lib/piggly/installer.rb +84 -42
  24. data/lib/piggly/parser.rb +43 -49
  25. data/lib/piggly/parser/grammar.tt +289 -313
  26. data/lib/piggly/parser/nodes.rb +270 -211
  27. data/lib/piggly/parser/traversal.rb +35 -33
  28. data/lib/piggly/parser/treetop_ruby19_patch.rb +1 -1
  29. data/lib/piggly/profile.rb +81 -60
  30. data/lib/piggly/reporter.rb +5 -18
  31. data/lib/piggly/reporter/base.rb +103 -0
  32. data/lib/piggly/reporter/html_dsl.rb +63 -0
  33. data/lib/piggly/reporter/index.rb +108 -0
  34. data/lib/piggly/reporter/procedure.rb +104 -0
  35. data/lib/piggly/reporter/resources/highlight.js +21 -0
  36. data/lib/piggly/reporter/{piggly.css → resources/piggly.css} +52 -12
  37. data/lib/piggly/reporter/{sortable.js → resources/sortable.js} +0 -0
  38. data/lib/piggly/tags.rb +280 -0
  39. data/lib/piggly/task.rb +191 -40
  40. data/lib/piggly/util.rb +8 -27
  41. data/lib/piggly/util/blankslate.rb +114 -0
  42. data/lib/piggly/util/cacheable.rb +19 -0
  43. data/lib/piggly/util/enumerable.rb +44 -0
  44. data/lib/piggly/util/file.rb +17 -0
  45. data/lib/piggly/util/process_queue.rb +96 -0
  46. data/lib/piggly/util/thunk.rb +39 -0
  47. data/lib/piggly/version.rb +8 -8
  48. data/spec/examples/compiler/cacheable_spec.rb +190 -0
  49. data/spec/examples/compiler/report_spec.rb +25 -0
  50. data/spec/{compiler → examples/compiler}/trace_spec.rb +7 -57
  51. data/spec/examples/config_spec.rb +61 -0
  52. data/spec/examples/dumper/index_spec.rb +197 -0
  53. data/spec/examples/dumper/procedure_spec.rb +116 -0
  54. data/spec/{grammar → examples/grammar}/expression_spec.rb +60 -60
  55. data/spec/{grammar → examples/grammar}/statements/assignment_spec.rb +15 -15
  56. data/spec/examples/grammar/statements/declaration_spec.rb +21 -0
  57. data/spec/{grammar → examples/grammar}/statements/exception_spec.rb +10 -10
  58. data/spec/{grammar → examples/grammar}/statements/if_spec.rb +47 -34
  59. data/spec/{grammar → examples/grammar}/statements/loop_spec.rb +5 -5
  60. data/spec/{grammar → examples/grammar}/statements/sql_spec.rb +11 -11
  61. data/spec/{grammar → examples/grammar}/tokens/comment_spec.rb +11 -11
  62. data/spec/{grammar → examples/grammar}/tokens/datatype_spec.rb +14 -8
  63. data/spec/{grammar → examples/grammar}/tokens/identifier_spec.rb +26 -10
  64. data/spec/{grammar → examples/grammar}/tokens/keyword_spec.rb +5 -5
  65. data/spec/{grammar → examples/grammar}/tokens/label_spec.rb +7 -7
  66. data/spec/{grammar → examples/grammar}/tokens/literal_spec.rb +1 -1
  67. data/spec/examples/grammar/tokens/lval_spec.rb +50 -0
  68. data/spec/{grammar → examples/grammar}/tokens/number_spec.rb +1 -1
  69. data/spec/{grammar → examples/grammar}/tokens/sqlkeywords_spec.rb +1 -1
  70. data/spec/{grammar → examples/grammar}/tokens/string_spec.rb +9 -9
  71. data/spec/{grammar → examples/grammar}/tokens/whitespace_spec.rb +1 -1
  72. data/spec/examples/installer_spec.rb +59 -0
  73. data/spec/examples/parser/nodes_spec.rb +73 -0
  74. data/spec/examples/parser/traversal_spec.rb +14 -0
  75. data/spec/examples/parser_spec.rb +115 -0
  76. data/spec/examples/profile_spec.rb +153 -0
  77. data/spec/{reporter/html_spec.rb → examples/reporter/html/dsl_spec.rb} +0 -0
  78. data/spec/examples/reporter/html/index_spec.rb +0 -0
  79. data/spec/examples/reporter/html_spec.rb +1 -0
  80. data/spec/examples/reporter_spec.rb +0 -0
  81. data/spec/{compiler → examples}/tags_spec.rb +10 -10
  82. data/spec/examples/task_spec.rb +0 -0
  83. data/spec/examples/util/cacheable_spec.rb +41 -0
  84. data/spec/examples/util/enumerable_spec.rb +64 -0
  85. data/spec/examples/util/file_spec.rb +40 -0
  86. data/spec/examples/util/process_queue_spec.rb +16 -0
  87. data/spec/examples/util/thunk_spec.rb +58 -0
  88. data/spec/examples/version_spec.rb +0 -0
  89. data/spec/issues/007_spec.rb +25 -0
  90. data/spec/issues/008_spec.rb +73 -0
  91. data/spec/issues/018_spec.rb +25 -0
  92. data/spec/spec_helper.rb +253 -9
  93. metadata +136 -93
  94. data/README.markdown +0 -116
  95. data/lib/piggly/compiler/cache.rb +0 -151
  96. data/lib/piggly/compiler/pretty.rb +0 -67
  97. data/lib/piggly/compiler/queue.rb +0 -46
  98. data/lib/piggly/compiler/tags.rb +0 -244
  99. data/lib/piggly/compiler/trace.rb +0 -91
  100. data/lib/piggly/filecache.rb +0 -40
  101. data/lib/piggly/parser/parser.rb +0 -11794
  102. data/lib/piggly/reporter/html.rb +0 -207
  103. data/spec/compiler/cache_spec.rb +0 -9
  104. data/spec/compiler/pretty_spec.rb +0 -9
  105. data/spec/compiler/queue_spec.rb +0 -3
  106. data/spec/compiler/rewrite_spec.rb +0 -3
  107. data/spec/config_spec.rb +0 -58
  108. data/spec/filecache_spec.rb +0 -70
  109. data/spec/fixtures/snippets.sql +0 -158
  110. data/spec/grammar/tokens/lval_spec.rb +0 -50
  111. data/spec/parser_spec.rb +0 -8
  112. data/spec/profile_spec.rb +0 -5
@@ -0,0 +1,17 @@
1
+ module Piggly
2
+ module Util
3
+ module File
4
+
5
+ # True if target file is older (by mtime) than any source file
6
+ def self.stale?(target, *sources)
7
+ if ::File.exists?(target)
8
+ oldest = ::File.mtime(target)
9
+ sources.any?{|x| ::File.mtime(x) > oldest }
10
+ else
11
+ true
12
+ end
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,96 @@
1
+ module Piggly
2
+ module Util
3
+
4
+ #
5
+ # Executes blocks in parallel subprocesses
6
+ #
7
+ class ProcessQueue
8
+
9
+ def self.concurrent=(count)
10
+ @concurrent = count
11
+ end
12
+
13
+ def self.concurrent
14
+ @concurrent || 1
15
+ end
16
+
17
+ def initialize(concurrent = self.class.concurrent)
18
+ @concurrent, @items = concurrent, []
19
+ end
20
+
21
+ def concurrent=(value)
22
+ @concurrent = value
23
+ end
24
+
25
+ def size
26
+ @items.size
27
+ end
28
+
29
+ def queue(&block)
30
+ @items << block
31
+ end
32
+
33
+ alias add queue
34
+
35
+ def execute
36
+ # Test if fork is supported
37
+ forkable =
38
+ begin
39
+ Process.wait(Process.fork { exit! 60 })
40
+ raise unless $?.exitstatus.to_i == 60
41
+ true
42
+ rescue Exception
43
+ false
44
+ end
45
+
46
+ if forkable
47
+ concurrently
48
+ else
49
+ serially
50
+ end
51
+ end
52
+
53
+ protected
54
+
55
+ def serially
56
+ $stderr.puts "ProcessQueue running serially"
57
+
58
+ while block = @items.shift
59
+ block.call
60
+ end
61
+ end
62
+
63
+ def concurrently
64
+ $stderr.puts "ProcessQueue running concurrently"
65
+ active = 0
66
+
67
+ # enable enterprise ruby feature
68
+ GC.copy_on_write_friendly = true if GC.respond_to?(:copy_on_write_friendly=)
69
+
70
+ while block = @items.shift
71
+ if active >= @concurrent
72
+ pid = Process.wait
73
+ active -= 1
74
+ end
75
+
76
+ # use exit! to avoid auto-running any test suites
77
+ Process.fork do
78
+ begin
79
+ block.call
80
+ exit! 0
81
+ rescue Exception
82
+ $stderr.puts $!
83
+ $stderr.puts "\t" + $!.backtrace.join("\n\t")
84
+ exit! 1
85
+ end
86
+ end
87
+
88
+ active += 1
89
+ end
90
+
91
+ Process.waitall
92
+ end
93
+
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,39 @@
1
+ module Piggly
2
+ module Util
3
+
4
+ # @todo: Ruby 1.9 BasicObject
5
+ begin
6
+ BlankSlate
7
+ rescue NameError
8
+ require "piggly/util/blankslate"
9
+ end
10
+
11
+ #
12
+ # Wraps a computation and delays its evaluation until
13
+ # a message is sent to it. Computation can be forced by
14
+ # calling `force!`
15
+ #
16
+ class Thunk < BlankSlate
17
+ def initialize(&block)
18
+ @block = block
19
+ end
20
+
21
+ def force!
22
+ unless @block.nil?
23
+ @value = @block.call
24
+ @block = nil
25
+ end
26
+
27
+ @value
28
+ end
29
+
30
+ def thunk?
31
+ true
32
+ end
33
+
34
+ def method_missing(name, *args, &block)
35
+ force!.send(name, *args, &block)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -1,15 +1,15 @@
1
1
  module Piggly
2
2
  module VERSION
3
- MAJOR = 1
4
- MINOR = 2
5
- TINY = 1
3
+ MAJOR = 2
4
+ MINOR = 0
5
+ TINY = 0
6
6
 
7
- STRING = [MAJOR, MINOR, TINY].join('.')
8
-
9
- RELEASE_DATE = '2010-04-22'
7
+ RELEASE_DATE = "2016-05-03"
8
+ end
10
9
 
11
- def self.to_s
12
- STRING
10
+ class << VERSION
11
+ def to_s
12
+ [VERSION::MAJOR, VERSION::MINOR, VERSION::TINY].join(".")
13
13
  end
14
14
  end
15
15
  end
@@ -0,0 +1,190 @@
1
+ require 'spec_helper'
2
+
3
+ module Piggly
4
+
5
+ =begin
6
+ describe Util::Cacheable do
7
+ before do
8
+ @compiler = Class.new { include Piggly::Util::Cacheable }
9
+ @compiler.stub(:name).and_return('TestCompiler')
10
+ end
11
+
12
+ describe "stale?" do
13
+ it "compares cache_path with source path and cache_sources" do
14
+ @compiler.stub(:cache_sources).
15
+ and_return(%w(parser.rb grammar.tt nodes.rb))
16
+
17
+ @compiler.should_receive(:cache_path).
18
+ with('source.sql').
19
+ and_return('source.cache')
20
+
21
+ Util::File.should_receive(:stale?).
22
+ with('source.cache', 'source.sql', 'parser.rb', 'grammar.tt', 'nodes.rb')
23
+
24
+ @compiler.stale?('source.sql')
25
+ end
26
+ end
27
+
28
+ describe "cache" do
29
+ before do
30
+ @procedure = mock('procedure')
31
+ @procedure.stub(:source_path).and_return('source path')
32
+ @procedure.stub(:source).and_return('SOURCE CODE')
33
+ @procedure.stub(:name).and_return('f')
34
+ end
35
+
36
+ context "when cache is stale" do
37
+ before do
38
+ @compiler.should_receive(:stale?).
39
+ and_return(true)
40
+
41
+ File.should_receive(:read).
42
+ with(@procedure.source_path).
43
+ and_return(@procedure.source)
44
+ end
45
+
46
+ it "parses the procedure source" do
47
+ @compiler.stub(:compile).
48
+ and_return(mock('result').as_null_object)
49
+ Compiler::Cacheable::CacheDirectory.stub(:lookup).
50
+ and_return(mock('cache').as_null_object)
51
+
52
+ Parser.should_receive(:parse).
53
+ with(@procedure.source)
54
+
55
+ @compiler.cache(@procedure)
56
+ end
57
+
58
+ it "passes the parse tree and transient arguments to the compiler" do
59
+ tree = mock('parse tree').as_null_object
60
+ args = %w(a b c)
61
+ block = lambda{|a,b| b }
62
+
63
+ Parser.stub(:parse).and_return(tree)
64
+ Compiler::Cacheable::CacheDirectory.stub(:lookup).
65
+ and_return(mock('cache').as_null_object)
66
+
67
+ # calling cache method below should pass the parse tree plus any
68
+ # arguments given to cache along to the abstract 'compile' method
69
+ @compiler.should_receive(:compile).
70
+ with(tree, *args.push(block)).
71
+ and_return(mock('result').as_null_object)
72
+
73
+ @compiler.cache(@procedure, *args, &block)
74
+ end
75
+
76
+ it "updates the cache with the results from the compiler" do
77
+ cache = mock('cache')
78
+ result = mock('result')
79
+
80
+ Parser.stub(:parse).
81
+ and_return(mock('parse tree').as_null_object)
82
+ @compiler.should_receive(:compile).
83
+ # with parse tree
84
+ and_return(result)
85
+
86
+ Compiler::Cacheable::CacheDirectory.should_receive(:lookup).
87
+ and_return(cache)
88
+ cache.should_receive(:replace).
89
+ with(result)
90
+
91
+ @compiler.cache(@procedure)
92
+ end
93
+
94
+ it "returns the cache object" do
95
+ Parser.stub(:parse).
96
+ and_return(mock('parse tree').as_null_object)
97
+ @compiler.should_receive(:compile).
98
+ and_return(mock('result'))
99
+
100
+ cache = mock('cache')
101
+ cache.stub(:replace)
102
+
103
+ Compiler::Cacheable::CacheDirectory.should_receive(:lookup).
104
+ and_return(cache)
105
+
106
+ @compiler.cache(@procedure).should == cache
107
+ end
108
+ end
109
+
110
+ context "when cache is fresh" do
111
+ before do
112
+ @compiler.should_receive(:stale?).
113
+ and_return(false)
114
+ end
115
+
116
+ it "returns the cached results from disk" do
117
+ cache = mock('cache')
118
+
119
+ Compiler::Cacheable::CacheDirectory.should_receive(:lookup).
120
+ and_return(cache)
121
+
122
+ @compiler.cache(@procedure).should == cache
123
+ end
124
+ end
125
+ end
126
+ end
127
+
128
+ describe Compiler::Cacheable::CacheDirectory do
129
+ before do
130
+ @cache = Compiler::Cacheable::CacheDirectory.new('directory-path')
131
+ end
132
+
133
+ describe "[]=" do
134
+ it "stores the new entry" do
135
+ @cache.stub(:write)
136
+ @cache[:foo] = 'data'
137
+ @cache[:foo].should == 'data'
138
+ @cache['foo'].should == 'data'
139
+ end
140
+
141
+ it "writes through to disk" do
142
+ @cache.should_receive(:write).
143
+ with('foo' => 'data')
144
+ @cache['foo'] = 'data'
145
+ end
146
+ end
147
+
148
+ describe "update" do
149
+ it "stores new entries" do
150
+ @cache.stub(:write)
151
+ @cache.update(:abc => 'abacus', :xyz => 'xylophone')
152
+ @cache[:abc].should == 'abacus'
153
+ @cache[:xyz].should == 'xylophone'
154
+ @cache['abc'].should == 'abacus'
155
+ @cache['xyz'].should == 'xylophone'
156
+ end
157
+
158
+ it "stores updated entries"
159
+ it "writes through to disk"
160
+ end
161
+
162
+ describe "replace" do
163
+ it "stores new entries"
164
+ it "stores updated entries"
165
+ it "removes previous entries"
166
+ it "writes through to disk"
167
+ end
168
+
169
+ describe "clear" do
170
+ it "removes all entries"
171
+ it "writes through to disk"
172
+ end
173
+
174
+ describe "[]" do
175
+ context "when entry is not already in memory" do
176
+ it "reads the entry from disk"
177
+ it "stores the entry in memory"
178
+ it "returns the associated value"
179
+ end
180
+
181
+ context "when entry is already in memory" do
182
+ it "does not read the entry from disk"
183
+ it "returns the associated value"
184
+ end
185
+ end
186
+
187
+ end
188
+ =end
189
+
190
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ module Piggly
4
+
5
+ describe Compiler::CoverageReport do
6
+ describe "compile" do
7
+ context "when trace cache is stale" do
8
+ it "does not request the trace compiler output"
9
+ it "returns nil"
10
+ end
11
+
12
+ context "when trace cache is fresh" do
13
+ it "recurses the children of non-terminal node"
14
+ it "does not recurse terminal nodes"
15
+
16
+ it "marks tagged terminal nodes"
17
+ it "does not mark untagged terminal nodes"
18
+
19
+ it "marks tagged non-terminal nodes"
20
+ it "does not mark untagged non-terminal nodes"
21
+ end
22
+ end
23
+ end
24
+
25
+ end
@@ -1,63 +1,13 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
1
+ require 'spec_helper'
2
2
  require 'ostruct'
3
3
 
4
4
  module Piggly
5
5
 
6
- # MockSyntaxNode
7
- class N < OpenStruct
8
- def self.terminal(value)
9
- new :value => value,
10
- :terminal? => true
11
- end
12
-
13
- def self.space
14
- terminal(' ')
15
- end
16
-
17
- def self.node(*children)
18
- new :elements => children
19
- end
20
-
21
- class Branch < N
22
- def elements
23
- children[0..-3] + [stubNode] + children[-2..-1]
24
- end
25
- end
26
-
27
- def self.branch(*children)
28
- raise ArgumentError unless children.size > 2
29
- Branch.new(:body => children[-2],
30
- :stubNode => terminal(''),
31
- :children => children)
32
- end
33
-
34
- def initialize(hash)
35
- super({:terminal? => false}.update(hash))
36
- end
37
-
38
- def trace?
39
- respond_to?(:stubNode)
40
- end
41
-
42
- def interval(start=0)
43
- @start ||= start
44
- @stop ||= if terminal?
45
- @start + value.size
46
- else
47
- # recursively compute intervals
48
- elements.inject(@start) do |prev, e|
49
- e.interval(prev).end
50
- end
51
- end
52
- @start...@stop
53
- end
54
- end
55
-
56
6
  =begin
57
- describe TraceCompiler, "with terminal root node" do
7
+ describe Compiler::Trace, "with terminal root node" do
58
8
  before do
59
9
  @tree = N.terminal('code')
60
- @compiler = TraceCompiler.new('file.sql')
10
+ @compiler = Compiler::Trace.new('file.sql')
61
11
  end
62
12
 
63
13
  it "compiles to original terminal" do
@@ -74,7 +24,7 @@ describe TraceCompiler, "with terminal root node" do
74
24
  end
75
25
  end
76
26
 
77
- describe TraceCompiler, "with regular root node" do
27
+ describe Compiler::Trace, "with regular root node" do
78
28
  before do
79
29
  @tree = N.node N.terminal('statement'),
80
30
  N.terminal('statement'),
@@ -82,7 +32,7 @@ describe TraceCompiler, "with regular root node" do
82
32
  N.terminal('statement')),
83
33
  N.terminal('statement'),
84
34
  N.terminal('statement')
85
- @compiler = TraceCompiler.new('file.sql')
35
+ @compiler = Compiler::Trace.new('file.sql')
86
36
  end
87
37
 
88
38
  it "compiles" do
@@ -100,7 +50,7 @@ describe TraceCompiler, "with regular root node" do
100
50
  end
101
51
  end
102
52
 
103
- describe TraceCompiler, "root node contains branches" do
53
+ describe Compiler::Trace, "root node contains branches" do
104
54
  before do
105
55
  @tree = N.node N.node(N.terminal('statement-1;'), N.space),
106
56
  N.branch(N.node(N.terminal('if-1'), N.space),
@@ -115,7 +65,7 @@ describe TraceCompiler, "root node contains branches" do
115
65
  N.node(N.terminal('consequence'), N.space),
116
66
  N.terminal('end if;'))
117
67
  @tree.interval # force computation
118
- @compiler = TraceCompiler.new('file.sql')
68
+ @compiler = Compiler::Trace.new('file.sql')
119
69
  end
120
70
 
121
71
  it "flattens" do