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
data/lib/tap.rb CHANGED
@@ -1,11 +1,5 @@
1
1
  autoload(:YAML, 'yaml') # expensive to load
2
2
 
3
- # Apply version-specific patches
4
- case RUBY_VERSION
5
- when /^1.9/
6
- $: << File.expand_path(File.dirname(__FILE__) + "/tap/patches/ruby19")
7
- end
8
-
9
3
  $:.unshift File.expand_path(File.dirname(__FILE__))
10
4
 
11
5
  require 'tap/constants'
@@ -13,9 +7,4 @@ require 'tap/constants'
13
7
  # require in order...
14
8
  require 'tap/exe'
15
9
  require 'tap/task'
16
- require 'tap/file_task'
17
-
18
- # Apply platform-specific patches
19
- # case RUBY_PLATFORM
20
- # when 'java'
21
- # end
10
+ require 'tap/file_task'
@@ -4,9 +4,6 @@ require 'tap/support/dependencies'
4
4
  require 'tap/support/executable_queue'
5
5
 
6
6
  module Tap
7
- module Support
8
- autoload(:Combinator, 'tap/support/combinator')
9
- end
10
7
 
11
8
  # App coordinates the setup and running of tasks, and provides an interface
12
9
  # to the application directory structure. App is convenient for use within
@@ -19,23 +16,22 @@ module Tap
19
16
  # access application-wide resources like the logger. Additionally, task
20
17
  # enque command are forwarded to App#enq:
21
18
  #
22
- # t1 = Task.new {|task, input| input += 1 }
19
+ # t1 = Task.intern {|task, input| input += 1 }
23
20
  # t1.enq(0)
24
21
  # app.enq(t1, 1)
25
22
  #
26
23
  # app.run
27
24
  # app.results(t1) # => [1, 2]
28
25
  #
29
- # When a task completes, the results will either be passed to the task
30
- # <tt>on_complete</tt> block (if set) or be collected into an Aggregator;
31
- # aggregated results may be accessed per-task, as shown above. Task
32
- # <tt>on_complete</tt> blocks typically enque other tasks, allowing the
33
- # construction of imperative workflows:
26
+ # When a task completes, the results will be passed to the task on_complete
27
+ # block, if set, or be collected into an Aggregator (aggregated results may
28
+ # be accessed per-task, as shown above); on_complete blocks typically enque
29
+ # other tasks, allowing the construction of imperative workflows:
34
30
  #
35
31
  # # clear the previous results
36
32
  # app.aggregator.clear
37
33
  #
38
- # t2 = Task.new {|task, input| input += 10 }
34
+ # t2 = Task.intern {|task, input| input += 10 }
39
35
  # t1.on_complete {|_result| t2.enq(_result) }
40
36
  #
41
37
  # t1.enq 0
@@ -52,32 +48,31 @@ module Tap
52
48
  #
53
49
  # Tasks allow the construction of dependency-based workflows as well; tasks
54
50
  # may be set to depend on other tasks such that the dependent task only
55
- # executes after the dependencies have been resolved (ie executed with a
56
- # given set of inputs).
51
+ # executes after the dependencies have been resolved.
57
52
  #
58
53
  # array = []
59
- # t1 = Task.new {|task, *inputs| array << inputs }
60
- # t2 = Task.new {|task, *inputs| array << inputs }
54
+ # t1 = Task.intern {|task, *inputs| array << inputs }
55
+ # t2 = Task.intern {|task| array << self }
61
56
  #
62
- # t1.depends_on(t2,1,2,3)
57
+ # t1.depends_on(t2)
63
58
  # t1.enq(4,5,6)
64
59
  #
65
60
  # app.run
66
- # array # => [[1,2,3], [4,5,6]]
61
+ # array # => [t2, [4,5,6]]
67
62
  #
68
63
  # Once a dependency is resolved, it will not execute again:
69
64
  #
70
65
  # t1.enq(7,8)
71
66
  # app.run
72
- # array # => [[1,2,3], [4,5,6], [7,8]]
67
+ # array # => [t2, [4,5,6], [7,8]]
73
68
  #
74
69
  # ==== Batching
75
70
  #
76
71
  # Tasks can be batched, allowing the same input to be enqued to multiple
77
72
  # tasks at once.
78
73
  #
79
- # t1 = Task.new {|task, input| input += 1 }
80
- # t2 = Task.new {|task, input| input += 10 }
74
+ # t1 = Task.intern {|task, input| input += 1 }
75
+ # t2 = Task.intern {|task, input| input += 10 }
81
76
  #
82
77
  # t1.batch_with(t2)
83
78
  # t1.enq 0
@@ -88,11 +83,8 @@ module Tap
88
83
  #
89
84
  # ==== Executables
90
85
  #
91
- # App can use any Executable object in place of a task. One way to initialize
92
- # an Executable for a method is to use the Object#_method defined by Tap. The
93
- # result can be enqued and incorporated into workflows, but they cannot be
94
- # batched.
95
- #
86
+ # App can enque and run any Executable object. One way to initialize an
87
+ # Executable for a method is to use the Object#_method added by Tap.
96
88
  # The mq (method enq) method generates and enques the method in one step.
97
89
  #
98
90
  # array = []
@@ -107,17 +99,15 @@ module Tap
107
99
  #
108
100
  # === Auditing
109
101
  #
110
- # All results generated by executable methods are audited to track how a given
111
- # input evolves during a workflow.
112
- #
102
+ # All results are audited to track how a given input evolves during a workflow.
113
103
  # To illustrate auditing, consider a workflow that uses the 'add_one' method
114
104
  # to add one to an input until the result is 3, then adds five more with the
115
105
  # 'add_five' method. The final result should always be 8.
116
106
  #
117
- # t1 = Tap::Task.new {|task, input| input += 1 }
107
+ # t1 = Tap::Task.intern {|task, input| input += 1 }
118
108
  # t1.name = "add_one"
119
109
  #
120
- # t2 = Tap::Task.new {|task, input| input += 5 }
110
+ # t2 = Tap::Task.intern {|task, input| input += 5 }
121
111
  # t2.name = "add_five"
122
112
  #
123
113
  # t1.on_complete do |_result|
@@ -189,9 +179,10 @@ module Tap
189
179
  attr_reader :state
190
180
 
191
181
  # A Tap::Support::Aggregator to collect the results of
192
- # methods that have no <tt>on_complete</tt> block
182
+ # methods that have no on_complete block
193
183
  attr_reader :aggregator
194
184
 
185
+ # A Tap::Support::Dependencies to track dependencies.
195
186
  attr_reader :dependencies
196
187
 
197
188
  config :debug, false, &c.flag # Flag debugging
@@ -270,36 +261,37 @@ module Tap
270
261
  # Execution methods
271
262
  #
272
263
 
273
- # Executes the input Executable with the inputs. Stores the result in
274
- # aggregator unless an on_complete block is set. Returns the audited
275
- # result.
276
- def execute(m, inputs)
277
- m._execute(*inputs)
278
- end
279
-
280
264
  # Sets state = State::READY unless the app is running. Returns self.
281
265
  def ready
282
- self.state = State::READY unless self.state == State::RUN
266
+ @state = State::READY unless state == State::RUN
283
267
  self
284
268
  end
285
269
 
286
- # Sequentially calls execute with the Executable methods and inputs in
287
- # queue; run continues until the queue is empty and then returns self.
288
- # Calls to run when already running will return immediately.
270
+ # Sequentially calls execute with the [executable, inputs] pairs in
271
+ # queue; run continues until the queue is empty and then returns self.
272
+ #
273
+ # ==== Run State
289
274
  #
290
- # Run checks the state of self before executing a method. If the state is
291
- # changed to State::STOP, then no more methods will be executed; currently
292
- # running methods will continute to completion. If the state is changed to
293
- # State::TERMINATE then no more methods will be executed and currently
294
- # running methods will be discontinued as described in terminate.
275
+ # Run checks the state of self before executing a method. If state
276
+ # changes from State::RUN, the following behaviors result:
277
+ #
278
+ # State::STOP:: No more executables will be executed; the current
279
+ # executable will continute to completion.
280
+ # State::TERMINATE:: No more executables will be executed and the
281
+ # currently running executable will be
282
+ # discontinued as described in terminate.
283
+ #
284
+ # Calls to run when the state is not State::READY do nothing and
285
+ # return immediately.
295
286
  def run
296
287
  return self unless state == State::READY
297
- self.state = State::RUN
288
+ @state = State::RUN
298
289
 
299
290
  # TODO: log starting run
300
291
  begin
301
292
  until queue.empty? || state != State::RUN
302
- execute(*queue.deq)
293
+ executable, inputs = queue.deq
294
+ executable._execute(*inputs)
303
295
  end
304
296
  rescue(TerminateError)
305
297
  # gracefully fail for termination errors
@@ -308,7 +300,7 @@ module Tap
308
300
  raise if debug?
309
301
  log($!.class, $!.message)
310
302
  ensure
311
- self.state = State::READY
303
+ @state = State::READY
312
304
  end
313
305
 
314
306
  # TODO: log run complete
@@ -321,7 +313,7 @@ module Tap
321
313
  #
322
314
  # Does nothing unless state is State::RUN.
323
315
  def stop
324
- self.state = State::STOP if self.state == State::RUN
316
+ @state = State::STOP if state == State::RUN
325
317
  self
326
318
  end
327
319
 
@@ -329,11 +321,11 @@ module Tap
329
321
  # state = State::TERMINATE. In this state, an executing task
330
322
  # will then raise a TerminateError upon check_terminate, thus
331
323
  # allowing the invocation of task-specific termination, perhaps
332
- # performing rollbacks. (see Tap::Task#check_terminate).
324
+ # performing rollbacks. (see Tap::Support::Executable#check_terminate).
333
325
  #
334
326
  # Does nothing if state == State::READY.
335
327
  def terminate
336
- self.state = State::TERMINATE unless self.state == State::READY
328
+ @state = State::TERMINATE unless state == State::READY
337
329
  self
338
330
  end
339
331
 
@@ -341,11 +333,6 @@ module Tap
341
333
  #
342
334
  # App.instance.info # => 'state: 0 (READY) queue: 0 results: 0'
343
335
  #
344
- # Provided information:
345
- #
346
- # state:: the integer and string values of self.state
347
- # queue:: the number of methods currently in the queue
348
- # results:: the total number of results in aggregator
349
336
  def info
350
337
  "state: #{state} (#{State.state_str(state)}) queue: #{queue.size} results: #{aggregator.size}"
351
338
  end
@@ -384,8 +371,8 @@ module Tap
384
371
  # Returns all aggregated results for the specified tasks. Results are
385
372
  # joined into a single array. Arrays of tasks are allowed as inputs.
386
373
  #
387
- # t1 = Task.new {|task, input| input += 1 }
388
- # t2 = Task.new {|task, input| input += 10 }
374
+ # t1 = Task.intern {|task, input| input += 1 }
375
+ # t2 = Task.intern {|task, input| input += 10 }
389
376
  # t3 = t2.initialize_batch_obj
390
377
  #
391
378
  # t1.enq(0)
@@ -403,18 +390,6 @@ module Tap
403
390
  "#<#{self.class.to_s}:#{object_id} root: #{root} >"
404
391
  end
405
392
 
406
- protected
407
-
408
- # A hook for handling unknown configurations in subclasses, called from
409
- # configure. If handle_configuration evaluates to false, then configure
410
- # raises an error.
411
- def handle_configuation(key, value)
412
- false
413
- end
414
-
415
- # Sets the state of the application
416
- attr_writer :state
417
-
418
393
  # TerminateErrors are raised to kill executing tasks when terminate is
419
394
  # called on an running App. They are handled by the run rescue code.
420
395
  class TerminateError < RuntimeError
@@ -1,7 +1,7 @@
1
1
  module Tap
2
2
  MAJOR = 0
3
3
  MINOR = 10
4
- TINY = 7
4
+ TINY = 8
5
5
 
6
6
  VERSION="#{MAJOR}.#{MINOR}.#{TINY}"
7
7
  WEBSITE="http://tap.rubyforge.org"
@@ -1,4 +1,4 @@
1
- require "#{File.dirname(__FILE__)}/../tap"
1
+ require File.dirname(__FILE__) + "/../tap"
2
2
  autoload(:OpenStruct, 'ostruct')
3
3
 
4
4
  module Tap
@@ -22,39 +22,49 @@ module Tap
22
22
  end
23
23
  end
24
24
 
25
- def self.set_declaration_base(base)
26
- # TODO -- warn if base is Object -- conflict with Rake
27
- declaration_base = base.to_s
28
- declaration_base = "" if ["Object", "Tap"].include?(declaration_base)
29
-
30
- base.instance_variable_set(:@tap_declaration_base, declaration_base.underscore)
31
- end
32
-
33
- def self.included(base)
34
- set_declaration_base(base)
25
+ module Rakish
26
+ def new(*args)
27
+ @instance ||= super
28
+ @instance.app.dependencies.register(@instance)
29
+ @instance
30
+ end
35
31
  end
36
-
32
+
37
33
  def self.extended(base)
38
- set_declaration_base(base)
34
+ declaration_base = base.to_s
35
+ case declaration_base
36
+ when "Object", "Tap", "main"
37
+ declaration_base = ""
38
+ end
39
+
40
+ base.instance_variable_set(:@declaration_base, declaration_base.underscore)
41
+ base.instance_variable_set(:@current_desc, nil)
42
+ end
43
+
44
+ def self.env
45
+ @env ||= Tap::Env.new(:load_paths => [], :command_paths => [], :generator_paths => [])
39
46
  end
40
47
 
41
- def tasc(*args, &block)
42
- # in this scheme, arg_names will be empty
43
- name, configs, dependencies, arg_names = resolve_args(args)
44
- declare(Tap::Task, name, configs, dependencies, arg_names, &block)
48
+ def env
49
+ @env ||= Declarations.env
45
50
  end
46
51
 
52
+ attr_accessor :declaration_base
53
+
54
+ attr_accessor :current_desc
55
+
47
56
  def task(*args, &block)
48
- name, configs, dependencies, arg_names = resolve_args(args)
49
-
50
- task_class = declare(Tap::Task, name, configs, dependencies, arg_names) do |*inputs|
57
+ const_name, configs, dependencies, arg_names = resolve_args(args)
58
+ task_class = declare(const_name, configs, dependencies) do |*inputs|
59
+ # collect inputs to make a rakish-args object
51
60
  args = {}
52
61
  arg_names.each do |arg_name|
53
62
  break if inputs.empty?
54
63
  args[arg_name] = inputs.shift
55
64
  end
56
-
57
65
  args = OpenStruct.new(args)
66
+
67
+ # execute each block assciated with this task
58
68
  self.class::BLOCKS.each do |task_block|
59
69
  case task_block.arity
60
70
  when 0 then task_block.call()
@@ -62,46 +72,37 @@ module Tap
62
72
  else task_block.call(self, args)
63
73
  end
64
74
  end
75
+
76
+ nil
65
77
  end
78
+ register_doc(task_class, arg_names)
66
79
 
80
+ # add the block to the task
67
81
  unless task_class.const_defined?(:BLOCKS)
68
82
  task_class.const_set(:BLOCKS, [])
69
83
  end
70
84
  task_class::BLOCKS << block unless block == nil
71
-
72
85
  task_class.instance
73
86
  end
74
87
 
75
- protected
76
-
77
- def config(key, value=nil, options={}, &block)
78
- if options[:desc] == nil
79
- caller[0] =~ Lazydoc::CALLER_REGEXP
80
- options[:desc] = Lazydoc.register($1, $3.to_i - 1)
81
- end
82
-
83
- [:config, key, value, options, block]
88
+ def namespace(name, &block)
89
+ current_base = declaration_base
90
+ @declaration_base = File.join(current_base, name.to_s.underscore)
91
+ yield
92
+ @declaration_base = current_base
84
93
  end
85
-
86
- def config_attr(key, value=nil, options={}, &block)
87
- if options[:desc] == nil
88
- caller[0] =~ Lazydoc::CALLER_REGEXP
89
- options[:desc] = Lazydoc.register($1, $3.to_i - 1)
90
- end
91
-
92
- [:config_attr, key, value, options, block]
93
- end
94
-
95
- def c
96
- Tap::Support::Validation
94
+
95
+ def desc(str)
96
+ self.current_desc = Lazydoc::Comment.new
97
+ current_desc.subject = str
97
98
  end
98
-
99
- private
100
99
 
101
- # Resolve the arguments for a task/rule. Returns a triplet of
102
- # [task_name, configs, prerequisites, arg_name_list].
100
+ protected
101
+
102
+ # Resolve the arguments for a task/rule. Returns an array of
103
+ # [task_name, configs, needs, arg_names].
103
104
  #
104
- # From Rake 0.8.3
105
+ # Adapted from Rake 0.8.3
105
106
  # Changes:
106
107
  # - no :needs support for the trailing Hash (which is now config)
107
108
  def resolve_args(args)
@@ -122,79 +123,88 @@ module Tap
122
123
 
123
124
  needs = needs.respond_to?(:to_ary) ? needs.to_ary : [needs]
124
125
  needs = needs.compact.collect do |need|
125
- dependency, argv = case need
126
- when Array then need
127
- else [need, []]
128
- end
129
-
130
- unless dependency.kind_of?(Class)
131
- dependency = declare(Tap::Task, dependency)
126
+ unless need.kind_of?(Class)
127
+ name = normalize_name(need).camelize
128
+ need = Support::Constant.constantize(name) do |base, constants|
129
+ declare(name)
130
+ end
132
131
  end
133
132
 
134
- if dependency.ancestors.include?(Tap::Task)
135
- [File.basename(dependency.default_name), dependency, argv]
136
- else
137
- raise ArgumentError, "malformed dependency declaration: #{need}"
133
+ unless need.ancestors.include?(Tap::Task)
134
+ raise ArgumentError, "not a task: #{need}"
138
135
  end
136
+
137
+ need
139
138
  end
140
139
 
141
- [task_name, configs, needs, arg_names]
140
+ [normalize_name(task_name), configs, needs, arg_names]
142
141
  end
143
-
144
- def arity(block)
145
- arity = block.arity
146
-
147
- case
148
- when arity > 0 then arity -= 1
149
- when arity < 0 then arity += 1
150
- end
151
-
152
- arity
142
+
143
+ def normalize_name(name)
144
+ name.to_s.underscore.tr(":", "/")
153
145
  end
154
146
 
155
- def declare(klass, name, configs={}, dependencies=[], arg_names=[], &block)
156
- # nest the constant name
157
- base = (self.kind_of?(Module) ? self : self.class).instance_variable_get(:@tap_declaration_base)
158
- name = File.join(base, name.to_s)
147
+ def declare(name, configs={}, dependencies=[], &block)
148
+ const_name = File.join(declaration_base, name).camelize
159
149
 
160
150
  # generate the subclass
161
- subclass = klass.subclass(name, configs, dependencies, &block)
162
-
163
- # register documentation
164
- caller[1] =~ Lazydoc::CALLER_REGEXP
165
- subclass.source_file = File.expand_path($1)
166
- lazydoc = subclass.lazydoc(false)
167
- lazydoc[subclass.to_s]['manifest'] = lazydoc.register($3.to_i - 1, Lazydoc::Declaration)
168
-
169
- if arg_names.empty?
170
- arity = block_given? ? arity(block) : -1
171
- case
172
- when arity > 0
173
- arg_names = Array.new(arity, "INPUT")
174
- when arity < 0
175
- arg_names = Array.new(-1 * arity - 1, "INPUT")
176
- arg_names << "INPUTS..."
151
+ subclass = Support::Constant.constantize(const_name) do |base, constants|
152
+ constants.each do |const|
153
+ # nesting Tasks into Tasks is required for
154
+ # namespaces with the same name as a task
155
+ base = base.const_set(const, Class.new(Tap::Task))
177
156
  end
157
+ base
158
+ end
159
+
160
+ subclass.extend Rakish
161
+
162
+ configs.each_pair do |key, value|
163
+ subclass.send(:config, key, value)
164
+ end
165
+
166
+ dependencies.each do |dependency|
167
+ dependency_name = File.basename(dependency.default_name)
168
+ subclass.send(:depends_on, dependency_name, dependency)
178
169
  end
179
170
 
180
- comment = Lazydoc::Comment.new
181
- comment.subject = arg_names.join(' ')
182
- lazydoc[subclass.to_s]['args'] = comment
171
+ if block_given?
172
+ subclass.send(:undef_method, :process) if subclass.method_defined?(:process)
173
+ subclass.send(:define_method, :process, &block)
174
+ end
183
175
 
184
176
  # update any dependencies in instance
185
- subclass.dependencies.each do |dependency, args|
186
- subclass.instance.depends_on(dependency.instance, *args)
177
+ subclass.dependencies.each do |dependency|
178
+ subclass.instance.depends_on(dependency.instance)
187
179
  end
188
180
 
189
- dir = File.dirname(lazydoc.source_file)
190
- manifest = Tap::Env.instance_for(dir).manifest(:tasks).build
181
+ # register the subclass in the manifest
182
+ manifest = env.tasks
191
183
  const_name = subclass.to_s
192
- unless manifest.entries.find {|lookup, const| const.name == const_name }
193
- manifest.entries << [const_name.underscore, Tap::Support::Constant.new(const_name, lazydoc.source_file)]
184
+ unless manifest.find {|const| const.name == const_name }
185
+ manifest.entries << Tap::Support::Constant.new(const_name)
194
186
  end
195
-
187
+
196
188
  subclass
197
189
  end
190
+
191
+ def register_doc(task_class, arg_names)
192
+
193
+ # register documentation
194
+ caller[1] =~ Lazydoc::CALLER_REGEXP
195
+ task_class.source_file = File.expand_path($1)
196
+ lazydoc = task_class.lazydoc(false)
197
+ lazydoc[task_class.to_s]['manifest'] = current_desc || lazydoc.register($3.to_i - 1, Lazydoc::Declaration)
198
+
199
+ if arg_names
200
+ comment = Lazydoc::Comment.new
201
+ comment.subject = arg_names.join(' ')
202
+ lazydoc[task_class.to_s]['args'] = comment
203
+ end
204
+
205
+ self.current_desc = nil
206
+ task_class
207
+ end
198
208
  end
199
209
 
200
210
  extend Declarations