rant 0.3.8 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/NEWS +19 -0
  2. data/README +51 -24
  3. data/Rantfile +7 -8
  4. data/doc/advanced.rdoc +3 -1
  5. data/doc/package.rdoc +280 -0
  6. data/doc/rantfile.rdoc +9 -19
  7. data/doc/rubyproject.rdoc +24 -16
  8. data/lib/rant/archive/minitar.rb +983 -0
  9. data/lib/rant/archive/rubyzip/ioextras.rb +122 -0
  10. data/lib/rant/archive/rubyzip/stdrubyext.rb +114 -0
  11. data/lib/rant/archive/rubyzip/tempfile_bugfixed.rb +195 -0
  12. data/lib/rant/archive/rubyzip.rb +1575 -0
  13. data/lib/rant/import/archive/tgz.rb +49 -0
  14. data/lib/rant/import/archive/zip.rb +67 -0
  15. data/lib/rant/import/archive.rb +312 -0
  16. data/lib/rant/import/autoclean.rb +2 -2
  17. data/lib/rant/import/c/dependencies.rb +3 -3
  18. data/lib/rant/import/clean.rb +1 -1
  19. data/lib/rant/import/directedrule.rb +1 -1
  20. data/lib/rant/import/package/tgz.rb +35 -0
  21. data/lib/rant/import/package/zip.rb +36 -0
  22. data/lib/rant/import/rubydoc.rb +1 -1
  23. data/lib/rant/import/rubypackage.rb +19 -77
  24. data/lib/rant/import/rubytest.rb +1 -1
  25. data/lib/rant/import/subfile.rb +28 -14
  26. data/lib/rant/import/win32/rubycmdwrapper.rb +1 -1
  27. data/lib/rant/import.rb +36 -16
  28. data/lib/rant/plugin/csharp.rb +1 -1
  29. data/lib/rant/rantenv.rb +2 -13
  30. data/lib/rant/rantfile.rb +11 -11
  31. data/lib/rant/rantlib.rb +7 -3
  32. data/lib/rant/rantsys.rb +53 -2
  33. data/lib/rant/rantvar.rb +62 -1
  34. data/misc/TODO +41 -0
  35. data/{devel-notes → misc/devel-notes} +6 -0
  36. data/misc/mt.rb +3 -0
  37. data/misc/t.rb +18 -0
  38. data/test/import/c/dependencies/test_c_dependencies.rb +18 -0
  39. data/test/import/package/MANIFEST +4 -0
  40. data/test/import/package/Rantfile +49 -0
  41. data/test/import/package/deep/sub/sub/f1 +1 -0
  42. data/test/import/package/sub/f1 +1 -0
  43. data/test/import/package/sub2/f1 +1 -0
  44. data/test/import/package/test_package.rb +425 -0
  45. data/test/import/subfile/Rantfile +8 -0
  46. data/test/import/subfile/test_subfile.rb +12 -0
  47. data/test/project_rb1/rantfile.rb +3 -4
  48. data/test/project_rb1/test_project_rb1.rb +16 -40
  49. data/test/rant-import/test_rant-import.rb +3 -3
  50. data/test/test_filelist.rb +39 -2
  51. data/test/tutil.rb +89 -3
  52. metadata +35 -6
  53. data/TODO +0 -21
  54. data/lib/rant/import/package.rb +0 -258
  55. /data/{rantmethods.rb → misc/rantmethods.rb} +0 -0
@@ -4,7 +4,7 @@ require 'rant/rantlib'
4
4
  class Rant::Generators::RubyPackage
5
5
 
6
6
  class << self
7
- def rant_generate(app, ch, args, &block)
7
+ def rant_gen(app, ch, args, &block)
8
8
  if !args || args.empty?
9
9
  self.new(:app => app, :__caller__ => ch, &block)
10
10
  elsif args.size == 1
@@ -109,7 +109,6 @@ class Rant::Generators::RubyPackage
109
109
  @app = opts[:app] || Rant.rantapp
110
110
  @pkg_dir = "pkg"
111
111
  @pkg_dir_task = nil
112
- @dist_dir_task = nil
113
112
  @gem_task = nil
114
113
  @tar_task = nil
115
114
  @zip_task = nil
@@ -185,6 +184,10 @@ class Rant::Generators::RubyPackage
185
184
  next if attr =~ /^gem\-./
186
185
  next if mapped_attrs.include? attr
187
186
  setter = "#{attr}="
187
+ if attr == "files"
188
+ spec.send(setter, val.dup) if val
189
+ next
190
+ end
188
191
  spec.send(setter, val) if spec.respond_to? setter
189
192
  }
190
193
  # `gem-' attributes override others for gem spec
@@ -198,50 +201,9 @@ class Rant::Generators::RubyPackage
198
201
 
199
202
  def pkg_dir_task
200
203
  return if @pkg_dir_task
201
- if @dist_dir_task
202
- # not ideal but should work: If only the gem task will
203
- # be run, dist dir creation wouldn't be necessary
204
- return @pkg_dir_task = @dist_dir_task
205
- end
206
204
  @pkg_dir_task = @app.gen(Rant::Generators::Directory, @pkg_dir)
207
205
  end
208
206
 
209
- def dist_dir_task
210
- return if @dist_dir_task
211
- pkg_name = pkg_dist_dir
212
- dist_dir = pkg_dist_dir
213
- @dist_dir_task = @app.gen(Rant::Generators::Directory,
214
- dist_dir => files) { |t|
215
- # ensure to create new and empty destination directory
216
- if Dir.entries(dist_dir).size > 2 # "." and ".."
217
- @app.sys.rm_rf(dist_dir)
218
- @app.sys.mkdir(dist_dir)
219
- end
220
- # evaluate directory structure first
221
- dirs = []
222
- fl = []
223
- files.each { |e|
224
- if test(?d, e)
225
- dirs << e unless dirs.include? e
226
- else # assuming e is a file
227
- fl << e
228
- dir = File.dirname(e)
229
- dirs << dir unless dir == "." || dirs.include?(dir)
230
- end
231
- }
232
- # create directory structure
233
- dirs.each { |dir|
234
- dest = File.join(dist_dir, dir)
235
- @app.sys.mkpath(dest) unless test(?d, dest)
236
- }
237
- # link or copy files
238
- fl.each { |f|
239
- dest = File.join(dist_dir, f)
240
- @app.sys.safe_ln(f, dest)
241
- }
242
- }
243
- end
244
-
245
207
  # Create task for gem building. If tname is a true value, a
246
208
  # shortcut-task will be created.
247
209
  def gem_task(tname = :gem)
@@ -302,16 +264,15 @@ class Rant::Generators::RubyPackage
302
264
  pkg_files = files
303
265
  if tname
304
266
  # shortcut task
305
- @app.task({:__caller__ => @ch, tname => pkg_name})
267
+ @app.cx.task({:__caller__ => @ch, tname => pkg_name})
306
268
  end
307
269
  # actual tar-creating task
308
- @tar_task = @app.file(:__caller__ => @ch,
309
- pkg_name => [pkg_dist_dir] + pkg_files) { |t|
310
- @app.sys.cd(@pkg_dir) {
311
- @app.sys %W(tar zcf #{tar_pkg_name} #{pkg_base_name})
312
- }
313
- }
314
- dist_dir_task
270
+ @app.cx.import "package/tgz"
271
+ @tar_task =
272
+ Rant::Generators::Package::Tgz.rant_gen(@app, @ch,
273
+ ["#@pkg_dir/#{pkg_base_name}",
274
+ # we use tar.gz extension here for backwards compatibility
275
+ {:files => pkg_files, :extension => ".tar.gz"}])
315
276
  end
316
277
 
317
278
  def zip_task(tname = :zip)
@@ -325,17 +286,10 @@ class Rant::Generators::RubyPackage
325
286
  @app.task({:__caller__ => @ch, tname => pkg_name})
326
287
  end
327
288
  # actual zip-creating task
328
- @zip_task = @app.file(:__caller__ => @ch,
329
- pkg_name => [pkg_dist_dir] + pkg_files) { |t|
330
- @app.sys.cd(@pkg_dir) {
331
- # zip options:
332
- # y: store symlinks instead of referenced files
333
- # r: recurse into directories
334
- # q: quiet operation
335
- @app.sys %W(zip -yqr #{zip_pkg_name} #{pkg_base_name})
336
- }
337
- }
338
- dist_dir_task
289
+ @app.cx.import "package/zip"
290
+ @zip_task =
291
+ Rant::Generators::Package::Zip.rant_gen(@app, @ch,
292
+ ["#@pkg_dir/#{pkg_base_name}", {:files => pkg_files}])
339
293
  end
340
294
 
341
295
  # Create a task which runs gem/zip/tar tasks.
@@ -361,23 +315,15 @@ class Rant::Generators::RubyPackage
361
315
 
362
316
  # Returns true if at least one task was defined.
363
317
  def def_available_tasks
364
- defined = false
365
- if Rant::Env.have_tar?
366
- # we don't create shortcut tasks, hence nil as argument
367
- self.tar_task(nil)
368
- defined = true
369
- end
370
- if Rant::Env.have_zip?
371
- self.zip_task(nil)
372
- defined = true
373
- end
318
+ self.tar_task(nil)
319
+ self.zip_task(nil)
374
320
  begin
375
321
  require 'rubygems'
376
322
  self.gem_task(nil)
377
323
  defined = true
378
324
  rescue LoadError
379
325
  end
380
- defined
326
+ true
381
327
  end
382
328
 
383
329
  def pkg_base_name
@@ -392,10 +338,6 @@ class Rant::Generators::RubyPackage
392
338
  pkg_dist_dir + ".gem"
393
339
  end
394
340
 
395
- #--
396
- # Arghhh... tar makes me feel angry
397
- #++
398
-
399
341
  def tar_pkg_name
400
342
  pkg_base_name + ".tar.gz"
401
343
  end
@@ -6,7 +6,7 @@ module Rant
6
6
 
7
7
  class << self
8
8
 
9
- def rant_generate(app, ch, args, &block)
9
+ def rant_gen(app, ch, args, &block)
10
10
  if !args || args.empty?
11
11
  self.new(app, ch, &block)
12
12
  elsif args.size == 1
@@ -6,33 +6,47 @@
6
6
  require 'rant/rantlib'
7
7
 
8
8
  class Rant::Generators::SubFile
9
- def self.rant_generate(rac, ch, args, &block)
9
+ def self.rant_gen(rac, ch, args, &block)
10
10
  case args.size
11
11
  when 1
12
- basedir, fine = nil, args.first
13
- path = fine
12
+ fine, basedir = args
14
13
  when 2
15
14
  basedir, fine = args
16
- path = File.join(basedir, fine)
17
15
  else
18
16
  rac.abort_at(ch, "SubFile takes one or two arguments.")
19
17
  end
18
+ deps = []
19
+ if fine.respond_to? :to_hash
20
+ # hash should contain only one element
21
+ fine = fine.to_hash
22
+ fine.each { |k, v|
23
+ ch = v && next if k == :__caller__
24
+ fine = k
25
+ if Rant::FileList === v
26
+ deps = v.dup
27
+ elsif v.respond_to? :to_ary
28
+ deps.concat(v.to_ary)
29
+ else
30
+ deps << v
31
+ end
32
+ }
33
+ end
34
+ path = basedir ? File.join(basedir, fine) : fine
20
35
  file_desc = rac.pop_desc
21
- rac.prepare_task(path, block, ch) { |name,pre,blk|
36
+ rac.prepare_task({path => deps}, block, ch) { |name,pre,blk|
22
37
  dir, file = File.split(fine.to_s)
23
38
  dirp = basedir ? File.join(basedir, dir) : dir
24
39
  unless dir == "."
25
- dt = rac.resolve(dirp)
26
- if dt.empty?
27
- dt = [if basedir
28
- rac.cx.gen(
29
- ::Rant::Generators::Directory, basedir, dir)
40
+ unless rac.tasks.include? dirp
41
+ if basedir
42
+ ::Rant::Generators::Directory.rant_gen(
43
+ rac, ch, [basedir, dir])
30
44
  else
31
- rac.cx.gen(
32
- ::Rant::Generators::Directory, dir)
33
- end]
45
+ ::Rant::Generators::Directory.rant_gen(
46
+ rac, ch, [dir])
47
+ end
34
48
  end
35
- pre.concat(dt)
49
+ pre << dirp
36
50
  end
37
51
  rac.cx.desc file_desc
38
52
  ::Rant::FileTask.new(rac, name, pre, &blk)
@@ -8,7 +8,7 @@ require 'rant/rantlib'
8
8
  module Rant::Generators
9
9
  module Win32
10
10
  module RubyCmdWrapper
11
- def self.rant_generate(rac, ch, args, &block)
11
+ def self.rant_gen(rac, ch, args, &block)
12
12
  fl = args.first
13
13
  unless args.size == 1 and fl.respond_to? :to_ary
14
14
  rac.abort_at(ch,
data/lib/rant/import.rb CHANGED
@@ -78,10 +78,10 @@ module Rant
78
78
  @mono_fn = nil
79
79
  @force = false
80
80
  @rantapp = nil
81
- @core_imports = []
82
- @lib_imports = []
83
81
  @included_plugins = []
84
82
  @included_imports = []
83
+ # contains all filenames as given to +require+
84
+ @included_files = []
85
85
  @skip_comments = true
86
86
  @reduce_whitespace = false
87
87
  @auto = false
@@ -234,7 +234,7 @@ EOF
234
234
  "This file should contains the core of rant, so import is impossible.",
235
235
  "Please check your rant installation!")
236
236
  end
237
- @core_imports << "rantlib"
237
+ @included_files << "rant/rantlib"
238
238
  resolve_requires rantlib
239
239
  end
240
240
 
@@ -242,13 +242,19 @@ EOF
242
242
  rs = ""
243
243
  @imports.each { |name|
244
244
  next if @included_imports.include? name
245
- path = get_lib_rant_path "import/#{name}.rb"
245
+ lib_name = "import/#{name}"
246
+ lib_fn = "#{lib_name}.rb"
247
+ rfn = "rant/#{lib_name}"
248
+ path = get_lib_rant_path lib_fn
246
249
  unless path
247
250
  abort("No such import - #{name}")
248
251
  end
249
- msg "Including import `#{name}'", path
250
- @included_imports << name.dup
251
- rs << resolve_requires(File.read(path))
252
+ @included_imports << name.dup
253
+ unless @included_files.include? rfn
254
+ @included_files << rfn
255
+ msg "Including import `#{name}'", path
256
+ rs << resolve_requires(File.read(path))
257
+ end
252
258
  }
253
259
  rs
254
260
  end
@@ -258,13 +264,19 @@ EOF
258
264
  @plugins.each { |name|
259
265
  lc_name = name.downcase
260
266
  next if @included_plugins.include? lc_name
261
- path = get_lib_rant_path "plugin/#{lc_name}.rb"
267
+ plugin_name = "plugin/#{lc_name}"
268
+ plugin_fn = "#{plugin_name}.rb"
269
+ rfn = "rant/#{plugin_name}"
270
+ path = get_lib_rant_path plugin_fn
262
271
  unless File.exist? path
263
272
  abort("No such plugin - #{name}")
264
273
  end
265
- msg "Including plugin `#{lc_name}'", path
266
274
  @included_plugins << lc_name
267
- rs << resolve_requires(File.read(path))
275
+ unless @included_files.include? rfn
276
+ @included_files << rfn
277
+ msg "Including plugin `#{lc_name}'", path
278
+ rs << resolve_requires(File.read(path))
279
+ end
268
280
  }
269
281
  rs
270
282
  end
@@ -283,6 +295,12 @@ EOF
283
295
  end
284
296
  # skip shebang line
285
297
  next if line =~ /^#! ?(\/|\\)?\w/
298
+ # uncomment line if +uncomment+ directive given
299
+ if line =~ /^\s*#.*#\s?rant-import:\s?uncomment\s*$/
300
+ line.sub! '#', ''
301
+ end
302
+ # skip line if +remove+ directive given
303
+ next if line =~ /#\s?rant-import:\s?remove\s*$/
286
304
  # skip pure comment lines
287
305
  next if line =~ /^\s*#/ if @skip_comments
288
306
  if line =~ /^=begin\s/
@@ -291,10 +309,11 @@ EOF
291
309
  end
292
310
  name = nil
293
311
  lib_file = nil
294
- if line =~ /\s*(require|load)\s+('|")rant\/(\w+)(\.rb)?('|")/
312
+ if line =~ /\s*(require|load)\s+('|")rant\/([\w\/]+)(\.rb)?('|")/
295
313
  # Rant library code
296
314
  name = $3
297
- elsif line =~ /\s*(require|load)\s+('|")rant\/(import\/\w+)(\.rb)?('|")/
315
+ elsif line =~
316
+ /\s*(require|load)\s+('|")rant\/(import\/[\w\/]+)(\.rb)?('|")/
298
317
  # some "import" code
299
318
  name = $3
300
319
  elsif line =~ /\s*(require|load)\s+('|")([^\2]+)\2[^r]*rant-import/
@@ -302,16 +321,17 @@ EOF
302
321
  lib_file = $3
303
322
  end
304
323
  if name
305
- next if @core_imports.include? name
324
+ rfn = "rant/#{name}"
325
+ next if @included_files.include? rfn
306
326
  path = get_lib_rant_path "#{name}.rb"
307
327
  msg "Including `#{name}'", path
308
- @core_imports << name
328
+ @included_files << rfn
309
329
  rs << resolve_requires(File.read(path))
310
330
  elsif lib_file
311
- next if @lib_imports.include? lib_file
331
+ next if @included_files.include? lib_file
312
332
  path = get_lib_path "#{lib_file}.rb"
313
333
  msg "Including `#{lib_file}'", path
314
- @lib_imports << lib_file
334
+ @included_files << lib_file
315
335
  rs << resolve_requires(File.read(path))
316
336
  else
317
337
  line.sub!(/^\s+/, '') if @reduce_whitespace
@@ -9,7 +9,7 @@ module Rant
9
9
  class Generators::Assembly < CsCompiler
10
10
  class << self
11
11
 
12
- def rant_generate(app, clr, args, &block)
12
+ def rant_gen(app, clr, args, &block)
13
13
  assembly = self.new(&block)
14
14
  if args.size == 1
15
15
  targ = args.first
data/lib/rant/rantenv.rb CHANGED
@@ -4,8 +4,8 @@ require 'rbconfig'
4
4
 
5
5
  module Rant end
6
6
 
7
- # This module provides some platform indenpendant
8
- # (let's hope) environment information.
7
+ # This module interfaces with the environment to provide
8
+ # information/conversion methods in a portable manner.
9
9
  module Rant::Env
10
10
  OS = ::Config::CONFIG['target']
11
11
  RUBY = ::Config::CONFIG['ruby_install_name']
@@ -176,14 +176,3 @@ module Rant::Console
176
176
 
177
177
  extend self
178
178
  end
179
-
180
- class Rant::CustomConsole
181
- include Rant::Console
182
-
183
- def initialize msg_prefix = RANT_PREFIX
184
- @msg_prefix = msg_prefix || ""
185
- end
186
- def msg_prefix=(str)
187
- @msg_prefix = str || ""
188
- end
189
- end
data/lib/rant/rantfile.rb CHANGED
@@ -170,7 +170,7 @@ module Rant
170
170
  include Node
171
171
 
172
172
  class << self
173
- def rant_generate(rac, ch, args, &block)
173
+ def rant_gen(rac, ch, args, &block)
174
174
  unless args.size == 1
175
175
  rac.abort("LightTask takes only one argument " +
176
176
  "which has to be the taskname (string or symbol)")
@@ -242,9 +242,9 @@ module Rant
242
242
  T0 = Time.at(0).freeze
243
243
 
244
244
  class << self
245
- def rant_generate(rac, ch, args, &block)
245
+ def rant_gen(rac, ch, args, &block)
246
246
  if args.size == 1
247
- UserTask.rant_generate(rac, ch, args, &block)
247
+ UserTask.rant_gen(rac, ch, args, &block)
248
248
  else
249
249
  rac.abort("Task generator currently takes only one" +
250
250
  " argument. (generates a UserTask)")
@@ -459,7 +459,7 @@ module Rant
459
459
  class UserTask < Task
460
460
 
461
461
  class << self
462
- def rant_generate(rac, ch, args, &block)
462
+ def rant_gen(rac, ch, args, &block)
463
463
  unless args.size == 1
464
464
  rac.abort("UserTask takes only one argument " +
465
465
  "which has to be like one given to the " +
@@ -594,7 +594,7 @@ module Rant
594
594
  # block will be called after complete directory creation.
595
595
  # After the block execution, the modification time of the
596
596
  # directory will be updated.
597
- def rant_generate(rac, ch, args, &block)
597
+ def rant_gen(rac, ch, args, &block)
598
598
  case args.size
599
599
  when 1
600
600
  name, pre, file, ln = rac.normalize_task_arg(args.first, ch)
@@ -630,11 +630,11 @@ module Rant
630
630
  task_block = nil
631
631
  desc_for_last = rac.pop_desc
632
632
  dirs.each { |dir|
633
- pre = [path]
634
- pre.compact!
633
+ pre = [path]
634
+ pre.compact!
635
635
  if dir.equal?(dirs.last)
636
636
  rac.cx.desc desc_for_last
637
- pre.concat prerequisites if prerequisites
637
+ pre = prerequisites + pre
638
638
  task_block = block
639
639
  end
640
640
  path = path.nil? ? dir : File.join(path, dir)
@@ -713,7 +713,7 @@ module Rant
713
713
  class SourceNode
714
714
  include Node
715
715
 
716
- def self.rant_generate(rac, ch, args)
716
+ def self.rant_gen(rac, ch, args)
717
717
  unless args.size == 1
718
718
  rac.abort_at(ch, "SourceNode takes one argument.")
719
719
  end
@@ -800,7 +800,7 @@ module Rant
800
800
  class Rule < ::Proc
801
801
  # Generate a rule by installing an at_resolve hook for
802
802
  # +rac+.
803
- def self.rant_generate(rac, ch, args, &block)
803
+ def self.rant_gen(rac, ch, args, &block)
804
804
  unless args.size == 1
805
805
  rac.abort_at(ch, "Rule takes only one argument.")
806
806
  end
@@ -863,7 +863,7 @@ module Rant
863
863
  end # class Rule
864
864
 
865
865
  class Action
866
- def self.rant_generate(rac, ch, args, &block)
866
+ def self.rant_gen(rac, ch, args, &block)
867
867
  unless args.empty?
868
868
  rac.warn_msg(rac.pos_text(ch[:file], ch[:ln]),
869
869
  "Action doesn't take arguments.")
data/lib/rant/rantlib.rb CHANGED
@@ -539,12 +539,12 @@ class Rant::RantApp
539
539
  pre = []
540
540
  # validate args
541
541
  generator = args.shift
542
- unless generator.respond_to? :rant_generate
542
+ unless generator.respond_to? :rant_gen
543
543
  abort_at(ch,
544
544
  "First argument to `gen' has to be a task-generator.")
545
545
  end
546
546
  # ask generator to produce a task for this application
547
- generator.rant_generate(self, ch, args, &block)
547
+ generator.rant_gen(self, ch, args, &block)
548
548
  end
549
549
 
550
550
  # Currently ignores block.
@@ -938,6 +938,10 @@ class Rant::RantApp
938
938
  end
939
939
  public :resolve
940
940
 
941
+ # This hook will be invoked when no matching task is found for a
942
+ # target. It may create one or more tasks for the target, which is
943
+ # given as argument, on the fly and return an array of the created
944
+ # tasks or nil.
941
945
  def at_resolve &block
942
946
  @resolve_hooks << block if block
943
947
  end
@@ -1244,7 +1248,7 @@ class Rant::RantApp
1244
1248
  end
1245
1249
  elsif Rant::CommandError === orig
1246
1250
  msg << orig.message if @opts[:err_commands]
1247
- elsif !(Rant::RantAbortException === orig)
1251
+ elsif orig && !(Rant::RantAbortException === orig)
1248
1252
  msg << orig.message << orig.backtrace[0..4]
1249
1253
  end
1250
1254
  end
data/lib/rant/rantsys.rb CHANGED
@@ -57,6 +57,7 @@ module Rant
57
57
  end
58
58
 
59
59
  def to_ary
60
+ #puts caller
60
61
  resolve if @pending
61
62
  @files
62
63
  end
@@ -68,7 +69,9 @@ module Rant
68
69
  def +(other)
69
70
  case other
70
71
  when Array
71
- dup.files.concat(other)
72
+ c = dup
73
+ c.files.concat(other)
74
+ c
72
75
  when FileList
73
76
  c = other.dup
74
77
  c.actions.concat(@actions)
@@ -80,11 +83,22 @@ module Rant
80
83
  end
81
84
  end
82
85
 
83
- def <<(file)
86
+ # Add file to filelist unless it matches an exclude pattern.
87
+ # Take care: Don't rely on any order when inserting a file
88
+ # with this method!
89
+ def add(file)
84
90
  @files << file unless file =~ ignore_rx
85
91
  self
86
92
  end
87
93
 
94
+ # Like #add but doesn't honor exclude patterns.
95
+ # Returns self.
96
+ def <<(file)
97
+ #STDERR.puts caller unless String === file
98
+ @actions << [:apply_ary_method_1, :push, file]
99
+ self
100
+ end
101
+
88
102
  def concat(ary)
89
103
  resolve if @pending
90
104
  ix = ignore_rx
@@ -316,10 +330,47 @@ module Rant
316
330
  def arglist
317
331
  to_ary.arglist
318
332
  end
333
+
334
+ # Same as #uniq! but evaluation is delayed until the next read
335
+ # access (e.g. by calling #each). Always returns self.
336
+ def lazy_uniq!
337
+ @actions << [:apply_ary_method, :uniq!]
338
+ @pending = true
339
+ self
340
+ end
341
+
342
+ # Same as #sort! but evaluation is delayed until the next read
343
+ # access (e.g. by calling #each). Always returns self.
344
+ def lazy_sort!
345
+ @actions << [:apply_ary_method, :sort!]
346
+ @pending = true
347
+ self
348
+ end
349
+
350
+ private
351
+ def apply_ary_method(meth)
352
+ @files.send meth
353
+ end
354
+ def apply_ary_method_1(meth, arg1)
355
+ @files.send meth, arg1
356
+ end
319
357
  end # class FileList
320
358
 
321
359
  class RacFileList < FileList
322
360
 
361
+ # Returns files if <tt>FileList === files</tt>, otherwise
362
+ # a new RacFileList with <tt>file.to_ary</tt> as initial set
363
+ # of files.
364
+ def self.filelist(rac, files)
365
+ return files if FileList === files
366
+ fl = self.new(rac)
367
+ fl.instance_eval {
368
+ @pending = false
369
+ @files = files.to_ary
370
+ }
371
+ fl
372
+ end
373
+
323
374
  attr_reader :subdir
324
375
  attr_reader :basedir
325
376
 
data/lib/rant/rantvar.rb CHANGED
@@ -16,7 +16,7 @@
16
16
  # If you're looking for general info about Rant, read the
17
17
  # README[link:files/README.html].
18
18
  module Rant
19
- VERSION = '0.3.8'
19
+ VERSION = '0.4.0'
20
20
 
21
21
  # Those are the filenames for rantfiles.
22
22
  # Case matters!
@@ -46,6 +46,67 @@ module Rant
46
46
  module Generators
47
47
  end
48
48
 
49
+ @__rant_no_value__ = Object.new.freeze
50
+ def self.__rant_no_value__
51
+ @__rant_no_value__
52
+ end
53
+
54
+ module MetaUtils
55
+ # Creates two accessor methods:
56
+ # obj.attr_name:: Return value of instance variable
57
+ # @attr_name
58
+ # obj.attr_name = val:: Set value instance variable
59
+ # @attr_name to val
60
+ # obj.attr_name val:: same as above
61
+ def rant_attr attr_name
62
+ attr_name = valid_attr_name attr_name
63
+ attr_writer attr_name
64
+ module_eval <<-EOD
65
+ def #{attr_name} val=Rant.__rant_no_value__
66
+ if val.equal? Rant.__rant_no_value__
67
+ @#{attr_name}
68
+ else
69
+ @#{attr_name} = val
70
+ end
71
+ end
72
+ EOD
73
+ nil
74
+ end
75
+ # Creates accessor methods like #rant_attr for the attribute
76
+ # attr_name. Additionally, values are converted with to_str
77
+ # before assignment to instance variables happens.
78
+ def string_attr attr_name
79
+ attr_name = valid_attr_name attr_name
80
+ module_eval <<-EOD
81
+ def #{attr_name}=(val)
82
+ if val.respond_to? :to_str
83
+ @#{attr_name} = val.to_str
84
+ else
85
+ raise ArgumentError,
86
+ "string (#to_str) value required", caller
87
+ end
88
+ end
89
+ def #{attr_name} val=Rant.__rant_no_value__
90
+ if val.equal? Rant.__rant_no_value__
91
+ @#{attr_name}
92
+ else
93
+ self.__send__(:#{attr_name}=, val)
94
+ end
95
+ end
96
+ EOD
97
+ nil
98
+ end
99
+ # attr_name is converted to a string with #to_s and has to
100
+ # match /^\w+$/. Returns attr_name.to_s.
101
+ def valid_attr_name attr_name
102
+ attr_name = attr_name.to_s
103
+ attr_name =~ /^\w+$/ or
104
+ raise ArgumentError,
105
+ "argument has to match /^\w+$/", caller
106
+ attr_name
107
+ end
108
+ end # module MetaUtils
109
+
49
110
  module RantVar
50
111
 
51
112
  class Error < RantError