class Plist::Emit::PlistBuilder

Public Class Methods

new(indent_str) click to toggle source
# File lib/plist/generator.rb, line 64
def initialize(indent_str)
  @indent_str = indent_str.to_s
end

Public Instance Methods

build(element, level=0) click to toggle source
# File lib/plist/generator.rb, line 68
def build(element, level=0)
  if element.respond_to? :to_plist_node
    element.to_plist_node
  else
    case element
    when Array
      if element.empty?
        tag('array', nil, level)
      else
        tag('array', nil, level) {
          element.collect {|e| build(e, level + 1) }.join
        }
      end
    when Hash
      if element.empty?
        tag('dict', nil, level)
      else
        tag('dict', '', level) do
          element.sort_by{|k,v| k.to_s }.collect do |k,v| 
            tag('key', CGI.escapeHTML(k.to_s), level + 1) +
            build(v, level + 1)
          end.join
        end
      end
    when true, false
      tag(element, nil, level)
    when Time
      tag('date', element.utc.strftime('%Y-%m-%dT%H:%M:%SZ'), level)
    when Date # also catches DateTime
      tag('date', element.strftime('%Y-%m-%dT%H:%M:%SZ'), level)
    when String, Symbol, Integer, Float
      tag(element_type(element), CGI.escapeHTML(element.to_s), level)
    when IO, StringIO
      data = element.tap(&:rewind).read 
      data_tag(data, level)
    else
      data = Marshal.dump(element)
      comment_tag('The <data> element below contains a Ruby object which has been serialized with Marshal.dump.') +
      data_tag(data, level)
    end
  end
end

Private Instance Methods

comment_tag(content) click to toggle source
# File lib/plist/generator.rb, line 157
def comment_tag(content)
  return "<!-- #{content} -->\n"
end
data_tag(data, level) click to toggle source
# File lib/plist/generator.rb, line 125
def data_tag(data, level)
  # note that apple plists are wrapped at a different length then
  # what ruby's base64 wraps by default.
  # I used #encode64 instead of #b64encode (which allows a length arg)
  # because b64encode is b0rked and ignores the length arg.
  tag('data', nil, level) do
    Base64.encode64(data)
          .gsub(/\s+/, '')
          .scan(/.{1,68}/o)
          .collect { |line| indent(line, level) }
          .join("\n")
          .concat("\n")
  end
end
element_type(item) click to toggle source
# File lib/plist/generator.rb, line 144
def element_type(item)
  case item
  when String, Symbol
    'string'
  when Integer
    'integer'
  when Float
    'real'
  else
    raise "Don't know about this data type... something must be wrong!"
  end
end
indent(str, level) click to toggle source
# File lib/plist/generator.rb, line 140
def indent(str, level)
  @indent_str.to_s * level + str
end
tag(type, contents, level, &block) click to toggle source
# File lib/plist/generator.rb, line 113
def tag(type, contents, level, &block)
  if block_given?
    indent("<#{type}>\n", level) +
    block.call +
    indent("</#{type}>\n", level)
  elsif contents.to_s.empty?
    indent("<#{type}/>\n", level)
  else
    indent("<#{type}>#{contents.to_s}</#{type}>\n", level)
  end
end