rant 0.3.4 → 0.3.6

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.
@@ -1,4 +1,8 @@
1
1
 
2
+ # rantsys.rb - Support for the +sys+ method/object.
3
+ #
4
+ # Copyright (C) 2005 Stefan Lang <langstefan@gmx.at>
5
+
2
6
  require 'fileutils'
3
7
  require 'rant/rantenv'
4
8
 
@@ -65,7 +69,7 @@ module Rant
65
69
  case other
66
70
  when Array
67
71
  dup.files.concat(other)
68
- when self.class
72
+ when FileList
69
73
  c = other.dup
70
74
  c.actions.concat(@actions)
71
75
  c.files.concat(@files)
@@ -97,8 +101,9 @@ module Rant
97
101
  if @files.respond_to? sym
98
102
  resolve if @pending
99
103
  fh = @files.hash
100
- @files.send(sym, *args, &block)
104
+ rv = @files.send(sym, *args, &block)
101
105
  @pending = true unless @files.hash == fh
106
+ rv.equal?(@files) ? self : rv
102
107
  else
103
108
  super
104
109
  end
@@ -118,7 +123,7 @@ module Rant
118
123
  end
119
124
 
120
125
  def include(*patterns)
121
- patterns.each { |pat|
126
+ patterns.flatten.each { |pat|
122
127
  @actions << [:apply_include, pat]
123
128
  }
124
129
  @pending = true
@@ -201,6 +206,17 @@ module Rant
201
206
  end
202
207
  private :mk_all_rx
203
208
 
209
+ def select &block
210
+ d = dup
211
+ d.actions << [:apply_select, block]
212
+ d
213
+ end
214
+
215
+ def apply_select blk
216
+ @files = @files.select &blk
217
+ end
218
+ private :apply_select
219
+
204
220
  # Remove all entries which contain a directory with the
205
221
  # given name.
206
222
  # If no argument or +nil+ given, remove all directories.
@@ -307,8 +323,13 @@ module Rant
307
323
 
308
324
  class RacFileList < FileList
309
325
 
326
+ attr_reader :subdir
327
+ attr_reader :basedir
328
+
310
329
  def initialize(rac, *patterns)
311
330
  @rac = rac
331
+ @subdir = @rac.current_subdir
332
+ @basedir = Dir.pwd
312
333
  super(*patterns)
313
334
  @ignore_hash = nil
314
335
  update_ignore_rx
@@ -321,6 +342,21 @@ module Rant
321
342
  @ignore_rx
322
343
  end
323
344
 
345
+ alias filelist_resolve resolve
346
+ def resolve
347
+ Dir.chdir(@basedir) { filelist_resolve }
348
+ end
349
+
350
+ def each &block
351
+ old_pwd = Dir.pwd
352
+ resolve if @pending
353
+ Dir.chdir(@basedir)
354
+ filelist_resolve
355
+ @files.each(&block)
356
+ ensure
357
+ Dir.chdir(old_pwd)
358
+ end
359
+
324
360
  private
325
361
  def update_ignore_rx
326
362
  ri = @rac.var[:ignore]
@@ -331,7 +367,44 @@ module Rant
331
367
  @ignore_hash = rh
332
368
  end
333
369
  end
334
- end
370
+ end # class RacFileList
371
+
372
+ class MultiFileList
373
+
374
+ attr_reader :cur_list
375
+
376
+ def initialize(rac)
377
+ @rac = rac
378
+ @cur_list = RacFileList.new(@rac)
379
+ @lists = [@cur_list]
380
+ end
381
+
382
+ def each_entry &block
383
+ @lists.each { |list|
384
+ list.each &block
385
+ }
386
+ end
387
+
388
+ def add(filelist)
389
+ # TODO: validate filelist
390
+ @cur_list = filelist
391
+ @lists << filelist
392
+ self
393
+ end
394
+
395
+ def method_missing(sym, *args, &block)
396
+ if @cur_list && @cur_list.respond_to?(sym)
397
+ if @cur_list.subdir == @rac.current_subdir
398
+ @cur_list.send(sym, *args, &block)
399
+ else
400
+ add(RacFileList.new(@rac))
401
+ @cur_list.send(sym, *args, &block)
402
+ end
403
+ else
404
+ super
405
+ end
406
+ end
407
+ end # class MultiFileList
335
408
 
336
409
  class CommandError < StandardError
337
410
  attr_reader :cmd
@@ -375,6 +448,13 @@ module Rant
375
448
  ::Rant.rac.cmd_msg msg if ::Rant.rac
376
449
  end
377
450
 
451
+ # Run an external command. When given one argument, this is
452
+ # subject to shell interpretation. Otherwise the first
453
+ # argument is the program to run, following arguments are
454
+ # given as arguments to the program.
455
+ #
456
+ # Note: This method is called on +sys <some_string>+
457
+ # invocation in an Rantfile.
378
458
  def sh(*cmd_args, &block)
379
459
  cmd_args.flatten!
380
460
  cmd = cmd_args.join(" ")
@@ -386,6 +466,8 @@ module Rant
386
466
  end
387
467
  end
388
468
 
469
+ # Run a new Ruby interpreter with the given arguments:
470
+ # sys.ruby "install.rb"
389
471
  def ruby(*args, &block)
390
472
  if args.size > 1
391
473
  sh([Env::RUBY] + args, &block)
@@ -427,6 +509,11 @@ module Rant
427
509
 
428
510
  end # module Sys
429
511
 
512
+ # An instance of this class is returned from the +sys+ method in
513
+ # Rantfiles (when called without arguments).
514
+ # sys.rm_rf "tmp"
515
+ # In this (Rantfile) example, the +rm_rf+ message is sent to an
516
+ # instance of this class.
430
517
  class SysObject
431
518
  include Sys
432
519
 
@@ -449,6 +536,7 @@ module Rant
449
536
  end
450
537
 
451
538
  private
539
+ # Delegates FileUtils messages to +rac+.
452
540
  def fu_output_message(cmd)
453
541
  @rac.cmd_msg cmd
454
542
  end
@@ -10,8 +10,13 @@
10
10
  # This file provides support for the +var+ attribute of the Rant
11
11
  # application (Rant::RantApp#var).
12
12
 
13
+ # Most constants (classes, modules etc.) of Rant live in this module,
14
+ # thus it acts as a namespace.
15
+ #
16
+ # If you're looking for general info about Rant, read the
17
+ # README[link:files/README.html].
13
18
  module Rant
14
- VERSION = '0.3.4'
19
+ VERSION = '0.3.6'
15
20
 
16
21
  # Those are the filenames for rantfiles.
17
22
  # Case matters!
@@ -67,6 +72,20 @@ module Rant
67
72
  end
68
73
  end
69
74
 
75
+ class NotAConstraintFactoryError < Error
76
+ attr_reader :obj
77
+ def initialize(obj, msg = nil)
78
+ @msg = msg
79
+ @obj = obj
80
+ end
81
+ def message
82
+ # TODO: handle @msg
83
+ obj_desc = @obj.inspect
84
+ obj_desc[7..-1] = "..." if obj_desc.length > 10
85
+ "#{obj_desc} is not a valid constraint factory"
86
+ end
87
+ end
88
+
70
89
  class InvalidVidError < Error
71
90
  def initialize(vid, msg = nil)
72
91
  @msg = msg
@@ -95,6 +114,8 @@ module Rant
95
114
  @store = {}
96
115
  # holds constraints for values in @store
97
116
  @constraints = {}
117
+ # set by default query
118
+ @current_var = nil
98
119
  end
99
120
 
100
121
  def query(*args, &block)
@@ -105,25 +126,57 @@ module Rant
105
126
  when 1
106
127
  arg = args.first
107
128
  if Hash === arg
108
- init_all arg
129
+ if arg.size == 1
130
+ arg.each { |k,v|
131
+ @current_var = k
132
+ self[k] = v if self[k].nil?
133
+ }
134
+ self
135
+ else
136
+ init_all arg
137
+ end
109
138
  else
110
139
  self[arg]
111
140
  end
112
141
  when 2..3
113
- vid, constraint, val = *args
142
+ @current_var, cf, val = *args
143
+ self.is cf
144
+ self[@current_var] = val if val
145
+ else
146
+ raise QueryError, "to many arguments"
147
+ end
148
+ end
149
+
150
+ def is ct, *ct_args
151
+ constrain @current_var,
152
+ get_factory(ct).rant_constraint(*ct_args)
153
+ self
154
+ end
155
+
156
+ def restrict vid, ct, *ct_args
157
+ if vid.respond_to? :to_ary
158
+ vid.to_ary.each { |v| restrict(v, ct, *ct_args) }
159
+ else
160
+ constrain vid,
161
+ get_factory(ct).rant_constraint(*ct_args)
162
+ end
163
+ self
164
+ end
165
+
166
+ def get_factory id
167
+ if String === id || Symbol === id
114
168
  begin
115
- constraint =
116
- Constraints.const_get(constraint).new
169
+ id = Constraints.const_get(id)
117
170
  rescue
118
- raise QueryError,
119
- "no such constraint: #{constraint}", caller
171
+ raise NotAConstraintFactoryError.new(ct), caller
120
172
  end
121
- constrain vid, constraint
122
- self[vid] = val if val
123
- else
124
- raise QueryError, "to many arguments"
125
173
  end
174
+ unless id.respond_to? :rant_constraint
175
+ raise NotAConstraintFactoryError.new(id), caller
176
+ end
177
+ id
126
178
  end
179
+ private :get_factory
127
180
 
128
181
  # Get var with name +vid+.
129
182
  def [](vid)
@@ -198,6 +251,10 @@ module Rant
198
251
  end
199
252
  end
200
253
 
254
+ def has_var?(vid)
255
+ !self[vid].nil?
256
+ end
257
+
201
258
  end # class Space
202
259
 
203
260
  module Constraint
@@ -211,9 +268,65 @@ module Rant
211
268
 
212
269
  module Constraints
213
270
 
271
+ class String
272
+ include Constraint
273
+
274
+ class << self
275
+ alias rant_constraint new
276
+ end
277
+
278
+ def filter(val)
279
+ if val.respond_to? :to_str
280
+ val.to_str
281
+ elsif Symbol === val
282
+ val.to_s
283
+ else
284
+ raise ConstraintError.new(self, val)
285
+ end
286
+ end
287
+ def default
288
+ ""
289
+ end
290
+ def to_s
291
+ "string"
292
+ end
293
+ end
294
+
295
+ class ToString < String
296
+ class << self
297
+ alias rant_constraint new
298
+ end
299
+ def filter(val)
300
+ val.to_s
301
+ end
302
+ end
303
+
304
+ class ::Range
305
+ def rant_constraint
306
+ case first
307
+ when ::Integer
308
+ IntegerInRange.new(self)
309
+ when ::Float
310
+ FloatInRange.new(self)
311
+ else
312
+ raise NotAConstraintFactoryError.new(self)
313
+ end
314
+ end
315
+ end
316
+
214
317
  class Integer
215
318
  include Constraint
216
319
 
320
+ class << self
321
+ def rant_constraint(range = nil)
322
+ if range
323
+ IntegerInRange.new(range)
324
+ else
325
+ self.new
326
+ end
327
+ end
328
+ end
329
+
217
330
  def filter(val)
218
331
  Kernel::Integer(val)
219
332
  rescue
@@ -227,9 +340,79 @@ module Rant
227
340
  end
228
341
  end
229
342
 
343
+ class IntegerInRange < Integer
344
+ def initialize(range)
345
+ @range = range
346
+ end
347
+ def filter(val)
348
+ i = super
349
+ if @range === i
350
+ i
351
+ else
352
+ raise ConstraintError.new(self, val)
353
+ end
354
+ end
355
+ def default
356
+ @range.min
357
+ end
358
+ def to_s
359
+ super + " #{@range}"
360
+ end
361
+ end
362
+
363
+ class Float
364
+ include Constraint
365
+
366
+ class << self
367
+ def rant_constraint(range = nil)
368
+ if range
369
+ FloatInRange.new(range)
370
+ else
371
+ self.new
372
+ end
373
+ end
374
+ end
375
+
376
+ def filter(val)
377
+ Kernel::Float(val)
378
+ rescue
379
+ raise ConstraintError.new(self, val)
380
+ end
381
+ def default
382
+ 0.0
383
+ end
384
+ def to_s
385
+ "float"
386
+ end
387
+ end
388
+
389
+ class FloatInRange < Float
390
+ def initialize(range)
391
+ @range = range
392
+ end
393
+ def filter(val)
394
+ i = super
395
+ if @range === i
396
+ i
397
+ else
398
+ raise ConstraintError.new(self, val)
399
+ end
400
+ end
401
+ def default
402
+ @range.first
403
+ end
404
+ def to_s
405
+ super + " #{@range}"
406
+ end
407
+ end
408
+
230
409
  class AutoList
231
410
  include Constraint
232
411
 
412
+ class << self
413
+ alias rant_constraint new
414
+ end
415
+
233
416
  def filter(val)
234
417
  if val.respond_to? :to_ary
235
418
  val.to_ary
@@ -250,6 +433,10 @@ module Rant
250
433
  class List
251
434
  include Constraint
252
435
 
436
+ class << self
437
+ alias rant_constraint new
438
+ end
439
+
253
440
  def filter(val)
254
441
  if val.respond_to? :to_ary
255
442
  val.to_ary
@@ -267,6 +454,60 @@ module Rant
267
454
 
268
455
  Array = List
269
456
 
457
+ class Bool
458
+ include Constraint
459
+ class << self
460
+ alias rant_constraint new
461
+ end
462
+ def filter(val)
463
+ if ::Symbol === val or ::Integer === val
464
+ val = val.to_s
465
+ end
466
+ if val == true
467
+ true
468
+ elsif val == false || val == nil
469
+ false
470
+ elsif val.respond_to? :to_str
471
+ case val.to_str
472
+ when /^\s*true\s*$/i: true
473
+ when /^\s*false\s*$/i: false
474
+ when /^\s*y(es)?\s*$/i: true
475
+ when /^\s*n(o)?\s*$/: false
476
+ when /^\s*on\s*$/i: true
477
+ when /^\s*off\s*$/i: false
478
+ when /^\s*1\s*$/: true
479
+ when /^\s*0\s*$/: false
480
+ else
481
+ raise ConstraintError.new(self, val)
482
+ end
483
+ else
484
+ raise ConstraintError.new(self, val)
485
+ end
486
+ end
487
+ def default
488
+ false
489
+ end
490
+ def to_s
491
+ "bool"
492
+ end
493
+ end
494
+
495
+ class BoolTrue < Bool
496
+ def default
497
+ true
498
+ end
499
+ end
500
+
501
+ #--
502
+ # perhaps this should stay a secret ;)
503
+ #++
504
+ def true.rant_constraint
505
+ BoolTrue.rant_constraint
506
+ end
507
+ def false.rant_constraint
508
+ Bool.rant_constraint
509
+ end
510
+
270
511
  end # module Constraints
271
512
 
272
513
  # A +vid+ has to be a String to be valid.