rake 0.5.0 → 0.5.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rake might be problematic. Click here for more details.

data/CHANGES CHANGED
@@ -1,5 +1,21 @@
1
1
  = Rake Changelog
2
2
 
3
+ == Version 0.5.3
4
+
5
+ * Added support for importing Rakefile and other dependencies.
6
+ * Fixed bug so that now rules can chain off of existing tasks as well
7
+ as existing files.
8
+ * Fixed verbose flag bug in the testing task. Shortened some failure
9
+ messages.
10
+ * Make FileUtils methods private at the top level module to avoid
11
+ accidental method leaking into other objects.
12
+ * Added test loader option to test task. "testrb" is no longer the
13
+ default test loader. It is now eating syntax errors that should
14
+ halt the unit tests.
15
+ * Revamped FileList so that it works more like and array (addressed
16
+ flatten bug). Added many tests around file list.
17
+ * Added +ext+ method to both String and FileList.
18
+
3
19
  == Version 0.5.0
4
20
 
5
21
  * Fixed documentation that was lacking the Rake module name (Tilman
@@ -10,7 +26,7 @@
10
26
  * The jamis rdoc template is only used if it exists.
11
27
  * Added fix for Ruby 1.8.2 test/unit and rails problem.
12
28
  * Added contributed rake man file (Jani Monoses).
13
- * Added Brian Chandler's fix for problems in --trace and --dry-run
29
+ * Added Brian Candler's fix for problems in --trace and --dry-run
14
30
  mode.
15
31
 
16
32
  == Version 0.4.15
data/Rakefile CHANGED
@@ -19,6 +19,7 @@ require 'rake/rdoctask'
19
19
  CLEAN.include('**/*.o')
20
20
  CLOBBER.include('doc/example/main', 'testdata')
21
21
  CLOBBER.include('test/data/**/temp_*')
22
+ CLOBBER.include('test/data/chains/play.*')
22
23
 
23
24
 
24
25
  def announce(msg='')
@@ -45,11 +46,16 @@ SRC_RB = FileList['lib/**/*.rb']
45
46
  # The default task is run if rake is given no explicit arguments.
46
47
 
47
48
  desc "Default Task"
48
- task :default => :testall
49
+ task :default => :alltests
49
50
 
50
51
  # Test Tasks ---------------------------------------------------------
51
52
 
52
- Rake::TestTask.new(:testall) do |t|
53
+ task :a => :alltests
54
+ task :f => :funtests
55
+ task :u => :unittests
56
+ task :c => :contribtests
57
+
58
+ Rake::TestTask.new(:alltests) do |t|
53
59
  t.test_files = FileList[
54
60
  'test/test*.rb',
55
61
  'test/contrib/test*.rb',
@@ -59,36 +65,37 @@ Rake::TestTask.new(:testall) do |t|
59
65
  t.verbose = true
60
66
  end
61
67
 
62
- Rake::TestTask.new(:test) do |t|
68
+ Rake::TestTask.new(:unittests) do |t|
63
69
  t.test_files = FileList['test/test*.rb']
64
70
  t.warning = true if t.respond_to? :warning
65
71
  t.verbose = true
66
72
  end
67
73
 
68
- Rake::TestTask.new(:testfun) do |t|
74
+ Rake::TestTask.new(:funtests) do |t|
69
75
  t.pattern = 'test/fun*.rb'
70
76
  t.warning = true if t.respond_to? :warning
71
77
  end
72
78
 
73
- Rake::TestTask.new(:testcontrib) do |t|
79
+ Rake::TestTask.new(:contribtests) do |t|
74
80
  t.pattern = 'test/contrib/test*.rb'
75
81
  t.verbose = true
76
82
  t.warning = true if t.respond_to? :warning
77
83
  end
78
84
 
79
85
  directory 'testdata'
80
- task :test => ['testdata']
81
-
86
+ [:alltests, :unittests, :contribtests, :funtests].each do |t|
87
+ task t => ['testdata']
88
+ end
82
89
 
83
90
  # Abbreviations
84
91
 
85
- task :ta => [:testall]
86
- task :tf => [:testfun]
87
- task :tc => [:testcontrib]
92
+ task :a => [:alltests]
93
+ task :u => [:unittests]
94
+ task :f => [:funtests]
95
+ task :c => [:contribtests]
88
96
 
89
97
  # CVS Tasks ----------------------------------------------------------
90
98
 
91
-
92
99
  # Install rake using the standard install.rb script.
93
100
 
94
101
  desc "Install the application"
@@ -268,7 +275,7 @@ desc "Make a new release"
268
275
  task :release => [
269
276
  :prerelease,
270
277
  :clobber,
271
- :testall,
278
+ :alltests,
272
279
  :update_version,
273
280
  :package,
274
281
  :tag] do
@@ -6,7 +6,7 @@ of Rake available.
6
6
  == Changes
7
7
 
8
8
  * Fixed bug where missing intermediate file dependencies could cause
9
- an abort with --trace or --dry-run. (Brian Chandler)
9
+ an abort with --trace or --dry-run. (Brian Candler)
10
10
 
11
11
  * Recursive rules are now supported (Tilman Sauerbeck).
12
12
 
@@ -46,7 +46,7 @@ Download:: http://rubyforge.org/project/showfiles.php?group_id=50
46
46
  Lots of people provided input to this release. Thanks to Tilman
47
47
  Sauerbeck for numerous patches, documentation fixes and suggestions.
48
48
  And for also pushing me to get this release out. Also, thanks to
49
- Brian Chandler for the finding and fixing --trace/dry-run fix. That
49
+ Brian Candler for the finding and fixing --trace/dry-run fix. That
50
50
  was an obscure bug. Also to Eric Hodel for some good suggestions.
51
51
 
52
52
  -- Jim Weirich
@@ -29,7 +29,7 @@
29
29
  # referenced as a library via a require statement, but it can be
30
30
  # distributed independently as an application.
31
31
 
32
- RAKEVERSION = '0.5.0'
32
+ RAKEVERSION = '0.5.3'
33
33
 
34
34
  require 'rbconfig'
35
35
  require 'ftools'
@@ -43,6 +43,76 @@ $trace = nil
43
43
  $dryrun = nil
44
44
  $silent = false
45
45
 
46
+ # Some objects are dupable, some are not. So we define a version of
47
+ # dup (called rake_dup) that returns self on the handful of classes
48
+ # that are not dupable.
49
+
50
+ module Kernel
51
+ # Duplicate an object if it can be duplicated. If it can not be
52
+ # cloned or duplicated, then just return the original object.
53
+ def rake_dup()
54
+ dup
55
+ end
56
+ end
57
+
58
+ [NilClass, FalseClass, TrueClass, Fixnum, Symbol].each do |clazz|
59
+ clazz.class_eval {
60
+ # Duplicate an object if it can be duplicated. If it can not be
61
+ # cloned or duplicated, then just return the original object.
62
+ def rake_dup() self end
63
+ }
64
+ end
65
+
66
+ ######################################################################
67
+ # User defined methods to be added to String.
68
+ #
69
+ class String
70
+ unless instance_methods.include? "ext"
71
+ # Replace the file extension with +newext+. If there is no
72
+ # extenson on the string, append the new extension to the end. If
73
+ # the new extension is not given, or is the empty string, remove
74
+ # any existing extension.
75
+ #
76
+ # +ext+ is a user added method for the String class.
77
+ def ext(newext='')
78
+ return self.dup if ['.', '..'].include? self
79
+ if newext != ''
80
+ newext = (newext =~ /^\./) ? newext : ("." + newext)
81
+ end
82
+ dup.sub!(%r(([^/\\])\.[^./\\]*$)) { $1 + newext } || self + newext
83
+ end
84
+ end
85
+ end
86
+
87
+
88
+ ######################################################################
89
+ module Rake
90
+
91
+ class << self
92
+ # Current Rake Application
93
+ def application
94
+ @application ||= RakeApp.new
95
+ end
96
+
97
+ def application=(app)
98
+ fail "RakeApp already exists" if defined?(@application)
99
+ @application = app
100
+ end
101
+ end
102
+
103
+ module Cloneable
104
+ def clone
105
+ sibling = self.class.new
106
+ instance_variables.each do |ivar|
107
+ value = self.instance_variable_get(ivar)
108
+ sibling.instance_variable_set(ivar, value.rake_dup)
109
+ end
110
+ sibling
111
+ end
112
+ alias dup clone
113
+ end
114
+ end
115
+
46
116
  ######################################################################
47
117
  # A Task is the basic unit of work in a Rakefile. Tasks have
48
118
  # associated actions (possibly more than one) and a list of
@@ -71,7 +141,7 @@ class Task
71
141
  # use +enhance+ to add actions and prerequisites.
72
142
  def initialize(task_name)
73
143
  @name = task_name
74
- @prerequisites = []
144
+ @prerequisites = FileList[]
75
145
  @actions = []
76
146
  @already_invoked = false
77
147
  @comment = nil
@@ -146,7 +216,7 @@ class Task
146
216
  $last_comment = nil
147
217
  end
148
218
 
149
- # Class Methods ----------------------------------------------------
219
+ # Rake Module Methods ----------------------------------------------
150
220
 
151
221
  class << self
152
222
 
@@ -170,13 +240,13 @@ class Task
170
240
  def [](task_name)
171
241
  task_name = task_name.to_s
172
242
  if task = TASKS[task_name]
173
- return task
243
+ return task
174
244
  end
175
245
  if task = enhance_with_matching_rule(task_name)
176
- return task
246
+ return task
177
247
  end
178
248
  if File.exist?(task_name)
179
- return FileTask.define_task(task_name)
249
+ return FileTask.define_task(task_name)
180
250
  end
181
251
  fail "Don't know how to build task '#{task_name}'"
182
252
  end
@@ -221,28 +291,28 @@ class Task
221
291
  # the enhanced task or nil of no rule was found.
222
292
  def enhance_with_matching_rule(task_name, level=0)
223
293
  fail Rake::RuleRecursionOverflowError,
224
- "Rule Recursion Too Deep" if level >= 16
294
+ "Rule Recursion Too Deep" if level >= 16
225
295
  RULES.each do |pattern, extensions, block|
226
- if md = pattern.match(task_name)
227
- ext = extensions.first
228
- case ext
229
- when String
230
- source = task_name.sub(/\.[^.]*$/, ext)
231
- when Proc
232
- source = ext.call(task_name)
233
- else
234
- fail "Don't know how to handle rule dependent: #{ext.inspect}"
235
- end
236
- if File.exist?(source)
237
- task = FileTask.define_task({task_name => [source]}, &block)
238
- task.source = source
239
- return task
240
- elsif parent = enhance_with_matching_rule(source, level+1)
241
- task = FileTask.define_task({task_name => [parent.name]}, &block)
242
- task.source = parent.name
243
- return task
244
- end
245
- end
296
+ if md = pattern.match(task_name)
297
+ ext = extensions.first
298
+ case ext
299
+ when String
300
+ source = task_name.sub(/\.[^.]*$/, ext)
301
+ when Proc
302
+ source = ext.call(task_name)
303
+ else
304
+ fail "Don't know how to handle rule dependent: #{ext.inspect}"
305
+ end
306
+ if File.exist?(source) || Task.task_defined?(source)
307
+ task = FileTask.define_task({task_name => [source]}, &block)
308
+ task.source = source
309
+ return task
310
+ elsif parent = enhance_with_matching_rule(source, level+1)
311
+ task = FileTask.define_task({task_name => [parent.name]}, &block)
312
+ task.source = parent.name
313
+ return task
314
+ end
315
+ end
246
316
  end
247
317
  nil
248
318
  rescue Rake::RuleRecursionOverflowError => ex
@@ -256,14 +326,14 @@ class Task
256
326
  def resolve_args(args)
257
327
  case args
258
328
  when Hash
259
- fail "Too Many Task Names: #{args.keys.join(' ')}" if args.size > 1
260
- fail "No Task Name Given" if args.size < 1
261
- task_name = args.keys[0]
262
- deps = args[task_name]
263
- deps = [deps] if (String===deps) || (Regexp===deps) || (Proc===deps)
329
+ fail "Too Many Task Names: #{args.keys.join(' ')}" if args.size > 1
330
+ fail "No Task Name Given" if args.size < 1
331
+ task_name = args.keys[0]
332
+ deps = args[task_name]
333
+ deps = [deps] if (String===deps) || (Regexp===deps) || (Proc===deps)
264
334
  else
265
- task_name = args
266
- deps = []
335
+ task_name = args
336
+ deps = []
267
337
  end
268
338
  [task_name, deps]
269
339
  end
@@ -367,6 +437,14 @@ def desc(comment)
367
437
  $last_comment = comment
368
438
  end
369
439
 
440
+ # Import the partial Rakekfile +fn+.
441
+ #
442
+ # Example:
443
+ # import ".depend"
444
+ #
445
+ def import(fn)
446
+ Rake.application.add_import(fn)
447
+ end
370
448
 
371
449
  ######################################################################
372
450
  # This a FileUtils extension that defines several additional commands
@@ -401,8 +479,10 @@ module FileUtils
401
479
  options = {}
402
480
  end
403
481
  unless block_given?
482
+ show_command = cmd.join(" ")
483
+ show_command = show_command[0,42] + "..." if show_command.length > 45
404
484
  block = lambda { |ok, status|
405
- ok or fail "Command failed with status (#{status.exitstatus}): [#{cmd.join(" ")}]"
485
+ ok or fail "Command failed with status (#{status.exitstatus}): [#{show_command}]"
406
486
  }
407
487
  end
408
488
  fu_check_options options, :noop, :verbose
@@ -440,10 +520,10 @@ module FileUtils
440
520
  cp(*args)
441
521
  else
442
522
  begin
443
- ln(*args)
523
+ ln(*args)
444
524
  rescue Errno::EOPNOTSUPP
445
- LN_SUPPORTED[0] = false
446
- cp(*args)
525
+ LN_SUPPORTED[0] = false
526
+ cp(*args)
447
527
  end
448
528
  end
449
529
  end
@@ -478,9 +558,9 @@ module RakeFileUtils
478
558
  module_eval(<<-EOS, __FILE__, __LINE__ + 1)
479
559
  def #{name}( *args, &block )
480
560
  super(*fu_merge_option(args,
481
- :verbose => $fileutils_verbose,
482
- :noop => $fileutils_nowrite),
483
- &block)
561
+ :verbose => $fileutils_verbose,
562
+ :noop => $fileutils_nowrite),
563
+ &block)
484
564
  end
485
565
  EOS
486
566
  end
@@ -499,9 +579,9 @@ module RakeFileUtils
499
579
  $fileutils_verbose = value unless value.nil?
500
580
  if block_given?
501
581
  begin
502
- yield
582
+ yield
503
583
  ensure
504
- $fileutils_verbose = oldvalue
584
+ $fileutils_verbose = oldvalue
505
585
  end
506
586
  end
507
587
  $fileutils_verbose
@@ -521,9 +601,9 @@ module RakeFileUtils
521
601
  $fileutils_nowrite = value unless value.nil?
522
602
  if block_given?
523
603
  begin
524
- yield
604
+ yield
525
605
  ensure
526
- $fileutils_nowrite = oldvalue
606
+ $fileutils_nowrite = oldvalue
527
607
  end
528
608
  end
529
609
  oldvalue
@@ -566,8 +646,20 @@ module RakeFileUtils
566
646
 
567
647
  end
568
648
 
649
+ ######################################################################
650
+ # Include the FileUtils file manipulation functions in the top level
651
+ # module, but mark them private so that they don't unintentionally
652
+ # define methods on other objects.
653
+
654
+ file_utils_methods = (FileUtils.methods - Object.methods)
569
655
  include RakeFileUtils
570
656
 
657
+ file_utils_methods.each do |name|
658
+ private name.to_sym
659
+ end
660
+ file_utils_methods = nil
661
+
662
+ ######################################################################
571
663
  module Rake
572
664
 
573
665
  class RuleRecursionOverflowError < StandardError
@@ -589,27 +681,82 @@ module Rake
589
681
  # A FileList is essentially an array with a few helper methods
590
682
  # defined to make file manipulation a bit easier.
591
683
  #
592
- class FileList < Array
684
+ # FileLists are lazy. When given a list of glob patterns for
685
+ # possible files to be included in the file list, instead of
686
+ # searching the file structures to find the files, a FileList holds
687
+ # the pattern for latter use.
688
+ #
689
+ # This allows us to define a number of FileList to match any number of
690
+ # files, but only search out the actual files when then FileList
691
+ # itself is actually used. The key is that the first time an
692
+ # element of the FileList/Array is requested, the pending patterns
693
+ # are resolved into a real list of file names.
694
+ #
695
+ class FileList
593
696
 
594
- # Rewrite all array methods (and to_s/inspect) to resolve the list
595
- # before running.
596
- method_list = Array.instance_methods - Object.instance_methods
597
- %w[to_a inspect].each do |meth|
598
- method_list << meth unless method_list.include? meth
599
- end
600
- method_list.each_with_index do |sym, i|
601
- if sym =~ /^[A-Za-z_]+$/
602
- name = sym
697
+ include Cloneable
698
+
699
+ # == Method Delegation
700
+ #
701
+ # The lazy evaluation magic of FileLists happens by implementing
702
+ # all the array specific methods to call +resolve+ before
703
+ # delegating the heavy lifting to an embedded array object
704
+ # (@items).
705
+ #
706
+ # In addition, there are two kinds of delegation calls. The
707
+ # regular kind delegates to the @items array and returns the
708
+ # result directly. Well, almost directly. It checks if the
709
+ # returned value is the @items object itself, and if so will
710
+ # return the FileList object instead.
711
+ #
712
+ # The second kind of delegation call is used in methods that
713
+ # normally return a new Array object. We want to capture the
714
+ # return value of these methods and wrap them in a new FileList
715
+ # object. We enumerate these methods in the +SPECIAL_RETURN+ list
716
+ # below.
717
+
718
+ # List of array methods (that are not in +Object+) that need to be
719
+ # delegated.
720
+ ARRAY_METHODS = Array.instance_methods - Object.instance_methods
721
+
722
+ # List of additional methods that must be delegated.
723
+ MUST_DEFINE = %w[to_a inspect]
724
+
725
+ # List of methods that should not be delegated here (we define
726
+ # special versions of them explicitly below).
727
+ MUST_NOT_DEFINE = %w[to_a to_ary partition *]
728
+
729
+ # List of delegated methods that return new array values which
730
+ # need wrapping.
731
+ SPECIAL_RETURN = %w[
732
+ map collect sort sort_by select find_all reject grep
733
+ compact flatten uniq values_at
734
+ + - & |
735
+ ]
736
+
737
+ DELEGATING_METHODS = (ARRAY_METHODS + MUST_DEFINE - MUST_NOT_DEFINE).sort.uniq
738
+
739
+ # Now do the delegation.
740
+ DELEGATING_METHODS.each_with_index do |sym, i|
741
+ if SPECIAL_RETURN.include?(sym)
742
+ ln = __LINE__+1
743
+ class_eval %{
744
+ def #{sym}(*args, &block)
745
+ resolve if @pending
746
+ result = @items.send(:#{sym}, *args, &block)
747
+ FileList.new.import(result)
748
+ end
749
+ }, __FILE__, ln
603
750
  else
604
- name = i
751
+ ln = __LINE__+1
752
+ class_eval %{
753
+ def #{sym}(*args, &block)
754
+ resolve if @pending
755
+ result = @items.send(:#{sym}, *args, &block)
756
+ result.object_id == @items.object_id ? self : result
757
+ end
758
+ }, __FILE__, ln
605
759
  end
606
- alias_method "array_#{name}", sym
607
- class_eval %{
608
- def #{sym}(*args, &block)
609
- resolve if @pending
610
- array_#{name}(*args, &block)
611
- end
612
- }
613
760
  end
614
761
 
615
762
  # Create a file list from the globbable patterns given. If you
@@ -628,6 +775,7 @@ module Rake
628
775
  @pending = false
629
776
  @exclude_patterns = DEFAULT_IGNORE_PATTERNS.dup
630
777
  @exclude_re = nil
778
+ @items = []
631
779
  patterns.each { |pattern| include(pattern) }
632
780
  yield self if block_given?
633
781
  end
@@ -667,72 +815,102 @@ module Rake
667
815
  # FileList['a.c', 'b.c'].exclude("a.*") => ['a.c', 'b.c']
668
816
  #
669
817
  def exclude(*patterns)
670
- # TODO: check for pending
671
818
  patterns.each do |pat| @exclude_patterns << pat end
672
819
  if ! @pending
673
- calculate_exclude_regexp
674
- reject! { |fn| fn =~ @exclude_re }
820
+ calculate_exclude_regexp
821
+ reject! { |fn| fn =~ @exclude_re }
675
822
  end
676
823
  self
677
824
  end
678
825
 
679
826
 
827
+ # Clear all the exclude patterns so that we exclude nothing.
680
828
  def clear_exclude
681
829
  @exclude_patterns = []
682
830
  calculate_exclude_regexp if ! @pending
683
831
  end
684
832
 
833
+ # Define equality.
834
+ def ==(array)
835
+ to_ary == array
836
+ end
837
+
838
+ # Return the internal array object.
839
+ def to_a
840
+ resolve
841
+ @items
842
+ end
843
+
844
+ # Return the internal array object.
845
+ def to_ary
846
+ resolve
847
+ @items
848
+ end
849
+
850
+ # Redefine * to return either a string or a new file list.
851
+ def *(other)
852
+ result = @items * other
853
+ case result
854
+ when Array
855
+ FileList.new.import(result)
856
+ else
857
+ result
858
+ end
859
+ end
860
+
685
861
  # Resolve all the pending adds now.
686
862
  def resolve
687
- @pending = false
688
- @pending_add.each do |fn| resolve_add(fn) end
689
- @pending_add = []
690
- resolve_exclude
863
+ if @pending
864
+ @pending = false
865
+ @pending_add.each do |fn| resolve_add(fn) end
866
+ @pending_add = []
867
+ resolve_exclude
868
+ end
691
869
  self
692
870
  end
693
871
 
694
872
  def calculate_exclude_regexp
695
873
  ignores = []
696
874
  @exclude_patterns.each do |pat|
697
- case pat
698
- when Regexp
699
- ignores << pat
700
- when /[*.]/
701
- Dir[pat].each do |p| ignores << p end
702
- else
703
- ignores << Regexp.quote(pat)
704
- end
875
+ case pat
876
+ when Regexp
877
+ ignores << pat
878
+ when /[*.]/
879
+ Dir[pat].each do |p| ignores << p end
880
+ else
881
+ ignores << Regexp.quote(pat)
882
+ end
705
883
  end
706
884
  if ignores.empty?
707
- @exclude_re = /^$/
885
+ @exclude_re = /^$/
708
886
  else
709
- re_str = ignores.collect { |p| "(" + p.to_s + ")" }.join("|")
710
- @exclude_re = Regexp.new(re_str)
887
+ re_str = ignores.collect { |p| "(" + p.to_s + ")" }.join("|")
888
+ @exclude_re = Regexp.new(re_str)
711
889
  end
712
890
  end
713
891
 
714
892
  def resolve_add(fn)
715
893
  case fn
716
894
  when Array
717
- fn.each { |f| self.resolve_add(f) }
895
+ fn.each { |f| self.resolve_add(f) }
718
896
  when %r{[*?]}
719
- add_matching(fn)
897
+ add_matching(fn)
720
898
  else
721
- self << fn
899
+ self << fn
722
900
  end
723
901
  end
724
902
 
725
903
  def resolve_exclude
726
904
  @exclude_patterns.each do |pat|
727
- case pat
728
- when Regexp
729
- reject! { |fn| fn =~ pat }
730
- when /[*.]/
731
- reject_list = Dir[pat]
732
- reject! { |fn| reject_list.include?(fn) }
733
- else
734
- reject! { |fn| fn == pat }
735
- end
905
+ case pat
906
+ when Regexp
907
+ reject! { |fn| fn =~ pat }
908
+ when /[*.]/
909
+ reject_list = Dir[pat]
910
+ reject! { |fn| reject_list.include?(fn) }
911
+ else
912
+ reject! { |fn| fn == pat }
913
+ end
736
914
  end
737
915
  self
738
916
  end
@@ -770,6 +948,30 @@ module Rake
770
948
  self
771
949
  end
772
950
 
951
+ # Return a new array with <tt>String#ext</tt> method applied to
952
+ # each member of the array.
953
+ #
954
+ # This method is a shortcut for:
955
+ #
956
+ # array.collect { |item| item.ext(newext) }
957
+ #
958
+ # +ext+ is a user added method for the Array class.
959
+ def ext(newext='')
960
+ collect { |fn| fn.ext(newext) }
961
+ end
962
+
963
+
964
+ # FileList version of partition. Needed because the nested arrays
965
+ # should be FileLists in this version.
966
+ def partition(&block) # :nodoc:
967
+ resolve
968
+ result = @items.partition(&block)
969
+ [
970
+ FileList.new.import(result[0]),
971
+ FileList.new.import(result[1]),
972
+ ]
973
+ end
974
+
773
975
  # Convert a FileList to a string by joining all elements with a space.
774
976
  def to_s
775
977
  resolve if @pending
@@ -779,7 +981,7 @@ module Rake
779
981
  # Add matching glob patterns.
780
982
  def add_matching(pattern)
781
983
  Dir[pattern].each do |fn|
782
- self << fn unless exclude?(fn)
984
+ self << fn unless exclude?(fn)
783
985
  end
784
986
  end
785
987
  private :add_matching
@@ -798,12 +1000,17 @@ module Rake
798
1000
  ]
799
1001
  @exclude_patterns = DEFAULT_IGNORE_PATTERNS.dup
800
1002
 
1003
+ def import(array)
1004
+ @items = array
1005
+ self
1006
+ end
1007
+
801
1008
  class << self
802
1009
  # Create a new file list including the files listed. Similar to:
803
1010
  #
804
1011
  # FileList.new(*args)
805
1012
  def [](*args)
806
- new(*args)
1013
+ new(*args)
807
1014
  end
808
1015
 
809
1016
  # Set the ignore patterns back to the default value. The
@@ -817,12 +1024,12 @@ module Rake
817
1024
  # ignored by Ruby's glob patterns and are not specifically
818
1025
  # listed in the ignore patterns.
819
1026
  def select_default_ignore_patterns
820
- @exclude_patterns = DEFAULT_IGNORE_PATTERNS.dup
1027
+ @exclude_patterns = DEFAULT_IGNORE_PATTERNS.dup
821
1028
  end
822
1029
 
823
1030
  # Clear the ignore patterns.
824
1031
  def clear_ignore_patterns
825
- @exclude_patterns = [ /^$/ ]
1032
+ @exclude_patterns = [ /^$/ ]
826
1033
  end
827
1034
  end
828
1035
  end
@@ -831,6 +1038,17 @@ end
831
1038
  # Alias FileList to be available at the top level.
832
1039
  FileList = Rake::FileList
833
1040
 
1041
+ ######################################################################
1042
+ module Rake
1043
+
1044
+ # Default Rakefile loader used by +import+.
1045
+ class DefaultLoader
1046
+ def load(fn)
1047
+ Kernel.load fn
1048
+ end
1049
+ end
1050
+ end
1051
+
834
1052
  ######################################################################
835
1053
  # Rake main application object. When invoking +rake+ from the command
836
1054
  # line, a RakeApp object is created and run.
@@ -872,7 +1090,12 @@ class RakeApp
872
1090
  # Create a RakeApp object.
873
1091
  def initialize
874
1092
  @rakefile = nil
1093
+ @pending_imports = []
1094
+ @imported = []
875
1095
  @nosearch = false
1096
+ @loaders = {}
1097
+ @default_loader = Rake::DefaultLoader.new
1098
+ Rake.application = self
876
1099
  end
877
1100
 
878
1101
  # True if one of the files in RAKEFILES is in the current directory.
@@ -880,8 +1103,8 @@ class RakeApp
880
1103
  def have_rakefile
881
1104
  RAKEFILES.each do |fn|
882
1105
  if File.exist?(fn)
883
- @rakefile = fn
884
- return true
1106
+ @rakefile = fn
1107
+ return true
885
1108
  end
886
1109
  end
887
1110
  return false
@@ -900,9 +1123,9 @@ class RakeApp
900
1123
  puts
901
1124
  OPTIONS.sort.each do |long, short, mode, desc|
902
1125
  if mode == GetoptLong::REQUIRED_ARGUMENT
903
- if desc =~ /\b([A-Z]{2,})\b/
904
- long = long + "=#{$1}"
905
- end
1126
+ if desc =~ /\b([A-Z]{2,})\b/
1127
+ long = long + "=#{$1}"
1128
+ end
906
1129
  end
907
1130
  printf " %-20s (%s)\n", long, short
908
1131
  printf " %s\n", desc
@@ -918,7 +1141,7 @@ class RakeApp
918
1141
  }.max
919
1142
  Task.tasks.each do |t|
920
1143
  if t.comment
921
- printf "rake %-#{width}s # %s\n", t.name, t.comment
1144
+ printf "rake %-#{width}s # %s\n", t.name, t.comment
922
1145
  end
923
1146
  end
924
1147
  end
@@ -993,13 +1216,14 @@ class RakeApp
993
1216
  while ! have_rakefile
994
1217
  Dir.chdir("..")
995
1218
  if Dir.pwd == here || @nosearch
996
- fail "No Rakefile found (looking for: #{RAKEFILES.join(', ')})"
1219
+ fail "No Rakefile found (looking for: #{RAKEFILES.join(', ')})"
997
1220
  end
998
1221
  here = Dir.pwd
999
1222
  end
1000
1223
  puts "(in #{Dir.pwd})" unless $silent
1001
1224
  $rakefile = @rakefile
1002
1225
  load @rakefile
1226
+ load_imports
1003
1227
  end
1004
1228
 
1005
1229
  # Collect the list of tasks on the command line. If no tasks are
@@ -1009,15 +1233,39 @@ class RakeApp
1009
1233
  tasks = []
1010
1234
  ARGV.each do |arg|
1011
1235
  if arg =~ /^(\w+)=(.*)$/
1012
- ENV[$1] = $2
1236
+ ENV[$1] = $2
1013
1237
  else
1014
- tasks << arg
1238
+ tasks << arg
1015
1239
  end
1016
1240
  end
1017
1241
  tasks.push("default") if tasks.size == 0
1018
1242
  tasks
1019
1243
  end
1020
1244
 
1245
+ # Add a file to the list of files to be imported.
1246
+ def add_import(fn)
1247
+ @pending_imports << fn
1248
+ end
1249
+
1250
+ # Load the pending list of imported files.
1251
+ def load_imports
1252
+ while fn = @pending_imports.shift
1253
+ next if @imported.member?(fn)
1254
+ Task[fn].invoke if Task.task_defined?(fn)
1255
+ ext = File.extname(fn)
1256
+ loader = @loaders[ext] || @default_loader
1257
+ loader.load(fn)
1258
+ @imported << fn
1259
+ end
1260
+ end
1261
+
1262
+ # Add a loader to handle imported files ending in the extension
1263
+ # +ext+.
1264
+ def add_loader(ext, loader)
1265
+ ext = ".#{ext}" unless ext =~ /^\./
1266
+ @loaders[ext] = loader
1267
+ end
1268
+
1021
1269
  # Run the +rake+ application.
1022
1270
  def run
1023
1271
  handle_options
@@ -1025,19 +1273,19 @@ class RakeApp
1025
1273
  tasks = collect_tasks
1026
1274
  load_rakefile
1027
1275
  if $show_tasks
1028
- display_tasks_and_comments
1276
+ display_tasks_and_comments
1029
1277
  elsif $show_prereqs
1030
- display_prerequisites
1278
+ display_prerequisites
1031
1279
  else
1032
- tasks.each { |task_name| Task[task_name].invoke }
1280
+ tasks.each { |task_name| Task[task_name].invoke }
1033
1281
  end
1034
1282
  rescue Exception => ex
1035
1283
  puts "rake aborted!"
1036
1284
  puts ex.message
1037
1285
  if $trace
1038
- puts ex.backtrace.join("\n")
1286
+ puts ex.backtrace.join("\n")
1039
1287
  else
1040
- puts ex.backtrace.find {|str| str =~ /#{@rakefile}/ } || ""
1288
+ puts ex.backtrace.find {|str| str =~ /#{@rakefile}/ } || ""
1041
1289
  end
1042
1290
  exit(1)
1043
1291
  end