bahuvrihi-tap 0.10.7 → 0.10.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. data/MIT-LICENSE +0 -2
  2. data/README +20 -31
  3. data/bin/rap +18 -8
  4. data/cgi/run.rb +47 -37
  5. data/cmd/console.rb +1 -1
  6. data/cmd/destroy.rb +3 -3
  7. data/cmd/generate.rb +3 -3
  8. data/cmd/manifest.rb +61 -53
  9. data/cmd/run.rb +1 -1
  10. data/doc/Class Reference +119 -110
  11. data/doc/Command Reference +76 -123
  12. data/doc/Syntax Reference +290 -0
  13. data/doc/Tutorial +307 -237
  14. data/lib/tap.rb +1 -12
  15. data/lib/tap/app.rb +46 -71
  16. data/lib/tap/constants.rb +1 -1
  17. data/lib/tap/declarations.rb +110 -100
  18. data/lib/tap/env.rb +141 -173
  19. data/lib/tap/exe.rb +5 -5
  20. data/lib/tap/file_task.rb +2 -2
  21. data/lib/tap/generator/base.rb +0 -4
  22. data/lib/tap/generator/destroy.rb +8 -12
  23. data/lib/tap/generator/generate.rb +19 -14
  24. data/lib/tap/generator/generators/command/command_generator.rb +1 -1
  25. data/lib/tap/generator/generators/config/config_generator.rb +3 -3
  26. data/lib/tap/generator/generators/file_task/file_task_generator.rb +1 -1
  27. data/lib/tap/generator/generators/generator/generator_generator.rb +27 -0
  28. data/lib/tap/generator/generators/generator/templates/task.erb +27 -0
  29. data/lib/tap/generator/generators/root/root_generator.rb +12 -12
  30. data/lib/tap/generator/generators/root/templates/Rakefile +1 -2
  31. data/lib/tap/generator/generators/root/templates/tapfile +11 -8
  32. data/lib/tap/generator/generators/task/task_generator.rb +1 -3
  33. data/lib/tap/generator/generators/task/templates/test.erb +1 -3
  34. data/lib/tap/root.rb +4 -2
  35. data/lib/tap/support/aggregator.rb +16 -3
  36. data/lib/tap/support/assignments.rb +10 -9
  37. data/lib/tap/support/audit.rb +58 -62
  38. data/lib/tap/support/class_configuration.rb +32 -43
  39. data/lib/tap/support/combinator.rb +7 -7
  40. data/lib/tap/support/configurable.rb +13 -14
  41. data/lib/tap/support/configurable_class.rb +6 -30
  42. data/lib/tap/support/configuration.rb +36 -9
  43. data/lib/tap/support/constant.rb +75 -13
  44. data/lib/tap/support/constant_manifest.rb +115 -0
  45. data/lib/tap/support/dependencies.rb +27 -67
  46. data/lib/tap/support/dependency.rb +44 -0
  47. data/lib/tap/support/executable.rb +78 -109
  48. data/lib/tap/support/executable_queue.rb +1 -1
  49. data/lib/tap/support/gems.rb +6 -0
  50. data/lib/tap/support/gems/rack.rb +197 -84
  51. data/lib/tap/support/instance_configuration.rb +29 -3
  52. data/lib/tap/support/intern.rb +46 -0
  53. data/lib/tap/support/join.rb +67 -11
  54. data/lib/tap/support/joins.rb +2 -0
  55. data/lib/tap/support/joins/fork.rb +1 -0
  56. data/lib/tap/support/joins/merge.rb +3 -1
  57. data/lib/tap/support/joins/sequence.rb +2 -2
  58. data/lib/tap/support/joins/switch.rb +3 -1
  59. data/lib/tap/support/joins/sync_merge.rb +6 -0
  60. data/lib/tap/support/lazy_attributes.rb +16 -1
  61. data/lib/tap/support/lazydoc.rb +21 -21
  62. data/lib/tap/support/lazydoc/comment.rb +59 -55
  63. data/lib/tap/support/lazydoc/definition.rb +36 -0
  64. data/lib/tap/support/lazydoc/document.rb +37 -13
  65. data/lib/tap/support/manifest.rb +120 -131
  66. data/lib/tap/support/minimap.rb +90 -0
  67. data/lib/tap/support/node.rb +4 -6
  68. data/lib/tap/support/parser.rb +63 -6
  69. data/lib/tap/support/schema.rb +11 -2
  70. data/lib/tap/support/shell_utils.rb +3 -5
  71. data/lib/tap/support/string_ext.rb +60 -0
  72. data/lib/tap/support/tdoc.rb +2 -2
  73. data/lib/tap/support/templater.rb +29 -15
  74. data/lib/tap/support/validation.rb +22 -11
  75. data/lib/tap/task.rb +155 -156
  76. data/lib/tap/tasks/load.rb +95 -8
  77. data/lib/tap/test/extensions.rb +2 -1
  78. data/lib/tap/test/script_tester.rb +7 -1
  79. data/template/index.erb +39 -32
  80. metadata +13 -13
  81. data/lib/tap/generator/generators/root/templates/test/tapfile_test.rb +0 -15
  82. data/lib/tap/patches/rake/rake_test_loader.rb +0 -8
  83. data/lib/tap/patches/rake/testtask.rb +0 -57
  84. data/lib/tap/patches/ruby19/backtrace_filter.rb +0 -51
  85. data/lib/tap/patches/ruby19/parsedate.rb +0 -16
  86. data/lib/tap/spec.rb +0 -42
  87. data/lib/tap/spec/adapter.rb +0 -25
  88. data/lib/tap/spec/inheritable_class_test_root.rb +0 -9
  89. data/lib/tap/support/constant_utils.rb +0 -127
  90. data/lib/tap/support/summary.rb +0 -30
@@ -71,7 +71,7 @@ module Tap
71
71
 
72
72
  protected
73
73
 
74
- attr_accessor :queue
74
+ attr_accessor :queue # :nodoc:
75
75
 
76
76
  # Checks if the input method is extended with Executable
77
77
  def check_method(method) # :nodoc:
@@ -2,6 +2,9 @@ require 'rubygems'
2
2
 
3
3
  module Tap
4
4
  module Support
5
+
6
+ # Methods for working with {RubyGems}[http://www.rubygems.org/]
7
+ # and other gems frequently used by Tap.
5
8
  module Gems
6
9
  module_function
7
10
 
@@ -23,6 +26,9 @@ module Tap
23
26
  Gem.loaded_specs[name]
24
27
  end
25
28
 
29
+ # Selects gem specs for which the block returns true. If
30
+ # latest is specified, only the latest version of each
31
+ # gem will be passed to the block.
26
32
  def select_gems(latest=true)
27
33
  index = latest ?
28
34
  Gem.source_index.latest_specs :
@@ -1,81 +1,159 @@
1
1
  require 'rack'
2
- require 'cgi'
3
2
  require 'yaml'
4
3
 
4
+ # in a future release, it looks like this will be changed
5
+ require 'rack/file'
6
+ #require 'rack/mime'
7
+
5
8
  module Tap
6
9
  module Support
7
10
  module Gems
8
11
 
9
- Tap::Env.manifest(:cgis, "cgi") do |search_path|
10
- Dir.glob(File.join(search_path, "**/*.rb")).collect do |path|
11
- ["/" + Tap::Root.relative_filepath(search_path, path), path]
12
+ Tap::Env.manifest(:cgis) do |env|
13
+ entries = []
14
+ env.root.glob(:cgi, "**/*.rb").each do |path|
15
+ env.root.relative_filepath(:cgi, path)
12
16
  end
17
+
18
+ entries = entries.sort_by {|path| File.basename(path) }
19
+ Support::Manifest.intern(entries) {|path| "/" + path }
13
20
  end
14
21
 
22
+ # = UNDER CONSTRUCTION
23
+ # Support for a Tap::Server, built on {Rack}[http://rack.rubyforge.org/].
24
+ #
25
+ # Tap::Support::Gems::Rack is intended to extend a Tap::Env
15
26
  module Rack
16
27
 
28
+ # The handler for the server (ex Rack::Handler::WEBrick)
17
29
  attr_accessor :handler
18
30
 
19
- def call(env)
20
- path = env['PATH_INFO']
31
+ # The default error template used by response
32
+ # when an error occurs.
33
+ DEFAULT_ERROR_TEMPLATE = %Q{
34
+ <html>
35
+ <body>
36
+ # Error handling request: <%= error.message %></br>
37
+ # <%= error.backtrace.join("<br/># ") %>
38
+
39
+ <code><pre>
40
+ <%= cgi.to_yaml %>
41
+ <%= rack.to_yaml %>
42
+ </pre></code>
43
+ </body>
44
+ </html>
45
+ }
46
+
47
+ # Creates a [status, headers, body] response using the result of the
48
+ # block as the body. The status and headers the defaults for
49
+ # {Rack::Response}[http://rack.rubyforge.org/doc/classes/Rack/Response.html].
50
+ # If an error occurs, a default error message is generated using the
51
+ # DEFAULT_ERROR_TEMPLATE.
52
+ def response(rack_env)
53
+ ::Rack::Response.new.finish do |res|
54
+ res.write begin
55
+ yield(res)
56
+ rescue
57
+ template(DEFAULT_ERROR_TEMPLATE, env_attrs(rack_env).merge(:error => $!))
58
+ end
59
+ end
60
+ end
61
+
62
+ # The {Rack}[http://rack.rubyforge.org/doc/] interface method. Call
63
+ # routesrequests (with preference) to:
64
+ # * static pages
65
+ # * cgi scripts
66
+ # * default responses
67
+ #
68
+ # === Static pages
69
+ # Static pages may be served from any env in self. A static page is
70
+ # served if a file with the request path exists under the 'public'
71
+ # directory for any env.
72
+ #
73
+ # Envs are searched in order, using the Env#search_path method.
74
+ #
75
+ # === CGI scripts
76
+ # Like static pages, cgi scripts may be served from any env in self.
77
+ # Scripts are discovered using a search of the cgi manifest. See
78
+ # cgi_response for more details.
79
+ #
80
+ # === Default responses
81
+ # The default response is path-dependent:
82
+ #
83
+ # path action
84
+ # /, /index render the manifest.
85
+ # all others render a 404 response
86
+ #
87
+ # The manifest may be refreshed by setting a query string:
88
+ #
89
+ # /?refresh=true
90
+ # /index?refresh=true
91
+ #
92
+ def call(rack_env)
93
+ path = rack_env['PATH_INFO']
21
94
 
22
95
  case
23
- when public_page = known_path(:public, path)
96
+ when static_path = search_path(:public, path) {|file| File.file?(file) }
24
97
  # serve named static pages
25
- response(env) { File.read(public_page) }
98
+ file_response(static_path, rack_env)
99
+
100
+ when cgi_path = search(:cgis, path)
101
+ # serve cgis
102
+ cgi_response(cgi_path, rack_env)
103
+
104
+ # when task_path = search(:tasks, path)
105
+ # # serve tasks
106
+ # cgi_response('task', rack_env)
26
107
 
27
- when cgi_page = search(:cgis, path)
28
- # serve cgis relative to a cgi path
29
- run_cgi(cgi_page, env)
30
-
31
108
  when path == "/" || path == "/index"
32
109
  # serve up the homepage
33
- if env["QUERY_STRING"] == "refresh=true"
34
- reset(:cgis) do |key, path|
35
- Support::Lazydoc[path].resolved = false
36
- end
110
+ if rack_env["QUERY_STRING"] == "refresh=true"
111
+ # reset(:cgis) do |key, path|
112
+ # Support::Lazydoc[path].resolved = false
113
+ # end
37
114
  end
38
- template_response('index', env)
39
-
40
- when config[:development] && template_page = known_path(:template, path)
41
- response(env) { template(File.read(template_page), env) }
115
+ render_response('index.erb', rack_env)
42
116
 
43
117
  else
44
118
  # handle all other requests as errors
45
- template_response('404', env)
119
+ render_response('404.erb', rack_env)
46
120
 
47
121
  end
48
122
  end
49
123
 
50
- def known_path(dir, path)
51
- each do |env|
52
- directory = env.root.filepath(dir)
53
- file = env.root.filepath(dir, path)
124
+ # Generates a [status, headers, body] response for the specified file.
125
+ # Patterned after {Rack::File#._call}[http://rack.rubyforge.org/doc/classes/Rack/File.html].
126
+ def file_response(path, rack_env)
127
+ response(rack_env) do |res|
128
+ content = File.read(path)
129
+ res.headers.merge!(
130
+ "Last-Modified" => File.mtime(path).httpdate,
131
+ "Content-Type" => ::Rack::File::MIME_TYPES[File.extname(path)] || "text/plain", # Rack::Mime.mime_type(File.extname(path), 'text/plain'),
132
+ "Content-Length" => content.size.to_s)
54
133
 
55
- if file != directory && file.index(directory) == 0 && File.exists?(file)
56
- return file
57
- end
134
+ content
58
135
  end
59
-
60
- nil
61
136
  end
62
137
 
63
- #--
64
- # Runs a cgi and returns an array as demanded by rack.
65
- def run_cgi(cgi_path, env)
138
+ # Generates a [status, headers, body] response for the specified cgi.
139
+ # The cgi will be run with ENV set as specified in rack_env.
140
+ def cgi_response(cgi_path, rack_env)
141
+
142
+ # setup standard ios for capture
66
143
  current_input = $stdin
67
144
  current_output = $stdout
68
145
 
69
- cgi_input = env['rack.input']
146
+ cgi_input = rack_env['rack.input']
70
147
  cgi_output = StringIO.new("")
71
148
 
72
149
  begin
73
150
  $stdin = cgi_input
74
151
  $stdout = cgi_output
152
+
153
+ # run the cgi
154
+ with_ENV(rack_env) { load(cgi_path) }
75
155
 
76
- with_env(env) { load(cgi_path) }
77
-
78
- # collect the headers and body from the cgi output
156
+ # collect the headers and body from the output
79
157
  headers, body = cgi_output.string.split(/\r?\n\r?\n/, 2)
80
158
 
81
159
  raise "missing headers from: #{cgi_path}" if headers == nil
@@ -87,65 +165,81 @@ module Tap
87
165
  hash
88
166
  end
89
167
 
168
+ # generate the response
90
169
  [headers.delete('Status') || 200, headers, body]
170
+
91
171
  rescue(Exception)
92
172
  # when an error occurs, return a standard cgi error with backtrace
93
173
  [500, {'Content-Type' => 'text/plain'}, %Q{#{$!.class}: #{$!.message}\n#{$!.backtrace.join("\n")}}]
174
+
94
175
  ensure
95
176
  $stdin = current_input
96
177
  $stdout = current_output
97
178
  end
98
179
  end
99
-
100
- # Executes block with ENV set to the specified hash. Non-string env variables are not set.
101
- def with_env(env)
102
- current_env = {}
103
- ENV.each_pair {|key, value| current_env[key] = value }
104
-
105
- begin
106
- ENV.clear
107
- env.each_pair {|key, value| ENV[key] = value if value.kind_of?(String)}
108
-
109
- yield
110
- ensure
111
- ENV.clear
112
- current_env.each_pair {|key, value| ENV[key] = value }
113
- end
114
- end
115
-
116
- DEFAULT_ERROR_TEMPLATE = %Q{
117
- <html>
118
- <body>
119
- # Error handling request: <%= error.message %></br>
120
- # <%= error.backtrace.join("<br/># ") %>
121
-
122
- <code><pre>
123
- <%= cgi.to_yaml %>
124
- <%= rack.to_yaml %>
125
- </pre></code>
126
- </body>
127
- </html>
128
- }
129
-
130
- def response(env)
131
- ::Rack::Response.new.finish do |res|
132
- res.write begin
133
- yield(res)
134
- rescue
135
- template(DEFAULT_ERROR_TEMPLATE, env, :error => $!)
180
+
181
+ # def cgi_template(name, attributes={})
182
+ # path = root.filepath(:template, "#{name}.erb")
183
+ # Templater.new( File.read(path), {:server => self}.merge(attributes) ).build
184
+ # end
185
+
186
+ # Generates a [status, headers, body] response using the first existing
187
+ # template matching path (as determined by Env#search_path) and the
188
+ # specified rack_env.
189
+ def render_response(path, rack_env)
190
+ # partition and sort the env variables into
191
+ # cgi and rack variables.
192
+ rack, cgi = rack_env.to_a.partition do |(key, value)|
193
+ key =~ /^rack/
194
+ end.collect do |part|
195
+ part.sort_by do |key, value|
196
+ key
197
+ end.inject({}) do |hash, (key,value)|
198
+ hash[key] = value
199
+ hash
136
200
  end
137
201
  end
202
+
203
+ response(rack_env) do
204
+ render(path, env_attrs(rack_env))
205
+ end
138
206
  end
139
207
 
140
- def cgi_template(name, attributes={})
141
- path = root.filepath(:template, "#{name}.erb")
142
- Templater.new( File.read(path), {:server => self}.merge(attributes) ).build
208
+ module Render
209
+ def renderer(path)
210
+ template = env.search_path(:template, path) {|file| File.file?(file) }
211
+ raise("no such template: #{path}") if template == nil
212
+ Tap::Support::Templater.new(File.read(template), marshal_dump).extend(Render)
213
+ end
214
+
215
+ def render(path, attrs={})
216
+ renderer(path).build(attrs)
217
+ end
143
218
  end
219
+
220
+ # Builds the specified template using the rack_env and additional
221
+ # attributes. The rack_env is partitioned into rack-related and
222
+ # cgi-related hashes (all rack_env entries where the key starts
223
+ # with 'rack' are rack-related, the others are cgi-related).
224
+ #
225
+ # The template is built with the following standard locals:
226
+ #
227
+ # server self
228
+ # cgi the cgi-related hash
229
+ # rack the rack-related hash
230
+ #
231
+ # Plus the attributes.
232
+ def render(path, attributes={}) # :nodoc:
233
+ path = search_path(:template, path) {|file| File.file?(file) }
234
+ raise("no such template: #{path}") if path == nil
144
235
 
145
- def template(template, env, attributes={})
236
+ template(File.read(path) , attributes)
237
+ end
238
+
239
+ def env_attrs(rack_env)
146
240
  # partition and sort the env variables into
147
241
  # cgi and rack variables.
148
- rack, cgi = env.to_a.partition do |(key, value)|
242
+ rack, cgi = rack_env.to_a.partition do |(key, value)|
149
243
  key =~ /^rack/
150
244
  end.collect do |part|
151
245
  part.sort_by do |key, value|
@@ -155,14 +249,33 @@ module Tap
155
249
  hash
156
250
  end
157
251
  end
158
-
159
- Templater.new( template , {:server => self, :env => env, :cgi => cgi, :rack => rack}.merge(attributes) ).build
252
+
253
+ {:env => self, :cgi => cgi, :rack => rack}
160
254
  end
161
255
 
162
- def template_response(name, env)
163
- path = known_path(:template, "#{name}.erb")
164
- response(env) { template(File.read(path), env) }
256
+ def template(template, attributes={}) # :nodoc:
257
+ Templater.new(template, attributes).extend(Render).build
165
258
  end
259
+
260
+ protected
261
+
262
+ # Executes block with ENV set to the specified hash.
263
+ # Non-string values in hash are skipped.
264
+ def with_ENV(hash) # :nodoc:
265
+ current_env = {}
266
+ ENV.each_pair {|key, value| current_env[key] = value }
267
+
268
+ begin
269
+ ENV.clear
270
+ hash.each_pair {|key, value| ENV[key] = value if value.kind_of?(String)}
271
+
272
+ yield
273
+ ensure
274
+ ENV.clear
275
+ current_env.each_pair {|key, value| ENV[key] = value }
276
+ end
277
+ end
278
+
166
279
  end
167
280
  end
168
281
  end
@@ -47,11 +47,24 @@ module Tap
47
47
  @class_config = class_config
48
48
  end
49
49
 
50
+ # Updates self to ensure that each class_config key
51
+ # has a value in self; the config.default value is
52
+ # set if a value does not already exist.
53
+ #
54
+ # Returns self.
55
+ def update(class_config=self.class_config)
56
+ class_config.each_pair do |key, config|
57
+ self[key] ||= config.default
58
+ end
59
+ self
60
+ end
61
+
50
62
  # Binds self to the specified receiver. Mapped keys are
51
63
  # removed from store and sent to their writer method on
52
64
  # receiver.
53
65
  def bind(receiver)
54
- raise ArgumentError.new("receiver cannot be nil") if receiver == nil
66
+ raise "already bound to: #{@receiver}" if bound?
67
+ raise ArgumentError, "receiver cannot be nil" if receiver == nil
55
68
 
56
69
  class_config.each_pair do |key, config|
57
70
  receiver.send(config.writer, store.delete(key)) if config.writer
@@ -88,7 +101,7 @@ module Tap
88
101
 
89
102
  # Associates the value the key. If bound? and the key
90
103
  # is a class_config key, then the value will be forwarded
91
- # to the class_config.writer method on the receiver.
104
+ # to the config.writer method on the receiver.
92
105
  def []=(key, value)
93
106
  case
94
107
  when bound? && config = class_config.map[key.to_sym]
@@ -99,7 +112,7 @@ module Tap
99
112
 
100
113
  # Retrieves the value corresponding to the key. If bound?
101
114
  # and the key is a class_config key, then the value is
102
- # obtained from the :key method on the receiver.
115
+ # obtained from the config.reader method on the receiver.
103
116
  def [](key)
104
117
  case
105
118
  when bound? && config = class_config.map[key.to_sym]
@@ -138,6 +151,19 @@ module Tap
138
151
  hash
139
152
  end
140
153
 
154
+ def to_yaml(opts)
155
+ hash = {}
156
+ store.each_pair do |key, value|
157
+ hash[key.to_s] = value
158
+ end
159
+
160
+ class_config.each_pair do |key, config|
161
+ hash[key.to_s] = bound? ? self[key] : config.default
162
+ end
163
+
164
+ hash.to_yaml(opts)
165
+ end
166
+
141
167
  # Overrides default inspect to show the to_hash values.
142
168
  def inspect
143
169
  "#<#{self.class}:#{object_id} to_hash=#{to_hash.inspect}>"