rant 0.3.4 → 0.3.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -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.