bahuvrihi-tap 0.11.2 → 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/rap +2 -3
- data/bin/tap +1 -1
- data/cmd/console.rb +2 -2
- data/cmd/manifest.rb +2 -2
- data/cmd/run.rb +7 -9
- data/cmd/server.rb +5 -5
- data/doc/Class Reference +17 -20
- data/doc/Tutorial +5 -7
- data/lib/tap.rb +2 -0
- data/lib/tap/app.rb +21 -31
- data/lib/tap/constants.rb +2 -2
- data/lib/tap/declarations.rb +85 -97
- data/lib/tap/declarations/declaration_task.rb +58 -0
- data/lib/tap/declarations/description.rb +24 -0
- data/lib/tap/env.rb +20 -16
- data/lib/tap/exe.rb +2 -2
- data/lib/tap/file_task.rb +224 -410
- data/lib/tap/generator/arguments.rb +9 -0
- data/lib/tap/generator/base.rb +105 -28
- data/lib/tap/generator/destroy.rb +29 -12
- data/lib/tap/generator/generate.rb +55 -39
- data/lib/tap/generator/generators/command/templates/command.erb +3 -3
- data/lib/tap/generator/generators/config/config_generator.rb +34 -3
- data/lib/tap/generator/generators/root/root_generator.rb +6 -9
- data/lib/tap/generator/generators/root/templates/Rakefile +4 -4
- data/lib/tap/generator/generators/task/templates/test.erb +1 -1
- data/lib/tap/root.rb +211 -156
- data/lib/tap/support/aggregator.rb +6 -9
- data/lib/tap/support/audit.rb +278 -357
- data/lib/tap/support/constant_manifest.rb +24 -21
- data/lib/tap/support/dependency.rb +1 -1
- data/lib/tap/support/executable.rb +26 -48
- data/lib/tap/support/join.rb +44 -19
- data/lib/tap/support/joins/sync_merge.rb +3 -5
- data/lib/tap/support/parser.rb +1 -1
- data/lib/tap/task.rb +195 -150
- data/lib/tap/tasks/dump.rb +2 -2
- data/lib/tap/test/extensions.rb +11 -13
- data/lib/tap/test/file_test.rb +71 -129
- data/lib/tap/test/file_test_class.rb +4 -1
- data/lib/tap/test/tap_test.rb +26 -154
- metadata +15 -22
- data/lib/tap/patches/optparse/summarize.rb +0 -62
- data/lib/tap/support/assignments.rb +0 -173
- data/lib/tap/support/class_configuration.rb +0 -182
- data/lib/tap/support/configurable.rb +0 -113
- data/lib/tap/support/configurable_class.rb +0 -271
- data/lib/tap/support/configuration.rb +0 -170
- data/lib/tap/support/instance_configuration.rb +0 -173
- data/lib/tap/support/lazydoc.rb +0 -386
- data/lib/tap/support/lazydoc/attributes.rb +0 -48
- data/lib/tap/support/lazydoc/comment.rb +0 -503
- data/lib/tap/support/lazydoc/config.rb +0 -17
- data/lib/tap/support/lazydoc/definition.rb +0 -36
- data/lib/tap/support/lazydoc/document.rb +0 -152
- data/lib/tap/support/lazydoc/method.rb +0 -24
- data/lib/tap/support/tdoc.rb +0 -409
- data/lib/tap/support/tdoc/tdoc_html_generator.rb +0 -38
- data/lib/tap/support/tdoc/tdoc_html_template.rb +0 -42
- data/lib/tap/support/validation.rb +0 -479
data/bin/rap
CHANGED
@@ -73,16 +73,15 @@ begin
|
|
73
73
|
<% entries.each do |name, const| %>
|
74
74
|
<% desc = if const.require_path == nil # should be a declaration %>
|
75
75
|
<% manifest = const.constantize.manifest %>
|
76
|
-
<% next if manifest == nil || manifest.
|
76
|
+
<% next if manifest == nil || manifest.empty? %>
|
77
77
|
<% manifest %>
|
78
78
|
<% else %>
|
79
79
|
<% const.document[const.name]['manifest'] %>
|
80
80
|
<% end %>
|
81
|
-
<% desc = desc.subject.to_s if desc.kind_of?(Tap::Support::Lazydoc::Comment) %>
|
82
81
|
<%= name.ljust(width) %><%= desc.empty? ? '' : ' # ' %><%= desc %>
|
83
82
|
<% end %>}
|
84
83
|
|
85
|
-
puts
|
84
|
+
puts Lazydoc.usage(__FILE__)
|
86
85
|
puts
|
87
86
|
puts "=== tap tasks ==="
|
88
87
|
puts env.summarize(:tasks, rap_template)
|
data/bin/tap
CHANGED
data/cmd/console.rb
CHANGED
@@ -7,12 +7,12 @@
|
|
7
7
|
# handle options
|
8
8
|
#
|
9
9
|
|
10
|
-
|
10
|
+
ConfigParser.new do |opts|
|
11
11
|
opts.separator ""
|
12
12
|
opts.separator "options:"
|
13
13
|
|
14
14
|
opts.on("-h", "--help", "Show this message") do
|
15
|
-
|
15
|
+
puts Lazydoc.usage(__FILE__)
|
16
16
|
puts opts
|
17
17
|
exit
|
18
18
|
end
|
data/cmd/manifest.rb
CHANGED
@@ -4,13 +4,13 @@
|
|
4
4
|
#
|
5
5
|
|
6
6
|
options = {}
|
7
|
-
|
7
|
+
ConfigParser.new do |opts|
|
8
8
|
|
9
9
|
opts.separator ""
|
10
10
|
opts.separator "options:"
|
11
11
|
|
12
12
|
opts.on("-h", "--help", "Show this message") do
|
13
|
-
|
13
|
+
puts Lazydoc.usage(__FILE__)
|
14
14
|
puts opts
|
15
15
|
exit
|
16
16
|
end
|
data/cmd/run.rb
CHANGED
@@ -13,24 +13,22 @@ app = Tap::App.instance
|
|
13
13
|
#
|
14
14
|
|
15
15
|
dump = false
|
16
|
-
|
16
|
+
ConfigParser.new do |opts|
|
17
17
|
opts.separator ""
|
18
18
|
opts.separator "configurations:"
|
19
19
|
|
20
|
-
Tap::
|
21
|
-
|
22
|
-
|
23
|
-
opts.
|
24
|
-
app.send(config.writer, value)
|
25
|
-
end
|
20
|
+
root_keys = Tap::Root.configurations.keys
|
21
|
+
Tap::App.configurations.each_pair do |key, config|
|
22
|
+
next if root_keys.include?(key)
|
23
|
+
opts.define(key, config.default, config.attributes)
|
26
24
|
end
|
27
25
|
|
28
26
|
opts.separator ""
|
29
27
|
opts.separator "options:"
|
30
|
-
|
28
|
+
|
31
29
|
opts.on("-h", "--help", "Show this message") do
|
32
|
-
opts.banner = Tap::Support::Lazydoc.usage(__FILE__)
|
33
30
|
Tap::App.lazydoc.resolve
|
31
|
+
puts Lazydoc.usage(__FILE__)
|
34
32
|
puts opts
|
35
33
|
exit
|
36
34
|
end
|
data/cmd/server.rb
CHANGED
@@ -11,22 +11,22 @@ env = Tap::Env.instance
|
|
11
11
|
# handle options
|
12
12
|
#
|
13
13
|
options = {:Port => 8080}
|
14
|
-
|
14
|
+
ConfigParser.new do |opts|
|
15
15
|
|
16
16
|
opts.separator ""
|
17
17
|
opts.separator "options:"
|
18
18
|
|
19
19
|
opts.on("-h", "--help", "Show this message") do
|
20
|
-
|
20
|
+
puts Lazydoc.usage(__FILE__)
|
21
21
|
puts opts
|
22
22
|
exit
|
23
23
|
end
|
24
24
|
|
25
|
-
opts.on("-p", "--port PORT",
|
26
|
-
options[:Port] = value
|
25
|
+
opts.on("-p", "--port PORT", "Specifies the port (default 8080)") do |value|
|
26
|
+
options[:Port] = value.to_i
|
27
27
|
end
|
28
28
|
|
29
|
-
opts.on("-d", "--development",
|
29
|
+
opts.on("-d", "--development", "Specifies development mode") do
|
30
30
|
env.config[:development] = true
|
31
31
|
end
|
32
32
|
|
data/doc/Class Reference
CHANGED
@@ -18,16 +18,14 @@ Executable extends objects allowing them to be used in workflows, enqued, and ru
|
|
18
18
|
|
19
19
|
Tasks are constructed such that <tt>process</tt> is the executable method (actually execute_with_callbacks is used to wrap process with before/after execute callbacks, but effectively this is the case). Hence <tt>process</tt> is the standard method overridden in Task subclasses.
|
20
20
|
|
21
|
-
====
|
21
|
+
==== {Configurable}[http://tap.rubyforge.org/configurable/]
|
22
22
|
|
23
23
|
http://tap.rubyforge.org/images/Configurable.png
|
24
24
|
|
25
|
-
Configurable
|
26
|
-
|
27
|
-
Instances of a Configurable class have a <tt>config</tt> method accessing a {InstanceConfiguration}[link:classes/Tap/Support/InstanceConfiguration.html] object. The instance configuration acts like a forwarding hash; read and write operations for declared configs get forwarded to class methods while undeclared configs are stored directly. The writer for a config may be defined through a block provided during config declaration. For instance:
|
28
|
-
|
25
|
+
Tap uses the {Configurable}[http://tap.rubyforge.org/configurable/] module to declare class configurations and make them available in for use in contexts like the command line. Configurations essentially consist of a reader, writer, and default value, but they may additionally be accessed through a hash-like config object. For instance:
|
26
|
+
|
29
27
|
class ConfigClass
|
30
|
-
include
|
28
|
+
include Configurable
|
31
29
|
|
32
30
|
config :key, 'value' do |input|
|
33
31
|
input.upcase
|
@@ -52,7 +50,7 @@ Is basically the same as:
|
|
52
50
|
end
|
53
51
|
end
|
54
52
|
|
55
|
-
|
53
|
+
And as you can see here:
|
56
54
|
|
57
55
|
c = ConfigClass.new
|
58
56
|
c.key # => 'VALUE'
|
@@ -65,12 +63,12 @@ As you can see here:
|
|
65
63
|
|
66
64
|
This setup is both fast and convenient.
|
67
65
|
|
68
|
-
====
|
66
|
+
==== {Configurable::Validation}[http://tap.rubyforge.org/configurable/classes/Configurable/Validation.html]
|
69
67
|
|
70
|
-
When configurations are set from the command line, the writer method
|
68
|
+
When configurations are set from the command line, the writer method inevitably receives a string, even though a non-string input may be desired. The {Validation}[http://tap.rubyforge.org/configurable/classes/Configurable/Validation.html] module provides standard blocks for validating and transforming inputs, accessible through the <tt>c</tt> method (ex: <tt>c.integer</tt> or <tt>c.regexp</tt>). These blocks (generally) load string inputs as YAML and validate that the result is the correct class; non-string inputs are simply validated.
|
71
69
|
|
72
70
|
class ValidatingClass
|
73
|
-
include
|
71
|
+
include Configurable
|
74
72
|
|
75
73
|
config :int, 1, &c.integer # assures the input is an integer
|
76
74
|
config :int_or_nil, 1, &c.integer_or_nil # integer or nil only
|
@@ -89,9 +87,9 @@ When configurations are set from the command line, the writer method will inevit
|
|
89
87
|
|
90
88
|
Validation blocks sometimes imply metadata. For instance <tt>c.flag</tt> makes a config into a flag on the command line.
|
91
89
|
|
92
|
-
====
|
90
|
+
==== {Lazydoc}[http://tap.rubyforge.org/lazydoc]
|
93
91
|
|
94
|
-
Ah lazydoc. Lazydoc fits into the space between live code and code documentation. Lazydoc can scan a file (code or not) and pull documentation into the object space where it can be utilized. Lazydoc uses a key-value syntax like this:
|
92
|
+
Ah lazydoc. {Lazydoc}[http://tap.rubyforge.org/lazydoc] fits into the space between live code and code documentation. Lazydoc can scan a file (code or not) and pull documentation into the object space where it can be utilized. Lazydoc uses a key-value syntax like this:
|
95
93
|
|
96
94
|
# ::key value
|
97
95
|
|
@@ -112,10 +110,10 @@ Lazydoc parses a constant name, the key, the value, and any comment following th
|
|
112
110
|
|
113
111
|
require 'tap'
|
114
112
|
|
115
|
-
lazydoc =
|
113
|
+
lazydoc = Lazydoc[__FILE__]
|
116
114
|
lazydoc.resolve
|
117
115
|
|
118
|
-
lazydoc['Name::Space']['key'].
|
116
|
+
lazydoc['Name::Space']['key'].comment # => "This documentation gets parsed."
|
119
117
|
lazydoc['Name::Space']['another'].value # => "another value"
|
120
118
|
|
121
119
|
Furthermore, Lazydoc can register specific lines for documentation. These lines are parsed to echo what happens in RDoc.
|
@@ -128,7 +126,7 @@ Furthermore, Lazydoc can register specific lines for documentation. These lines
|
|
128
126
|
|
129
127
|
require 'tap'
|
130
128
|
|
131
|
-
lazydoc =
|
129
|
+
lazydoc = Lazydoc[__FILE__]
|
132
130
|
code_comment = lazydoc.register(2)
|
133
131
|
lazydoc.resolve
|
134
132
|
|
@@ -146,7 +144,7 @@ When no constant name is specified for a Lazydoc key, Env uses a constant based
|
|
146
144
|
# If more than one task is defined in this file, or if Sample::Task
|
147
145
|
# is not defined by loading this file, Tap will run into trouble.
|
148
146
|
|
149
|
-
However, the best practice is to include the namespace explicitly.
|
147
|
+
However, the best practice is to include the namespace explicitly. See the {Lazydoc}[http://tap.rubyforge.org/lazydoc] documentation for more information.
|
150
148
|
|
151
149
|
=== Tap::Task
|
152
150
|
|
@@ -205,7 +203,7 @@ Tracking the evolution of a result through a workflow can get complex; Tap audit
|
|
205
203
|
t3.name = 'trois'
|
206
204
|
|
207
205
|
app._results(t2).collect do |_result|
|
208
|
-
_result.
|
206
|
+
_result.dump
|
209
207
|
end.join("---\n")
|
210
208
|
# =>
|
211
209
|
# o-[] "input"
|
@@ -222,7 +220,7 @@ Tracking the evolution of a result through a workflow can get complex; Tap audit
|
|
222
220
|
|
223
221
|
http://tap.rubyforge.org/images/Root.png
|
224
222
|
|
225
|
-
A Root represents the base of a directory structure. Roots allow you to alias
|
223
|
+
A Root represents the base of a directory structure. Roots allow you to alias relative paths, basically allowing you to develop code for a conceptual directory structure that can be defined later.
|
226
224
|
|
227
225
|
root = Tap::Root.new '/path/to/root'
|
228
226
|
root.root # => '/path/to/root'
|
@@ -248,8 +246,7 @@ Tap tracks inputs as they are modified by various tasks, again through Executabl
|
|
248
246
|
Auditing is largely invisible except in <tt>on_complete</tt> blocks. <tt>on_complete</tt> blocks receive the audited results so that this information can be used, as needed, to make decisions.
|
249
247
|
|
250
248
|
Task.new.on_complete do |_result| # _result is an Audit instance
|
251
|
-
_result.
|
252
|
-
_result._original # the original value
|
249
|
+
_result.value # the current value
|
253
250
|
end
|
254
251
|
|
255
252
|
To help indicate when a result is actually a result and when it is an audit, Tap uses a convention whereby a leading underscore signals auditing is involved.
|
data/doc/Tutorial
CHANGED
@@ -98,8 +98,6 @@ Here is a corresponding class:
|
|
98
98
|
|
99
99
|
Simple enough; the name corresponds to the class, configurations (and dependencies, although they aren't show) are written out individually, and the block corresponds to process. There are a few differences, especially relating to process, but for the moment lets gloss over them and see how Goodnight works.
|
100
100
|
|
101
|
-
Goodnight.configurations.to_hash # => {:message => 'goodnight'}
|
102
|
-
|
103
101
|
goodnight = Goodnight.new
|
104
102
|
goodnight.message # => 'goodnight'
|
105
103
|
goodnight.process('moon') # => 'goodnight moon'
|
@@ -108,7 +106,7 @@ Simple enough; the name corresponds to the class, configurations (and dependenci
|
|
108
106
|
hello.message # => 'hello'
|
109
107
|
hello.process('world') # => 'hello world'
|
110
108
|
|
111
|
-
Totally straightforward. Goodnight stores the default configurations, each instance has accessors to the configurations, and the defaults may be overridden during initialization, or later. Class definitions allow validation/transformation blocks to be specified for configurations. These blocks process inputs (ex the string inputs from the command line), quite literally defining the writer for a configuration accessor. A set of standard blocks are available through +c+, an alias for the
|
109
|
+
Totally straightforward. Goodnight stores the default configurations, each instance has accessors to the configurations, and the defaults may be overridden during initialization, or later. Class definitions allow validation/transformation blocks to be specified for configurations. These blocks process inputs (ex the string inputs from the command line), quite literally defining the writer for a configuration accessor. A set of standard blocks are available through +c+, an alias for the {Configurable::Validation}[http://tap.rubyforge.org/configurable/classes/Configurable/Validation.html] module.
|
112
110
|
|
113
111
|
[lib/goodnight.rb]
|
114
112
|
|
@@ -166,9 +164,9 @@ Now from the command line:
|
|
166
164
|
--name NAME Specify a name
|
167
165
|
--use FILE Loads inputs from file
|
168
166
|
|
169
|
-
Take a quick look at the documentation. Class definitions
|
167
|
+
Take a quick look at the documentation. Class definitions map documentation and, in some cases, metadata to the command line; the configurations now have comments and reverse is a switch! Rich mapping allows tasks to act as an script interface, not unlike {OptionParser}[http://www.ruby-doc.org/stdlib/libdoc/optparse/rdoc/classes/OptionParser.html] (check out the {Configurable}[http://tap.rubyforge.org/configurable/] gem and specifically {ConfigParser}[http://tap.rubyforge.org/configurable/classes/ConfigParser.html] for more details).
|
170
168
|
|
171
|
-
|
169
|
+
This is a stand-alone goodnight script:
|
172
170
|
|
173
171
|
[goodnight]
|
174
172
|
|
@@ -208,7 +206,7 @@ Tap comes with two executables, rap and tap. The tap executable is more verbose
|
|
208
206
|
% cd sample
|
209
207
|
% tap generate task goodnight
|
210
208
|
|
211
|
-
Take a look at the task files
|
209
|
+
Take a look at the task files and you find something like this:
|
212
210
|
|
213
211
|
[lib/goodnight.rb]
|
214
212
|
|
@@ -247,7 +245,7 @@ Take a look at the task files an you find something like this:
|
|
247
245
|
app.run
|
248
246
|
|
249
247
|
assert_equal ["goodnight moon"], app.results(task)
|
250
|
-
assert_audit_equal
|
248
|
+
assert_audit_equal [[nil, "moon"], [task, "goodnight moon"]], app._results(task)[0]
|
251
249
|
end
|
252
250
|
end
|
253
251
|
|
data/lib/tap.rb
CHANGED
data/lib/tap/app.rb
CHANGED
@@ -106,9 +106,8 @@ module Tap
|
|
106
106
|
# add_five = Tap::Task.intern({}, 'add_five') {|task, input| input += 5 }
|
107
107
|
#
|
108
108
|
# add_one.on_complete do |_result|
|
109
|
-
# # _result is the audit
|
110
|
-
#
|
111
|
-
# current_value = _result._current
|
109
|
+
# # _result is the audit
|
110
|
+
# current_value = _result.value
|
112
111
|
#
|
113
112
|
# if current_value < 3
|
114
113
|
# add_one.enq(_result)
|
@@ -128,33 +127,23 @@ module Tap
|
|
128
127
|
# through a different series of tasks. With auditing you can see how each
|
129
128
|
# input came to the final value of 8:
|
130
129
|
#
|
131
|
-
#
|
132
|
-
#
|
133
|
-
#
|
134
|
-
#
|
135
|
-
#
|
136
|
-
#
|
137
|
-
#
|
138
|
-
#
|
139
|
-
#
|
140
|
-
#
|
141
|
-
#
|
142
|
-
#
|
143
|
-
#
|
144
|
-
#
|
145
|
-
#
|
146
|
-
#
|
147
|
-
#
|
148
|
-
# o-[add_one] 2
|
149
|
-
# o-[add_one] 3
|
150
|
-
# o-[add_five] 8
|
151
|
-
#
|
152
|
-
# How 0 became 8:
|
153
|
-
# o-[] 0
|
154
|
-
# o-[add_one] 1
|
155
|
-
# o-[add_one] 2
|
156
|
-
# o-[add_one] 3
|
157
|
-
# o-[add_five] 8
|
130
|
+
# "\n" + Tap::Support::Audit.dump(app._results(add_five), "")
|
131
|
+
# # => %Q{
|
132
|
+
# # o-[] 2
|
133
|
+
# # o-[add_one] 3
|
134
|
+
# # o-[add_five] 8
|
135
|
+
# #
|
136
|
+
# # o-[] 1
|
137
|
+
# # o-[add_one] 2
|
138
|
+
# # o-[add_one] 3
|
139
|
+
# # o-[add_five] 8
|
140
|
+
# #
|
141
|
+
# # o-[] 0
|
142
|
+
# # o-[add_one] 1
|
143
|
+
# # o-[add_one] 2
|
144
|
+
# # o-[add_one] 3
|
145
|
+
# # o-[add_five] 8
|
146
|
+
# # }
|
158
147
|
#
|
159
148
|
# See Tap::Support::Audit for more details.
|
160
149
|
class App < Root
|
@@ -378,9 +367,10 @@ module Tap
|
|
378
367
|
# app.results(t1, t0) # => ["1.1", "0.0"]
|
379
368
|
#
|
380
369
|
def results(*tasks)
|
381
|
-
_results(tasks).collect {|_result| _result.
|
370
|
+
_results(tasks).collect {|_result| _result.value }
|
382
371
|
end
|
383
372
|
|
373
|
+
# Returns a string like: "#<Tap::App:#{object_id} root: #{root} >"
|
384
374
|
def inspect
|
385
375
|
"#<#{self.class.to_s}:#{object_id} root: #{root} >"
|
386
376
|
end
|
data/lib/tap/constants.rb
CHANGED
data/lib/tap/declarations.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require File.dirname(__FILE__) + "/../tap"
|
2
|
-
|
2
|
+
require "tap/declarations/description"
|
3
|
+
require "tap/declarations/declaration_task"
|
3
4
|
|
4
5
|
module Tap
|
5
6
|
#--
|
@@ -8,38 +9,9 @@ module Tap
|
|
8
9
|
# the top level (for main/Object) while extend should be used
|
9
10
|
# in all other cases.
|
10
11
|
module Declarations
|
11
|
-
Lazydoc = Tap::Support::Lazydoc
|
12
12
|
include Tap::Support::ShellUtils
|
13
13
|
|
14
|
-
|
15
|
-
class Declaration < Comment
|
16
|
-
attr_accessor :desc
|
17
|
-
|
18
|
-
def resolve(lines)
|
19
|
-
super
|
20
|
-
|
21
|
-
@subject = case
|
22
|
-
when content.empty? || content[0][0].to_s !~ /^::desc(.*)/
|
23
|
-
desc.to_s
|
24
|
-
else
|
25
|
-
content[0].shift
|
26
|
-
$1.strip
|
27
|
-
end
|
28
|
-
|
29
|
-
self
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
module Rakish
|
35
|
-
def new(*args)
|
36
|
-
@instance ||= super
|
37
|
-
@instance.app.dependencies.register(@instance)
|
38
|
-
@instance
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def self.extended(base)
|
14
|
+
def self.extended(base) # :nodoc:
|
43
15
|
declaration_base = base.to_s
|
44
16
|
case declaration_base
|
45
17
|
when "Object", "Tap", "main"
|
@@ -50,58 +22,51 @@ module Tap
|
|
50
22
|
base.instance_variable_set(:@current_desc, nil)
|
51
23
|
end
|
52
24
|
|
25
|
+
# The Tap::Env for Dir.pwd
|
53
26
|
def self.env
|
54
27
|
@env ||= Tap::Env.instance_for(Dir.pwd)
|
55
28
|
end
|
56
29
|
|
30
|
+
# The environment in which declared task classes are registered.
|
31
|
+
# By default Declarations.env
|
57
32
|
def declaration_env
|
58
33
|
@declaration_env ||= Declarations.env
|
59
34
|
end
|
60
35
|
|
61
36
|
attr_writer :declaration_base
|
62
37
|
|
38
|
+
# The base constant for all task declarations, prepended to the task name.
|
63
39
|
def declaration_base
|
64
40
|
@declaration_base ||= ''
|
65
41
|
end
|
66
42
|
|
67
43
|
attr_writer :current_desc
|
68
44
|
|
45
|
+
# Tracks the current description, which will be used to
|
46
|
+
# document the next task declaration.
|
69
47
|
def current_desc
|
70
48
|
@current_desc ||= nil
|
71
49
|
end
|
72
50
|
|
51
|
+
# Declares a task with a rake-like syntax
|
73
52
|
def task(*args, &block)
|
74
|
-
|
75
|
-
task_class = declare(
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
args = OpenStruct.new(args)
|
83
|
-
|
84
|
-
# execute each block assciated with this task
|
85
|
-
self.class::BLOCKS.each do |task_block|
|
86
|
-
case task_block.arity
|
87
|
-
when 0 then task_block.call()
|
88
|
-
when 1 then task_block.call(self)
|
89
|
-
else task_block.call(self, args)
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
nil
|
94
|
-
end
|
95
|
-
register_doc(task_class, arg_names)
|
53
|
+
task_name, configs, needs, arg_names = resolve_args(args)
|
54
|
+
task_class = declare(task_name, configs, needs)
|
55
|
+
|
56
|
+
# set the arg_names for the subclass
|
57
|
+
task_class.arg_names = arg_names
|
58
|
+
|
59
|
+
# register the current_desc
|
60
|
+
register_doc(task_class)
|
96
61
|
|
97
62
|
# add the block to the task
|
98
|
-
|
99
|
-
task_class.const_set(:BLOCKS, [])
|
100
|
-
end
|
101
|
-
task_class::BLOCKS << block unless block == nil
|
63
|
+
task_class.blocks << block if block
|
102
64
|
task_class.instance
|
103
65
|
end
|
104
66
|
|
67
|
+
# Appends name to the declaration base for the duration of the block.
|
68
|
+
# This has the effect of nesting any task declarations within the
|
69
|
+
# Name module or class.
|
105
70
|
def namespace(name, &block)
|
106
71
|
current_base = declaration_base
|
107
72
|
@declaration_base = File.join(current_base, name.to_s.underscore)
|
@@ -109,43 +74,60 @@ module Tap
|
|
109
74
|
@declaration_base = current_base
|
110
75
|
end
|
111
76
|
|
77
|
+
# Sets the current description for use by the next task declaration.
|
112
78
|
def desc(str)
|
113
79
|
self.current_desc = str
|
114
80
|
end
|
115
81
|
|
116
82
|
protected
|
117
83
|
|
118
|
-
#
|
84
|
+
# A helper to resolve the arguments for a task; returns the array
|
119
85
|
# [task_name, configs, needs, arg_names].
|
120
86
|
#
|
121
87
|
# Adapted from Rake 0.8.3
|
122
88
|
# Changes:
|
123
89
|
# - no :needs support for the trailing Hash (which is now config)
|
124
|
-
def resolve_args(args)
|
90
|
+
def resolve_args(args) # :nodoc:
|
125
91
|
task_name = args.shift
|
126
92
|
arg_names = args
|
127
93
|
configs = {}
|
128
94
|
needs = []
|
129
95
|
|
96
|
+
# resolve hash task_names, for the syntax:
|
97
|
+
# task :name => [dependencies]
|
130
98
|
if task_name.is_a?(Hash)
|
131
99
|
hash = task_name
|
132
|
-
|
133
|
-
|
100
|
+
case hash.length
|
101
|
+
when 0
|
102
|
+
task_name = nil
|
103
|
+
when 1
|
104
|
+
task_name = hash.keys[0]
|
105
|
+
needs = hash[task_name]
|
106
|
+
else
|
107
|
+
raise ArgumentError, "multiple task names specified: #{hash.keys.inspect}"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# ensure a task name is specified
|
112
|
+
if task_name == nil
|
113
|
+
raise ArgumentError, "no task name specified" if args.empty?
|
134
114
|
end
|
135
115
|
|
116
|
+
# pop off configurations, if present, using the syntax:
|
117
|
+
# task :name, :one, :two, {configs...}
|
136
118
|
if arg_names.last.is_a?(Hash)
|
137
119
|
configs = arg_names.pop
|
138
120
|
end
|
139
121
|
|
140
122
|
needs = needs.respond_to?(:to_ary) ? needs.to_ary : [needs]
|
141
123
|
needs = needs.compact.collect do |need|
|
124
|
+
|
142
125
|
unless need.kind_of?(Class)
|
126
|
+
# lookup or declare non-class dependencies
|
143
127
|
name = normalize_name(need).camelize
|
144
|
-
need = Support::Constant.constantize(name)
|
145
|
-
declare(name)
|
146
|
-
end
|
128
|
+
need = Support::Constant.constantize(name) {|base, constants| declare(name) }
|
147
129
|
end
|
148
|
-
|
130
|
+
|
149
131
|
unless need.ancestors.include?(Tap::Task)
|
150
132
|
raise ArgumentError, "not a task: #{need}"
|
151
133
|
end
|
@@ -156,45 +138,57 @@ module Tap
|
|
156
138
|
[normalize_name(task_name), configs, needs, arg_names]
|
157
139
|
end
|
158
140
|
|
159
|
-
|
160
|
-
|
141
|
+
# helper to translate rake-style names to tap-style names, ie
|
142
|
+
#
|
143
|
+
# normalize_name('nested:name') # => "nested/name"
|
144
|
+
# normalize_name(:symbol) # => "symbol"
|
145
|
+
#
|
146
|
+
def normalize_name(name) # :nodoc:
|
147
|
+
name.to_s.tr(":", "/")
|
161
148
|
end
|
162
149
|
|
163
|
-
|
164
|
-
|
150
|
+
# Looks up or creates the DeclarationTask subclass specified by name
|
151
|
+
# (nested within declaration_base), and adds the configs and dependencies.
|
152
|
+
# Declare also registers the subclass in the declaration_env tasks
|
153
|
+
# manifest.
|
154
|
+
#
|
155
|
+
# Configurations are always validated using the yaml transformation block
|
156
|
+
# (see {Configurable::Validation.yaml}[http://tap.rubyforge.org/configurable/classes/Configurable/Validation.html]).
|
157
|
+
#
|
158
|
+
def declare(name, configs={}, dependencies=[])
|
159
|
+
# assemble the constant name
|
160
|
+
const_name = File.join(declaration_base, name.to_s).camelize
|
165
161
|
|
166
|
-
# generate the subclass
|
162
|
+
# lookup or generate the subclass
|
167
163
|
subclass = Support::Constant.constantize(const_name) do |base, constants|
|
168
164
|
constants.each do |const|
|
169
|
-
# nesting
|
170
|
-
# namespaces with the same name
|
171
|
-
|
165
|
+
# nesting Task classes into other Task classes
|
166
|
+
# is required for namespaces with the same name
|
167
|
+
# as a task
|
168
|
+
base = base.const_set(const, Class.new(DeclarationTask))
|
172
169
|
end
|
173
170
|
base
|
174
171
|
end
|
175
|
-
|
176
|
-
subclass.extend Rakish
|
177
172
|
|
173
|
+
# check a correct class was found
|
174
|
+
unless subclass.ancestors.include?(DeclarationTask)
|
175
|
+
raise "not a DeclarationTask: #{subclass}"
|
176
|
+
end
|
177
|
+
|
178
|
+
# append configuration (note that specifying a desc
|
179
|
+
# prevents lazydoc registration of these lines)
|
180
|
+
convert_to_yaml = Configurable::Validation.yaml
|
178
181
|
configs.each_pair do |key, value|
|
179
|
-
subclass.send(:config, key, value)
|
182
|
+
subclass.send(:config, key, value, :desc => "", &convert_to_yaml)
|
180
183
|
end
|
181
184
|
|
185
|
+
# add dependencies
|
182
186
|
dependencies.each do |dependency|
|
183
187
|
dependency_name = File.basename(dependency.default_name)
|
184
188
|
subclass.send(:depends_on, dependency_name, dependency)
|
185
189
|
end
|
186
190
|
|
187
|
-
if
|
188
|
-
subclass.send(:undef_method, :process) if subclass.method_defined?(:process)
|
189
|
-
subclass.send(:define_method, :process, &block)
|
190
|
-
end
|
191
|
-
|
192
|
-
# update any dependencies in instance
|
193
|
-
subclass.dependencies.each do |dependency|
|
194
|
-
subclass.instance.depends_on(dependency.instance)
|
195
|
-
end
|
196
|
-
|
197
|
-
# register the subclass in the manifest
|
191
|
+
# register the subclass in the manifest, if necessary
|
198
192
|
manifest = declaration_env.tasks
|
199
193
|
const_name = subclass.to_s
|
200
194
|
unless manifest.entries.any? {|const| const.name == const_name }
|
@@ -204,23 +198,17 @@ module Tap
|
|
204
198
|
subclass
|
205
199
|
end
|
206
200
|
|
207
|
-
|
208
|
-
|
201
|
+
# a helper to register the current_desc as the task_class.manifest
|
202
|
+
def register_doc(task_class) # :nodoc:
|
209
203
|
# register documentation
|
210
204
|
caller[1] =~ Lazydoc::CALLER_REGEXP
|
211
205
|
task_class.source_file = File.expand_path($1)
|
212
|
-
|
206
|
+
|
207
|
+
manifest = task_class.lazydoc.register($3.to_i - 1, Description)
|
213
208
|
manifest.desc = current_desc
|
214
209
|
task_class.manifest = manifest
|
215
210
|
|
216
211
|
self.current_desc = nil
|
217
|
-
|
218
|
-
if arg_names
|
219
|
-
comment = Lazydoc::Comment.new
|
220
|
-
comment.subject = arg_names.collect {|name| name.to_s.upcase }.join(' ')
|
221
|
-
task_class.args = comment
|
222
|
-
end
|
223
|
-
|
224
212
|
task_class
|
225
213
|
end
|
226
214
|
end
|