lib/rant/rantvar.rb in rant-0.3.2 vs lib/rant/rantvar.rb in rant-0.3.4
- old
+ new
@@ -1,82 +1,301 @@
+# rantvar.rb - Constants required by all Rant code.
+#
+# Copyright (C) 2005 Stefan Lang <langstefan@gmx.at>
+#
+# This program is free software.
+# You can distribute/modify this program under the terms of
+# the GNU LGPL, Lesser General Public License version 2.1.
+#
# This file provides support for the +var+ attribute of the Rant
# application (Rant::RantApp#var).
module Rant
+ VERSION = '0.3.4'
+
+ # Those are the filenames for rantfiles.
+ # Case matters!
+ RANTFILES = [ "Rantfile",
+ "rantfile",
+ "Rantfile.rb",
+ "rantfile.rb",
+ ]
+
+ # Names of plugins and imports for which code was loaded.
+ # Files that where loaded with the `import' commant are directly
+ # added; files loaded with the `plugin' command are prefixed with
+ # "plugin/".
+ CODE_IMPORTS = []
+
+ class RantAbortException < StandardError
+ end
+
+ class RantDoneException < StandardError
+ end
+
+ class RantError < StandardError
+ end
+
+ class RantfileException < RantError
+ end
+
+ # This module is a namespace for generator classes.
+ module Generators
+ end
+
module RantVar
- class Error < StandardError
+ class Error < RantError
end
class ConstraintError < Error
+
+ attr_reader :constraint, :val
+
+ def initialize(constraint, val, msg = nil)
+ #super(msg)
+ @msg = msg
+ @constraint = constraint
+ @val = val
+ end
+
+ def message
+ # TODO: handle @msg
+ val_desc = @val.inspect
+ val_desc[7..-1] = "..." if val_desc.length > 10
+ "#{val_desc} doesn't match constraint: #@constraint"
+ end
end
class InvalidVidError < Error
+ def initialize(vid, msg = nil)
+ @msg = msg
+ @vid = vid
+ end
+ def message
+ # TODO: handle @msg
+ vid_desc = @vid.inspect
+ vid_desc[7..-1] = "..." if vid_desc.length > 10
+ "#{vid_desc} is not a valid var identifier"
+ end
end
class InvalidConstraintError < Error
end
+ class QueryError < Error
+ end
+
class Space
+ @@env_ref = Object.new
+
def initialize
# holds all values
@store = {}
# holds constraints for values in @store
@constraints = {}
end
+ def query(*args, &block)
+ # currently ignoring block
+ case args.size
+ when 0
+ raise QueryError, "no arguments", caller
+ when 1
+ arg = args.first
+ if Hash === arg
+ init_all arg
+ else
+ self[arg]
+ end
+ when 2..3
+ vid, constraint, val = *args
+ begin
+ constraint =
+ Constraints.const_get(constraint).new
+ rescue
+ raise QueryError,
+ "no such constraint: #{constraint}", caller
+ end
+ constrain vid, constraint
+ self[vid] = val if val
+ else
+ raise QueryError, "to many arguments"
+ end
+ end
+
# Get var with name +vid+.
def [](vid)
- unless RantVar.valid_vid? vid
- raise InvalidVidError, vid
- end
- @store[vid]
+ vid = RantVar.valid_vid vid
+ val = @store[vid]
+ val.equal?(@@env_ref) ? ENV[vid] : val
end
# Set var with name +vid+ to val. Throws a ConstraintError
# if +val+ doesn't match the constraint on +vid+ (if a
# constraint is registered for +vid+).
def []=(vid, val)
- unless RantVar.valid_vid? vid
- raise InvalidVidError, vid
- end
+ vid = RantVar.valid_vid(vid)
c = @constraints[vid]
- @store[vid] = c ? c.filter(val) : val
+ if @store[vid] == @@env_ref
+ ENV[vid] = c ? c.filter(val) : val
+ else
+ @store[vid] = c ? c.filter(val) : val
+ end
end
+ # Use ENV instead of internal store for given vars.
+ # Probably useful for vars like CC, CFLAGS, etc.
+ def env *vars
+ vars.flatten.each { |var|
+ vid = RantVar.valid_vid(var)
+ cur_val = @store[vid]
+ next if cur_val == @@env_ref
+ ENV[vid] = cur_val unless cur_val.nil?
+ @store[vid] = @@env_ref
+ }
+ nil
+ end
+
+ def set_all hash
+ unless Hash === hash
+ raise QueryError,
+ "set_all argument has to be a hash"
+ end
+ hash.each_pair { |k, v|
+ self[k] = v
+ }
+ end
+
+ def init_all hash
+ unless Hash === hash
+ raise QueryError,
+ "init_all argument has to be a hash"
+ end
+ hash.each_pair { |k, v|
+ self[k] = v if self[k].nil?
+ }
+ end
+
# Add +constraint+ for var with id +vid+.
def constrain vid, constraint
- unless RantVar.valid_vid? vid
- raise InvalidVidError, vid
- end
+ vid = RantVar.valid_vid(vid)
unless RantVar.valid_constraint? constraint
raise InvalidConstraintError, constraint
end
@constraints[vid] = constraint
+ if @store.member? vid
+ begin
+ val = @store[vid]
+ @store[vid] = constraint.filter(@store[vid])
+ rescue
+ @store[vid] = constraint.default
+ raise ConstraintError.new(constraint, val)
+ end
+ else
+ @store[vid] = constraint.default
+ end
end
end # class Space
module Constraint
- end # module Constraint
+ def matches? val
+ filter val
+ true
+ rescue
+ return false
+ end
+ end
+ module Constraints
+
+ class Integer
+ include Constraint
+
+ def filter(val)
+ Kernel::Integer(val)
+ rescue
+ raise ConstraintError.new(self, val)
+ end
+ def default
+ 0
+ end
+ def to_s
+ "integer"
+ end
+ end
+
+ class AutoList
+ include Constraint
+
+ def filter(val)
+ if val.respond_to? :to_ary
+ val.to_ary
+ elsif val.nil?
+ raise ConstraintError.new(self, val)
+ else
+ [val]
+ end
+ end
+ def default
+ []
+ end
+ def to_s
+ "list or single, non-nil value"
+ end
+ end
+
+ class List
+ include Constraint
+
+ def filter(val)
+ if val.respond_to? :to_ary
+ val.to_ary
+ else
+ raise ConstraintError.new(self, val)
+ end
+ end
+ def default
+ []
+ end
+ def to_s
+ "list (Array)"
+ end
+ end
+
+ Array = List
+
+ end # module Constraints
+
# A +vid+ has to be a String to be valid.
- def valid_vid?(obj)
- String === obj
+ def valid_vid(obj)
+ case obj
+ when String: obj
+ when Symbol: obj.to_s
+ else
+ if obj.respond_to? :to_str
+ obj.to_str
+ else
+ raise InvalidVidError.new(obj)
+ end
+ end
end
# A constraint has to respond to the following methods:
# [filter(val)]
# Filter _val_ or throw ConstraintError if _val_ doesn't
# match constraint.
# [matches?(val)]
# Return true if _val_ matches constraint.
def valid_constraint?(obj)
# TODO: check for arity
- obj.respond_to?(:filter) && obj.respond_to?(:matches?)
+ obj.respond_to?(:filter) &&
+ obj.respond_to?(:matches?) &&
+ obj.respond_to?(:default)
end
- module_function :valid_constraint?, :valid_vid?
+ module_function :valid_constraint?, :valid_vid
end # module RantVar
end # module Rant