#!/usr/bin/env ruby ###################################### # Copyright 2006, Ben Bleything. # # # # # # Distributed under the MIT license. # ###################################### # # plist data types: # # CFString -> String # CFNumber -> Float(?) # CFBoolean -> or # CFDate -> Date # CFData -> binary data # # CFArray -> Array # CFDictionary -> Hash (important: all keys must be CFString/String) # require 'date' module Plist VERSION = '0.0.1' def to_plist(header = true) output = [] if header output << '' output << '' output << '' end output << plist_node(self) output << '' if header return output.join end private def plist_node(element) output = '' case element when Array output << tag('array') { element.collect {|e| plist_node(e)}.join } when Hash inner_tags = [] element.each do |k,v| inner_tags << tag('key', k.to_s) inner_tags << plist_node(v) end output << tag('dict') { inner_tags.join } when true, false output << "<#{element}/>" when Time output << tag('date', element.utc.strftime('%Y-%m-%dT%H:%M:%SZ')) when Date # also catches DateTime output << tag('date', element.strftime('%Y-%m-%dT%H:%M:%SZ')) when String, Symbol, Fixnum, Bignum, Integer, Float output << tag(element_type(element), element.to_s) else output << tag('data', Marshal.dump(element)) end return output end def tag(type, contents = '', &block) contents << block.call if block_given? return "<#{type}>#{contents.to_s}" end def element_type(item) return case item when Array: 'array' when String, Symbol: 'string' when Fixnum, Bignum, Integer: 'integer' when Float: 'real' when Array: 'array' when Hash: 'dict' else raise "Don't know about this data type... something must be wrong!" end end end class Array include Plist end class Hash include Plist end