# = TITLE: # # Information # # = COPYING: # # Copyright (c) 2007 Psi T Corp. # # This file is part of the ProUtils' Ratch program. # # Ratch is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Ratch is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Ratch. If not, see . require 'yaml' require 'facets/hash/rekey' module Ratch # Validation Error class ValidationError < Exception end # class Information class << self def instance_attributes @attributes ||= [] end # Define an attribute. def attr_accessor(name, *aliases, &blk) instance_attributes << name.to_s instance_attributes.uniq! if blk define_method(name, &blk) attr_writer(name) else super(name) end aliases.each{ |aliaz| alias_accessor(aliaz, name) } end # Define an attribute alias. def alias_accessor(aliaz, name) alias_method aliaz, name alias_method "#{aliaz}=", "#{name}=" end def validation @validation ||= [] end def validate(message, &block) validation << [message, block] end # Does this class provide open access? # #def open_access? # false #end end def instance_data @instance_data ||= {} end # List attributes. (Needed?) def attributes self.class.instance_attributes end # Initialize #################### def initialize(data={}) update(data) end def update(data) instance_data.update(data.rekey(:to_s)) data.each do |k,v| send("#{k}=", v) rescue nil end # TODO Could add yield(self) via: #yld.to_h.each do |k,v| # send( "#{k}=", v ) rescue nil #end end # Access #################### # Fetch attribute value, but return nil if it doesn't exist. #-- # TODO Use in method missing instead? #++ def [](name) begin h = send(name) rescue NoMethodError h = nil end end # Gathers a group of info hash entries into a merged hash. # The +names+ are taken in most to least significant order. # # gather(:package) # # TODO Change name of this method to something better? def gather( *names ) result = names.inject({}) do |hash,name| attributes.each do |n| if n.to_s =~ /^#{name}_(.*?)$/ hash[$1] = self[n.to_s] if self[n.to_s] end end hash end result end # Collects a group of info entries into a hash. # Arguments are a list of info entry names and/or # a hash or new name to info entry name. # # select(:name, :version, :date => :released) # # This is used to collect info to pass to tools. def select( *args ) maps = (Hash === args.last ? args.pop : {}) h = {} args.each{ |k| h[k.to_s] = self[k] } maps.each{ |k, i| h[k.to_s] = self[i] } h end # Validation ###################### # def valid? begin validate return true rescue ValidationError return false end end # def validate self.class.validation.each do |message, block| raise(ValidationError, message) unless instance_eval(&block) end end alias_method :assert_valid, :validate # Conversion ################# # Order of attributes for yaml conversion. def to_yaml_properties attributes.collect{ |a| "@#{a}" } end # Use YAML format. def to_yaml( opts={} ) require 'yaml' super end # For yaml conversion, no tag. def taguri; nil; end # Convert to hash. def to_hash attributes.inject({}) do |h, a| v = self[a.to_s] #send(a) h[a] = v unless v.nil? h end end alias_method :to_h, :to_hash # Use generic XML format. def to_xml( opts={} ) raise "not yet implemented" end # # Use XOXO microformat. # # def to_xoxo( opts={} ) # begin # require 'blow/xoxo' # EXTERNAL DEPENDENCY! # rescue LoadError # puts 'Blow (http://blow.rubyforge.org) is required to use XOXO format' # end # XOXO.dump(self.to_hash, opts) # end # Arbitrary information ############################ # # TODO Perhaps not define this at all if open_access? is false. # # def method_missing( s, *a, &b ) # super unless self.class.open_access? # s = s.to_s # if s[-1,1] == '=' # (class << self; self; end).class_eval do # attr_accessor s.chomp('=') # end # send(s,*a,&b) # else # nil #super # end # end end end