rant 0.3.2 → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/rant/rantlib.rb CHANGED
@@ -13,38 +13,6 @@ require 'rant/rantenv'
13
13
  require 'rant/rantfile'
14
14
  require 'rant/rantsys'
15
15
 
16
- module Rant
17
- VERSION = '0.3.2'
18
-
19
- # Those are the filenames for rantfiles.
20
- # Case matters!
21
- RANTFILES = [ "Rantfile",
22
- "rantfile",
23
- "Rantfile.rb",
24
- "rantfile.rb",
25
- ]
26
-
27
- # Names of plugins and imports for which code was loaded.
28
- # Files that where loaded with the `import' commant are directly
29
- # added; files loaded with the `plugin' command are prefixed with
30
- # "plugin/".
31
- CODE_IMPORTS = []
32
-
33
- class RantAbortException < StandardError
34
- end
35
-
36
- class RantDoneException < StandardError
37
- end
38
-
39
- class RantfileException < StandardError
40
- end
41
-
42
- # This module is a namespace for generator classes.
43
- module Generators
44
- end
45
-
46
- end
47
-
48
16
  # There is one problem with executing Rantfiles in a special context:
49
17
  # In the top-level execution environment, there are some methods
50
18
  # available which are not available to all objects. One example is the
@@ -56,6 +24,9 @@ end
56
24
  Rant::MAIN_OBJECT = self
57
25
 
58
26
  class Array
27
+
28
+ # Concatenates all elements like #join(' ') but also puts quotes
29
+ # around strings that contain a space.
59
30
  def arglist
60
31
  self.shell_pathes.join(' ')
61
32
  end
@@ -82,6 +53,16 @@ class Array
82
53
  end
83
54
  end
84
55
 
56
+ class String
57
+ def sub_ext(ext, new_ext = nil)
58
+ if new_ext
59
+ self.sub(/#{Regexp.escape ext}$/, new_ext)
60
+ else
61
+ self.sub(/\.[^.]+$/, ".#{ext}")
62
+ end
63
+ end
64
+ end
65
+
85
66
  module Rant::Lib
86
67
 
87
68
  # Parses one string (elem) as it occurs in the array
@@ -89,51 +70,13 @@ module Rant::Lib
89
70
  # E.g.:
90
71
  # p parse_caller_elem "/usr/local/lib/ruby/1.8/irb/workspace.rb:52:in `irb_binding'"
91
72
  # prints:
92
- # {:method=>"irb_binding", :ln=>52, :file=>"/usr/local/lib/ruby/1.8/irb/workspace.rb"}
73
+ # {:ln=>52, :file=>"/usr/local/lib/ruby/1.8/irb/workspace.rb"}
93
74
  def parse_caller_elem elem
94
75
  parts = elem.split(":")
95
- rh = { :file => parts[0],
96
- :ln => parts[1].to_i
97
- }
98
- =begin
99
- # commented for better performance
100
- meth = parts[2]
101
- if meth && meth =~ /\`(\w+)'/
102
- meth = $1
103
- end
104
- rh[:method] = meth
105
- =end
106
- rh
76
+ { :file => parts[0], :ln => parts[1].to_i }
107
77
  end
108
-
109
78
  module_function :parse_caller_elem
110
79
 
111
- # currently unused
112
- class Caller
113
- def self.[](i)
114
- new(caller[i+1])
115
- end
116
- def initialize(clr)
117
- @clr = clr
118
- @file = @ln = nil
119
- end
120
- def file
121
- unless @file
122
- ca = Lib.parse_caller_elem(clr)
123
- @file = ca[:file]
124
- @ln = ca[:ln]
125
- end
126
- @file
127
- end
128
- def ln
129
- unless @ln
130
- ca = Lib.parse_caller_elem(clr)
131
- @file = ca[:file]
132
- @ln = ca[:ln]
133
- end
134
- @ln
135
- end
136
- end
137
80
  end
138
81
 
139
82
  # The methods in this module are the public interface to Rant that can
@@ -141,62 +84,69 @@ end
141
84
  module RantContext
142
85
  include Rant::Generators
143
86
 
87
+ Env = Rant::Env
88
+ FileList = Rant::FileList
89
+
144
90
  # Define a basic task.
145
91
  def task targ, &block
146
- rantapp.task(targ, &block)
92
+ rac.task(targ, &block)
147
93
  end
148
94
 
149
95
  # Define a file task.
150
96
  def file targ, &block
151
- rantapp.file(targ, &block)
97
+ rac.file(targ, &block)
152
98
  end
153
99
 
154
100
  # Add code and/or prerequisites to existing task.
155
101
  def enhance targ, &block
156
- rantapp.enhance(targ, &block)
102
+ rac.enhance(targ, &block)
157
103
  end
158
104
 
159
105
  def desc(*args)
160
- rantapp.desc(*args)
106
+ rac.desc(*args)
161
107
  end
162
108
 
163
109
  def gen(*args, &block)
164
- rantapp.gen(*args, &block)
110
+ rac.gen(*args, &block)
165
111
  end
166
112
 
167
113
  def import(*args, &block)
168
- rantapp.import(*args, &block)
114
+ rac.import(*args, &block)
169
115
  end
170
116
 
171
117
  def plugin(*args, &block)
172
- rantapp.plugin(*args, &block)
118
+ rac.plugin(*args, &block)
173
119
  end
174
120
 
175
121
  # Look in the subdirectories, given by args,
176
122
  # for rantfiles.
177
123
  def subdirs *args
178
- rantapp.subdirs(*args)
124
+ rac.subdirs(*args)
179
125
  end
180
126
 
181
127
  def source rantfile
182
- rantapp.source(rantfile)
128
+ rac.source(rantfile)
129
+ end
130
+
131
+ def sys(*args, &block)
132
+ rac.sys(*args)
183
133
  end
184
134
 
185
- def sys *args
186
- rantapp.sys(*args)
135
+ def var(*args, &block)
136
+ rac.var(*args, &block)
187
137
  end
188
138
  end # module RantContext
189
139
 
190
140
  class RantAppContext
191
- include Rant
192
141
  include RantContext
193
142
 
194
143
  def initialize(app)
195
- @rantapp = app
144
+ @rac = app
196
145
  end
197
146
 
198
- def rantapp
199
- @rantapp
147
+ # +rac+ stands for "rant compiler"
148
+ def rac
149
+ @rac
200
150
  end
201
151
 
202
152
  def method_missing(sym, *args)
@@ -212,11 +162,10 @@ class RantAppContext
212
162
  end
213
163
 
214
164
  module Rant
215
- include RantContext
216
165
 
217
166
  # In the class definition of Rant::RantApp, this will be set to a
218
167
  # new application object.
219
- @@rantapp = nil
168
+ @@rac = nil
220
169
 
221
170
  class << self
222
171
 
@@ -246,42 +195,30 @@ module Rant
246
195
  def run(first_arg=nil, *other_args)
247
196
  other_args = other_args.flatten
248
197
  args = first_arg.nil? ? ARGV.dup : ([first_arg] + other_args)
249
- if @@rantapp && !@@rantapp.ran?
250
- @@rantapp.args.replace(args.flatten)
251
- @@rantapp.run
198
+ if @@rac && !@@rac.ran?
199
+ @@rac.args.replace(args.flatten)
200
+ @@rac.run
252
201
  else
253
- @@rantapp = Rant::RantApp.new(args)
254
- @@rantapp.run
202
+ @@rac = Rant::RantApp.new(args)
203
+ @@rac.run
255
204
  end
256
205
  end
257
206
 
258
- def rantapp
259
- @@rantapp
207
+ def rac
208
+ @@rac
260
209
  end
261
210
 
262
- def rantapp=(app)
263
- @@rantapp = app
211
+ def rac=(app)
212
+ @@rac = app
264
213
  end
265
214
 
266
215
  # "Clear" the current Rant application. After this call,
267
216
  # Rant has the same state as immediately after startup.
268
217
  def reset
269
- @@rantapp = nil
218
+ @@rac = nil
270
219
  end
271
220
  end
272
221
 
273
- def rantapp
274
- @@rantapp
275
- end
276
-
277
- # Pre 0.2.7: Manually making necessary methods module
278
- # functions. Note that it caused problems with caller
279
- # parsing when the Rantfile did a `require "rant"' (irb!).
280
- #module_function :task, :file, :desc, :subdirs,
281
- # :gen, :source, :enhance, :sys, :plugin
282
-
283
- extend self
284
-
285
222
  end # module Rant
286
223
 
287
224
  class Rant::RantApp
@@ -290,6 +227,9 @@ class Rant::RantApp
290
227
  # Important: We try to synchronize all tasks referenced indirectly
291
228
  # by @rantfiles with the task hash @tasks. The task hash is
292
229
  # intended for fast task lookup per task name.
230
+ #
231
+ # All tasks are registered to the system by the +prepare_task+
232
+ # method.
293
233
 
294
234
  # The RantApp class has no own state.
295
235
 
@@ -323,6 +263,8 @@ class Rant::RantApp
323
263
  [ "--trace-abort", GetoptLong::NO_ARGUMENT, nil ],
324
264
  ]
325
265
 
266
+ # Reference project's root directory in task names by preceding
267
+ # them with this character.
326
268
  ROOT_DIR_ID = "#"
327
269
  ESCAPE_ID = "\\"
328
270
 
@@ -342,16 +284,14 @@ class Rant::RantApp
342
284
  # may be called through an instance_eval on this object (e.g. from
343
285
  # plugins).
344
286
  attr_reader :context
345
- # The [] and []= operators may be used to set/get values from this
346
- # object (like a hash). It is intended to let the different
347
- # modules, plugins and tasks to communicate to each other.
348
- attr_reader :var
287
+ alias cx context
349
288
  # A hash with all tasks. For fast task lookup use this hash with
350
289
  # the taskname as key.
351
290
  attr_reader :tasks
352
- # A list with of all imports (code loaded with +import+).
291
+ # A list of all imports (code loaded with +import+).
353
292
  attr_reader :imports
354
-
293
+ # Current subdirectory relative to project's root directory
294
+ # (#rootdir).
355
295
  attr_reader :current_subdir
356
296
 
357
297
  def initialize *args
@@ -359,7 +299,7 @@ class Rant::RantApp
359
299
  # Rantfiles will be loaded in the context of this object.
360
300
  @context = RantAppContext.new(self)
361
301
  @sys = ::Rant::SysObject.new(self)
362
- Rant.rantapp ||= self
302
+ Rant.rac ||= self
363
303
  @rantfiles = []
364
304
  @tasks = {}
365
305
  @opts = {
@@ -373,6 +313,7 @@ class Rant::RantApp
373
313
  @done = false
374
314
  @plugins = []
375
315
  @var = Rant::RantVar::Space.new
316
+ @var.query :ignore, :AutoList, []
376
317
  @imports = []
377
318
 
378
319
  @task_show = nil
@@ -380,7 +321,7 @@ class Rant::RantApp
380
321
 
381
322
  @orig_pwd = nil
382
323
  @current_subdir = ""
383
-
324
+ @resolve_hooks = []
384
325
  end
385
326
 
386
327
  def [](opt)
@@ -412,22 +353,6 @@ class Rant::RantApp
412
353
  ### experimental support for subdirectories ######################
413
354
  def expand_project_path(path)
414
355
  expand_path(@current_subdir, path)
415
- =begin
416
- case path
417
- when nil: @current_subdir.dup
418
- when "": @current_subdir.dup
419
- when /^#/: path.sub(/^#/, '')
420
- when /^\\#/: path.sub(/^\\/, '')
421
- else
422
- #puts "epp: current_subdir: #@current_subdir"
423
- if @current_subdir.empty?
424
- # we are in project's root directory
425
- path
426
- else
427
- File.join(@current_subdir, path)
428
- end
429
- end
430
- =end
431
356
  end
432
357
  def expand_path(subdir, path)
433
358
  case path
@@ -456,7 +381,8 @@ class Rant::RantApp
456
381
  def goto(dir)
457
382
  # TODO: optimize
458
383
  p_dir = expand_project_path(dir)
459
- abs_path = project_to_fs_path(dir)
384
+ base = rootdir.empty? ? Dir.pwd : rootdir
385
+ abs_path = p_dir.empty? ? base : File.join(base, p_dir)
460
386
  @current_subdir = p_dir
461
387
  unless Dir.pwd == abs_path
462
388
  #puts "pwd: #{Dir.pwd}; abs_path: #{abs_path}"
@@ -466,6 +392,7 @@ class Rant::RantApp
466
392
  #STDERR.puts "rant: in #{p_dir}"
467
393
  end
468
394
  end
395
+ # +dir+ is a path relative to +rootdir+
469
396
  def goto_project_dir(dir)
470
397
  # TODO: optimize
471
398
  goto "##{dir}"
@@ -512,6 +439,7 @@ class Rant::RantApp
512
439
  end
513
440
  # run tasks
514
441
  run_tasks
442
+ goto "#"
515
443
  raise Rant::RantDoneException
516
444
  rescue Rant::RantDoneException
517
445
  @done = true
@@ -522,6 +450,10 @@ class Rant::RantApp
522
450
  err_msg "Invalid Rantfile: " + $!.message
523
451
  $stderr.puts "rant aborted!"
524
452
  return 1
453
+ rescue Rant::RantError
454
+ err_msg $!.message, $!.backtrace[0..4]
455
+ $stderr.puts "rant aborted!"
456
+ return 1
525
457
  rescue Rant::RantAbortException
526
458
  $stderr.puts "rant aborted!"
527
459
  return 1
@@ -535,7 +467,7 @@ class Rant::RantApp
535
467
  @plugins.each { |plugin| plugin.rant_quit }
536
468
  # restore pwd
537
469
  Dir.pwd != @orig_pwd && Dir.chdir(@orig_pwd)
538
- Rant.rantapp = self.class.new
470
+ Rant.rac = self.class.new
539
471
  end
540
472
 
541
473
  ###### methods accessible through RantContext ####################
@@ -573,14 +505,6 @@ class Rant::RantApp
573
505
  file = ch[:file]
574
506
  # validate args
575
507
  generator = args.shift
576
- # Let modules/classes from the Generator namespace override
577
- # other generators.
578
- begin
579
- if generator.is_a? Module
580
- generator = ::Rant::Generators.const_get(generator.to_s)
581
- end
582
- rescue NameError, ArgumentError
583
- end
584
508
  unless generator.respond_to? :rant_generate
585
509
  abort(pos_text(file, ln),
586
510
  "First argument to `gen' has to be a task-generator.")
@@ -591,20 +515,23 @@ class Rant::RantApp
591
515
 
592
516
  # Currently ignores block.
593
517
  def import(*args, &block)
518
+ ch = Rant::Lib::parse_caller_elem(caller[1])
594
519
  if block
595
- warn_msg "import: currently ignoring block"
520
+ warn_msg pos_text(ch[:file], ch[:ln]),
521
+ "import: ignoring block"
596
522
  end
597
523
  args.flatten.each { |arg|
598
524
  unless String === arg
599
- abort("import: currently " +
600
- "only strings are allowed as arguments")
525
+ abort(pos_text(ch[:file], ch[:ln]),
526
+ "import: only strings allowed as arguments")
601
527
  end
602
528
  unless @imports.include? arg
603
529
  unless Rant::CODE_IMPORTS.include? arg
604
530
  begin
605
531
  require "rant/import/#{arg}"
606
532
  rescue LoadError => e
607
- abort("No such import - #{arg}")
533
+ abort(pos_text(ch[:file], ch[:ln]),
534
+ "No such import - #{arg}")
608
535
  end
609
536
  Rant::CODE_IMPORTS << arg.dup
610
537
  end
@@ -683,9 +610,11 @@ class Rant::RantApp
683
610
  def source rantfile
684
611
  rf, is_new = rantfile_for_path(rantfile)
685
612
  return false unless is_new
613
+ build rantfile
686
614
  unless rf.exist?
687
- abort("source: No such file to load - #{rantfile}")
615
+ abort("source: No such file - #{rantfile}")
688
616
  end
617
+
689
618
  load_file rf
690
619
  true
691
620
  end
@@ -704,7 +633,7 @@ class Rant::RantApp
704
633
  end
705
634
  unless arg.is_a? String
706
635
  abort(pos_text(file, ln),
707
- "in `subdirs' command: arguments must be strings")
636
+ "subdirs: arguments must be strings")
708
637
  end
709
638
  loaded = false
710
639
  prev_subdir = @current_subdir
@@ -727,22 +656,32 @@ class Rant::RantApp
727
656
  goto_project_dir prev_subdir
728
657
  end
729
658
  unless loaded || quiet?
730
- warn_msg(pos_text(file, ln) + "; in `subdirs' command:",
731
- "No Rantfile in subdir `#{arg}'.")
659
+ warn_msg(pos_text(file, ln),
660
+ "subdirs: No Rantfile in subdir `#{arg}'.")
732
661
  end
733
662
  }
734
663
  rescue SystemCallError => e
735
- abort(pos_text(file, ln),
736
- "in `subdirs' command: " + e.message)
664
+ abort(pos_text(file, ln), "subdirs: " + e.message)
737
665
  end
738
666
 
739
- def sys(*args)
667
+ def sys(*args, &block)
740
668
  if args.empty?
741
669
  @sys
742
670
  else
743
671
  @sys.sh(*args)
744
672
  end
745
673
  end
674
+
675
+ # The [] and []= operators may be used to set/get values from this
676
+ # object (like a hash). It is intended to let the different
677
+ # modules, plugins and tasks to communicate with each other.
678
+ def var(*args, &block)
679
+ if args.empty?
680
+ @var
681
+ else
682
+ @var.query(*args, &block)
683
+ end
684
+ end
746
685
  ##################################################################
747
686
 
748
687
  # Pop (remove and return) current pending task description.
@@ -759,6 +698,12 @@ class Rant::RantApp
759
698
  raise Rant::RantAbortException
760
699
  end
761
700
 
701
+ def abort_at(ch, *msg)
702
+ err_msg(pos_text(ch[:file], ch[:ln]), msg)
703
+ $stderr.puts caller if @opts[:trace_abort]
704
+ raise Rant::RantAbortException
705
+ end
706
+
762
707
  def help
763
708
  puts "rant [-f RANTFILE] [OPTIONS] tasks..."
764
709
  puts
@@ -769,27 +714,56 @@ class Rant::RantApp
769
714
 
770
715
  def show_descriptions
771
716
  tlist = select_tasks { |t| t.description }
717
+ # +target_list+ aborts if no task defined, so we can be sure
718
+ # that +default+ is not nil
719
+ def_target = target_list.first
772
720
  if tlist.empty?
773
- msg "No described targets."
721
+ puts "rant # => " + list_task_names(
722
+ resolve(def_target)).join(', ')
723
+ msg "No described tasks."
774
724
  return
775
725
  end
776
726
  prefix = "rant "
777
727
  infix = " # "
778
728
  name_length = 0
779
729
  tlist.each { |t|
780
- if t.name.length > name_length
781
- name_length = t.name.length
730
+ if t.full_name.length > name_length
731
+ name_length = t.full_name.length
782
732
  end
783
733
  }
784
734
  name_length < 7 && name_length = 7
785
735
  cmd_length = prefix.length + name_length
736
+ # TODO: show what's done if rant is invoked without argument
737
+ unless tlist.first.full_name == def_target
738
+ defaults = list_task_names(
739
+ resolve(def_target)).join(', ')
740
+ puts "#{prefix}#{' ' * name_length}#{infix}=> #{defaults}"
741
+ end
786
742
  tlist.each { |t|
787
- print(prefix + t.name.ljust(name_length) + infix)
743
+ print(prefix + t.full_name.ljust(name_length) + infix)
788
744
  dt = t.description.sub(/\s+$/, "")
789
745
  puts dt.sub("\n", "\n" + ' ' * cmd_length + infix + " ")
790
746
  }
791
747
  true
792
748
  end
749
+ def list_task_names(*tasks)
750
+ rsl = []
751
+ tasks.flatten.each { |t|
752
+ if t.respond_to?(:has_actions?) && t.has_actions?
753
+ rsl << t
754
+ elsif t.respond_to? :prerequisites
755
+ if t.prerequisites.empty?
756
+ rsl << t
757
+ else
758
+ rsl.concat(list_task_names(t.prerequisites))
759
+ end
760
+ else
761
+ rsl << t
762
+ end
763
+ }
764
+ rsl
765
+ end
766
+ private :list_task_names
793
767
 
794
768
  # Increase verbosity.
795
769
  def more_verbose
@@ -864,8 +838,8 @@ class Rant::RantApp
864
838
  not @rantfiles.all? { |f| f.tasks.empty? }
865
839
  end
866
840
 
867
- def run_tasks
868
- unless have_any_task?
841
+ def target_list
842
+ if !have_any_task? && @resolve_hooks.empty?
869
843
  abort("No tasks defined for this rant application!")
870
844
  end
871
845
 
@@ -876,49 +850,81 @@ class Rant::RantApp
876
850
  target_list = @force_targets + @arg_targets
877
851
  # The target list is a list of strings, not Task objects!
878
852
  if target_list.empty?
879
- have_default = @rantfiles.any? { |f|
880
- f.tasks.any? { |t| t.name == "default" }
881
- }
882
- if have_default
853
+ def_tasks = resolve "default"
854
+ #have_default = @rantfiles.any? { |f|
855
+ # f.tasks.any? { |t| t.name == "default" }
856
+ #}
857
+ unless def_tasks.empty?
883
858
  target_list << "default"
884
859
  else
885
860
  first = nil
886
861
  @rantfiles.each { |f|
887
862
  unless f.tasks.empty?
888
- first = f.tasks.first.name
863
+ first = f.tasks.first.full_name
889
864
  break
890
865
  end
891
866
  }
892
867
  target_list << first
893
868
  end
894
869
  end
870
+ target_list
871
+ end
872
+
873
+ def run_tasks
895
874
  # Now, run all specified tasks in all rantfiles,
896
875
  # rantfiles in reverse order.
897
876
  opt = {}
898
877
  matching_tasks = 0
899
878
  target_list.each do |target|
900
- matching_tasks = 0
901
- if @force_targets.include?(target)
902
- opt[:force] = true
903
- @force_targets.delete(target)
904
- end
905
- ### pre 0.3.1 ###
906
- #(select_tasks { |t| t.name == target }).each { |t|
907
- select_tasks_by_name(target).each { |t|
908
- matching_tasks += 1
909
- begin
910
- t.invoke(opt)
911
- rescue Rant::TaskFail => e
912
- # TODO: Report failed dependancy.
913
- abort("Task `#{e.tname}' fail.")
914
- end
915
- }
916
- if matching_tasks == 0
879
+ goto "#"
880
+ if build(target) == 0
917
881
  abort("Don't know how to build `#{target}'.")
918
882
  end
919
883
  end
920
884
  end
921
885
 
886
+ # Invoke all tasks necessary to build +target+. Returns the number
887
+ # of tasks invoked.
888
+ def build target, opt = {}
889
+ opt[:force] = true if @force_targets.delete(target)
890
+ matching_tasks = 0
891
+ resolve(target).each { |t|
892
+ matching_tasks += 1
893
+ begin
894
+ t.invoke(opt)
895
+ rescue Rant::TaskFail => e
896
+ # TODO: Report failed dependancy.
897
+ abort("Task `#{e.tname}' fail.")
898
+ end
899
+ }
900
+ matching_tasks
901
+ end
902
+
903
+ def resolve task_name, rel_project_dir = @current_subdir
904
+ #select_tasks_by_name task_name, rel_project_dir
905
+ # Note: first lines copied from +select_tasks_by_name+
906
+ # for efficiency reasons
907
+ s = @tasks[expand_path(rel_project_dir, task_name)]
908
+ case s
909
+ when nil
910
+ @resolve_hooks.each { |s|
911
+ # Note: will probably change to get more params
912
+ s = s[task_name]
913
+ return s if s
914
+ }
915
+ []
916
+ when Rant::Worker: [s]
917
+ else # assuming MetaTask
918
+ s
919
+ end
920
+ end
921
+ public :resolve
922
+
923
+ def at_resolve &block
924
+ @resolve_hooks << block if block
925
+ end
926
+ public :at_resolve
927
+
922
928
  # Returns a list with all tasks for which yield
923
929
  # returns true.
924
930
  def select_tasks
@@ -1074,8 +1080,8 @@ class Rant::RantApp
1074
1080
  ARGV.replace(old_argv)
1075
1081
  rem_args.each { |ra|
1076
1082
  if ra =~ /(^[^=]+)=([^=]+)$/
1077
- msg 2, "Environment: #$1=#$2"
1078
- ENV[$1] = $2
1083
+ msg 2, "var: #$1=#$2"
1084
+ @var[$1] = $2
1079
1085
  else
1080
1086
  @arg_targets << ra
1081
1087
  end
@@ -1165,13 +1171,15 @@ class Rant::RantApp
1165
1171
  name = normalize_task_name(k, file, ln)
1166
1172
  pre = v
1167
1173
  }
1168
- if pre.respond_to? :to_ary
1169
- pre = pre.to_ary.dup
1170
- pre.map! { |elem|
1171
- normalize_task_name(elem, file, ln)
1172
- }
1173
- else
1174
- pre = [normalize_task_name(pre, file, ln)]
1174
+ unless ::Rant::FileList === pre
1175
+ if pre.respond_to? :to_ary
1176
+ pre = pre.to_ary.dup
1177
+ pre.map! { |elem|
1178
+ normalize_task_name(elem, file, ln)
1179
+ }
1180
+ else
1181
+ pre = [normalize_task_name(pre, file, ln)]
1182
+ end
1175
1183
  end
1176
1184
  else
1177
1185
  name = normalize_task_name(targ, file, ln)
@@ -1216,9 +1224,9 @@ class Rant::RantApp
1216
1224
  end
1217
1225
  end
1218
1226
 
1219
- # Just ensure that Rant.rantapp holds an RantApp after loading
1227
+ # Just ensure that Rant.rac holds an RantApp after loading
1220
1228
  # this file. The code in initialize will register the new app with
1221
- # Rant.rantapp= if necessary.
1229
+ # Rant.rac= if necessary.
1222
1230
  self.new
1223
1231
 
1224
1232
  end # class Rant::RantApp