drake 0.8.7.0.2.4 → 0.9.0.0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (132) hide show
  1. data/.gemtest +0 -0
  2. data/CHANGES +77 -9
  3. data/{CHANGES.drake → CHANGES-drake} +6 -2
  4. data/MIT-LICENSE +2 -0
  5. data/{README → README.rdoc} +30 -18
  6. data/Rakefile +144 -130
  7. data/Rakefile-drake +67 -0
  8. data/TODO +1 -1
  9. data/bin/drake +2 -0
  10. data/doc/command_line_usage.rdoc +25 -11
  11. data/doc/glossary.rdoc +2 -2
  12. data/doc/jamis.rb +2 -2
  13. data/doc/parallel.rdoc +37 -29
  14. data/doc/proto_rake.rdoc +22 -22
  15. data/doc/rake.1.gz +0 -0
  16. data/doc/rakefile.rdoc +56 -33
  17. data/doc/rational.rdoc +6 -6
  18. data/doc/release_notes/rake-0.4.15.rdoc +1 -1
  19. data/doc/release_notes/rake-0.5.0.rdoc +1 -1
  20. data/doc/release_notes/rake-0.7.0.rdoc +1 -1
  21. data/doc/release_notes/rake-0.7.2.rdoc +3 -3
  22. data/doc/release_notes/rake-0.7.3.rdoc +2 -2
  23. data/doc/release_notes/rake-0.8.0.rdoc +1 -1
  24. data/doc/release_notes/rake-0.8.2.rdoc +3 -3
  25. data/doc/release_notes/rake-0.8.3.rdoc +2 -2
  26. data/doc/release_notes/rake-0.8.4.rdoc +1 -1
  27. data/doc/release_notes/rake-0.8.5.rdoc +1 -1
  28. data/doc/release_notes/rake-0.8.6.rdoc +1 -1
  29. data/doc/release_notes/rake-0.8.7.rdoc +1 -1
  30. data/doc/release_notes/rake-0.9.0.rdoc +112 -0
  31. data/install.rb +14 -12
  32. data/lib/rake.rb +31 -2527
  33. data/lib/rake/alt_system.rb +7 -6
  34. data/lib/rake/application.rb +626 -0
  35. data/lib/rake/classic_namespace.rb +1 -0
  36. data/lib/rake/clean.rb +2 -4
  37. data/lib/rake/cloneable.rb +25 -0
  38. data/lib/rake/contrib/compositepublisher.rb +2 -5
  39. data/lib/rake/contrib/ftptools.rb +5 -8
  40. data/lib/rake/contrib/publisher.rb +2 -8
  41. data/lib/rake/contrib/rubyforgepublisher.rb +2 -4
  42. data/lib/rake/contrib/sshpublisher.rb +4 -6
  43. data/lib/rake/contrib/sys.rb +7 -25
  44. data/lib/rake/default_loader.rb +10 -0
  45. data/lib/rake/dsl.rb +2 -0
  46. data/lib/rake/dsl_definition.rb +143 -0
  47. data/lib/rake/early_time.rb +18 -0
  48. data/lib/rake/ext/core.rb +27 -0
  49. data/lib/rake/ext/module.rb +39 -0
  50. data/lib/rake/ext/string.rb +167 -0
  51. data/lib/rake/ext/time.rb +14 -0
  52. data/lib/rake/file_creation_task.rb +24 -0
  53. data/lib/rake/file_list.rb +403 -0
  54. data/lib/rake/file_task.rb +47 -0
  55. data/lib/rake/file_utils.rb +112 -0
  56. data/lib/rake/file_utils_ext.rb +142 -0
  57. data/lib/rake/gempackagetask.rb +6 -90
  58. data/lib/rake/invocation_chain.rb +51 -0
  59. data/lib/rake/invocation_exception_mixin.rb +16 -0
  60. data/lib/rake/loaders/makefile.rb +13 -15
  61. data/lib/rake/multi_task.rb +16 -0
  62. data/lib/rake/name_space.rb +25 -0
  63. data/lib/rake/packagetask.rb +13 -12
  64. data/lib/rake/parallel.rb +17 -28
  65. data/lib/rake/pathmap.rb +1 -0
  66. data/lib/rake/pseudo_status.rb +24 -0
  67. data/lib/rake/rake_module.rb +29 -0
  68. data/lib/rake/rake_test_loader.rb +10 -2
  69. data/lib/rake/rdoctask.rb +211 -190
  70. data/lib/rake/ruby182_test_unit_fix.rb +9 -7
  71. data/lib/rake/rule_recursion_overflow_error.rb +20 -0
  72. data/lib/rake/runtest.rb +4 -6
  73. data/lib/rake/task.rb +351 -0
  74. data/lib/rake/task_argument_error.rb +7 -0
  75. data/lib/rake/task_arguments.rb +74 -0
  76. data/lib/rake/task_manager.rb +307 -0
  77. data/lib/rake/tasklib.rb +1 -2
  78. data/lib/rake/testtask.rb +57 -27
  79. data/lib/rake/version.rb +13 -0
  80. data/lib/rake/win32.rb +4 -4
  81. data/test/contrib/test_sys.rb +8 -31
  82. data/test/data/access/Rakefile +33 -0
  83. data/test/data/comments/Rakefile +18 -0
  84. data/test/data/default/Rakefile +1 -1
  85. data/test/data/deprecated_import/Rakefile +1 -0
  86. data/test/data/dryrun/Rakefile +1 -1
  87. data/test/data/file_creation_task/Rakefile +1 -1
  88. data/test/data/namespace/Rakefile +9 -0
  89. data/test/data/rakelib/test1.rb +1 -0
  90. data/test/data/verbose/Rakefile +34 -0
  91. data/test/{filecreation.rb → file_creation.rb} +11 -7
  92. data/test/functional/functional_test.rb +25 -0
  93. data/test/{session_functional.rb → functional/session_based_tests.rb} +141 -23
  94. data/test/in_environment.rb +7 -5
  95. data/test/{test_application.rb → lib/application_test.rb} +331 -143
  96. data/test/{test_clean.rb → lib/clean_test.rb} +1 -0
  97. data/test/{test_definitions.rb → lib/definitions_test.rb} +4 -4
  98. data/test/lib/dsl_test.rb +52 -0
  99. data/test/{test_earlytime.rb → lib/earlytime_test.rb} +1 -2
  100. data/test/{test_extension.rb → lib/extension_test.rb} +2 -2
  101. data/test/{test_file_creation_task.rb → lib/file_creation_task_test.rb} +1 -1
  102. data/test/{test_file_task.rb → lib/file_task_test.rb} +9 -5
  103. data/test/{test_filelist.rb → lib/filelist_test.rb} +38 -24
  104. data/test/{test_fileutils.rb → lib/fileutils_test.rb} +27 -22
  105. data/test/{test_ftp.rb → lib/ftp_test.rb} +0 -0
  106. data/test/{test_invocation_chain.rb → lib/invocation_chain_test.rb} +0 -0
  107. data/test/{test_makefile_loader.rb → lib/makefile_loader_test.rb} +0 -0
  108. data/test/{test_multitask.rb → lib/multitask_test.rb} +3 -2
  109. data/test/{test_namespace.rb → lib/namespace_test.rb} +0 -0
  110. data/test/lib/package_task_test.rb +82 -0
  111. data/test/{test_parallel.rb → lib/parallel_test.rb} +5 -5
  112. data/test/{test_pathmap.rb → lib/pathmap_test.rb} +3 -2
  113. data/test/{test_pseudo_status.rb → lib/pseudo_status_test.rb} +0 -0
  114. data/test/{test_rake.rb → lib/rake_test.rb} +1 -1
  115. data/test/{test_rdoc_task.rb → lib/rdoc_task_test.rb} +19 -23
  116. data/test/{test_require.rb → lib/require_test.rb} +8 -2
  117. data/test/{test_rules.rb → lib/rules_test.rb} +4 -5
  118. data/test/{test_task_arguments.rb → lib/task_arguments_test.rb} +5 -5
  119. data/test/{test_task_manager.rb → lib/task_manager_test.rb} +15 -5
  120. data/test/{test_tasks.rb → lib/task_test.rb} +91 -28
  121. data/test/{test_tasklib.rb → lib/tasklib_test.rb} +0 -0
  122. data/test/{test_test_task.rb → lib/test_task_test.rb} +3 -3
  123. data/test/lib/testtask_test.rb +49 -0
  124. data/test/{test_top_level_functions.rb → lib/top_level_functions_test.rb} +5 -3
  125. data/test/{test_win32.rb → lib/win32_test.rb} +19 -0
  126. data/test/rake_test_setup.rb +6 -10
  127. data/test/ruby_version_test.rb +3 -0
  128. data/test/test_helper.rb +19 -0
  129. metadata +108 -66
  130. data/Rakefile.drake +0 -73
  131. data/test/functional.rb +0 -15
  132. data/test/test_package_task.rb +0 -118
@@ -1,10 +1,13 @@
1
- module Test
2
- module Unit
3
- module Collector
4
- class Dir
1
+ # Local Rake override to fix bug in Ruby 0.8.2
2
+ module Test # :nodoc:
3
+ # Local Rake override to fix bug in Ruby 0.8.2
4
+ module Unit # :nodoc:
5
+ # Local Rake override to fix bug in Ruby 0.8.2
6
+ module Collector # :nodoc:
7
+ # Local Rake override to fix bug in Ruby 0.8.2
8
+ class Dir # :nodoc:
5
9
  undef collect_file
6
- def collect_file(name, suites, already_gathered)
7
- # loadpath = $:.dup
10
+ def collect_file(name, suites, already_gathered) # :nodoc:
8
11
  dir = File.dirname(File.expand_path(name))
9
12
  $:.unshift(dir) unless $:.first == dir
10
13
  if(@req)
@@ -14,7 +17,6 @@ module Test
14
17
  end
15
18
  find_test_cases(already_gathered).each{|t| add_suite(suites, t.suite)}
16
19
  ensure
17
- # $:.replace(loadpath)
18
20
  $:.delete_at $:.rindex(dir)
19
21
  end
20
22
  end
@@ -0,0 +1,20 @@
1
+
2
+ module Rake
3
+
4
+ # Error indicating a recursion overflow error in task selection.
5
+ class RuleRecursionOverflowError < StandardError
6
+ def initialize(*args)
7
+ super
8
+ @targets = []
9
+ end
10
+
11
+ def add_target(target)
12
+ @targets << target
13
+ end
14
+
15
+ def message
16
+ super + ": [" + @targets.reverse.join(' => ') + "]"
17
+ end
18
+ end
19
+
20
+ end
data/lib/rake/runtest.rb CHANGED
@@ -1,5 +1,3 @@
1
- #!/usr/bin/env ruby
2
-
3
1
  require 'test/unit'
4
2
  require 'test/unit/assertions'
5
3
 
@@ -8,12 +6,12 @@ module Rake
8
6
 
9
7
  def run_tests(pattern='test/test*.rb', log_enabled=false)
10
8
  Dir["#{pattern}"].each { |fn|
11
- puts fn if log_enabled
9
+ $stderr.puts fn if log_enabled
12
10
  begin
13
- load fn
11
+ require fn
14
12
  rescue Exception => ex
15
- puts "Error in #{fn}: #{ex.message}"
16
- puts ex.backtrace
13
+ $stderr.puts "Error in #{fn}: #{ex.message}"
14
+ $stderr.puts ex.backtrace
17
15
  assert false
18
16
  end
19
17
  }
data/lib/rake/task.rb ADDED
@@ -0,0 +1,351 @@
1
+ require 'rake/invocation_exception_mixin'
2
+
3
+ module Rake
4
+
5
+ # #########################################################################
6
+ # A Task is the basic unit of work in a Rakefile. Tasks have associated
7
+ # actions (possibly more than one) and a list of prerequisites. When
8
+ # invoked, a task will first ensure that all of its prerequisites have an
9
+ # opportunity to run and then it will execute its own actions.
10
+ #
11
+ # Tasks are not usually created directly using the new method, but rather
12
+ # use the +file+ and +task+ convenience methods.
13
+ #
14
+ class Task
15
+ # List of prerequisites for a task.
16
+ attr_reader :prerequisites
17
+
18
+ # List of actions attached to a task.
19
+ attr_reader :actions
20
+
21
+ # Application owning this task.
22
+ attr_accessor :application
23
+
24
+ # Comment for this task. Restricted to a single line of no more than 50
25
+ # characters.
26
+ attr_reader :comment
27
+
28
+ # Full text of the (possibly multi-line) comment.
29
+ attr_reader :full_comment
30
+
31
+ # Array of nested namespaces names used for task lookup by this task.
32
+ attr_reader :scope
33
+
34
+ # File/Line locations of each of the task definitions for this
35
+ # task (only valid if the task was defined with the detect
36
+ # location option set).
37
+ attr_reader :locations
38
+
39
+ # Return task name
40
+ def to_s
41
+ name
42
+ end
43
+
44
+ def inspect
45
+ "<#{self.class} #{name} => [#{prerequisites.join(', ')}]>"
46
+ end
47
+
48
+ # List of sources for task.
49
+ attr_writer :sources
50
+ def sources
51
+ @sources ||= []
52
+ end
53
+
54
+ # List of prerequisite tasks
55
+ def prerequisite_tasks
56
+ prerequisites.collect { |pre| lookup_prerequisite(pre) }
57
+ end
58
+
59
+ def lookup_prerequisite(prerequisite_name)
60
+ application[prerequisite_name, @scope]
61
+ end
62
+ private :lookup_prerequisite
63
+
64
+ # First source from a rule (nil if no sources)
65
+ def source
66
+ @sources.first if defined?(@sources)
67
+ end
68
+
69
+ # Create a task named +task_name+ with no actions or prerequisites. Use
70
+ # +enhance+ to add actions and prerequisites.
71
+ def initialize(task_name, app)
72
+ @name = task_name.to_s
73
+ @prerequisites = []
74
+ @actions = []
75
+ @already_invoked = false
76
+ @full_comment = nil
77
+ @comment = nil
78
+ @lock = Monitor.new
79
+ @application = app
80
+ @scope = app.current_scope
81
+ @arg_names = nil
82
+ @locations = []
83
+ end
84
+
85
+ # Enhance a task with prerequisites or actions. Returns self.
86
+ def enhance(deps=nil, &block)
87
+ @prerequisites |= deps if deps
88
+ @actions << block if block_given?
89
+ self
90
+ end
91
+
92
+ # Name of the task, including any namespace qualifiers.
93
+ def name
94
+ @name.to_s
95
+ end
96
+
97
+ # Name of task with argument list description.
98
+ def name_with_args # :nodoc:
99
+ if arg_description
100
+ "#{name}#{arg_description}"
101
+ else
102
+ name
103
+ end
104
+ end
105
+
106
+ # Argument description (nil if none).
107
+ def arg_description # :nodoc:
108
+ @arg_names ? "[#{(arg_names || []).join(',')}]" : nil
109
+ end
110
+
111
+ # Name of arguments for this task.
112
+ def arg_names
113
+ @arg_names || []
114
+ end
115
+
116
+ # Reenable the task, allowing its tasks to be executed if the task
117
+ # is invoked again.
118
+ def reenable
119
+ @already_invoked = false
120
+ end
121
+
122
+ # Clear the existing prerequisites and actions of a rake task.
123
+ def clear
124
+ clear_prerequisites
125
+ clear_actions
126
+ self
127
+ end
128
+
129
+ # Clear the existing prerequisites of a rake task.
130
+ def clear_prerequisites
131
+ prerequisites.clear
132
+ self
133
+ end
134
+
135
+ # Clear the existing actions on a rake task.
136
+ def clear_actions
137
+ actions.clear
138
+ self
139
+ end
140
+
141
+ # Invoke the task if it is needed. Prerequisites are invoked first.
142
+ def invoke(*args)
143
+ if application.options.threads == 1
144
+ invoke_serial(*args)
145
+ else
146
+ invoke_parallel(*args)
147
+ end
148
+ end
149
+
150
+ def invoke_serial(*args) # :nodoc:
151
+ task_args = TaskArguments.new(arg_names, args)
152
+ invoke_with_call_chain(task_args, InvocationChain::EMPTY)
153
+ end
154
+
155
+ # Same as invoke, but explicitly pass a call chain to detect
156
+ # circular dependencies.
157
+ def invoke_with_call_chain(task_args, invocation_chain) # :nodoc:
158
+ new_chain = InvocationChain.append(self, invocation_chain)
159
+ if application.options.threads == 1
160
+ @lock.synchronize do
161
+ return unless prepare_invoke
162
+ invoke_prerequisites(task_args, new_chain)
163
+ execute(task_args) if needed?
164
+ end
165
+ else
166
+ return unless prepare_invoke
167
+ # see parallel.rb
168
+ collect_for_parallel_execution(task_args, new_chain, invocation_chain)
169
+ end
170
+ rescue Exception => ex
171
+ add_chain_to(ex, new_chain)
172
+ raise ex
173
+ end
174
+ protected :invoke_with_call_chain
175
+
176
+ def prepare_invoke # :nodoc:
177
+ if application.options.randomize
178
+ @prerequisites = @prerequisites.sort_by { rand }
179
+ end
180
+ if application.options.trace
181
+ $stderr.puts "** Invoke #{name} #{format_trace_flags}"
182
+ end
183
+ return if @already_invoked
184
+ @already_invoked = true
185
+ end
186
+ private :prepare_invoke
187
+
188
+ def add_chain_to(exception, new_chain)
189
+ exception.extend(InvocationExceptionMixin) unless exception.respond_to?(:chain)
190
+ exception.chain = new_chain if exception.chain.nil?
191
+ end
192
+ private :add_chain_to
193
+
194
+ # Invoke all the prerequisites of a task.
195
+ def invoke_prerequisites(task_args, invocation_chain) # :nodoc:
196
+ prereqs = prerequisite_tasks
197
+ prereqs.each { |prereq|
198
+ prereq_args = task_args.new_scope(prereq.arg_names)
199
+ prereq.invoke_with_call_chain(prereq_args, invocation_chain)
200
+ }
201
+ prereqs
202
+ end
203
+
204
+ # Format the trace flags for display.
205
+ def format_trace_flags
206
+ flags = []
207
+ flags << "first_time" unless @already_invoked
208
+ flags << "not_needed" unless needed?
209
+ flags.empty? ? "" : "(" + flags.join(", ") + ")"
210
+ end
211
+ private :format_trace_flags
212
+
213
+ # Execute the actions associated with this task.
214
+ def execute(args=nil)
215
+ args ||= EMPTY_TASK_ARGS
216
+ if application.options.dryrun
217
+ $stderr.puts "** Execute (dry run) #{name}"
218
+ return
219
+ end
220
+ if application.options.trace
221
+ $stderr.puts "** Execute #{name}"
222
+ end
223
+ application.enhance_with_matching_rule(name) if @actions.empty?
224
+ @actions.each do |act|
225
+ case act.arity
226
+ when 1
227
+ act.call(self)
228
+ else
229
+ act.call(self, args)
230
+ end
231
+ end
232
+ end
233
+
234
+ # Is this task needed?
235
+ def needed?
236
+ true
237
+ end
238
+
239
+ # Timestamp for this task. Basic tasks return the current time for their
240
+ # time stamp. Other tasks can be more sophisticated.
241
+ def timestamp
242
+ prerequisite_tasks.collect { |pre| pre.timestamp }.max || Time.now
243
+ end
244
+
245
+ # Add a description to the task. The description can consist of an option
246
+ # argument list (enclosed brackets) and an optional comment.
247
+ def add_description(description)
248
+ return if ! description
249
+ comment = description.strip
250
+ add_comment(comment) if comment && ! comment.empty?
251
+ end
252
+
253
+ # Writing to the comment attribute is the same as adding a description.
254
+ def comment=(description)
255
+ add_description(description)
256
+ end
257
+
258
+ # Add a comment to the task. If a comment already exists, separate
259
+ # the new comment with " / ".
260
+ def add_comment(comment)
261
+ if @full_comment
262
+ @full_comment << " / "
263
+ else
264
+ @full_comment = ''
265
+ end
266
+ @full_comment << comment
267
+ if @full_comment =~ /\A([^.]+?\.)( |$)/
268
+ @comment = $1
269
+ else
270
+ @comment = @full_comment
271
+ end
272
+ end
273
+ private :add_comment
274
+
275
+ # Set the names of the arguments for this task. +args+ should be
276
+ # an array of symbols, one for each argument name.
277
+ def set_arg_names(args)
278
+ @arg_names = args.map { |a| a.to_sym }
279
+ end
280
+
281
+ # Return a string describing the internal state of a task. Useful for
282
+ # debugging.
283
+ def investigation
284
+ result = "------------------------------\n"
285
+ result << "Investigating #{name}\n"
286
+ result << "class: #{self.class}\n"
287
+ result << "task needed: #{needed?}\n"
288
+ result << "timestamp: #{timestamp}\n"
289
+ result << "pre-requisites: \n"
290
+ prereqs = prerequisite_tasks
291
+ prereqs.sort! {|a,b| a.timestamp <=> b.timestamp}
292
+ prereqs.each do |p|
293
+ result << "--#{p.name} (#{p.timestamp})\n"
294
+ end
295
+ latest_prereq = prerequisite_tasks.collect { |pre| pre.timestamp }.max
296
+ result << "latest-prerequisite time: #{latest_prereq}\n"
297
+ result << "................................\n\n"
298
+ return result
299
+ end
300
+
301
+ # ----------------------------------------------------------------
302
+ # Rake Module Methods
303
+ #
304
+ class << self
305
+
306
+ # Clear the task list. This cause rake to immediately forget all the
307
+ # tasks that have been assigned. (Normally used in the unit tests.)
308
+ def clear
309
+ Rake.application.clear
310
+ end
311
+
312
+ # List of all defined tasks.
313
+ def tasks
314
+ Rake.application.tasks
315
+ end
316
+
317
+ # Return a task with the given name. If the task is not currently
318
+ # known, try to synthesize one from the defined rules. If no rules are
319
+ # found, but an existing file matches the task name, assume it is a file
320
+ # task with no dependencies or actions.
321
+ def [](task_name)
322
+ Rake.application[task_name]
323
+ end
324
+
325
+ # TRUE if the task name is already defined.
326
+ def task_defined?(task_name)
327
+ Rake.application.lookup(task_name) != nil
328
+ end
329
+
330
+ # Define a task given +args+ and an option block. If a rule with the
331
+ # given name already exists, the prerequisites and actions are added to
332
+ # the existing task. Returns the defined task.
333
+ def define_task(*args, &block)
334
+ Rake.application.define_task(self, *args, &block)
335
+ end
336
+
337
+ # Define a rule for synthesizing tasks.
338
+ def create_rule(*args, &block)
339
+ Rake.application.create_rule(*args, &block)
340
+ end
341
+
342
+ # Apply the scope to the task name according to the rules for
343
+ # this kind of task. Generic tasks will accept the scope as
344
+ # part of the name.
345
+ def scope_name(scope, task_name)
346
+ (scope + [task_name]).join(':')
347
+ end
348
+
349
+ end # class << Rake::Task
350
+ end # class Rake::Task
351
+ end
@@ -0,0 +1,7 @@
1
+ module Rake
2
+
3
+ # Error indicating an ill-formed task declaration.
4
+ class TaskArgumentError < ArgumentError
5
+ end
6
+
7
+ end
@@ -0,0 +1,74 @@
1
+ module Rake
2
+
3
+ ####################################################################
4
+ # TaskArguments manage the arguments passed to a task.
5
+ #
6
+ class TaskArguments
7
+ include Enumerable
8
+
9
+ attr_reader :names
10
+
11
+ # Create a TaskArgument object with a list of named arguments
12
+ # (given by :names) and a set of associated values (given by
13
+ # :values). :parent is the parent argument object.
14
+ def initialize(names, values, parent=nil)
15
+ @names = names
16
+ @parent = parent
17
+ @hash = {}
18
+ names.each_with_index { |name, i|
19
+ @hash[name.to_sym] = values[i] unless values[i].nil?
20
+ }
21
+ end
22
+
23
+ # Create a new argument scope using the prerequisite argument
24
+ # names.
25
+ def new_scope(names)
26
+ values = names.collect { |n| self[n] }
27
+ self.class.new(names, values, self)
28
+ end
29
+
30
+ # Find an argument value by name or index.
31
+ def [](index)
32
+ lookup(index.to_sym)
33
+ end
34
+
35
+ # Specify a hash of default values for task arguments. Use the
36
+ # defaults only if there is no specific value for the given
37
+ # argument.
38
+ def with_defaults(defaults)
39
+ @hash = defaults.merge(@hash)
40
+ end
41
+
42
+ def each(&block)
43
+ @hash.each(&block)
44
+ end
45
+
46
+ def method_missing(sym, *args, &block)
47
+ lookup(sym.to_sym)
48
+ end
49
+
50
+ def to_hash
51
+ @hash
52
+ end
53
+
54
+ def to_s
55
+ @hash.inspect
56
+ end
57
+
58
+ def inspect
59
+ to_s
60
+ end
61
+
62
+ protected
63
+
64
+ def lookup(name)
65
+ if @hash.has_key?(name)
66
+ @hash[name]
67
+ elsif @parent
68
+ @parent.lookup(name)
69
+ end
70
+ end
71
+ end
72
+
73
+ EMPTY_TASK_ARGS = TaskArguments.new([], [])
74
+ end