Skip to content

Instantly share code, notes, and snippets.

@deathbob
Created March 4, 2010 21:03
Show Gist options
  • Save deathbob/322107 to your computer and use it in GitHub Desktop.
Save deathbob/322107 to your computer and use it in GitHub Desktop.
---- config/initializers/to_plist.rb
require 'rails_extensions/plist'
ActiveRecord::Base.class_eval do
include Plist
end
---- rails_extensions/plist.rb
module Plist
def to_plist(options = {})
hash = ActiveRecord::Serialization::Serializer.new(self, options).serializable_record
# hash.to_plist
PlistXmlSerializer.new(hash, options).serialize
end
class PlistXmlSerializer
attr_reader :options
def initialize(record, options = nil)
@record = record
@options = options ? options.dup : {}
end
def builder
@builder ||= begin
options[:indent] ||= 2
builder = options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent])
unless options[:skip_instruct]
builder.instruct!
builder.declare!(:DOCTYPE, :plist, :PUBLIC, "-//Apple//DTD PLIST 1.0//EN", "http://www.apple.com/DTDs/PropertyList-1.0.dtd" )
options[:skip_instruct] = true
end
builder
end
end
def serialize
if options[:do_not_add_version]
build_attributes
else
builder.plist(:version => "1.0" ) do
build_attributes
end
end
end
def build_attributes
builder.dict do
@record.each do |k, v|
builder.key k.to_s
case v
# weird v.class doesn't work, but plain old v does
when String
builder.string v
when Time
builder.date v.strftime('%Y-%m-%dT%H:%M:%SZ')
when Fixnum
builder.integer v
when BigDecimal
builder.real v
when FalseClass
builder.false
when TrueClass
builder.true
else
builder.string v
end
end
end
end
# xml.comment!("COMMENT")
# xml.declare!("DECLARATION")
# xml.cdata!("CDATA")
# def to_s
# serialize
# end
# def to_plist(options = {:root => 'dict'})
# options[:indent] ||= 2
# xml = options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent])
# unless options[:skip_instruct]
# xml.instruct!
# xml.declare!(%w{DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"} )
# xml.plist(:version => "1.0" ) do
# xml.dict do
# self.attributes.each do |k, v|
# xml.key k.to_s
# xml.string v.to_s
# end
# end
# end
# end
# end
# module Enumerable
# def to_plist(*a)
# to_a.to_plist(*a)
# end
# end
end
end
class Array
def to_plist(options = {})
raise "Not all elements respond to to_plist" unless all? { |e| e.respond_to? :to_plist }
require 'builder' unless defined?(Builder)
options = options.dup
options[:root] ||= all? { |e| e.is_a?(first.class) && first.class.to_s != "Hash" } ? ActiveSupport::Inflector.pluralize(ActiveSupport::Inflector.underscore(first.class.name)) : "records"
options[:children] ||= options[:root].singularize
options[:indent] ||= 2
options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent])
root = options.delete(:root).to_s
children = options.delete(:children)
if !options.has_key?(:dasherize) || options[:dasherize]
root = root.dasherize
end
unless options.delete(:skip_instruct)
options[:builder].instruct!
options[:builder].declare!(:DOCTYPE, :plist, :PUBLIC, "-//Apple//DTD PLIST 1.0//EN", "http://www.apple.com/DTDs/PropertyList-1.0.dtd" )
end
opts = options.merge({ :root => children })
plist = options[:builder]
# yield plist if block_given?
plist.plist(:version => "1.0" ) do
if options[:hash]
plist.tag!('dict') do
each do |e|
plist.key e.id
e.to_plist(opts.merge({ :skip_instruct => true, :do_not_add_version => true }))
end
end
else
plist.tag!('array') do
each { |e| e.to_plist(opts.merge({ :skip_instruct => true, :do_not_add_version => true })) }
end
end
end
plist.target!
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment