piggly 1.2.1 → 2.0.0

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