pax_global_header00006660000000000000000000000064137731772050014526gustar00rootroot0000000000000052 comment=ce8f9ae42a114f603ea200c955e420782bffc4ad plist-3.6.0/000077500000000000000000000000001377317720500126675ustar00rootroot00000000000000plist-3.6.0/.gitignore000066400000000000000000000001271377317720500146570ustar00rootroot00000000000000/.bundle/ /.yardoc /Gemfile.lock /_yardoc/ /coverage/ /doc/ /pkg/ /spec/reports/ /tmp/ plist-3.6.0/.travis.yml000066400000000000000000000004621377317720500150020ustar00rootroot00000000000000--- language: ruby cache: bundler branches: only: - master rvm: - jruby-18mode - jruby-19mode - 1.9.3 - 2.0.0-p648 # macOS - 2.1.10 - 2.2.10 - 2.3.8 - 2.4.5 - 2.5.3 - 2.6 - 2.7 - 3.0 - ruby-head - jruby-head before_install: gem install bundler -v '~> 1.14' --conservative plist-3.6.0/CHANGELOG.rdoc000066400000000000000000000123641377317720500150350ustar00rootroot00000000000000= plist - All-purpose Property List manipulation library === Unreleased https://github.com/patsplat/plist/compare/v3.6.0...HEAD * Your contribution here! === 3.6.0 (2020-12-30) https://github.com/patsplat/plist/compare/v3.5.0...v3.6.0 New features and important changes: * Do not indent multiline string values (https://github.com/patsplat/plist/pull/54) * Add `Plist::UnimplementedElementError` (https://github.com/patsplat/plist/pull/51) * Add support for text inside `` (https://github.com/patsplat/plist/pull/49) Housekeeping: * Add Ruby 2.7 and 3.0 to CI (https://github.com/patsplat/plist/pull/55) * add docker-compose for development (https://github.com/patsplat/plist/pull/47) * Replace `require` with `require_relative`(https://github.com/patsplat/plist/pull/52) === 3.5.0 (2018-12-22) https://github.com/patsplat/plist/compare/v3.4.0...v3.5.0 * Only ship the required libs in the gem artifact (https://github.com/patsplat/plist/pull/48) === 3.4.0 (2017-12-08) https://github.com/patsplat/plist/compare/v3.3.0...v3.4.0 * Support custom indent string (https://github.com/patsplat/plist/pull/44) === 3.3.0 (2017-04-28) https://github.com/patsplat/plist/compare/dece870...v3.3.0 * Fix ASCII/UTF-8 error (https://github.com/patsplat/plist/pull/38). * Fix Fixnum, Bignum deprecations in Ruby 2.4 * Fix unused variable `e` warning === 3.2.0 (2016-01-28) https://github.com/patsplat/plist/compare/ea0b4e7...dece870 * Changed sort to sort_by in Plist::Emit.plist_node to allow mixed symbol and string hash keys * Updated deprecated File.exists? to File.exist? * Fixed defect in PData in which exception was thrown when element was read from plist === 3.1.0 (2010-02-23) 2010-02-23: * Ruby 1.9.x compatibility! 2010-02-16: * excise a bunch of unnecessary @@ variables * fix up some tests for cross-version compatibility 2010-02-14: * generalized cleanup: * fix old file headers * modernize rakefile * clean up rdoc 2010-01-08: * move from RubyForge Subversion to GitHub 2007-02-22 (r81): * make the plist parser accept strings contain XML or any object that responds to #read (File and StringIO being the intended targets here). Test and idea contributed by Chuck Remes. 2006-09-20 (r80): * tweak a comment in generator.rb to make it clear that we're not using Base64.b64encode because it's broken. === 3.0.0 (2006-09-20) 2006-09-20 (r77 - r79): * move IndentedString inside Plist::Emit and :nodoc: it * Tag 3.0.0! (from rev 78) 2006-09-19 (r73 - r75): * Really fix the rakefile this time (apparently I deleted some code that I needed...) * alter the fix_whitespace rake task to ignore the assets directory * cleanup whitespace 2006-09-18 (r70 - r72): * Update this file ;) * Fix Rakefile * gem install -t now works correctly * Remove super-sekr1t rdoc staging area from rdoc publishing task 2006-09-15 (r64 - r69): * Change behavior of empty collection elements to match What Apple Does * Fix some gem packaging infrastructure 2006-09-13 (r61 - r63): * Merge generator injection removal branch into trunk! 2006-09-13 (r52 - r60): * Fix indentation/newlines in generator (finally!) * Refix indentation to be more faithful to the way Apple emits their plists * Remove horrific regex and replace it with proper comment parsing * Empty plists return nil when parsed * Sort hash keys before emitting (now we can test multi-element hashes!) * Inject #<=> into Symbol so that sorting Symbol-keyed hashes won't freak out === 2.1.2 (2006-09-20) 2006-09-12 (r47 - r51): * More test rejiggering * New tests to expose some bugs 2006-09-10 (r33 - r46): * Update tests for new generator code * Rejigger some tests * Make the generator try to call #to_plist_node on any object it tries to serialize, thus allowing class authors to define how their objects will be serialized * Marshal.dump unrecognized objects into elements * Make the parser strip out comments and Marshal.load elements if possible * Update some rdoc === 2.1.1 (2006-09-10) 2006-09-10 (r31 - r32): * Added encoding / decoding for entities (& etc) * Changed parsing of elements to return StringIO objects * Fixed bug with empty tags 2006-08-24 (r25 - r30): * Invert ownership of methods in the generator, allowing us to remove the self.extend(self) * New branch to remove method inject from parser 2006-08-23 (r22 - r24): * Add rcov task to Rakefile * Add some tests 2006-08-20 (r9 - r21): * Add a bunch of rdoc and rdoc infrastructure * Add rake task to clean up errant whitespace * Spin off a branch to remove a bunch of method injection in the generator code * Rename some tests for clarity's sake * Replace NARF generation code with Ben's generation code * Update tests * This broke indentation (will be fixed later) * Add Plist::Emit.dump, so you can dump objects which don't include Plist::Emit, update tests to match * Fix a bug with the method that wraps output in the plist header/footer 2006-08-19 (r1 - r8): * The beginnings of merging the plist project into the NARF plist library (under the plist project's name) * fancier project infrastructure (more tests, Rakefile, the like) * Add/update copyright notices in the source files * Move a bunch of documentation out to README * Split library into chunks * Properly delete files when cleaning up from tests plist-3.6.0/Dockerfile000066400000000000000000000001261377317720500146600ustar00rootroot00000000000000FROM ruby:2.5.3-alpine3.8 RUN apk update && apk add git WORKDIR /app COPY . . CMD sh plist-3.6.0/Gemfile000066400000000000000000000001321377317720500141560ustar00rootroot00000000000000source "https://rubygems.org" # Specify your gem's dependencies in plist.gemspec gemspec plist-3.6.0/LICENSE.txt000066400000000000000000000020671377317720500145170ustar00rootroot00000000000000Copyright (c) 2006-2010, Ben Bleything and Patrick May Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. plist-3.6.0/README.rdoc000066400000000000000000000160001377317720500144720ustar00rootroot00000000000000= All-purpose Property List manipulation library {Gem Version}[https://rubygems.org/gems/plist] {Build Status}[https://travis-ci.org/patsplat/plist] Plist is a library to manipulate Property List files, also known as plists. It can parse plist files into native Ruby data structures as well as generating new plist files from your Ruby objects. == Usage === Security considerations Plist.parse_xml uses Marshal.load for attributes. If the attribute contains malicious data, an attacker can gain code execution. You should never use Plist.parse_xml with untrusted plists! === Parsing result = Plist.parse_xml('path/to/example.plist') result.class => Hash "#{result['FirstName']} #{result['LastName']}" => "John Public" result['ZipPostal'] => "12345" ==== Example Property List FirstName John LastName Public StreetAddr1 123 Anywhere St. StateProv CA City Some Town CountryName United States AreaCode 555 LocalPhoneNumber 5551212 ZipPostal 12345 === Generation plist also provides the ability to generate plists from Ruby objects. The following Ruby classes are converted into native plist types: Array, Bignum, Date, DateTime, Fixnum, Float, Hash, Integer, String, Symbol, Time, true, false * +Array+ and +Hash+ are both recursive; their elements will be converted into plist nodes inside the and containers (respectively). * +IO+ (and its descendants) and +StringIO+ objects are read from and their contents placed in a element. * User classes may implement +to_plist_node+ to dictate how they should be serialized; otherwise the object will be passed to Marshal.dump and the result placed in a element. See below for more details. ==== Creating a plist There are two ways to generate complete plists. Given an object: obj = [1, :two, {'c' => 0xd}] If you've mixed in Plist::Emit (which is already done for +Array+ and +Hash+), you can simply call +to_plist+: obj.to_plist This is equivalent to calling Plist::Emit.dump(obj). Either one will yield: 1 two c 13 You can also dump plist fragments by passing +false+ as the second parameter: Plist::Emit.dump('holy cow!', false) => "holy cow!" ==== Custom serialization If your class can be safely coerced into a native plist datatype, you can implement +to_plist_node+. Upon encountering an object of a class it doesn't recognize, the plist library will check to see if it responds to +to_plist_node+, and if so, insert the result of that call into the plist output. An example: class MyFancyString ... def to_plist_node return "#{self.defancify}" end end When you attempt to serialize a +MyFancyString+ object, the +to_plist_node+ method will be called and the object's contents will be defancified and placed in the plist. If for whatever reason you can't add this method, your object will be serialized with Marshal.dump instead. ==== Custom indent You can customize the default indent foramt (default format is tab) or specify the indent format on each serialization. For example, if you want to reduce size of plist output, you can set the indent to nil. An example to change default indent format: Plist::Emit::DEFAULT_INDENT = nil An example to specify indent format on dump: Plist::Emit.dump({:foo => :bar}, false) => "\n\tfoo\n\tbar\n\n" Plist::Emit.dump({:foo => :bar}, false, :indent => nil) => "\nfoo\nbar\n\n" == Links [Rubygems] https://rubygems.org/gems/plist [GitHub] https://github.com/bleything/plist [RDoc] http://www.rubydoc.info/gems/plist == Credits plist was authored by Ben Bleything and Patrick May . Patrick wrote most of the code; Ben contributed his plist generation library. The project is currently maintained by @mattbrictson[https://github.com/mattbrictson]. Other folks who have helped along the way: [Martin Dittus] who pointed out that +Time+ wasn't enough for plist Dates, especially those in ~/Library/Cookies/Cookies.plist [Chuck Remes] who pushed Patrick towards implementing #to_plist [Mat Schaffer] who supplied code and test cases for elements [Michael Granger] for encouragement and help [Carsten Bormann, Chris Hoffman, Dana Contreras, Hongli Lai, Johan Sørensen] for contributing Ruby 1.9.x compatibility fixes And thank you to all of the other GitHub contributors[https://github.com/patsplat/plist/graphs/contributors] not mentioned here! == License and Copyright plist is released under the MIT License. Portions of the code (notably the Rakefile) contain code pulled and/or adapted from other projects. These files contain a comment at the top describing what was used. === MIT License Copyright (c) 2006-2010, Ben Bleything and Patrick May Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. plist-3.6.0/Rakefile000066400000000000000000000003061377317720500143330ustar00rootroot00000000000000require "bundler/gem_tasks" require "rake/testtask" Rake::TestTask.new(:test) do |t| t.libs << "test" t.libs << "lib" t.test_files = FileList["test/**/test_*.rb"] end task :default => :test plist-3.6.0/bin/000077500000000000000000000000001377317720500134375ustar00rootroot00000000000000plist-3.6.0/bin/console000077500000000000000000000005241377317720500150300ustar00rootroot00000000000000#!/usr/bin/env ruby require "bundler/setup" require "plist" # You can add fixtures and/or initialization code here to make experimenting # with your gem easier. You can also use a different console, if you like. # (If you use this, don't forget to add pry to your Gemfile!) # require "pry" # Pry.start require "irb" IRB.start(__FILE__) plist-3.6.0/bin/setup000077500000000000000000000002031377317720500145200ustar00rootroot00000000000000#!/usr/bin/env bash set -euo pipefail IFS=$'\n\t' set -vx bundle install # Do any other automated setup that you need to do here plist-3.6.0/docker-compose.yml000066400000000000000000000001071377317720500163220ustar00rootroot00000000000000version: '3' services: dev: build: . volumes: - .:/app plist-3.6.0/lib/000077500000000000000000000000001377317720500134355ustar00rootroot00000000000000plist-3.6.0/lib/plist.rb000066400000000000000000000005611377317720500151170ustar00rootroot00000000000000# encoding: utf-8 # = plist # # This is the main file for plist. Everything interesting happens in # Plist and Plist::Emit. # # Copyright 2006-2010 Ben Bleything and Patrick May # Distributed under the MIT License # require 'base64' require 'cgi' require 'stringio' require_relative 'plist/generator' require_relative 'plist/parser' require_relative 'plist/version' plist-3.6.0/lib/plist/000077500000000000000000000000001377317720500145705ustar00rootroot00000000000000plist-3.6.0/lib/plist/generator.rb000066400000000000000000000140541377317720500171070ustar00rootroot00000000000000# encoding: utf-8 # = plist # # Copyright 2006-2010 Ben Bleything and Patrick May # Distributed under the MIT License # module Plist # === Create a plist # You can dump an object to a plist in one of two ways: # # * Plist::Emit.dump(obj) # * obj.to_plist # * This requires that you mixin the Plist::Emit module, which is already done for +Array+ and +Hash+. # # The following Ruby classes are converted into native plist types: # Array, Bignum, Date, DateTime, Fixnum, Float, Hash, Integer, String, Symbol, Time, true, false # * +Array+ and +Hash+ are both recursive; their elements will be converted into plist nodes inside the and containers (respectively). # * +IO+ (and its descendants) and +StringIO+ objects are read from and their contents placed in a element. # * User classes may implement +to_plist_node+ to dictate how they should be serialized; otherwise the object will be passed to Marshal.dump and the result placed in a element. # # For detailed usage instructions, refer to USAGE[link:files/docs/USAGE.html] and the methods documented below. module Emit DEFAULT_INDENT = "\t" # Helper method for injecting into classes. Calls Plist::Emit.dump with +self+. def to_plist(envelope = true, options = {}) Plist::Emit.dump(self, envelope, options) end # Helper method for injecting into classes. Calls Plist::Emit.save_plist with +self+. def save_plist(filename, options = {}) Plist::Emit.save_plist(self, filename, options) end # The following Ruby classes are converted into native plist types: # Array, Bignum, Date, DateTime, Fixnum, Float, Hash, Integer, String, Symbol, Time # # Write us (via RubyForge) if you think another class can be coerced safely into one of the expected plist classes. # # +IO+ and +StringIO+ objects are encoded and placed in elements; other objects are Marshal.dump'ed unless they implement +to_plist_node+. # # The +envelope+ parameters dictates whether or not the resultant plist fragment is wrapped in the normal XML/plist header and footer. Set it to false if you only want the fragment. def self.dump(obj, envelope = true, options = {}) options = { :indent => DEFAULT_INDENT }.merge(options) output = PlistBuilder.new(options[:indent]).build(obj) output = wrap(output) if envelope output end # Writes the serialized object's plist to the specified filename. def self.save_plist(obj, filename, options = {}) File.open(filename, 'wb') do |f| f.write(obj.to_plist(true, options)) end end private class PlistBuilder def initialize(indent_str) @indent_str = indent_str.to_s end 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 element below contains a Ruby object which has been serialized with Marshal.dump.') + data_tag(data, level) end end end private def tag(type, contents, level, &block) if block_given? indent("<#{type}>\n", level) + block.call + indent("\n", level) elsif contents.to_s.empty? indent("<#{type}/>\n", level) else indent("<#{type}>#{contents.to_s}\n", level) end end 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 def indent(str, level) @indent_str.to_s * level + str end 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 def comment_tag(content) return "\n" end end def self.wrap(contents) output = '' + "\n" output << '' + "\n" output << '' + "\n" output << contents output << '' + "\n" output end end end class Array #:nodoc: include Plist::Emit end class Hash #:nodoc: include Plist::Emit end plist-3.6.0/lib/plist/parser.rb000077500000000000000000000131471377317720500164220ustar00rootroot00000000000000# encoding: utf-8 # = plist # # Copyright 2006-2010 Ben Bleything and Patrick May # Distributed under the MIT License # # Plist parses Mac OS X xml property list files into ruby data structures. # # === Load a plist file # This is the main point of the library: # # r = Plist.parse_xml(filename_or_xml) module Plist # Raised when an element is not implemented class UnimplementedElementError < RuntimeError; end # Note that I don't use these two elements much: # # + Date elements are returned as DateTime objects. # + Data elements are implemented as Tempfiles # # Plist.parse_xml will blow up if it encounters a Date element. # If you encounter such an error, or if you have a Date element which # can't be parsed into a Time object, please create an issue # attaching your plist file at https://github.com/patsplat/plist/issues # so folks can implement the proper support. def self.parse_xml(filename_or_xml) listener = Listener.new # parser = REXML::Parsers::StreamParser.new(File.new(filename), listener) parser = StreamParser.new(filename_or_xml, listener) parser.parse listener.result end class Listener # include REXML::StreamListener attr_accessor :result, :open def initialize @result = nil @open = [] end def tag_start(name, attributes) @open.push PTag.mappings[name].new end def text(contents) if @open.last @open.last.text ||= '' @open.last.text.concat(contents) end end def tag_end(name) last = @open.pop if @open.empty? @result = last.to_ruby else @open.last.children.push last end end end class StreamParser def initialize(plist_data_or_file, listener) if plist_data_or_file.respond_to? :read @xml = plist_data_or_file.read elsif File.exist? plist_data_or_file @xml = File.read(plist_data_or_file) else @xml = plist_data_or_file end @listener = listener end TEXT = /([^<]+)/ CDATA = // XMLDECL_PATTERN = /<\?xml\s+(.*?)\?>*/m DOCTYPE_PATTERN = /\s*)/m COMMENT_START = /\A/m UNIMPLEMENTED_ERROR = 'Unimplemented element. ' \ 'Consider reporting via https://github.com/patsplat/plist/issues' def parse plist_tags = PTag.mappings.keys.join('|') start_tag = /<(#{plist_tags})([^>]*)>/i end_tag = /<\/(#{plist_tags})[^>]*>/i require 'strscan' @scanner = StringScanner.new(@xml) until @scanner.eos? if @scanner.scan(COMMENT_START) @scanner.scan(COMMENT_END) elsif @scanner.scan(XMLDECL_PATTERN) encoding = parse_encoding_from_xml_declaration(@scanner[1]) next if encoding.nil? # use the specified encoding for the rest of the file next unless String.method_defined?(:force_encoding) @scanner.string = @scanner.rest.force_encoding(encoding) elsif @scanner.scan(DOCTYPE_PATTERN) next elsif @scanner.scan(start_tag) @listener.tag_start(@scanner[1], nil) if (@scanner[2] =~ /\/$/) @listener.tag_end(@scanner[1]) end elsif @scanner.scan(TEXT) @listener.text(@scanner[1]) elsif @scanner.scan(CDATA) @listener.text(@scanner[1]) elsif @scanner.scan(end_tag) @listener.tag_end(@scanner[1]) else raise UnimplementedElementError.new(UNIMPLEMENTED_ERROR) end end end private def parse_encoding_from_xml_declaration(xml_declaration) return unless defined?(Encoding) xml_encoding = xml_declaration.match(/(?:\A|\s)encoding=(?:"(.*?)"|'(.*?)')(?:\s|\Z)/) return if xml_encoding.nil? begin Encoding.find(xml_encoding[1]) rescue ArgumentError nil end end end class PTag def self.mappings @mappings ||= {} end def self.inherited(sub_class) key = sub_class.to_s.downcase key.gsub!(/^plist::/, '') key.gsub!(/^p/, '') unless key == "plist" mappings[key] = sub_class end attr_accessor :text, :children def initialize @children = [] end def to_ruby raise "Unimplemented: " + self.class.to_s + "#to_ruby on #{self.inspect}" end end class PList < PTag def to_ruby children.first.to_ruby if children.first end end class PDict < PTag def to_ruby dict = {} key = nil children.each do |c| if key.nil? key = c.to_ruby else dict[key] = c.to_ruby key = nil end end dict end end class PKey < PTag def to_ruby CGI.unescapeHTML(text || '') end end class PString < PTag def to_ruby CGI.unescapeHTML(text || '') end end class PArray < PTag def to_ruby children.collect do |c| c.to_ruby end end end class PInteger < PTag def to_ruby text.to_i end end class PTrue < PTag def to_ruby true end end class PFalse < PTag def to_ruby false end end class PReal < PTag def to_ruby text.to_f end end require 'date' class PDate < PTag def to_ruby DateTime.parse(text) end end require 'base64' class PData < PTag def to_ruby data = Base64.decode64(text.gsub(/\s+/, '')) unless text.nil? begin return Marshal.load(data) rescue Exception io = StringIO.new io.write data io.rewind return io end end end end plist-3.6.0/lib/plist/version.rb000066400000000000000000000000771377317720500166060ustar00rootroot00000000000000# encoding: utf-8 module Plist VERSION = '3.6.0'.freeze end plist-3.6.0/plist.gemspec000066400000000000000000000021331377317720500153660ustar00rootroot00000000000000# encoding: utf-8 lib = File.expand_path("../lib", __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require "plist/version" Gem::Specification.new do |spec| spec.name = "plist" spec.version = Plist::VERSION spec.authors = ["Ben Bleything", "Patrick May"] spec.summary = "All-purpose Property List manipulation library" spec.description = "Plist is a library to manipulate Property List files, "\ "also known as plists. It can parse plist files into "\ "native Ruby data structures as well as generating new "\ "plist files from your Ruby objects." spec.homepage = "https://github.com/patsplat/plist" spec.license = "MIT" spec.files = %w{LICENSE.txt} + Dir.glob("lib/**/*", File::FNM_DOTMATCH).reject { |f| File.directory?(f) } spec.require_paths = ["lib"] spec.required_ruby_version = ">= 1.9.3" spec.add_development_dependency "bundler", ">= 1.14" spec.add_development_dependency "rake", "~> 10.5" spec.add_development_dependency "test-unit", "~> 1.2" end plist-3.6.0/test/000077500000000000000000000000001377317720500136465ustar00rootroot00000000000000plist-3.6.0/test/assets/000077500000000000000000000000001377317720500151505ustar00rootroot00000000000000plist-3.6.0/test/assets/AlbumData.xml000066400000000000000000000114171377317720500175300ustar00rootroot00000000000000 Application Version 5.0.4 (263) Archive Path /Users/username/Pictures/iPhoto Library List of Albums AlbumId 999000 AlbumName Library KeyList 7 Master PhotoCount 1 PlayMusic YES RepeatSlideShow YES SecondsPerSlide 3 SlideShowUseTitles SongPath TransitionDirection 0 TransitionName Dissolve TransitionSpeed 1 Album Type Special Roll AlbumId 999001 AlbumName Last Roll Filter Mode All Filters Count 1 Operation In Last Type Roll KeyList 7 PhotoCount 1 PlayMusic YES RepeatSlideShow YES SecondsPerSlide 3 SlideShowUseTitles SongPath TransitionDirection 0 TransitionName Dissolve TransitionSpeed 1 Album Type Special Month AlbumId 999002 AlbumName Last 12 Months Filter Mode All Filters KeyList 7 PhotoCount 1 PlayMusic YES RepeatSlideShow YES SecondsPerSlide 3 SlideShowUseTitles SongPath TransitionDirection 0 TransitionName Dissolve TransitionSpeed 1 Album Type Regular AlbumId 9 AlbumName An Album KeyList 7 PhotoCount 1 PlayMusic YES RepeatSlideShow YES SecondsPerSlide 3 SlideShowUseTitles SongPath TransitionDirection 0 TransitionName Dissolve TransitionSpeed 1 List of Keywords List of Rolls Album Type Regular AlbumId 6 AlbumName Roll 1 KeyList 7 Parent 999000 PhotoCount 1 Major Version 2 Master Image List 7 Aspect Ratio 1 Caption fallow_keep.png.450x450.2005-12-04 Comment a comment DateAsTimerInterval 158341389 ImagePath /Users/username/Pictures/iPhoto Library/2006/01/07/fallow_keep.png.450x450.2005-12-04.jpg MediaType Image MetaModDateAsTimerInterval 158341439.728129 ModDateAsTimerInterval 158341389 Rating 0 Roll 6 ThumbPath /Users/username/Pictures/iPhoto Library/2006/01/07/Thumbs/7.jpg Minor Version 0 plist-3.6.0/test/assets/Cookies.plist000066400000000000000000000047731377317720500176340ustar00rootroot00000000000000 Created 151936595.697543 Domain .cleveland.com Expires 2007-10-25T12:36:35Z Name CTC Path / Value :broadband: Created 151778895.063041 Domain .gamefaqs.com Expires 2006-04-21T16:47:58Z Name ctk Path / Value NDM1YmJlYmU0NjZiOGYxZjc1NjgxODg0YmRkMA%3D%3D Created 183530456 Domain arstechnica.com Expires 2006-10-26T13:56:36Z Name fontFace Path / Value 1 Created 183004526 Domain .sourceforge.net Expires 2006-10-20T02:35:26Z Name FRQSTR Path / Value 18829595x86799:1:1440x87033:1:1440x86799:1:1440x87248:1:1440|18829595|18829595|18829595|18829595 Created 151053128.640531 Domain .tvguide.com Expires 2025-10-10T07:12:17Z Name DMSEG Path / Value 1BDF3D1CC07FC70F&D04451&434EC763&4351FD51&0& Created 151304125.760261 Domain .code.blogspot.com Expires 2038-01-18T00:00:00Z Name __utma Path / Value 11680422.1172819419.1129611326.1129611326.1129611326.1 Created 599529600 Domain .tvguide.com Expires 2020-01-01T00:00:00Z Name gfm Path / Value 0 plist-3.6.0/test/assets/commented.plist000066400000000000000000000003661377317720500202050ustar00rootroot00000000000000 plist-3.6.0/test/assets/example_data.bin000066400000000000000000000001441377317720500202650ustar00rootroot00000000000000plist-3.6.0/test/assets/example_data.jpg000066400000000000000000000224371377317720500203060ustar00rootroot00000000000000JFIFPhotoshop 3.08BIM@ICC_PROFILE0applmntrRGB XYZ  acspAPPL-applq|ySrXYZ,gXYZ@bXYZTwtpthchad|,rTRCgTRCbTRCvcgtndin>desc,ddscmHmmod(cprt-XYZ g< XYZ hhXYZ '/XYZ Rsf32 B&lcurvcurvcurvvcgt'lIHt< ph} %n "/#%2&()}*,9-.0-1u245H6d7r8|9:;<=>?A BCDEFGGHIJLM@NbOPQRT U1VVWXY[\R]^`a[bce fZghik2lbmnoq*rastvwWxyz{|}~ހ,B[vٌ"Eh̔)8FT_hpv|ͩܪٲl;۾Կ #@E!̪q8Б^,ԦZ8ژC܄"Zߌ&X'bM{33cq_3J))iLZF5 < u J4--6"!b"$ %l&')7*p+,.//0M1^2h3m4r5w6y7z8z9x:t;pM?<@(AABCDEFGHIJKLNOP QRST"U'V/W3X9Y?ZF[N\S]_^l_y`abcef.g^hiklLmnopqrstuvwy z!{7|P}k~΁:]ڊ -;IT]ekqvtcQ<$ ڬo`SIC?<<=@EIMPM;! ĺūƚljyhUC/ҼӱԟՆfAٺچS!ޚtQ+I[j.z>Pa$q5E V CpP|>5_ < 6XtwV0 d!:""#$%&o'E(()*+O,,-.h/-/01w2:234f556|7.78999:;R< <=>D??@AUBBCDXEEFGCGHITJJKUKLM'MN0NO9OPDPQVQRrSST-TUaVVWBXXYZ\] ^_`(a5bCcTdjefghiklAminopqstu0v@wIxPyPzJ{C|5}%~~ρȂǃńrZ>bD픵S'֙zbI2עxdK/ݮƯ۶Dhɾ :ToŌƪ,Ŕ&ыԅײk5 (dnindin6XQb([P T9@J=-F_w,CYp,GbJu1d EFcK  o <  | Y ? 49O|  )=Xo.E^}  !>!"r##$T$%&D&'(?()*7*+,2,-.i/?00123|4V5/66789n:G;;<=>|?W@3AABCDEFyGkHbI^J\K[L_MgNpO}PQRSTUVXYZ*[A\X]t^_`b.czdf6gi5jkmnRopr,stv wrxz {N|};oڇc-v0앝NJD!B϶W`Jƻ_FϘkWK*-'Gd+C[t 'Ed1_&\ J`HG r H )  &I|,OzF%nhp! !=!"#]$$%y&)&'(6()*5*+,2,-.i/?00123|4V5/66789n:G;;<=>|?W@3AABCDEFyGkHbI^J\K[L_MgNpO}PQRSTUW X#Y?Za[\]_ `Aa~bdeNfgiOjlmjnp qyrt(uyvxyhz|}O~j G P>\91 !  : j Yo*Z: z j!a"Y#[$`%o&'(*+=,-/1W346T79;<>$?d@[AQBFC?D9E6F/G'H"IJKLLMNOPQRSTUVWXYZ[\^_(`Uabd ePfgiOjkmnUoprCsuvywyiz|h}iuЇ0یFՔhQ|y>V eSZ>ȴ,˨&Τ!џԚהډj޻6o$'&!MWV+hR< Qdesc Color LCDmluc enUS(jaJP:Color LCD000 LCDmmod^KtextCopyright Apple Computer, Inc., 2005CC00 }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ? BAO - UmD𽿁%ucNgS\]b-**7wss #STZ7,%ZpgU':(]WRZ2W\ppq3N\:rJN)NR✗?M|:gmkkWkl/$z,crGJ#5WЧ`8ʴ yJR/1Uq45J)rƲEQ£m^Vd\c-|'ŸRK[:t-.\LzNe8xF%Z:FK٦gwƭ:,bRaha)Ӝh>j*O(~a dSj^YnZ6b[KkwFQ21eè01G8S]g x֜ISrn;[ʞom֩OʜEGN<ԔRiY-zma<;tuKf[ƃ}>M1;nXF EFJSpQWyy)hnuw}SwvvNo{i#$#fuyN1ҹ\p8nK|ݹ5h߳;)*kTVڧ} Ϣ?YZkz&c׊=V;+zI]6Iӧ8dY.$Q۪/31X>OX%)EB.SARnTFSmot 7*S#ԂqG% Rוrb׌ 4V&X\-IG/QJHNzunJ1zt8nV||3l18J4Q/Q6ZrVnMۣm a/=f`fc+7c@pP 2z1U1;9\W4,6߫l' aF5bfVֶ~wZhև}ož%F{K.YwKfV 447C$hD1XlB0I489c'SeFmr|niOf|*:r<ڋ9iAŦފ׌_WV~8.|UԼa|>5&4s=;SlEy-e_(8,ۇ1ZXo(N֩FcF$:u%*HMSa3?aԒN|u%%hϑ'K+_\ُï xږg~q=s|Ko?5_Iz4;KNLIKmxGf}f8> \N juѡKէ 2JUeiR+G,ҎJ,&*JDIӄRRBRU&ӍJ߅^pxƺ?-CHxY&'%X'h_=ׅ[moHMewR C 2mu8K3g^^2u%*}✮UI%NQ+:I9)&Ӄ2%:' \ZUtUΜ&4]칬;#Ӵ Op,Q,h\\EYR6VxU7N=eR8Qg9BN8Y_#9*0J:+Ɣ%)muKu{u9?xZ@PY}ge4pUQJ Ú5|e'dJT*Ae/RTWju)VJV J.;!W}u-u Γx@(K۴]WXwl43G>-& )g!e=;0ؼ#kǞI'yae%W~2,^#C3@|bE1)&91flHJ)ɨH*\JNV[4>ASM{Gw 8PoNtS);%t/.?S/"Xu?SGU]Ql=HdTKM/S77N5)L -o a⥚(SJ<>*kS3b%J8+/vN78Khxt;  o@5#Ru:~d|5bث,F9m&$67qcoqvfeե[{(Ӕm p#RHNX=0Xocxlv\D|&ǂ-dt;^Ŭ@5+<֐į=}|3>[`x5Yk*5qpK^*u}ZgBVJ5&ԔpiKsXùlM8QJLENA)J 1gέy h2xǺڥwNMuE.m./yzoaukrY۔H$.8?L~S9iTƦ>Yb?$,5,+{*k'Jg7ZnNKs|XZj58g u:R FT!JmV_ N1:t)¥JΟ*oWTm);uhڇ}h~kndbK۔Kk2ƎĪgVB4ʎ5+Ҧ3U5EJ?isF*(w|NP:үI\Tj {:_QJOG=|$oxr6]΋F  IMs com.apple.syncservices:9583BE42-EC1A-4B3F-B248-7904BA60634B com.apple.syncservices:2A222E96-4CC6-4320-BE0C-61D5F08C2E64 com.apple.syncservices:64DAA772-4558-49F8-9B87-C4A32D5E05C1 com.apple.syncservices:AF7C6884-B760-4E55-A4D5-B1B114C8A7DC com.apple.syncservices:ECC7FAED-47D6-4DB9-8120-2F029C7D64C8 com.apple.syncservices:D704F079-F869-4613-9CFC-697C1976E8F4 URLs com.apple.syncservices:5BA97109-F8E3-46A9-AF0B-5F8C093F49EA com.apple.syncservices.RecordEntityName com.apple.contacts.Contact display as company person email addresses com.apple.syncservices:B97DCC9C-5B00-4D38-AB06-4B7A5D6BC369 com.apple.syncservices:E508D679-43E1-49E2-B5D7-F14A8E48C067 com.apple.syncservices:C6478063-34A5-4CCB-BD41-1F131D56F7BD com.apple.syncservices:2B3E352C-7831-4349-9A87-0FA4BD290515 first name Mat image /9j/4AAQSkZJRgABAQAAAQABAAD/7QAcUGhvdG9zaG9wIDMuMAA4QklNBAQAAAAAAAD/ 4g9ASUNDX1BST0ZJTEUAAQEAAA8wYXBwbAIAAABtbnRyUkdCIFhZWiAH1gAFABUAFAAg AAZhY3NwQVBQTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9tYAAQAAAADTLWFwcGxx EHyAeZ4fvAacU+DW7cbVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5yWFla AAABLAAAABRnWFlaAAABQAAAABRiWFlaAAABVAAAABR3dHB0AAABaAAAABRjaGFkAAAB fAAAACxyVFJDAAABqAAAAA5nVFJDAAABuAAAAA5iVFJDAAAByAAAAA52Y2d0AAAB2AAA BhJuZGluAAAH7AAABj5kZXNjAAAOLAAAAGRkc2NtAAAOkAAAAEhtbW9kAAAO2AAAAChj cHJ0AAAPAAAAAC1YWVogAAAAAAAAZwIAADyoAAAJjlhZWiAAAAAAAABowAAAq7QAAB5o WFlaIAAAAAAAACcUAAAXvwAAqy9YWVogAAAAAAAA81IAAQAAAAEWz3NmMzIAAAAAAAEM QgAABd7///MmAAAHkgAA/ZH///ui///9owAAA9wAAMBsY3VydgAAAAAAAAABAc0AAGN1 cnYAAAAAAAAAAQHNAABjdXJ2AAAAAAAAAAEBzQAAdmNndAAAAAAAAAAAAAMBAAACAAAA JwCJARYBsAJsA0kESAV0BsgIPAnXC5YNcA9oEX0ToxXSGAwaJRvMHW4fDSCbIi8jtSUy JqooFil9KuEsOS2MLtwwLTF1Mr80CDVINmQ3cjh8OYs6nTuuPL890j7lP/hBCUIUQxtE H0UdRhhHDkf9SOhJ30r0TBxNQE5iT4NQo1HEUudUDVUxVlZXhFizWeRbGlxSXY9e0mAU YVtin2PhZSBmWmeWaMtp/WsybGJtkm7Gb/hxKnJhc5502HYYd1d4mHmyerx7wHzFfc9+ 1n/egOmB94MHhBiFLIZCh1uIdomViraL2Yz+jiKPRZBokY+SrpPMlOWV/ZcVmCmZOJpG m1ScX51onnCfdqB8oYGiiqORpJmlo6asp7yozancqumr9q0ArgWvBK/8sO+x2bK/s5q0 bLU7thK2/7f8uPu5+Lr0u+68573bvtS/0MDKwcnCzMPUxN/F88cLyCPJQMpFyyHL5cyq zXHOOM79z8XQkdFe0izS/dPP1KbVf9Za1zjYF9j42dnamNtD2+TchN0i3cDeWt7z34zg JuC/4Vjh8OKL4yfjxeRi5QHlouZN5wDnwOh76TPp5eqP6zPr0exj7PLtce3w7l/uzu8z 75Pv9PBK8KDw+/GN8iny2fOD9Cn0yfVp9gj2qfdM9/H4ovla+hr66vvN/MD9yf7Q//8A AAAUAEYAkQD0AYQCNQMQBA0FPAaSCA8Jtgt1DUoPNBEtEy0VNhcUGJ0aIhujHRsekB/+ IWIixCQgJWwmuyf8KTcqcCumLNUuAy8vME0xXjJoM200cjV3Nnk3ejh6OXg6dDtwPGc9 Wz5NPzxAKEEUQf1C5EPRRM9F1kbcR+JI50nsSvBL9kz+TgNPB1ANURNSF1MdVCJVJ1Yv VzNYOVk/WkZbTlxTXV9ebF95YIxhomK9Y+BlBWYuZ15ol2nQaw5sTG2NbqdvsXC1cbpy xHPLdNN13nbsd/x5DXohezd8UH1rfop/q4DOgfODF4Q6hV2GhIejiMGJ2oryjAqNHo4t jzuQSZFUkl2TZZRrlXGWdpd/mIWZi5qQm5Gcl52dnp6fnKCdoZiilaOMpICldKZjp1Go PKkkqg2q9KvarL6tqK6Rr4Cwb7FgslOzSbRDtT+2PLc8uD25QLpFu0m8Tb1Qvk2/O8Ah wQrB9sLiw83EusWrxprHich5yWjKVctDzC/NGs4DzurPz9DE0cPSvNOx1J/VhtZm10HY F9jp2brahttT3CHc8N3F3prfdOBR4Svh+uLA44XkSeUO5dPml+db6B/o4+mm6mrrLuvz 7Lbteu4+7wPvx/CM8VDyFPLX8530YfUk9er2rfdx+DX4+vm9+oH7RfwK/M79kv5W/x7/ /wAAAAkAIABDAHAApwDoAVAB1gJ8Az4EHAUcBjUHXwiaCecLPAyVDekPExA2EVgSdBON FKEVrxa6F7sYtRmoGpMbdxxWHTAeAh7QH5kgZCE6Ih8i/yPgJL0llyZvJ0UoGijpKbgq hCtPLBcs3S2jLmgvLS/xMLQxdzI6MvYzrzRmNRo1yzZ8Ny432jiJOTk56jqdO1I8CjzF PYQ+RD8IP8xAkUFVQhZC2UOZRFhFFkXQRopHQ0f0SKRJVEoBSqxLVUv5TJVNJ02tTjBO tE85T75QRFDMUVZR41JyUwNTl1QtVMZVYVYAVqBXQlgDWO1Z81r7XANdCl4QXxpgKGE1 YkNjVGRqZYJmm2e4aNdp92sabEFtaW6Nb69wzXHrcwh0H3UwdkB3SXhQeVB6SntDfDV9 JX4Rfvp/44DPgciCx4PFhMCFuoauh5+IiYlyilqLPowfjQCN4I7Aj6GQg5FikkSTHpPt lLWVgZZTlyeX/JjWmbaal5t6nGKdSZ4ynxygBqDvodeivqOjpJill6aSp4eoeKlkqkur L6wTrPet3a7Gr7GwqLGgsqazr7S/tdu2+rgeuUS6aLuJvKu9yb7owATBIMI6w1TEb8WM xqrHx8jpygjLLMxSzYHOxtAm0YvS/9SF1hTXstlr2zXdFt8M4SjjZOXI6G7rae7F8ur4 1P//AABuZGluAAAAAAAABjYAAJQXAABYjQAAUbUAAI5iAAAoWwAAFqgAAFANAABUOQAC o9cAAkAAAAFKPQADAQAAAgAAABQALQBGAF8AdwCOAKUAvADTAOkA/wEWASwBQwFZAXAB hgGdAbQBywHjAfsCEwIsAkcCYgKGAqoC0AL3Ax8DSgN1A6EDzwP/BDEEZASZBNEFCgVF BYEFwQYCBkYGigbQBxkHYweuB/sISwimCQgJbwnVCjwKpQsQC3wL6gxZDMsNPw24DjQO tA85D8EQTxDjEXwSChKIEwUThxQKFI8VFxWfFikWsxc9F8oYWBjjGW8Z/BqJGxUbohwu HLkdRR3SHl4e7R99IBAgpSE+IdYiciMSI7MkVCT5JaAmRCbsJ5UoPyjnKY0qNyrfK4cs MizZLZkuaS8/MBgw7jHGMqIzfDRWNS82CDbjN7w4ljluOkc7Hjv1PMw9pD58P1dAM0ER QexCz0O0RJ9FjEZ5R2tIYkleSlxLW0xfTWdOcE99UIxRnVKsU75U0VXjVvhYCFkXWipb QVxYXXRelV++YPNiLmN6ZM1mNmewaTVqkmvTbQ9uUm+WcOByLHOBdNJ2IHdyeL96CXtO fJF9zH8CgDuBb4KjhBWF2oehiWOLLYz1jrSQdpIwk+yVnZdOmPiaopxKnfOf66JEpKen FqmZrCGurbFCs8+2V7jhu2C9qr/JwfzESsa7yV/MRs+Y02vX2tzd39riV+T157bqg+1L 8AjykvT69yr5LfsI/L3+g///AAAAJwBHAGQAgACaALMAzADkAPwBEwErAUMBWwF0AYwB pQG+AdgB8gIMAicCRQJkAooCsgLbAwUDMQNfA44DvgPxBCYEXASUBM4FDAVKBYsF0AYX BmAGqgb4B0gHmgfuCEcIpgkKCXIJ3ApICrcLKQudDBQMjw0LDYwOEQ6ZDyYPthBJEOER fBISEp4TLBO8FE8U4xV6FhMWrBdGF+UYhRklGcgabhsUG70caB0SHcEecB8hH9MghiE9 IfEipiNdJBEkxSV5Jikm2CeIKDYo4imKKjUq3iuHLDIs2S2ZLmkvPzAYMO4xxjKiM3w0 VjUvNgg24ze8OJY5bjpHOx479TzMPaQ+fD9XQDNBEUHsQs9DtESfRYxGeUdrSGJJXkpc S1tMX01nTnBPfVCMUZ1SrFO/VNRV7FcKWCNZP1phW4hcrl3cXwpgQWF+YrxkBWVOZqFn 92lPaqxsD21qbslwIHF5ctB0KHV5dsl4GXloerV8An1Pfpp/6oE8go6D9IV1hveIc4nw i3OM8o5tj+2Rb5LxlHmWApePmR+atpxRnfOffKD2onukCqWmp1GpEKrbrLSulLCBsmu0 WbY3uBe57bu7va2/vMHSw+nGBMghykHMZ86P0LfS4dUP1z/Zctum3dvgFuJV5I7m1ekU 617tqu/x8kT0lPbm+Tr7k/3w//8AAABVAIoAtwDhAQgBLgFUAXoBoAHGAe0CFQI+AmoC ngLUAwwDRwOFA8UECQRQBJoE6gU+BZcF9wZcBscHOQexCDEIrAkhCZsKFwqZCyALqww6 DNANag4KDq8PWRAHELkRbxIqEugTsBSAFVoWOhcfGA0Y/BnsGtwbyxy3HaMejR96IGoh YSJZI1skYCVvJoInpSjPKgArPSyHLf8vqzFXMwc0sTZUN/E5hjsVPJ4+JD9kQFtBUUJG Qz9EOUU2Ri9HJ0giSR5KGEsPTAVM/U3zTuhP3lDUUclSu1OvVKdVoVaiV6NYpVmsWrtb z1zlXgVfKGBVYYtixGQJZVBmomf3aU9qlWvTbRBuVW+ccOxyQ3OndQ52eXfveWl65nxo feh/aYDxgnWEE4XQh4eJMIrbjICOGY+wkUaS1ZRolfiXipkdmrWcUZ3zn3yg9qJ5pAal nac+qO2qoKxWrgmvubFlsv+0mbYct5+5GbqEu++9U761wBnBgcLvxFrFzMc+yLTKLMuo zSbOpNAh0Z/TG9Sa1hTXlNkQ2oncAd1q3rvf+eE24m/jneTA5eDm/egT6STqJ+sm7CHt E+4B7unv0PCp8X/yTfMZ8930m/VX9gT2svdW9+/4ifkZ+aL6K/qv+x37jPv6/Gj8tv0E /VL9oP3v/jz+gf7G/wz/Uf+X/9z//wAAZGVzYwAAAAAAAAAKQ29sb3IgTENEAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAG1sdWMAAAAAAAAAAgAAAAxlblVTAAAAEgAAAChq YUpQAAAADgAAADoAQwBvAGwAbwByACAATABDAEQwqzDpMPwAIABMAEMARG1tb2QAAAAA AAAGEAAAnF4AAAAAwEuKAAAAAAAAAAAAAAAAAAAAAAB0ZXh0AAAAAENvcHlyaWdodCBB cHBsZSBDb21wdXRlciwgSW5jLiwgMjAwNQAAAAD/2wBDAAEBAQEBAQEBAQEBAQEBAQEB AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBD AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB AQEBAQEBAQEBAQEBAQH/wAARCAAwADADAREAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAA AAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1Fh ByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpT VFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKz tLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEA AwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAEC AxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2 Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaX mJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP0 9fb3+Pn6/9oADAMBAAIRAxEAPwDd+Bfxs/4J+ftC/EFPhp4M+LXjLQtVl8P6pr9trvxE 8L2/gfwldRaU9tHPYw6/rU6WZ1OcXJms7F3R7tLe5WItKio3+XePyHPcBh3icwwjwNNT VOVarjcsqSVacJTUZ4bB47FV4RajJzqTgqaulKXPKKf9XVcGklKhWpYyV1y0cHDGynGH M06inVwdOnJKTimoTlJ/yuKcl+c/7cf7TXw68GfEbWvg38B/HWtXuv8AgbxrbC88aeCN O8KeNtJ8W+HU0e2uJrRxr+lR6Vosa63Pc6Zd3Ed3dfakshcWN7FHPiT6nhzheq8PLM8f gMFjcur4R0qOIzXHV8DQp4uT9+pg/wCzpvE4yrQWigoToXlKUoylGy+SzDGqVaOFpYzE 4XE066nUw+Hw1PE1p0opcsayxEVRw8KjbV5WqWS5XGMtfCfCn/BSS1vtOvLddC0uw1zR TJDqGha0ltZ6zfmFTvNlOHjsGuCzRiWAWjqpwkZLudmmZ+GWd4KeGcatOvgsYlKlmWFo 1MVhKdOcrpVoPmqqPLGVqlRqLSTUVq3WD4jybEQrc/to4jDc6q4OtVp0a8pRi1aml7sr N/BHmaejfb6p/ZM/bi+E3x2+I+g/CT4qG0+HHijxfr9h4X8K6tpkU2peHZ9Z1G4e2tLb Wr28Nt9iW6uHtrRLq2t3t47uRvPEUTKEMdwRnmXU54jDqOIwMaEcR7edOFOpHl1nCph4 1pzpxkmpU5pybjuklFvKnm+V4m0I1qlPFKrKnKjJ80XHRwdOr7OPPKLUlOL5UmlZ6tH7 LaX+wnruj+JtYQ6v4bg8O3TtdQX1tNfXGtz3S+X5Zvra4shbxoN9wD5NwTH8hwQ7AfNu WJlGC5G5RUZKU3BRV/j5eXmqKWiSbjzScfeS6dVOFOMpPn91t7J3fVN3dna6Ts1vpre/ e2n7I4sZgB4khcAjk2YDdQTzjnkZ7E4x0rnlGu5cynCNONpu655L4ZN83urduTVo37M7 KSprVOTu2lb1vtqn5NN9rtn8DNrPotj4P1nxWuqaa+t6JqOmwWPg14rqPVb2O7ErHXpJ 5rZdNt9J06eOOGRZLiS8up3MUduqL5j/ANUzweIxWOw+AqOpTw+LjVjUxyXtKUVCLlPD QVJuo8RUhtpGEYtTbetvhcTmdLC4CtjcN7KtKlOEIwjUgnGdRyUKklLXlXLJ6xXM9r2l E89i8deMPFHiAW3h3SrS417WIUl1vVpsyM1pJCYUgUkGGzRYwpmntmSacARMTGSrfT4L g7A08LGjVq4mWFwtSUcvwFFKEYVIzU6lepK6dRJuSjGvenT+OK5uVnx8M2zLMcXKOEo0 /rGIUZYvE1E23Brl5Fpy01aMbuHvTej926PQbb4J3MxhvNUvmj1mYK5mtWMaKwXaN7ke Y7BAEBUDcFAICjJ6MVUxuBi8O6EVhZKShTneXLHmV780LJOUvhs2pN+r+mwnCWHqRjXr YmbxVrylBta2fvJ3u5KNldtaaNaHkviCfW/CniVGlnurm4tLlvMuWZ7ad0tmVrW6EgkD NJGMNDcRtBNDJGhEnTFYbB4PGYOrQjCnSTSVOKinBTn/ABIRjKCcYyfxU5xlGUZtcu58 bmlPFZZmEnz1Kjpyvzy5otqLtTm2pLmlFRVpQcWmrN6K39eMX/BXvxf8Ef8AglZ+yn+1 FqHgOL4ufFXUvGGofAXxBa61rz6LpOrL4Rk1qB/E/ibUNOFzqj39/wCH9DtTp5hs7hW8 RXkt9ewfZeJfxyjwDhc44yzbh54x5fhaWG/tKE6dGNap70aUY0acJKEHyTqxdSUqkZKl FxjJzkj6ivxNUweUYTM/Ye3q1JLDyg5OEOZ8znUlJc1oz5GoxSfvS68rt7T+zl/wXL/Z j+OHw68MeIfG2pad8Gfifq1x4ss9c+G9/qh8S2+jP4TsNV8QSXq66LDTGOj6l4Y0mbU7 S/1Ow0yFrpLrSYZLm6tt0nicR+FmfZVmOIw+CoVczwVOhQrU8fGn7BVqdarRoez9k51L 1aeIrQoyp0pVZWlSnKKjKx7eR8UYLNKOHUqtLCYqtUqwlh6lRONJ04TqylKo1FKm6UJS VSajFtON20rfhV4X/wCCcHjT4tfs/wDww8a6P8UbLUNI8efAnxR43Fnp+iaPJ4Ul8Y+G PGep6PoOgprf2LTtU0DQtV0YWtzLqLw3NvBfWN3Fb6YI7oRQ+pU44y7KOMs4y+OQ1aOO yvNMPToVHjcwq5pWoY/AU8RWnPL62MrUMRjFiKOKouMVTkkqblVlOEpP162Twzjhz61V zLB08HUhhoPERwuBhl0HCrXjVqxxOEwkcZGhhqaw1aUY0qkVTlU9yT5YHydo3wjl+F89 14WvtOtbbW9Iu59N1mWAiRftlndS2d7HDdsA00MNzDLHG/yq8W11ABGP3ThLM8Zn7l7P D14ydSXPKvR9lOKcrqFVSSVOUacrOkk5qSkmvdODAZTgMuwlOpQnh60KkVy18PONWlW5 dFWozsnOnNrmpyaXNF3suaw7xP4j07QJ1t7q70/T4LcQ+bqWuXDW8csspVEstOtoA1zc yAFczP5FvllSNpHJx97i+FZ4+lWviIU3To89ZVKMpQioON4QUZxnOULJTqOVOFlfmbbv liM5pYGrBSowp0rpOvUrxpQlKW0Yppt1HfZLdXt1OT8deFrTxx4Ov5LYQPdQWc19Zzxx NCztEjSeWzMiylZohgZ4BIODxX5/UwWJynFUW7VYTSlGVGnKPNFSST9nJRnzuMleMk9t G/dZ0ZlgqGc5biv3XLUp05SpzcXdyim7Qn/LJpptq7X2bXPDfi34j1/TP2evhl8MLfxV rE/gbQvFt74wg8JvdEaEnibxhoIfUPEUdqjYmupYLFNPtpbhi1ktvfRwwwi8mefsyPDQ qZzjM1qRoyxeY4OVPmUf9po0cFXpUYUZxcVKFOfNCcXDmjWs3fmp2Xx/F2WYHCcIZA8P SlTxFLGuFSpBv2WLji8PUryqVFdqdSlWpOFKVoyhCUoOLjytcj+yTqnw+t/irqs3xQaO f4f2fwx+NWu6hYXBiaC+13Tvg/45tPCsSRT7Unu/7b1WBLAEgTTTBGVlYgerxVh8WsqU sBHlzR4nLsHg6sedTprGZngvaXnC8o026NOdaNpNKkmveSv8rwl9SWbwWZu+XU8LjcTi qWjVVUcHiXFO9veXNKMVdPmkldXaf9FXhq6+Kv7OHwn+HOh6Z8UtLT4X/DvS/iH4V8Ca fd/DdbC31C113xbrFpoNtc6Trni5vEC3HijS9UvbtF1XWPEV/o93qqrZxGw0ibH8M0c+ p8U8UcYZ7Q/tGjj6OJorD5nUx2Wxq4rHZBks8dXjXw9PJvYRhg8XilTpRp0KHPDnVeX1 lRhH+ycn4Fq4TPeHvDTF4bLcRkuaYvCYPPMTk/1vGYTB0cZWwHOqWLxGYS9q/er4Wnia UqsKlfCYudpYVKpU/I/4nfFr4uftMfFH4l/Hq50LwZ4bmvfG/h2y1X/hFdKudC07WdNk g1HS7O+07w3DqF5punXGoWPhG4uNYu7c28F5qtzcah9iDXU71/ZnDuNoZRlNX+1MU6+O x+WzxlWpGlRwtTDZxLC4apVo0XgcJh41HetD2FJw5oe97WtUk21+D5lh6NHi3NMi4aiq WVZHn08rwzqTrYiWIynDYidOjGftMROnSqKioSq1F7jc7wpQikiG30m31jxJE2vW01yb maOax+3QfadJuQkqy2sc0UmQZIZLVZoo5NsfmW4kiYyEof1ThPN8ZXqyoYyjar7D2uDW LhWdGrGpKM3erFRhNuUef2dWcpvk5lFOLS9LPchwlSU5xi3F1IN8saVRRqQTUZU41Oad KpZWVSHK9Ur7HrOv6bDY6XepLIsEk1tIomO1EeWZGjVVGVwhyQqDnaO5rzuLMtnVUq8a MY4q/tJ+znHlduVWhyxai3dqC5VLl1u7yRFCvTw2DnSc7QjTlBOV76pr3npdt35rtp6u z6/l58Tp9a/4QvwpaGeR9B0vxD4t0iYNGCn9tWc8Uds8tyAWkzpk3l2kbn92kdwq57fK ZCqNPNszozjBYqWGwOJopP3/AKrNP2ySvqo4mKcmrpc8HZc7b/M+IamOxGUZPTvN4DDY vMMPqvcjjI1rx55JJ3lhpR9l0SVXfp4bFDIsEs0eXtwjQzNA53xiRTGglCkOiybtg8wC OYgx7mZsD6uVSEqkKcmo1eaNSCqR0lytSk4XVpONrvlbnTT5rJI+QVOpTXtHdws4ylBv TnTSU+XVKTsldKMvhi73P6qv2xdTurPwB4OtLyJYdT8T+KdTj0fRVbVdUaxs9D0C/tNI 1mTVVEumpfQalr/hTS9TNzeTTjUpr+RMCS3lb/Obw+yDCxoVYYnF4qWa5fUorFOrSp08 Pio8S47D5xmOKxGJapPE4uWHwWM5cHSoqNHB1oVKibSZ/ojwdm+Gy/PKWaZPl1SPD+Oy KtmWBqY7khm0MwyrJ8RleHwc8FG/1Wh/amb1I0sTOblXr4GNClzSpy5vN/2TfCPw7+It h8ZdI8S3UWgeA57C58PQapY2UEUPh25gvdR8UaBrKwWqWyyW+jxahZ397ksLq0gvImlN s0qJ+6Z3m2JyfGZbWoJ4qr/bEqsoyd1i6WDw9HLFSlJyly/WauBlZyvKM588OZxkfzRj atd18pjRpujia2Ejj6sIyak3m2NzTPLVLvlqv6vjsJTi01LljBS5L3l8RRyWL6te2unQ 3OvXmk6rfWv/AAkp8rTLS5tbC4MVrc2keueRr0djdWqx3NjE+lRzCGQqY1Ytt/rrhDMl mWTU6+YUcRUx1GSq1KtepShVpOVpRw3u83O8PTnTpSpRpqN+dxm4yczWTr1YupRdKhep ONWN/bOTTs5+9K/K1d82qejVrtG14gkm8ZSz+H3EYn0nwnqfiCOJUQrPdWV1Y+S5BL7J jbrKiBctGZpGVs7Su2fYnE1qH17DUIVauX0Y4qnQlyxhVp4erCWJTSfK60sO5Qi4yko+ 9BtrU8LEwjOvi8FiJRhKpQjJOOqjK7cZL3ZON5qO6TjfS2h4/wDD6HQ7DQbGDW9A0jXN I1K/vtZ1rw7rFtDqOn6gmo3P2mS3vIZ8jzVi2KssRjltJo0ktpI2jjcfjHGHDmPxbweL wuJxGXZmlOvTxmXVpYfE4JVbeyjTlBRtCnCUI1ISjUhO8o1YyhI9nhfF4DBYb6pj8Hhs dg685TxWExdNV6VR1JOUnUjJNqd7OE4OM4OzpSi46fKPxLk+GVz8RPiFqXwm8Jnwx4It ZLbSdP0Z9TvdXsLi7NnaxaxADqM1xcPpkusrPNaQtcSvBAI9k42RtH25fDP8PluTYHiP NVmOayqVsTVxcKNLD16dKnWqfVqsZ0IU4LEfVko1JqEY1JSacGnJS+RzWOQVs4z3EcO5 bLCZTTjSwlHDSrVMRRq1506axEGq8pzdB4r3qacpSgoxlGcXFOP2zq154J8LaP8As6XU f7QyeJvHun+NPG8vj/Vl8SyeJdM0jw/p13d24/szStZWeLSptautO0C5tJdQuHm1ZodL 1fRoo10WO6X4Ovk2a458VU58NV6WArYbDf2RQpUZYavDHxnh3QxDrYXkq1HSofWXOWHt GNOc8PilJV6lKX0OJzPA5PHhyrlvFeFxGOxSxWFzSNHHRxGEqYHnqqVKrhanMqEHKcVC liV7Wc5RxOFs4Kov0E/YK+Nn7O3hj4W/G5fih4/+EXg+9u/F2qWVjpfinXdO0/xNdeGr 7wXaRS6h4bttLvb2LxB5eoXF9Z2mn29hdWtypFnblEgkt5/yLjjgzxA/tbJMflOV5zm8 aeVU5YrDxqY+GFli3j8VzyTqLDUsFivZeyqVa+InSrxnN1puTkuf08tzfI5YWrRq4vL8 NTjiZwp1qjpSxdDDwwlGVCFKbVatXw1OMZU6dCnCpQeHgqdKzp8q8RtvAfhX4lRt4in8 O3WiaNqHm33haH7Q0GsabpBkH2JL25SeS4OorbqlxcxrMsaO0sSq6IrH+xvDDhTN8/yS hmedVq1CNOnKjhM1yyvSprEzwlWdNYrERcZKpT9pFxlzRiqqpuUo3nd8mOxOGw8aUKbl OpWp0q9J1VyP2VSCl7NqCXs6sV+8UUrxT5ejRz2kfCRvBXjK68Ry+Ir3xDaXul3OixwX RtUNja3DCQr/AKPAovDMyRI8kpV40QKI2ZpJG+yzPJs3y7E1I5hUji6FTD16Ea2Ei6c0 p0pRnKrSTnSbk4x0oezjBqTlTbk3Hy8NTpYidfEKdWWIlFU5RruMoxUJOdqcoRTld2T5 7vlfuvV3/Nv4g/EkeD9N1Pw9Yy7deS51HTbK3QgyWECXEsAvblhnbshANtGx8yaYq+0R qzV5FKWFxeVYGtU5JYhUKUYxg1LkcLc9So+WylLlSVOSbTakvdSPkMyzOpgKlbC0m/a3 lFKS1g5ac132jtZJN20sj5h0LWI7CIxXEl/bZMjLe2u2dY5JCQ0zwloyzEFhuLscnIBO APFzHAyxM/aQjhqr91OhWbpOcYq6hGpaSS0TtZbWfn5GXY2GGi4VZ4mi221WpWqRhKVl zSptxk21dX5pWbuo3SS//9k= last name Schaffer phone numbers com.apple.syncservices:64ED42EB-109B-43A9-BEFC-3463D944251A com.apple.syncservices:FB7585EB-A3DE-46D5-920C-DF8028689BC5 com.apple.syncservices:020036FD-22B3-41C9-BC3D-CDA6083582C6 com.apple.syncservices:C6661518-90CA-45C7-A988-02F73B958951 primary URL com.apple.syncservices:5BA97109-F8E3-46A9-AF0B-5F8C093F49EA primary email address com.apple.syncservices:B97DCC9C-5B00-4D38-AB06-4B7A5D6BC369 primary phone number com.apple.syncservices:64ED42EB-109B-43A9-BEFC-3463D944251A primary related name com.apple.syncservices:CD0B7021-0228-4770-8FB0-3739479E9788 primary street address com.apple.syncservices:377B9105-9D15-4F69-BCD6-B01E587F7760 related names com.apple.syncservices:CD0B7021-0228-4770-8FB0-3739479E9788 street addresses com.apple.syncservices:377B9105-9D15-4F69-BCD6-B01E587F7760 plist-3.6.0/test/assets/non-ascii-but-utf-8.plist000066400000000000000000000003721377317720500216400ustar00rootroot00000000000000 non-ascii-but-utf8-character ™ plist-3.6.0/test/assets/test_data_elements.plist000066400000000000000000000016261377317720500220760ustar00rootroot00000000000000 stringio dGhpcyBpcyBhIHN0cmluZ2lvIG9iamVjdA== file AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAA== io AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAA== marshal BAhvOhZNYXJzaGFsYWJsZU9iamVjdAY6CUBmb28iHnRoaXMgb2JqZWN0IHdh cyBtYXJzaGFsZWQ= nodata plist-3.6.0/test/assets/test_empty_key.plist000066400000000000000000000005061377317720500212730ustar00rootroot00000000000000 key 1 subkey 2 plist-3.6.0/test/test_data_elements.rb000066400000000000000000000066701377317720500200500ustar00rootroot00000000000000require 'test/unit' require 'plist' require 'stringio' class MarshalableObject attr_accessor :foo def initialize(str) @foo = str end end class TestDataElements < Test::Unit::TestCase def setup @result = Plist.parse_xml('test/assets/test_data_elements.plist') end def test_data_object_header expected = < element below contains a Ruby object which has been serialized with Marshal.dump. --> BAhvOhZNYXJzaGFsYWJsZU9iamVjdAY6CUBmb28iHnRoaXMgb2JqZWN0IHdhcyBtYXJz aGFsZWQ= END expected_elements = expected.chomp.split("\n") actual = Plist::Emit.dump(Object.new, false) actual_elements = actual.chomp.split("\n") # check for header assert_equal expected_elements.shift, actual_elements.shift # check for opening and closing data tags assert_equal expected_elements.shift, actual_elements.shift assert_equal expected_elements.pop, actual_elements.pop end def test_marshal_round_trip expected = MarshalableObject.new('this object was marshaled') actual = Plist.parse_xml(Plist::Emit.dump(expected, false)) assert_kind_of expected.class, actual assert_equal expected.foo, actual.foo end def test_generator_io_and_file expected = < AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== END expected.chomp! fd = IO.sysopen('test/assets/example_data.bin') io = IO.open(fd, 'r') # File is a subclass of IO, so catching IO in the dispatcher should work for File as well... f = File.open('test/assets/example_data.bin') assert_equal expected, Plist::Emit.dump(io, false).chomp assert_equal expected, Plist::Emit.dump(f, false).chomp assert_instance_of StringIO, @result['io'] assert_instance_of StringIO, @result['file'] io.rewind f.rewind assert_equal io.read, @result['io'].read assert_equal f.read, @result['file'].read io.close f.close end def test_generator_string_io expected = < dGhpcyBpcyBhIHN0cmluZ2lvIG9iamVjdA== END sio = StringIO.new('this is a stringio object') assert_equal expected.chomp, Plist::Emit.dump(sio, false).chomp assert_instance_of StringIO, @result['stringio'] sio.rewind assert_equal sio.read, @result['stringio'].read end # this functionality is credited to Mat Schaffer, # who discovered the plist with the data tag # supplied the test data, and provided the parsing code. def test_data # test reading plist elements data = Plist.parse_xml("test/assets/example_data.plist"); assert_equal(File.open("test/assets/example_data.jpg"){|f| f.read }, data['image'].read) # test writing data elements expected = File.read("test/assets/example_data.plist") result = data.to_plist # File.open('result.plist', 'w') {|f|f.write(result)} # debug assert_equal(expected, result) # Test changing the object in the plist to a StringIO and writing. # This appears extraneous given that plist currently returns a StringIO, # so the above writing test also flexes StringIO#to_plist_node. # However, the interface promise is to return an IO, not a particular class. # plist used to return Tempfiles, which was changed solely for performance reasons. data['image'] = StringIO.new(File.read("test/assets/example_data.jpg")) assert_equal(expected, data.to_plist) end end plist-3.6.0/test/test_generator.rb000066400000000000000000000066151377317720500172300ustar00rootroot00000000000000require 'test/unit' require 'plist' class SerializableObject attr_accessor :foo def initialize(str) @foo = str end def to_plist_node return "#{CGI.escapeHTML(@foo)}" end end class TestGenerator < Test::Unit::TestCase def test_to_plist_vs_plist_emit_dump_no_envelope source = [1, :b, true] to_plist = source.to_plist(false) plist_emit_dump = Plist::Emit.dump(source, false) assert_equal to_plist, plist_emit_dump end def test_to_plist_vs_plist_emit_dump_with_envelope source = [1, :b, true] to_plist = source.to_plist plist_emit_dump = Plist::Emit.dump(source) assert_equal to_plist, plist_emit_dump end def test_dumping_serializable_object str = 'this object implements #to_plist_node' so = SerializableObject.new(str) assert_equal "#{str}", Plist::Emit.dump(so, false) end def test_write_plist data = [1, :two, {:c => 'dee'}] data.save_plist('test.plist') file = File.open('test.plist') {|f| f.read} assert_equal file, data.to_plist File.unlink('test.plist') end # The hash in this test was failing with 'hsh.keys.sort', # we are making sure it works with 'hsh.keys.sort_by'. def test_sorting_keys hsh = {:key1 => 1, :key4 => 4, 'key2' => 2, :key3 => 3} output = Plist::Emit.dump(hsh, false) expected = <<-STR key1 1 key2 2 key3 3 key4 4 STR assert_equal expected, output.gsub(/[\t]/, "\s\s") end def test_custom_indent hsh = { :key1 => 1, 'key2' => 2 } output_plist_dump_with_envelope = Plist::Emit.dump(hsh, true, :indent => nil) output_plist_dump_no_envelope = Plist::Emit.dump(hsh, false, :indent => nil) expected_with_envelope = <<-STR key1 1 key2 2 STR expected_no_envelope = <<-STR key1 1 key2 2 STR assert_equal expected_with_envelope, output_plist_dump_with_envelope assert_equal expected_no_envelope, output_plist_dump_no_envelope hsh.save_plist('test.plist', :indent => nil) output_plist_file = File.read('test.plist') assert_equal expected_with_envelope, output_plist_file File.unlink('test.plist') end def test_string_containing_newlines source = { data: { a_multiline_string: "This is a string with\nmultiple line\nbreaks.", a_normal_string: "This is a string without a line break.", integer: 100 } } plist_emit_dump = Plist::Emit.dump(source, true) assert_equal(<<-EXPECTED, plist_emit_dump.gsub(/\t/, " ")) data a_multiline_string This is a string with multiple line breaks. a_normal_string This is a string without a line break. integer 100 EXPECTED end end plist-3.6.0/test/test_generator_basic_types.rb000066400000000000000000000027551377317720500216160ustar00rootroot00000000000000require 'test/unit' require 'plist' class TestGeneratorBasicTypes < Test::Unit::TestCase def wrap(tag, content) return "<#{tag}>#{content}" end def test_strings expected = wrap('string', 'testdata') assert_equal expected, Plist::Emit.dump('testdata', false).chomp assert_equal expected, Plist::Emit.dump(:testdata, false).chomp end def test_strings_with_escaping expected = wrap('string', "<Fish & Chips>") assert_equal expected, Plist::Emit.dump('', false).chomp end def test_integers [42, 2376239847623987623, -8192].each do |i| assert_equal wrap('integer', i), Plist::Emit.dump(i, false).chomp end end def test_floats [3.14159, -38.3897, 2398476293847.9823749872349980].each do |i| assert_equal wrap('real', i), Plist::Emit.dump(i, false).chomp end end def test_booleans assert_equal "", Plist::Emit.dump(true, false).chomp assert_equal "", Plist::Emit.dump(false, false).chomp end def test_time test_time = Time.now assert_equal wrap('date', test_time.utc.strftime('%Y-%m-%dT%H:%M:%SZ')), Plist::Emit.dump(test_time, false).chomp end def test_dates test_date = Date.today test_datetime = DateTime.now assert_equal wrap('date', test_date.strftime('%Y-%m-%dT%H:%M:%SZ')), Plist::Emit.dump(test_date, false).chomp assert_equal wrap('date', test_datetime.strftime('%Y-%m-%dT%H:%M:%SZ')), Plist::Emit.dump(test_datetime, false).chomp end end plist-3.6.0/test/test_generator_collections.rb000066400000000000000000000025501377317720500216200ustar00rootroot00000000000000require 'test/unit' require 'plist' class TestGeneratorCollections < Test::Unit::TestCase def test_array expected = < 1 2 3 END assert_equal expected, [1,2,3].to_plist(false) end def test_empty_array expected = < END assert_equal expected, [].to_plist(false) end def test_hash expected = < abc 123 foo bar END # thanks to recent changes in the generator code, hash keys are sorted before emission, # so multi-element hash tests should be reliable. We're testing that here too. assert_equal expected, {:foo => :bar, :abc => 123}.to_plist(false) end def test_empty_hash expected = < END assert_equal expected, {}.to_plist(false) end def test_hash_with_array_element expected = < ary 1 b 3 END assert_equal expected, {:ary => [1,:b,'3']}.to_plist(false) end def test_array_with_hash_element expected = < foo bar b 3 END assert_equal expected, [{:foo => 'bar'}, :b, 3].to_plist(false) end end plist-3.6.0/test/test_parser.rb000077500000000000000000000071731377317720500165410ustar00rootroot00000000000000require 'test/unit' require 'plist' class TestParser < Test::Unit::TestCase def test_parse_xml result = Plist.parse_xml("test/assets/AlbumData.xml") # dict assert_kind_of(Hash, result) expected = [ "List of Albums", "Minor Version", "Master Image List", "Major Version", "List of Keywords", "Archive Path", "List of Rolls", "Application Version" ] assert_equal(expected.sort, result.keys.sort) # array assert_kind_of(Array, result["List of Rolls"]) assert_equal([ {"PhotoCount"=>1, "KeyList"=>["7"], "Parent"=>999000, "Album Type"=>"Regular", "AlbumName"=>"Roll 1", "AlbumId"=>6}], result["List of Rolls"]) # string assert_kind_of(String, result["Application Version"]) assert_equal("5.0.4 (263)", result["Application Version"]) # integer assert_kind_of(Integer, result["Major Version"]) assert_equal(2, result["Major Version"]) # true assert_kind_of(TrueClass, result["List of Albums"][0]["Master"]) assert(result["List of Albums"][0]["Master"]) # false assert_kind_of(FalseClass, result["List of Albums"][1]["SlideShowUseTitles"]) assert(!result["List of Albums"][1]["SlideShowUseTitles"]) end # uncomment this test to work on speed optimization # def test_load_something_big # plist = Plist.parse_xml("~/Pictures/iPhoto Library/AlbumData.xml") # end # date fields are credited to def test_date_fields result = Plist.parse_xml("test/assets/Cookies.plist") assert_kind_of(DateTime, result.first['Expires']) assert_equal DateTime.parse("2007-10-25T12:36:35Z"), result.first['Expires'] end # bug fix for empty # reported by Matthias Peick # reported and fixed by Frederik Seiffert def test_empty_dict_key data = Plist.parse_xml("test/assets/test_empty_key.plist"); assert_equal("2", data['key']['subkey']) end def test_cdata data = Plist.parse_xml("]]>") assert_equal('', data) end def test_mixed_text_and_cdata data = Plist.parse_xml('text and unescaped]]>') assert_equal('text and unescaped', data) end def test_unescaped_cdata_inside_cdata data = Plist.parse_xml(']]>') assert_equal('', data) end # bug fix for decoding entities # reported by Matthias Peick def test_decode_entities data = Plist.parse_xml('Fish & Chips') assert_equal('Fish & Chips', data) end def test_comment_handling_and_empty_plist assert_nothing_raised do assert_nil(Plist.parse_xml(File.read('test/assets/commented.plist'))) end end def test_filename_or_xml_is_stringio require 'stringio' str = StringIO.new data = Plist.parse_xml(str) assert_nil data end def test_filename_or_xml_is_encoded_with_ascii_8bit # skip if Ruby version does not support String#force_encoding return unless String.method_defined?(:force_encoding) xml = File.read("test/assets/non-ascii-but-utf-8.plist") xml.force_encoding("ASCII-8BIT") assert_nothing_raised do data = Plist.parse_xml(xml) assert_equal("\u0099", data["non-ascii-but-utf8-character"]) end end def test_unimplemented_element assert_raise Plist::UnimplementedElementError do Plist.parse_xml('Fish & Chips') end end end