plist 2.1.1 → 2.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -29,8 +29,10 @@ RELEASE_NAME = "REL #{PKG_VERSION}"
29
29
  RUBYFORGE_PROJECT = "plist"
30
30
  RUBYFORGE_USER = ENV['RUBYFORGE_USER']
31
31
 
32
- TEST_FILES = Dir.glob('test/**/*').delete_if {|item| item.include?( "\.svn" ) }
33
- RELEASE_FILES = [ "Rakefile", "README", "MIT-LICENSE" ] + TEST_FILES + Dir.glob( "lib/*" ).delete_if { |item| item.include?( "\.svn" ) }
32
+ TEST_FILES = Dir.glob('test/test_*').delete_if { |item| item.include?( "\.svn" ) }
33
+ TEST_ASSETS = Dir.glob('test/assets/*').delete_if { |item| item.include?( "\.svn" ) }
34
+ LIB_FILES = Dir.glob('lib/**/*').delete_if { |item| item.include?( "\.svn" ) }
35
+ RELEASE_FILES = [ "Rakefile", "README", "MIT-LICENSE", "docs/USAGE" ] + LIB_FILES + TEST_FILES + TEST_ASSETS
34
36
 
35
37
  task :default => [ :test ]
36
38
  # Run the unit tests
@@ -0,0 +1,51 @@
1
+ === Example Property List
2
+
3
+ <?xml version="1.0" encoding="UTF-8"?>
4
+ <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
5
+ <plist version="1.0">
6
+ <dict>
7
+ <key>FirstName</key>
8
+ <string>John</string>
9
+
10
+ <key>LastName</key>
11
+ <string>Public</string>
12
+
13
+ <key>StreetAddr1</key>
14
+ <string>123 Anywhere St.</string>
15
+
16
+ <key>StateProv</key>
17
+ <string>CA</string>
18
+
19
+ <key>City</key>
20
+ <string>Some Town</string>
21
+
22
+ <key>CountryName</key>
23
+ <string>United States</string>
24
+
25
+ <key>AreaCode</key>
26
+ <string>555</string>
27
+
28
+ <key>LocalPhoneNumber</key>
29
+ <string>5551212</string>
30
+
31
+ <key>ZipPostal</key>
32
+ <string>12345</string>
33
+ </dict>
34
+ </plist>
35
+
36
+ === Parsing
37
+
38
+ result = Plist::parse_xml("path/to/example.plist")
39
+
40
+ result.class
41
+ => Hash
42
+
43
+ "#{result["FirstName"]} #{result["LastName"]}"
44
+ => "John Public"
45
+
46
+ result["ZipPostal"]
47
+ => "12345"
48
+
49
+ === Generation
50
+
51
+ coming.soon {|i| i.promise }
@@ -15,5 +15,5 @@ require 'plist/generator'
15
15
  require 'plist/parser'
16
16
 
17
17
  module Plist
18
- VERSION = '2.1.1'
18
+ VERSION = '2.1.2'
19
19
  end
@@ -0,0 +1,167 @@
1
+ ##############################################################
2
+ # Copyright 2006, Ben Bleything <ben@bleything.net> and #
3
+ # Patrick May <patrick@hexane.org> #
4
+ # #
5
+ # Distributed under the MIT license. #
6
+ ##############################################################
7
+
8
+ # === Save a plist
9
+ # You can turn the variables back into a plist string:
10
+ #
11
+ # r.to_plist
12
+ #
13
+ # There is a convenience method for saving a variable to a file:
14
+ #
15
+ # r.save_plist(filename)
16
+ #
17
+ # Only these ruby types can be converted into a plist:
18
+ #
19
+ # String
20
+ # Float
21
+ # DateTime
22
+ # Integer
23
+ # FalseClass
24
+ # TrueClass
25
+ # Array
26
+ # Hash
27
+ #
28
+ # Notes:
29
+ #
30
+ # + Array and Hash are recursive -- the elements of an Array and the values of a Hash
31
+ # must convert to a plist.
32
+ # + The keys of the Hash must be strings.
33
+ # + The contents of data elements are returned as a Tempfile.
34
+ # + Data elements can be set with to an open IO or a StringIO
35
+ #
36
+ # If you have suggestions for mapping other Ruby types to the plist types, send a note to:
37
+ #
38
+ # mailto:plist@hexane.org
39
+ #
40
+ # I'll take a look and probably add it, I'm just reticent to create too many
41
+ # "convenience" methods without at least agreeing with someone :-)
42
+ module Plist
43
+ module Emit
44
+ def save_plist(filename)
45
+ File.open(filename, 'wb') do |f|
46
+ f.write(self.to_plist)
47
+ end
48
+ end
49
+
50
+ # Only the expected classes can be emitted as a plist:
51
+ # String, Float, DateTime, Integer, TrueClass, FalseClass, Array, Hash
52
+ #
53
+ # Write me if you think another class can be coerced safely into one of the
54
+ # expected plist classes (plist@hexane.org)
55
+ def to_plist( header = true )
56
+ if (header)
57
+ Plist::_xml(self.to_plist_node)
58
+ else
59
+ self.to_plist_node
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ class String
66
+ include Plist::Emit
67
+ def to_plist_node
68
+ "<string>#{CGI::escapeHTML(self)}</string>"
69
+ end
70
+ end
71
+
72
+ class Symbol
73
+ include Plist::Emit
74
+ def to_plist_node
75
+ "<string>#{CGI::escapeHTML(self.to_s)}</string>"
76
+ end
77
+ end
78
+
79
+ class Float
80
+ include Plist::Emit
81
+ def to_plist_node
82
+ "<real>#{self}</real>"
83
+ end
84
+ end
85
+
86
+ class Time
87
+ include Plist::Emit
88
+ def to_plist_node
89
+ "<date>#{self.utc.strftime('%Y-%m-%dT%H:%M:%SZ')}</date>"
90
+ end
91
+ end
92
+
93
+ class Date
94
+ include Plist::Emit
95
+ def to_plist_node
96
+ "<date>#{self.strftime('%Y-%m-%dT%H:%M:%SZ')}</date>"
97
+ end
98
+ end
99
+
100
+ class Integer
101
+ include Plist::Emit
102
+ def to_plist_node
103
+ "<integer>#{self}</integer>"
104
+ end
105
+ end
106
+
107
+ class FalseClass
108
+ include Plist::Emit
109
+ def to_plist_node
110
+ "<false/>"
111
+ end
112
+ end
113
+
114
+ class TrueClass
115
+ include Plist::Emit
116
+ def to_plist_node
117
+ "<true/>"
118
+ end
119
+ end
120
+
121
+ class Array
122
+ include Plist::Emit
123
+ def to_plist_node
124
+ fragment = "<array>\n"
125
+ self.each do |e|
126
+ element_plist = e.to_plist_node
127
+ element_plist.each do |l|
128
+ fragment += "\t#{l.chomp}\n"
129
+ end
130
+ end
131
+ fragment += "</array>"
132
+ fragment
133
+ end
134
+ end
135
+
136
+ class Hash
137
+ include Plist::Emit
138
+ def to_plist_node
139
+ fragment = "<dict>\n"
140
+ self.keys.sort.each do |k|
141
+ fragment += "\t<key>#{CGI::escapeHTML(k)}</key>\n"
142
+ element_plist = self[k].to_plist_node
143
+ element_plist.each do |l|
144
+ fragment += "\t#{l.chomp}\n"
145
+ end
146
+ end
147
+ fragment += "</dict>"
148
+ fragment
149
+ end
150
+ end
151
+
152
+ require 'stringio'
153
+ [ IO, StringIO ].each do |io_class|
154
+ io_class.module_eval do
155
+ include Plist::Emit
156
+ def to_plist_node
157
+ self.rewind
158
+ data = self.read
159
+
160
+ output = "<data>\n"
161
+ Base64::encode64(data).gsub(/\s+/, '').scan(/.{1,68}/o) { output << $& << "\n" }
162
+ output << "</data>"
163
+
164
+ output
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,230 @@
1
+ ##############################################################
2
+ # Copyright 2006, Ben Bleything <ben@bleything.net> and #
3
+ # Patrick May <patrick@hexane.org> #
4
+ # #
5
+ # Distributed under the MIT license. #
6
+ ##############################################################
7
+ #
8
+ # Plist parses Mac OS X xml property list files into ruby data structures.
9
+ #
10
+ # === Load a plist file
11
+ # This is the main point of the library:
12
+ #
13
+ # r = Plist::parse_xml( filename_or_xml )
14
+ module Plist
15
+ TEMPLATE = <<-XML
16
+ <?xml version="1.0" encoding="UTF-8"?>
17
+ <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
18
+ <plist version="1.0">
19
+ %plist%
20
+ </plist>
21
+ XML
22
+ def Plist::_xml( xml )
23
+ TEMPLATE.sub( /%plist%/, xml )
24
+ end
25
+
26
+ # Note that I don't use these two elements much:
27
+ #
28
+ # + Date elements are returned as DateTime objects.
29
+ # + Data elements are implemented as Tempfiles
30
+ #
31
+ # Plist::parse_xml will blow up if it encounters a data element.
32
+ # If you encounter such an error, or if you have a Date element which
33
+ # can't be parsed into a Time object, please send your plist file to
34
+ # plist@hexane.org so that I can implement the proper support.
35
+ def Plist::parse_xml( filename_or_xml )
36
+ listener = Listener.new
37
+ #parser = REXML::Parsers::StreamParser.new(File.new(filename), listener)
38
+ parser = StreamParser.new(filename_or_xml, listener)
39
+ parser.parse
40
+ listener.result
41
+ end
42
+
43
+ class Listener
44
+ #include REXML::StreamListener
45
+
46
+ attr_accessor :result, :open
47
+
48
+ def initialize
49
+ @result = nil
50
+ @open = Array.new
51
+ end
52
+
53
+
54
+ def tag_start(name, attributes)
55
+ @open.push PTag::mappings[name].new
56
+ end
57
+
58
+ def text( contents )
59
+ @open.last.text = contents if @open.last
60
+ end
61
+
62
+ def tag_end(name)
63
+ last = @open.pop
64
+ if @open.empty?
65
+ @result = last.to_ruby
66
+ else
67
+ @open.last.children.push last
68
+ end
69
+ end
70
+ end
71
+
72
+ class StreamParser
73
+ def initialize( filename_or_xml, listener )
74
+ @filename_or_xml = filename_or_xml
75
+ @listener = listener
76
+ end
77
+
78
+ TEXT = /([^<]+)/
79
+ XMLDECL_PATTERN = /<\?xml\s+(.*?)\?>*/um
80
+ DOCTYPE_PATTERN = /\s*<!DOCTYPE\s+(.*?)(\[|>)/um
81
+
82
+
83
+ def parse
84
+ plist_tags = PTag::mappings.keys.join('|')
85
+ start_tag = /<(#{plist_tags})([^>]*)>/i
86
+ end_tag = /<\/(#{plist_tags})[^>]*>/i
87
+
88
+ require 'strscan'
89
+ @scanner = StringScanner.new( if (File.exists? @filename_or_xml)
90
+ File.open(@filename_or_xml, "r") {|f| f.read}
91
+ else
92
+ @filename_or_xml
93
+ end )
94
+ until @scanner.eos?
95
+ if @scanner.scan(XMLDECL_PATTERN)
96
+ elsif @scanner.scan(DOCTYPE_PATTERN)
97
+ elsif @scanner.scan(start_tag)
98
+ @listener.tag_start(@scanner[1], nil)
99
+ if (@scanner[2] =~ /\/$/)
100
+ @listener.tag_end(@scanner[1])
101
+ end
102
+ elsif @scanner.scan(TEXT)
103
+ @listener.text(@scanner[1])
104
+ elsif @scanner.scan(end_tag)
105
+ @listener.tag_end(@scanner[1])
106
+ else
107
+ raise "Unimplemented element"
108
+ end
109
+ end
110
+ end
111
+ end
112
+
113
+ class PTag
114
+ @@mappings = { }
115
+ def PTag::mappings
116
+ @@mappings
117
+ end
118
+
119
+ def PTag::inherited( sub_class )
120
+ key = sub_class.to_s.downcase
121
+ key.gsub!(/^plist::/, '' )
122
+ key.gsub!(/^p/, '') unless key == "plist"
123
+
124
+ @@mappings[key] = sub_class
125
+ end
126
+
127
+ attr_accessor :text, :children
128
+ def initialize
129
+ @children = Array.new
130
+ end
131
+
132
+ def to_ruby
133
+ raise "Unimplemented: " + self.class.to_s + "#to_ruby on #{self.inspect}"
134
+ end
135
+ end
136
+
137
+ class PList < PTag
138
+ def to_ruby
139
+ children.first.to_ruby
140
+ end
141
+ end
142
+
143
+ class PDict < PTag
144
+ def to_ruby
145
+ dict = Hash.new
146
+ key = nil
147
+
148
+ children.each do |c|
149
+ if key.nil?
150
+ key = c.to_ruby
151
+ else
152
+ dict[key] = c.to_ruby
153
+ key = nil
154
+ end
155
+ end
156
+
157
+ dict
158
+ end
159
+ end
160
+
161
+ class PKey < PTag
162
+ def to_ruby
163
+ CGI::unescapeHTML(text || '')
164
+ end
165
+ end
166
+
167
+ class PString < PTag
168
+ def to_ruby
169
+ CGI::unescapeHTML(text || '')
170
+ end
171
+ end
172
+
173
+ class PArray < PTag
174
+ def to_ruby
175
+ children.collect do |c|
176
+ c.to_ruby
177
+ end
178
+ end
179
+ end
180
+
181
+ class PInteger < PTag
182
+ def to_ruby
183
+ text.to_i
184
+ end
185
+ end
186
+
187
+ class PTrue < PTag
188
+ def to_ruby
189
+ true
190
+ end
191
+ end
192
+
193
+ class PFalse < PTag
194
+ def to_ruby
195
+ false
196
+ end
197
+ end
198
+
199
+ class PReal < PTag
200
+ def to_ruby
201
+ text.to_f
202
+ end
203
+ end
204
+
205
+ require 'date'
206
+ class PDate < PTag
207
+ def to_ruby
208
+ DateTime.parse(text)
209
+ end
210
+ end
211
+
212
+ require 'base64'
213
+ class PData < PTag
214
+ def to_ruby
215
+ # replacing Tempfile with StringIO
216
+ # think it might be a bit nicer
217
+ #require 'tempfile'
218
+ #tf = Tempfile.new("plist.tmp")
219
+ #tf.write Base64.decode64(text.gsub(/\s+/,''))
220
+ #tf.close
221
+ # is this a good idea?
222
+ #tf.open
223
+ #tf
224
+ io = StringIO.new
225
+ io.write Base64.decode64(text.gsub(/\s+/,''))
226
+ io.rewind
227
+ io
228
+ end
229
+ end
230
+ end
metadata CHANGED
@@ -1,61 +1,61 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.8.11.3
2
+ rubygems_version: 0.9.0
3
3
  specification_version: 1
4
4
  name: plist
5
5
  version: !ruby/object:Gem::Version
6
- version: 2.1.1
7
- date: 2006-09-10 00:00:00 -04:00
6
+ version: 2.1.2
7
+ date: 2006-09-20 00:00:00 -07:00
8
8
  summary: All-purpose Property List manipulation library.
9
9
  require_paths:
10
- - lib
10
+ - lib
11
11
  email:
12
12
  homepage: http://plist.rubyforge.org
13
13
  rubyforge_project: plist
14
- description: "Plist is a library to manipulate Property List files, also known as plists. It
15
- can parse plist files into native Ruby data structures as well as generating new
16
- plist files from your Ruby objects."
14
+ 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.
17
15
  autorequire: plist
18
16
  default_executable:
19
17
  bindir: bin
20
18
  has_rdoc: true
21
19
  required_ruby_version: !ruby/object:Gem::Version::Requirement
22
20
  requirements:
23
- -
24
- - ">"
25
- - !ruby/object:Gem::Version
26
- version: 0.0.0
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
27
24
  version:
28
25
  platform: ruby
29
26
  signing_key:
30
27
  cert_chain:
28
+ post_install_message:
31
29
  authors:
32
- - Ben Bleything and Patrick May
30
+ - Ben Bleything and Patrick May
33
31
  files:
34
- - Rakefile
35
- - README
36
- - MIT-LICENSE
37
- - test/assets
38
- - test/test_generator_basic_types.rb
39
- - test/test_parser.rb
40
- - test/assets/AlbumData.xml
41
- - test/assets/Cookies.plist
42
- - test/assets/example_data.jpg
43
- - test/assets/example_data.plist
44
- - test/assets/test_empty_key.plist
45
- - lib/plist
46
- - lib/plist.rb
32
+ - Rakefile
33
+ - README
34
+ - MIT-LICENSE
35
+ - docs/USAGE
36
+ - lib/plist
37
+ - lib/plist.rb
38
+ - lib/plist/generator.rb
39
+ - lib/plist/parser.rb
40
+ - test/test_generator_basic_types.rb
41
+ - test/test_parser.rb
42
+ - test/assets/AlbumData.xml
43
+ - test/assets/Cookies.plist
44
+ - test/assets/example_data.jpg
45
+ - test/assets/example_data.plist
46
+ - test/assets/test_empty_key.plist
47
47
  test_files:
48
- - test/assets
49
- - test/test_generator_basic_types.rb
50
- - test/test_parser.rb
51
- - test/assets/AlbumData.xml
52
- - test/assets/Cookies.plist
53
- - test/assets/example_data.jpg
54
- - test/assets/example_data.plist
55
- - test/assets/test_empty_key.plist
48
+ - test/test_generator_basic_types.rb
49
+ - test/test_parser.rb
56
50
  rdoc_options: []
51
+
57
52
  extra_rdoc_files: []
53
+
58
54
  executables: []
55
+
59
56
  extensions: []
57
+
60
58
  requirements: []
61
- dependencies: []
59
+
60
+ dependencies: []
61
+