=begin header Simple scheme for properties $Author: Hiroshi IGARASHI $ $Date: Mon Mar 8 16:36:13 1999$ =end class Properties =begin Class Properties This class is *not* Thread-Safe. =end include Enumerable attr_accessor(:default) =begin Properties object for dafault values. =end # @changed # whether is changed # @property # mapping key to value # @desc # description lines # @index # mapping key -> (line number in @desc) def initialize(default=nil) =begin Make an empty Properties with specified default values. =end @default = default @changed = true @property = {} @desc = [] @index = {} end def setProperty(key, val) =begin Sets a value val to property which has the specified name key. Returns the previous value, or nil when the property has no value. =end p([key, val]) if $DEBUG @changed = true old_val = @property[key] @property[key] = val # remove description line if val is nil. if val.nil? @desc[@index[key]] = nil end old_val end alias []= setProperty =begin operator form of setProperty =end def getProperty(key, default_val=nil) =begin Returns the value of the property specified by key. When there is not the property, returns the default value default if it is specified, returns nil otherwise. =end p([key, default_val]) if $DEBUG if val = @property[key] val else if (not @default.nil?) and (val = @default.getProperty(key)) val else default_val end end end alias [] getProperty =begin oprerator form of getProperty =end def method_missing(mid, *args, &iter) p([mid.id2name, args]) if $DEBUG case mid.id2name when /^(.+)=$/ key = $1 val = args[0] self.setProperty(key, val) when /^(.+)$/ key = $1 default_val = args[0] self.getProperty(key, default_val) else raise NameError.new end end def addComment(comment) =begin Adds a comment to the tail of the descriptions =end # @desc << ('; ' + comment) @desc << comment self end def list(output=STDERR) =begin Lists the contents of this properties to specified stream output. =end output.puts("changed = " + @changed.inspect) @property.each_pair do |key, value| # output.lprintln(key, ' = ', value) output.print(key, ' = ', value.inspect, "\n") end nil end alias dump list def load(input) =begin Loads properties from input. input must be IO or String(filename). =end case input # input stream when IO loadStream(input) # file name when String input = File.expand_path(input) file = File.open(input) loadStream(file) else raise 'Properties:invalid input' end self end public(:load) private def loadStream(str) =begin Loads descriptions from the stream str. =end @changed = false @desc = [] @index = {} line_num = 0 while line = str.gets line.strip! # line = Kconv.tolocal(line) @desc[line_num] = line if line == '' # empty line -> nop elsif line =~ /^\s*;.*$/ # comment -> nop elsif line =~ /^\s*#.*$/ # comment -> nop elsif line =~ /^\s*([^\s=]+)\s*=\s*(.+)\s*$/ key, val = $1, eval($2) # p [key, val] @property[key] = val @index[key] = line_num else # error (should some exception be raised?) STDERR.print("Properties:invalid description:#{$.}\n") end line_num += 1 end end public def save(output) =begin Saves properties to outptu. output must be IO or String(filename). =end case output # output stream when IO updateDesc saveStream(output) # filename when String updateDesc output = File.expand_path(output) file = File.open(output, 'w') saveStream(file) file.close else p output.type raise 'Properties:invalid output' end self end def each(*args, &iter) @property.each(*args, &iter) end def each_key(*args, &iter) @property.each_key(*args, &iter) end def each_pair(*args, &iter) @property.each_pair(*args, &iter) end private def updateDesc =begin Reflects current properties to descriptions. =end if @changed @property.each_pair do |key, val| # key is new property if @index[key].nil? @index[key] = @desc.length end # update the description line. @desc[@index[key]] = "#{key} = #{val.inspect}" end end self end def saveStream(str) =begin Saves properties to output stream str. =end @desc.each do |line| # str.lprintln(line) unless line.nil? str.print(line, "\n") unless line.nil? end end end