bahuvrihi-tap 0.10.8 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History +12 -0
- data/README +2 -0
- data/bin/rap +1 -1
- data/doc/Class Reference +16 -7
- data/doc/Command Reference +1 -2
- data/doc/Tutorial +3 -5
- data/lib/tap/app.rb +70 -75
- data/lib/tap/constants.rb +2 -2
- data/lib/tap/env.rb +23 -25
- data/lib/tap/file_task.rb +1 -1
- data/lib/tap/generator/generators/command/command_generator.rb +2 -2
- data/lib/tap/generator/generators/command/templates/command.erb +2 -2
- data/lib/tap/generator/generators/config/config_generator.rb +1 -1
- data/lib/tap/generator/generators/file_task/file_task_generator.rb +1 -1
- data/lib/tap/generator/generators/generator/generator_generator.rb +1 -1
- data/lib/tap/generator/generators/root/root_generator.rb +1 -1
- data/lib/tap/generator/generators/root/templates/gemspec +1 -1
- data/lib/tap/generator/generators/task/task_generator.rb +1 -1
- data/lib/tap/support/constant_manifest.rb +3 -2
- data/lib/tap/support/executable.rb +6 -0
- data/lib/tap/support/gems/rake.rb +20 -2
- data/lib/tap/task.rb +66 -108
- data/lib/tap/tasks/rake.rb +2 -39
- data/lib/tap/test/file_test.rb +1 -1
- data/lib/tap/test/utils.rb +2 -2
- metadata +1 -6
- data/cmd/server.rb +0 -42
- data/lib/tap/support/gems/rack.rb +0 -282
- data/template/404.erb +0 -12
- data/template/index.erb +0 -49
- data/vendor/url_encoded_pair_parser.rb +0 -93
data/History
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
== 0.11.0 / 2008-10-20
|
2
|
+
|
3
|
+
Significant update to Tap with many internal reworks.
|
4
|
+
Major changes include:
|
5
|
+
|
6
|
+
* Addition of Parser/Schema
|
7
|
+
* Addition of rap and task declarations
|
8
|
+
* Removal of Workflow in preference of workflow
|
9
|
+
definitions within Task
|
10
|
+
* Refactoring of Test modules
|
11
|
+
* Expanded/updated documentation
|
12
|
+
|
1
13
|
== 0.10.1 / 2008-08-21
|
2
14
|
|
3
15
|
Update of Tap with a few improvements to manifests
|
data/README
CHANGED
@@ -28,6 +28,8 @@ Check out these links for tutorials, development, and bug tracking.
|
|
28
28
|
|
29
29
|
A simple task illustrates the usage of tap:
|
30
30
|
|
31
|
+
[lib/goodnight.rb]
|
32
|
+
|
31
33
|
# Goodnight::manifest your basic goodnight moon task
|
32
34
|
# Says goodnight with a configurable message.
|
33
35
|
class Goodnight < Tap::Task
|
data/bin/rap
CHANGED
data/doc/Class Reference
CHANGED
@@ -32,6 +32,10 @@ Instances of a Configurable class have a <tt>config</tt> method accessing a {Ins
|
|
32
32
|
config :key, 'value' do |input|
|
33
33
|
input.upcase
|
34
34
|
end
|
35
|
+
|
36
|
+
def initialize
|
37
|
+
initialize_config
|
38
|
+
end
|
35
39
|
end
|
36
40
|
|
37
41
|
Is basically the same as:
|
@@ -112,7 +116,7 @@ Lazydoc parses a constant name, the key, the value, and any comment following th
|
|
112
116
|
lazydoc.resolve
|
113
117
|
|
114
118
|
lazydoc['Name::Space']['key'].to_s # => "This documentation gets parsed."
|
115
|
-
lazydoc['Name::Space']['another'].
|
119
|
+
lazydoc['Name::Space']['another'].value # => "another value"
|
116
120
|
|
117
121
|
Furthermore, Lazydoc can register specific lines for documentation. These lines are parsed to echo what happens in RDoc.
|
118
122
|
|
@@ -186,10 +190,12 @@ and batched.
|
|
186
190
|
|
187
191
|
Batched tasks enque together, and therefore execute sequentially with the same inputs. Results are aggregated into the underlying Tap::App.
|
188
192
|
|
189
|
-
t1.
|
190
|
-
runlist # => [t0, t1, t2, t3, t2]
|
193
|
+
t1.enq('input')
|
191
194
|
|
192
195
|
app = Tap::App.instance
|
196
|
+
app.run
|
197
|
+
|
198
|
+
runlist # => [t0, t1, t2, t3, t2]
|
193
199
|
app.results(t2) # => ["input:one:two", "input:three:two"]
|
194
200
|
|
195
201
|
Tracking the evolution of a result through a workflow can get complex; Tap audits workflows to help. In the audit trail, the tasks are identified by name. Lets set the names of the tasks and take a look at the audit trails of the t2 results:
|
@@ -199,7 +205,7 @@ Tracking the evolution of a result through a workflow can get complex; Tap audit
|
|
199
205
|
t3.name = 'trois'
|
200
206
|
|
201
207
|
app._results(t2).collect do |_result|
|
202
|
-
_result.
|
208
|
+
_result._to_s
|
203
209
|
end.join("---\n")
|
204
210
|
# =>
|
205
211
|
# o-[] "input"
|
@@ -221,7 +227,7 @@ A Root represents the base of a directory structure. Roots allow you to alias di
|
|
221
227
|
root = Tap::Root.new '/path/to/root'
|
222
228
|
root.root # => '/path/to/root'
|
223
229
|
root['config'] # => '/path/to/root/config'
|
224
|
-
root.filepath('config', 'sample.yml') # => '/path/to/root/config/
|
230
|
+
root.filepath('config', 'sample.yml') # => '/path/to/root/config/sample.yml'
|
225
231
|
|
226
232
|
While simple, this ability to alias paths is useful, powerful, and forms the basis of the Tap execution environment.
|
227
233
|
|
@@ -261,15 +267,18 @@ Instances of Tap::App coordinate the execution of tasks. Apps are basically a s
|
|
261
267
|
log = StringIO.new
|
262
268
|
app = Tap::App.instance
|
263
269
|
app.logger = Logger.new(log)
|
270
|
+
app.logger.formatter = lambda do |severity, time, progname, msg|
|
271
|
+
" %s %s: %s\n" % [severity[0,1], progname, msg]
|
272
|
+
end
|
264
273
|
|
265
274
|
t = Tap::Task.intern {|task, *inputs| inputs }
|
266
275
|
t.log 'action', 'to app'
|
267
|
-
log.string # => " I
|
276
|
+
log.string # => " I action: to app\n"
|
268
277
|
|
269
278
|
t.enq(1)
|
270
279
|
t.enq(2,3)
|
271
280
|
|
272
|
-
app.queue.to_a # => [[t, [1]], [t, [2,3]]
|
281
|
+
app.queue.to_a # => [[t, [1]], [t, [2,3]]]
|
273
282
|
app.run
|
274
283
|
app.results(t) # => [[1], [2,3]]
|
275
284
|
|
data/doc/Command Reference
CHANGED
@@ -27,7 +27,7 @@ Generate and destory launch generator scripts, similar to those in {Rails}[http:
|
|
27
27
|
{command}[link:classes/Tap/Generator/Generators/CommandGenerator.html]:: a new command
|
28
28
|
{config}[link:classes/Tap/Generator/Generators/ConfigGenerator.html]:: a static config file for the specified task
|
29
29
|
{file_task}[link:classes/Tap/Generator/Generators/FileTaskGenerator.html]:: a file task and test
|
30
|
-
{generator}[link:classes/Tap/Generator/
|
30
|
+
{generator}[link:classes/Tap/Generator/Generators/GeneratorGenerator.html]:: a new generator
|
31
31
|
{root}[link:classes/Tap/Generator/Generators/RootGenerator.html]:: the basic directory structure
|
32
32
|
{task}[link:classes/Tap/Generator/Generators/TaskGenerator.html]:: a task class and test
|
33
33
|
|
@@ -68,7 +68,6 @@ Manifest prints a list of all resources (commands, tasks, generators, etc) avail
|
|
68
68
|
generate (cmd/generate.rb)
|
69
69
|
manifest (cmd/manifest.rb)
|
70
70
|
run (cmd/run.rb)
|
71
|
-
server (cmd/server.rb)
|
72
71
|
tasks
|
73
72
|
dump (lib/tap/tasks/dump.rb)
|
74
73
|
load (lib/tap/tasks/load.rb)
|
data/doc/Tutorial
CHANGED
@@ -86,8 +86,6 @@ Going back to the first example, lets take a look at how a task declaration maps
|
|
86
86
|
|
87
87
|
Here is a corresponding class:
|
88
88
|
|
89
|
-
[Tapfile]
|
90
|
-
|
91
89
|
# Goodnight::manifest your basic goodnight moon task
|
92
90
|
# Says goodnight with a configurable message.
|
93
91
|
class Goodnight < Tap::Task
|
@@ -259,7 +257,7 @@ Run the test:
|
|
259
257
|
|
260
258
|
Run the task:
|
261
259
|
|
262
|
-
%
|
260
|
+
% rap goodnight moon
|
263
261
|
I[23:22:19] goodnight moon
|
264
262
|
|
265
263
|
Ok, lets share it. Print the current gemspec manifest:
|
@@ -269,7 +267,7 @@ Ok, lets share it. Print the current gemspec manifest:
|
|
269
267
|
Rakefile
|
270
268
|
lib/goodnight.rb
|
271
269
|
sample.gemspec
|
272
|
-
|
270
|
+
true tap.yml
|
273
271
|
test/goodnight_test.rb
|
274
272
|
true test/tap_test_helper.rb
|
275
273
|
true test/tap_test_suite.rb
|
@@ -284,7 +282,7 @@ As you can see, this needs an update to include the task file. Open up sample.g
|
|
284
282
|
s.platform = Gem::Platform::RUBY
|
285
283
|
s.summary = "sample"
|
286
284
|
s.require_path = "lib"
|
287
|
-
s.add_dependency("tap", "
|
285
|
+
s.add_dependency("tap", ">= 0.11")
|
288
286
|
s.files = %W{
|
289
287
|
lib/goodnight.rb
|
290
288
|
tap.yml
|
data/lib/tap/app.rb
CHANGED
@@ -6,91 +6,91 @@ require 'tap/support/executable_queue'
|
|
6
6
|
module Tap
|
7
7
|
|
8
8
|
# App coordinates the setup and running of tasks, and provides an interface
|
9
|
-
# to the application directory structure.
|
10
|
-
#
|
11
|
-
#
|
9
|
+
# to the application directory structure. All tasks have an App (by default
|
10
|
+
# App.instance) through which tasks access access application-wide resources
|
11
|
+
# like the logger, executable queue, aggregator, and dependencies.
|
12
12
|
#
|
13
13
|
# === Running Tasks
|
14
14
|
#
|
15
|
-
#
|
16
|
-
# access application-wide resources like the logger. Additionally, task
|
17
|
-
# enque command are forwarded to App#enq:
|
15
|
+
# Task enque command are forwarded to App#enq:
|
18
16
|
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
# app.enq(
|
17
|
+
# t0 = Task.intern {|task, input| "#{input}.0" }
|
18
|
+
# t0.enq('a')
|
19
|
+
# app.enq(t0, 'b')
|
22
20
|
#
|
23
21
|
# app.run
|
24
|
-
# app.results(
|
22
|
+
# app.results(t0) # => ['a.0', 'b.0']
|
25
23
|
#
|
26
24
|
# When a task completes, the results will be passed to the task on_complete
|
27
25
|
# block, if set, or be collected into an Aggregator (aggregated results may
|
28
|
-
# be accessed per-task, as shown above); on_complete blocks typically
|
29
|
-
# other tasks, allowing the construction of imperative
|
26
|
+
# be accessed per-task, as shown above); on_complete blocks typically
|
27
|
+
# execute or enque other tasks, allowing the construction of imperative
|
28
|
+
# workflows:
|
30
29
|
#
|
31
30
|
# # clear the previous results
|
32
31
|
# app.aggregator.clear
|
33
32
|
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
# t1.enq 0
|
38
|
-
# t1.enq 10
|
33
|
+
# t1 = Task.intern {|task, input| "#{input}.1" }
|
34
|
+
# t0.on_complete {|_result| t1.enq(_result) }
|
35
|
+
# t0.enq 'c'
|
39
36
|
#
|
40
37
|
# app.run
|
41
|
-
# app.results(
|
42
|
-
# app.results(
|
38
|
+
# app.results(t0) # => []
|
39
|
+
# app.results(t1) # => ['c.0.1']
|
43
40
|
#
|
44
|
-
# Here
|
41
|
+
# Here t0 has no results because the on_complete block passed them to t1 in
|
45
42
|
# a simple sequence.
|
46
43
|
#
|
47
|
-
#
|
44
|
+
# === Dependencies
|
48
45
|
#
|
49
|
-
# Tasks allow the construction of dependency-based workflows
|
50
|
-
#
|
51
|
-
# executes after the dependencies have been resolved.
|
46
|
+
# Tasks allow the construction of dependency-based workflows such that a
|
47
|
+
# dependent task only executes after its dependencies have been resolved.
|
52
48
|
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
#
|
49
|
+
# runlist = []
|
50
|
+
# t0 = Task.intern {|task| runlist << task }
|
51
|
+
# t1 = Task.intern {|task| runlist << task }
|
56
52
|
#
|
57
|
-
#
|
58
|
-
#
|
53
|
+
# t0.depends_on(t1)
|
54
|
+
# t0.enq
|
59
55
|
#
|
60
56
|
# app.run
|
61
|
-
#
|
57
|
+
# runlist # => [t1, t0]
|
62
58
|
#
|
63
59
|
# Once a dependency is resolved, it will not execute again:
|
64
60
|
#
|
65
|
-
#
|
61
|
+
# t0.enq
|
66
62
|
# app.run
|
67
|
-
#
|
63
|
+
# runlist # => [t1, t0, t0]
|
68
64
|
#
|
69
|
-
#
|
65
|
+
# === Batching
|
70
66
|
#
|
71
67
|
# Tasks can be batched, allowing the same input to be enqued to multiple
|
72
68
|
# tasks at once.
|
73
69
|
#
|
74
|
-
#
|
75
|
-
#
|
70
|
+
# t0 = Task.intern {|task, input| "#{input}.0" }
|
71
|
+
# t1 = Task.intern {|task, input| "#{input}.1" }
|
76
72
|
#
|
77
|
-
#
|
78
|
-
#
|
73
|
+
# t0.batch_with(t1)
|
74
|
+
# t0.enq 'a'
|
75
|
+
# t1.enq 'b'
|
79
76
|
#
|
80
77
|
# app.run
|
81
|
-
# app.results(
|
82
|
-
# app.results(
|
78
|
+
# app.results(t0) # => ['a.0', 'b.0']
|
79
|
+
# app.results(t1) # => ['a.1', 'b.1']
|
83
80
|
#
|
84
|
-
#
|
81
|
+
# === Executables
|
85
82
|
#
|
86
|
-
# App can enque and run any Executable object.
|
87
|
-
#
|
88
|
-
#
|
83
|
+
# App can enque and run any Executable object. Arbitrary methods may be
|
84
|
+
# made into Executables using Object#_method. The mq (method enq) method
|
85
|
+
# generates and enques methods in one step.
|
89
86
|
#
|
90
87
|
# array = []
|
88
|
+
#
|
89
|
+
# # longhand
|
91
90
|
# m = array._method(:push)
|
92
|
-
#
|
93
|
-
#
|
91
|
+
# m.enq(1)
|
92
|
+
#
|
93
|
+
# # shorthand
|
94
94
|
# app.mq(array, :push, 2)
|
95
95
|
#
|
96
96
|
# array.empty? # => true
|
@@ -100,29 +100,29 @@ module Tap
|
|
100
100
|
# === Auditing
|
101
101
|
#
|
102
102
|
# All results are audited to track how a given input evolves during a workflow.
|
103
|
-
# To illustrate auditing, consider
|
104
|
-
# to add one to an input until the result is 3, then adds five more with the
|
105
|
-
# 'add_five' method. The final result should always be 8.
|
106
|
-
#
|
107
|
-
# t1 = Tap::Task.intern {|task, input| input += 1 }
|
108
|
-
# t1.name = "add_one"
|
103
|
+
# To illustrate auditing, consider and addition workflow that ends in eights.
|
109
104
|
#
|
110
|
-
#
|
111
|
-
#
|
105
|
+
# add_one = Tap::Task.intern({}, 'add_one') {|task, input| input += 1 }
|
106
|
+
# add_five = Tap::Task.intern({}, 'add_five') {|task, input| input += 5 }
|
112
107
|
#
|
113
|
-
#
|
108
|
+
# add_one.on_complete do |_result|
|
114
109
|
# # _result is the audit; use the _current method
|
115
110
|
# # to get the current value in the audit trail
|
111
|
+
# current_value = _result._current
|
116
112
|
#
|
117
|
-
#
|
113
|
+
# if current_value < 3
|
114
|
+
# add_one.enq(_result)
|
115
|
+
# else
|
116
|
+
# add_five.enq(_result)
|
117
|
+
# end
|
118
118
|
# end
|
119
119
|
#
|
120
|
-
#
|
121
|
-
#
|
122
|
-
#
|
120
|
+
# add_one.enq(0)
|
121
|
+
# add_one.enq(1)
|
122
|
+
# add_one.enq(2)
|
123
123
|
#
|
124
124
|
# app.run
|
125
|
-
# app.results(
|
125
|
+
# app.results(add_five) # => [8,8,8]
|
126
126
|
#
|
127
127
|
# Although the results are indistinguishable, each achieved the final value
|
128
128
|
# through a different series of tasks. With auditing you can see how each
|
@@ -130,7 +130,7 @@ module Tap
|
|
130
130
|
#
|
131
131
|
# # app.results returns the actual result values
|
132
132
|
# # app._results returns the audits for these values
|
133
|
-
# app._results(
|
133
|
+
# app._results(add_five).each do |_result|
|
134
134
|
# puts "How #{_result._original} became #{_result._current}:"
|
135
135
|
# puts _result._to_s
|
136
136
|
# puts
|
@@ -257,10 +257,6 @@ module Tap
|
|
257
257
|
name == nil ? nil : filepath('config', "#{name}.yml")
|
258
258
|
end
|
259
259
|
|
260
|
-
#
|
261
|
-
# Execution methods
|
262
|
-
#
|
263
|
-
|
264
260
|
# Sets state = State::READY unless the app is running. Returns self.
|
265
261
|
def ready
|
266
262
|
@state = State::READY unless state == State::RUN
|
@@ -337,10 +333,8 @@ module Tap
|
|
337
333
|
"state: #{state} (#{State.state_str(state)}) queue: #{queue.size} results: #{aggregator.size}"
|
338
334
|
end
|
339
335
|
|
340
|
-
# Enques the task with the inputs. If the task is batched,
|
341
|
-
# task in task.batch will be enqued with the inputs. Returns task.
|
342
|
-
#
|
343
|
-
# An Executable may provided instead of a task.
|
336
|
+
# Enques the task (or Executable) with the inputs. If the task is batched,
|
337
|
+
# then each task in task.batch will be enqued with the inputs. Returns task.
|
344
338
|
def enq(task, *inputs)
|
345
339
|
case task
|
346
340
|
when Tap::Task
|
@@ -371,16 +365,17 @@ module Tap
|
|
371
365
|
# Returns all aggregated results for the specified tasks. Results are
|
372
366
|
# joined into a single array. Arrays of tasks are allowed as inputs.
|
373
367
|
#
|
374
|
-
#
|
375
|
-
#
|
376
|
-
#
|
368
|
+
# t0 = Task.intern {|task, input| "#{input}.0" }
|
369
|
+
# t1 = Task.intern {|task, input| "#{input}.1" }
|
370
|
+
# t2 = Task.intern {|task, input| "#{input}.2" }
|
371
|
+
# t1.batch_with(t2)
|
377
372
|
#
|
378
|
-
#
|
379
|
-
#
|
373
|
+
# t0.enq(0)
|
374
|
+
# t1.enq(1)
|
380
375
|
#
|
381
376
|
# app.run
|
382
|
-
# app.results(
|
383
|
-
# app.results(
|
377
|
+
# app.results(t0, t1.batch) # => ["0.0", "1.1", "1.2"]
|
378
|
+
# app.results(t1, t0) # => ["1.1", "0.0"]
|
384
379
|
#
|
385
380
|
def results(*tasks)
|
386
381
|
_results(tasks).collect {|_result| _result._current}
|
data/lib/tap/constants.rb
CHANGED
data/lib/tap/env.rb
CHANGED
@@ -450,22 +450,22 @@ module Tap
|
|
450
450
|
# be returned if the block returns true.
|
451
451
|
#
|
452
452
|
# Returns nil if no file can be found.
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
453
|
+
def search_path(dir, path)
|
454
|
+
each do |env|
|
455
|
+
directory = env.root.filepath(dir)
|
456
|
+
file = env.root.filepath(dir, path)
|
457
|
+
|
458
|
+
# check the file is relative to the
|
459
|
+
# directory, and that the file exists.
|
460
|
+
if file.rindex(directory, 0) == 0 &&
|
461
|
+
File.exists?(file) &&
|
462
|
+
(!block_given? || yield(file))
|
463
|
+
return file
|
464
|
+
end
|
465
|
+
end
|
466
|
+
|
467
|
+
nil
|
468
|
+
end
|
469
469
|
|
470
470
|
# def reset(name, &block)
|
471
471
|
# each do |env|
|
@@ -474,30 +474,28 @@ module Tap
|
|
474
474
|
# end
|
475
475
|
# end
|
476
476
|
|
477
|
-
|
478
|
-
|
477
|
+
#
|
478
|
+
TEMPLATES = {}
|
479
|
+
TEMPLATES[:commands] = %Q{<% if count > 1 %>
|
479
480
|
<%= env_name %>:
|
480
481
|
<% end %>
|
481
482
|
<% entries.each do |name, const| %>
|
482
483
|
<%= name.ljust(width) %>
|
483
|
-
<% end %>}
|
484
|
-
|
485
|
-
:tasks => %Q{<% if count > 1 %>
|
484
|
+
<% end %>}
|
485
|
+
TEMPLATES[:tasks] = %Q{<% if count > 1 %>
|
486
486
|
<%= env_name %>:
|
487
487
|
<% end %>
|
488
488
|
<% entries.each do |name, const| %>
|
489
489
|
<% desc = const.document[const.name]['manifest'] %>
|
490
490
|
<%= name.ljust(width) %><%= desc.empty? ? '' : ' # ' %><%= desc %>
|
491
|
-
<% end %>}
|
492
|
-
|
493
|
-
:generators => %Q{<% if count > 1 %>
|
491
|
+
<% end %>}
|
492
|
+
TEMPLATES[:generators] = %Q{<% if count > 1 %>
|
494
493
|
<%= env_name %>:
|
495
494
|
<% end %>
|
496
495
|
<% entries.each do |name, const| %>
|
497
496
|
<% desc = const.document[const.name]['generator'] %>
|
498
497
|
<%= name.ljust(width) %><%= desc.empty? ? '' : ' # ' %><%= desc %>
|
499
498
|
<% end %>}
|
500
|
-
}
|
501
499
|
|
502
500
|
def summarize(name, template=TEMPLATES[name])
|
503
501
|
count = 0
|