#!/usr/bin/env ruby -w # $Id: chplist.rb 1299 2008-05-12 14:55:08Z admin $ require 'rubygems' require 'plist' class Plwrap attr_accessor :pl attr_accessor :filename attr_accessor :binary attr_accessor :do_conversion def initialize(fn) do_conversion = true @filename = fn if ! File.exists?(fn) @pl = Plist::parse_xml(Hash.new.to_plist) return end @binary = false ret = %x{file #{fn}} if ret =~ /binary|data/ if do_conversion @binary = true %x{plutil -convert xml1 #{fn}} else raise "I'm not allowed to convert binary plist" end end @pl = Plist::parse_xml(@filename) end def get(key,path=nil) if(!path and get_without_path_ok?(key)) path = guesspath(key) end mpath = modpath(path) return eval("@pl" + mpath) end def typeof(key,path=nil) return self.get(key,path).class end def set(key, val, klass=nil, path=nil) begin if(!path and get_without_path_ok?(key)) path = guesspath(key) end rescue Exception => e if e.message =~ /oo many/ raise e end path = key end mpath = modpath(path) mpath = "[\"#{key}\"]" if !mpath return eval("@pl" + mpath + "= convert(val,key,klass,path)") end def modpath(p) return p.split("::").map{|a| '["' + a + '"]'}.join("") if p end def guesspath(key,base=@pl) raise "base is not set in guesspath" if !base base.each do |a,b| if key == a return a end if b.methods.include?("each") if x = guesspath(key,b) x = a + "::" + x return x end end end return false end def set_without_path_ok?(key) num = num_of_keys_with_this_name(@pl,key) if num > 1 raise "Too many occurences of #{key} in tree (#{num} times)" end return true end def get_without_path_ok?(key) num = num_of_keys_with_this_name(@pl,key) if num == 0 raise "Key #{key} does not exist" elsif num > 1 raise "Too many occurences of #{key} in tree (#{num} times)" end return true end def num_of_keys_with_this_name(base, key) sum = 0 raise "base is not set in num_of_keys_with_this_name" if !base base.each do |a,b| sum += 1 if key == a if b.methods.include?("each") sum += num_of_keys_with_this_name(b,key) end end return sum end def write(fn = @filename) Plist::Emit::save_plist(@pl, fn) %x{plutil -convert binary1 #{fn}} if do_conversion and @binary end def convert(val,key=nil,klass=nil,path=nil) if !klass raise ArgumentError, "Key needed if klass not given" if !key if get_without_path_ok?(key) klass = typeof(key,path) end end case klass.to_s when "Boolean"; return ["true","1"].include?(val) when "TrueClass"; return ["true","1"].include?(val) when "FalseClass"; return ["true","1"].include?(val) when "Array"; return val.split("::") when "Hash"; raise "Conversion of hashes not yet implemented" when "String"; return val.to_s when "Integer"; return val.to_i when "Fixnum"; return val.to_i when "Float"; return val.to_f else raise "Unknown class #{klass}" end end end if ARGV.size < 4 puts "Usage: $0 file key path val klass\n" exit 1 end file,key,path,val,klass = ARGV klass = nil if ["","nil"].include?(klass) path = nil if ["","nil"].include?(path) pw = Plwrap.new file begin pw.set(key,val,klass,path) rescue Exception => e puts e.message exit 0 end pw.write(file)