plist 3.3.0 → 3.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.rdoc +7 -1
- data/README.rdoc +28 -5
- data/lib/plist.rb +0 -3
- data/lib/plist/generator.rb +174 -166
- data/lib/plist/parser.rb +30 -32
- data/lib/plist/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d5fa8e33a6700467ad3d91f7513275c19e020433e4e66b9df83020e38d04c24b
|
4
|
+
data.tar.gz: 2c588eb552e98c74d99b47138434e09a4dc3965857f2a9eb6af84fa14926b2ff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4600738237509772e5a8a9299b370e8a3c611e5b5540a40889c4623a5e88c080515f177c2e74e49cf93a29df36afd9097da9787aa82d40af14f75fd076e5c68b
|
7
|
+
data.tar.gz: bf5f666db425a2b664fdbba0b81ae14d38a4d88035ca7a29b66c35bfb9b87defe3216b0bc1cc67e5c960f174ad97b2e47b290cc86aaca56cffc4e325265d43e2
|
data/CHANGELOG.rdoc
CHANGED
@@ -2,10 +2,16 @@
|
|
2
2
|
|
3
3
|
=== Unreleased
|
4
4
|
|
5
|
-
https://github.com/patsplat/plist/compare/v3.
|
5
|
+
https://github.com/patsplat/plist/compare/v3.4.0...HEAD
|
6
6
|
|
7
7
|
* Your contribution here!
|
8
8
|
|
9
|
+
=== 3.4.0 (2017-12-08)
|
10
|
+
|
11
|
+
https://github.com/patsplat/plist/compare/v3.3.0...v3.4.0
|
12
|
+
|
13
|
+
* Support custom indent string (https://github.com/patsplat/plist/pull/44)
|
14
|
+
|
9
15
|
=== 3.3.0 (2017-04-28)
|
10
16
|
|
11
17
|
https://github.com/patsplat/plist/compare/dece870...v3.3.0
|
data/README.rdoc
CHANGED
@@ -7,9 +7,14 @@ Plist is a library to manipulate Property List files, also known as plists. It
|
|
7
7
|
|
8
8
|
== Usage
|
9
9
|
|
10
|
+
=== Security considerations
|
11
|
+
|
12
|
+
Plist.parse_xml uses Marshal.load for <data/> attributes. If the <data/> attribute contains malicious data, an attacker can gain code execution.
|
13
|
+
You should never use Plist.parse_xml with untrusted plists!
|
14
|
+
|
10
15
|
=== Parsing
|
11
16
|
|
12
|
-
result = Plist
|
17
|
+
result = Plist.parse_xml('path/to/example.plist')
|
13
18
|
|
14
19
|
result.class
|
15
20
|
=> Hash
|
@@ -112,15 +117,32 @@ When you attempt to serialize a +MyFancyString+ object, the +to_plist_node+ meth
|
|
112
117
|
|
113
118
|
If for whatever reason you can't add this method, your object will be serialized with <tt>Marshal.dump</tt> instead.
|
114
119
|
|
120
|
+
==== Custom indent
|
121
|
+
|
122
|
+
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 <tt>nil</tt>.
|
123
|
+
|
124
|
+
An example to change default indent format:
|
125
|
+
|
126
|
+
Plist::Emit::DEFAULT_INDENT = nil
|
127
|
+
|
128
|
+
An example to specify indent format on dump:
|
129
|
+
|
130
|
+
Plist::Emit.dump({:foo => :bar}, false)
|
131
|
+
=> "<dict>\n\t<key>foo</key>\n\t<string>bar</string>\n</dict>\n"
|
132
|
+
|
133
|
+
Plist::Emit.dump({:foo => :bar}, false, :indent => nil)
|
134
|
+
=> "<dict>\n<key>foo</key>\n<string>bar</string>\n</dict>\n"
|
135
|
+
|
136
|
+
|
115
137
|
== Links
|
116
138
|
|
117
|
-
[
|
118
|
-
[GitHub]
|
119
|
-
[RDoc] http://
|
139
|
+
[Rubygems] https://rubygems.org/gems/plist
|
140
|
+
[GitHub] https://github.com/bleything/plist
|
141
|
+
[RDoc] http://www.rubydoc.info/gems/plist
|
120
142
|
|
121
143
|
== Credits
|
122
144
|
|
123
|
-
plist
|
145
|
+
plist was authored by Ben Bleything <mailto:ben@bleything.net> and Patrick May <mailto:patrick@hexane.org>. Patrick wrote most of the code; Ben contributed his plist generation library. The project is currently maintained by @mattbrictson[https://github.com/mattbrictson].
|
124
146
|
|
125
147
|
Other folks who have helped along the way:
|
126
148
|
|
@@ -129,6 +151,7 @@ Other folks who have helped along the way:
|
|
129
151
|
[<b>Mat Schaffer</b>] who supplied code and test cases for <tt><data></tt> elements
|
130
152
|
[<b>Michael Granger</b>] for encouragement and help
|
131
153
|
[<b>Carsten Bormann, Chris Hoffman, Dana Contreras, Hongli Lai, Johan Sørensen</b>] for contributing Ruby 1.9.x compatibility fixes
|
154
|
+
And thank you to all of the other GitHub contributors[https://github.com/patsplat/plist/graphs/contributors] not mentioned here!
|
132
155
|
|
133
156
|
== License and Copyright
|
134
157
|
|
data/lib/plist.rb
CHANGED
data/lib/plist/generator.rb
CHANGED
@@ -6,208 +6,216 @@
|
|
6
6
|
# Distributed under the MIT License
|
7
7
|
#
|
8
8
|
|
9
|
-
module Plist
|
10
|
-
|
11
|
-
#
|
12
|
-
# You can dump an object to a plist in one of two ways:
|
13
|
-
#
|
14
|
-
# * <tt>Plist::Emit.dump(obj)</tt>
|
15
|
-
# * <tt>obj.to_plist</tt>
|
16
|
-
# * This requires that you mixin the <tt>Plist::Emit</tt> module, which is already done for +Array+ and +Hash+.
|
17
|
-
#
|
18
|
-
# The following Ruby classes are converted into native plist types:
|
19
|
-
# Array, Bignum, Date, DateTime, Fixnum, Float, Hash, Integer, String, Symbol, Time, true, false
|
20
|
-
# * +Array+ and +Hash+ are both recursive; their elements will be converted into plist nodes inside the <array> and <dict> containers (respectively).
|
21
|
-
# * +IO+ (and its descendants) and +StringIO+ objects are read from and their contents placed in a <data> element.
|
22
|
-
# * User classes may implement +to_plist_node+ to dictate how they should be serialized; otherwise the object will be passed to <tt>Marshal.dump</tt> and the result placed in a <data> element.
|
23
|
-
#
|
24
|
-
# For detailed usage instructions, refer to USAGE[link:files/docs/USAGE.html] and the methods documented below.
|
25
|
-
module Plist::Emit
|
26
|
-
# Helper method for injecting into classes. Calls <tt>Plist::Emit.dump</tt> with +self+.
|
27
|
-
def to_plist(envelope = true)
|
28
|
-
return Plist::Emit.dump(self, envelope)
|
29
|
-
end
|
30
|
-
|
31
|
-
# Helper method for injecting into classes. Calls <tt>Plist::Emit.save_plist</tt> with +self+.
|
32
|
-
def save_plist(filename)
|
33
|
-
Plist::Emit.save_plist(self, filename)
|
34
|
-
end
|
35
|
-
|
36
|
-
# The following Ruby classes are converted into native plist types:
|
37
|
-
# Array, Bignum, Date, DateTime, Fixnum, Float, Hash, Integer, String, Symbol, Time
|
9
|
+
module Plist
|
10
|
+
# === Create a plist
|
11
|
+
# You can dump an object to a plist in one of two ways:
|
38
12
|
#
|
39
|
-
#
|
13
|
+
# * <tt>Plist::Emit.dump(obj)</tt>
|
14
|
+
# * <tt>obj.to_plist</tt>
|
15
|
+
# * This requires that you mixin the <tt>Plist::Emit</tt> module, which is already done for +Array+ and +Hash+.
|
40
16
|
#
|
41
|
-
#
|
17
|
+
# The following Ruby classes are converted into native plist types:
|
18
|
+
# Array, Bignum, Date, DateTime, Fixnum, Float, Hash, Integer, String, Symbol, Time, true, false
|
19
|
+
# * +Array+ and +Hash+ are both recursive; their elements will be converted into plist nodes inside the <array> and <dict> containers (respectively).
|
20
|
+
# * +IO+ (and its descendants) and +StringIO+ objects are read from and their contents placed in a <data> element.
|
21
|
+
# * User classes may implement +to_plist_node+ to dictate how they should be serialized; otherwise the object will be passed to <tt>Marshal.dump</tt> and the result placed in a <data> element.
|
42
22
|
#
|
43
|
-
#
|
44
|
-
|
45
|
-
|
23
|
+
# For detailed usage instructions, refer to USAGE[link:files/docs/USAGE.html] and the methods documented below.
|
24
|
+
module Emit
|
25
|
+
DEFAULT_INDENT = "\t"
|
26
|
+
|
27
|
+
# Helper method for injecting into classes. Calls <tt>Plist::Emit.dump</tt> with +self+.
|
28
|
+
def to_plist(envelope = true, options = {})
|
29
|
+
options = { :indent => DEFAULT_INDENT }.merge(options)
|
30
|
+
return Plist::Emit.dump(self, envelope, options)
|
31
|
+
end
|
46
32
|
|
47
|
-
|
33
|
+
# Helper method for injecting into classes. Calls <tt>Plist::Emit.save_plist</tt> with +self+.
|
34
|
+
def save_plist(filename, options = {})
|
35
|
+
options = { :indent => DEFAULT_INDENT }.merge(options)
|
36
|
+
Plist::Emit.save_plist(self, filename, options)
|
37
|
+
end
|
48
38
|
|
49
|
-
|
50
|
-
|
39
|
+
# The following Ruby classes are converted into native plist types:
|
40
|
+
# Array, Bignum, Date, DateTime, Fixnum, Float, Hash, Integer, String, Symbol, Time
|
41
|
+
#
|
42
|
+
# Write us (via RubyForge) if you think another class can be coerced safely into one of the expected plist classes.
|
43
|
+
#
|
44
|
+
# +IO+ and +StringIO+ objects are encoded and placed in <data> elements; other objects are <tt>Marshal.dump</tt>'ed unless they implement +to_plist_node+.
|
45
|
+
#
|
46
|
+
# 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.
|
47
|
+
def self.dump(obj, envelope = true, options = {})
|
48
|
+
options = { :indent => DEFAULT_INDENT }.merge(options)
|
49
|
+
output = plist_node(obj, options)
|
50
|
+
|
51
|
+
output = wrap(output) if envelope
|
52
|
+
|
53
|
+
return output
|
54
|
+
end
|
51
55
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
+
# Writes the serialized object's plist to the specified filename.
|
57
|
+
def self.save_plist(obj, filename, options = {})
|
58
|
+
options = { :indent => DEFAULT_INDENT }.merge(options)
|
59
|
+
File.open(filename, 'wb') do |f|
|
60
|
+
f.write(obj.to_plist(true, options))
|
61
|
+
end
|
56
62
|
end
|
57
|
-
end
|
58
63
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
if element.respond_to? :to_plist_node
|
64
|
-
output << element.to_plist_node
|
65
|
-
else
|
66
|
-
case element
|
67
|
-
when Array
|
68
|
-
if element.empty?
|
69
|
-
output << "<array/>\n"
|
70
|
-
else
|
71
|
-
output << tag('array') {
|
72
|
-
element.collect {|e| plist_node(e)}
|
73
|
-
}
|
74
|
-
end
|
75
|
-
when Hash
|
76
|
-
if element.empty?
|
77
|
-
output << "<dict/>\n"
|
78
|
-
else
|
79
|
-
inner_tags = []
|
64
|
+
private
|
65
|
+
def self.plist_node(element, options = {})
|
66
|
+
options = { :indent => DEFAULT_INDENT }.merge(options)
|
67
|
+
output = ''
|
80
68
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
69
|
+
if element.respond_to? :to_plist_node
|
70
|
+
output << element.to_plist_node
|
71
|
+
else
|
72
|
+
case element
|
73
|
+
when Array
|
74
|
+
if element.empty?
|
75
|
+
output << "<array/>\n"
|
76
|
+
else
|
77
|
+
output << tag('array', '', options) {
|
78
|
+
element.collect {|e| plist_node(e, options)}
|
79
|
+
}
|
85
80
|
end
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
81
|
+
when Hash
|
82
|
+
if element.empty?
|
83
|
+
output << "<dict/>\n"
|
84
|
+
else
|
85
|
+
inner_tags = []
|
86
|
+
|
87
|
+
element.keys.sort_by{|k| k.to_s }.each do |k|
|
88
|
+
v = element[k]
|
89
|
+
inner_tags << tag('key', CGI.escapeHTML(k.to_s), options)
|
90
|
+
inner_tags << plist_node(v, options)
|
91
|
+
end
|
92
|
+
|
93
|
+
output << tag('dict', '', options) {
|
94
|
+
inner_tags
|
95
|
+
}
|
96
|
+
end
|
97
|
+
when true, false
|
98
|
+
output << "<#{element}/>\n"
|
99
|
+
when Time
|
100
|
+
output << tag('date', element.utc.strftime('%Y-%m-%dT%H:%M:%SZ'), options)
|
101
|
+
when Date # also catches DateTime
|
102
|
+
output << tag('date', element.strftime('%Y-%m-%dT%H:%M:%SZ'), options)
|
103
|
+
when String, Symbol, Integer, Float
|
104
|
+
output << tag(element_type(element), CGI.escapeHTML(element.to_s), options)
|
105
|
+
when IO, StringIO
|
106
|
+
element.rewind
|
107
|
+
contents = element.read
|
108
|
+
# note that apple plists are wrapped at a different length then
|
109
|
+
# what ruby's base64 wraps by default.
|
110
|
+
# I used #encode64 instead of #b64encode (which allows a length arg)
|
111
|
+
# because b64encode is b0rked and ignores the length arg.
|
112
|
+
data = "\n"
|
113
|
+
Base64.encode64(contents).gsub(/\s+/, '').scan(/.{1,68}/o) { data << $& << "\n" }
|
114
|
+
output << tag('data', data, options)
|
115
|
+
else
|
116
|
+
output << comment('The <data> element below contains a Ruby object which has been serialized with Marshal.dump.')
|
117
|
+
data = "\n"
|
118
|
+
Base64.encode64(Marshal.dump(element)).gsub(/\s+/, '').scan(/.{1,68}/o) { data << $& << "\n" }
|
119
|
+
output << tag('data', data, options)
|
90
120
|
end
|
91
|
-
when true, false
|
92
|
-
output << "<#{element}/>\n"
|
93
|
-
when Time
|
94
|
-
output << tag('date', element.utc.strftime('%Y-%m-%dT%H:%M:%SZ'))
|
95
|
-
when Date # also catches DateTime
|
96
|
-
output << tag('date', element.strftime('%Y-%m-%dT%H:%M:%SZ'))
|
97
|
-
when String, Symbol, Integer, Float
|
98
|
-
output << tag(element_type(element), CGI::escapeHTML(element.to_s))
|
99
|
-
when IO, StringIO
|
100
|
-
element.rewind
|
101
|
-
contents = element.read
|
102
|
-
# note that apple plists are wrapped at a different length then
|
103
|
-
# what ruby's base64 wraps by default.
|
104
|
-
# I used #encode64 instead of #b64encode (which allows a length arg)
|
105
|
-
# because b64encode is b0rked and ignores the length arg.
|
106
|
-
data = "\n"
|
107
|
-
Base64::encode64(contents).gsub(/\s+/, '').scan(/.{1,68}/o) { data << $& << "\n" }
|
108
|
-
output << tag('data', data)
|
109
|
-
else
|
110
|
-
output << comment( 'The <data> element below contains a Ruby object which has been serialized with Marshal.dump.' )
|
111
|
-
data = "\n"
|
112
|
-
Base64::encode64(Marshal.dump(element)).gsub(/\s+/, '').scan(/.{1,68}/o) { data << $& << "\n" }
|
113
|
-
output << tag('data', data )
|
114
121
|
end
|
122
|
+
|
123
|
+
return output
|
115
124
|
end
|
116
125
|
|
117
|
-
|
118
|
-
|
126
|
+
def self.comment(content)
|
127
|
+
return "<!-- #{content} -->\n"
|
128
|
+
end
|
119
129
|
|
120
|
-
|
121
|
-
|
122
|
-
|
130
|
+
def self.tag(type, contents = '', options = {}, &block)
|
131
|
+
options = { :indent => DEFAULT_INDENT }.merge(options)
|
132
|
+
out = nil
|
123
133
|
|
124
|
-
|
125
|
-
|
134
|
+
if block_given?
|
135
|
+
out = IndentedString.new(options[:indent])
|
136
|
+
out << "<#{type}>"
|
137
|
+
out.raise_indent
|
126
138
|
|
127
|
-
|
128
|
-
out = IndentedString.new
|
129
|
-
out << "<#{type}>"
|
130
|
-
out.raise_indent
|
139
|
+
out << block.call
|
131
140
|
|
132
|
-
|
141
|
+
out.lower_indent
|
142
|
+
out << "</#{type}>"
|
143
|
+
else
|
144
|
+
out = "<#{type}>#{contents.to_s}</#{type}>\n"
|
145
|
+
end
|
133
146
|
|
134
|
-
out.
|
135
|
-
out << "</#{type}>"
|
136
|
-
else
|
137
|
-
out = "<#{type}>#{contents.to_s}</#{type}>\n"
|
147
|
+
return out.to_s
|
138
148
|
end
|
139
149
|
|
140
|
-
|
141
|
-
|
150
|
+
def self.wrap(contents)
|
151
|
+
output = ''
|
142
152
|
|
143
|
-
|
144
|
-
|
153
|
+
output << '<?xml version="1.0" encoding="UTF-8"?>' + "\n"
|
154
|
+
output << '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">' + "\n"
|
155
|
+
output << '<plist version="1.0">' + "\n"
|
145
156
|
|
146
|
-
|
147
|
-
output << '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">' + "\n"
|
148
|
-
output << '<plist version="1.0">' + "\n"
|
157
|
+
output << contents
|
149
158
|
|
150
|
-
|
151
|
-
|
152
|
-
output << '</plist>' + "\n"
|
153
|
-
|
154
|
-
return output
|
155
|
-
end
|
159
|
+
output << '</plist>' + "\n"
|
156
160
|
|
157
|
-
|
158
|
-
|
159
|
-
when String, Symbol
|
160
|
-
'string'
|
161
|
+
return output
|
162
|
+
end
|
161
163
|
|
162
|
-
|
163
|
-
|
164
|
+
def self.element_type(item)
|
165
|
+
case item
|
166
|
+
when String, Symbol
|
167
|
+
'string'
|
164
168
|
|
165
|
-
|
166
|
-
|
169
|
+
when Integer
|
170
|
+
'integer'
|
167
171
|
|
168
|
-
|
169
|
-
|
170
|
-
end
|
171
|
-
end
|
172
|
-
private
|
173
|
-
class IndentedString #:nodoc:
|
174
|
-
attr_accessor :indent_string
|
175
|
-
|
176
|
-
def initialize(str = "\t")
|
177
|
-
@indent_string = str
|
178
|
-
@contents = ''
|
179
|
-
@indent_level = 0
|
180
|
-
end
|
172
|
+
when Float
|
173
|
+
'real'
|
181
174
|
|
182
|
-
|
183
|
-
|
175
|
+
else
|
176
|
+
raise "Don't know about this data type... something must be wrong!"
|
177
|
+
end
|
184
178
|
end
|
179
|
+
private
|
180
|
+
class IndentedString #:nodoc:
|
181
|
+
attr_accessor :indent_string
|
182
|
+
|
183
|
+
def initialize(str = "\t")
|
184
|
+
@indent_string = str
|
185
|
+
@contents = ''
|
186
|
+
@indent_level = 0
|
187
|
+
end
|
185
188
|
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
+
def to_s
|
190
|
+
return @contents
|
191
|
+
end
|
189
192
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
+
def raise_indent
|
194
|
+
@indent_level += 1
|
195
|
+
end
|
193
196
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
self << f
|
198
|
-
end
|
199
|
-
else
|
200
|
-
# if it's already indented, don't bother indenting further
|
201
|
-
unless val =~ /\A#{@indent_string}/
|
202
|
-
indent = @indent_string * @indent_level
|
197
|
+
def lower_indent
|
198
|
+
@indent_level -= 1 if @indent_level > 0
|
199
|
+
end
|
203
200
|
|
204
|
-
|
201
|
+
def <<(val)
|
202
|
+
if val.is_a? Array
|
203
|
+
val.each do |f|
|
204
|
+
self << f
|
205
|
+
end
|
205
206
|
else
|
206
|
-
|
207
|
-
|
207
|
+
# if it's already indented, don't bother indenting further
|
208
|
+
unless val =~ /\A#{@indent_string}/
|
209
|
+
indent = @indent_string * @indent_level
|
208
210
|
|
209
|
-
|
210
|
-
|
211
|
+
@contents << val.gsub(/^/, indent)
|
212
|
+
else
|
213
|
+
@contents << val
|
214
|
+
end
|
215
|
+
|
216
|
+
# it already has a newline, don't add another
|
217
|
+
@contents << "\n" unless val =~ /\n$/
|
218
|
+
end
|
211
219
|
end
|
212
220
|
end
|
213
221
|
end
|
data/lib/plist/parser.rb
CHANGED
@@ -11,41 +11,41 @@
|
|
11
11
|
# === Load a plist file
|
12
12
|
# This is the main point of the library:
|
13
13
|
#
|
14
|
-
# r = Plist
|
14
|
+
# r = Plist.parse_xml(filename_or_xml)
|
15
15
|
module Plist
|
16
|
-
# Note that I don't use these two elements much:
|
17
|
-
#
|
18
|
-
# + Date elements are returned as DateTime objects.
|
19
|
-
# + Data elements are implemented as Tempfiles
|
20
|
-
#
|
21
|
-
# Plist
|
22
|
-
# If you encounter such an error, or if you have a Date element which
|
23
|
-
# can't be parsed into a Time object, please
|
24
|
-
#
|
25
|
-
|
16
|
+
# Note that I don't use these two elements much:
|
17
|
+
#
|
18
|
+
# + Date elements are returned as DateTime objects.
|
19
|
+
# + Data elements are implemented as Tempfiles
|
20
|
+
#
|
21
|
+
# Plist.parse_xml will blow up if it encounters a Date element.
|
22
|
+
# If you encounter such an error, or if you have a Date element which
|
23
|
+
# can't be parsed into a Time object, please create an issue
|
24
|
+
# attaching your plist file at https://github.com/patsplat/plist/issues
|
25
|
+
# so folks can implement the proper support.
|
26
|
+
def self.parse_xml(filename_or_xml)
|
26
27
|
listener = Listener.new
|
27
|
-
#parser = REXML::Parsers::StreamParser.new(File.new(filename), listener)
|
28
|
+
# parser = REXML::Parsers::StreamParser.new(File.new(filename), listener)
|
28
29
|
parser = StreamParser.new(filename_or_xml, listener)
|
29
30
|
parser.parse
|
30
31
|
listener.result
|
31
32
|
end
|
32
33
|
|
33
34
|
class Listener
|
34
|
-
#include REXML::StreamListener
|
35
|
+
# include REXML::StreamListener
|
35
36
|
|
36
37
|
attr_accessor :result, :open
|
37
38
|
|
38
39
|
def initialize
|
39
40
|
@result = nil
|
40
|
-
@open =
|
41
|
+
@open = []
|
41
42
|
end
|
42
43
|
|
43
|
-
|
44
44
|
def tag_start(name, attributes)
|
45
|
-
@open.push PTag
|
45
|
+
@open.push PTag.mappings[name].new
|
46
46
|
end
|
47
47
|
|
48
|
-
def text(
|
48
|
+
def text(contents)
|
49
49
|
@open.last.text = contents if @open.last
|
50
50
|
end
|
51
51
|
|
@@ -60,11 +60,11 @@ module Plist
|
|
60
60
|
end
|
61
61
|
|
62
62
|
class StreamParser
|
63
|
-
def initialize(
|
63
|
+
def initialize(plist_data_or_file, listener)
|
64
64
|
if plist_data_or_file.respond_to? :read
|
65
65
|
@xml = plist_data_or_file.read
|
66
66
|
elsif File.exist? plist_data_or_file
|
67
|
-
@xml = File.read(
|
67
|
+
@xml = File.read(plist_data_or_file)
|
68
68
|
else
|
69
69
|
@xml = plist_data_or_file
|
70
70
|
end
|
@@ -78,15 +78,14 @@ module Plist
|
|
78
78
|
COMMENT_START = /\A<!--/
|
79
79
|
COMMENT_END = /.*?-->/m
|
80
80
|
|
81
|
-
|
82
81
|
def parse
|
83
|
-
plist_tags = PTag
|
82
|
+
plist_tags = PTag.mappings.keys.join('|')
|
84
83
|
start_tag = /<(#{plist_tags})([^>]*)>/i
|
85
84
|
end_tag = /<\/(#{plist_tags})[^>]*>/i
|
86
85
|
|
87
86
|
require 'strscan'
|
88
87
|
|
89
|
-
@scanner = StringScanner.new(
|
88
|
+
@scanner = StringScanner.new(@xml)
|
90
89
|
until @scanner.eos?
|
91
90
|
if @scanner.scan(COMMENT_START)
|
92
91
|
@scanner.scan(COMMENT_END)
|
@@ -132,22 +131,21 @@ module Plist
|
|
132
131
|
end
|
133
132
|
|
134
133
|
class PTag
|
135
|
-
|
136
|
-
|
137
|
-
@@mappings
|
134
|
+
def self.mappings
|
135
|
+
@mappings ||= {}
|
138
136
|
end
|
139
137
|
|
140
|
-
def
|
138
|
+
def self.inherited(sub_class)
|
141
139
|
key = sub_class.to_s.downcase
|
142
|
-
key.gsub!(/^plist::/, ''
|
140
|
+
key.gsub!(/^plist::/, '')
|
143
141
|
key.gsub!(/^p/, '') unless key == "plist"
|
144
142
|
|
145
|
-
|
143
|
+
mappings[key] = sub_class
|
146
144
|
end
|
147
145
|
|
148
146
|
attr_accessor :text, :children
|
149
147
|
def initialize
|
150
|
-
@children =
|
148
|
+
@children = []
|
151
149
|
end
|
152
150
|
|
153
151
|
def to_ruby
|
@@ -163,7 +161,7 @@ module Plist
|
|
163
161
|
|
164
162
|
class PDict < PTag
|
165
163
|
def to_ruby
|
166
|
-
dict =
|
164
|
+
dict = {}
|
167
165
|
key = nil
|
168
166
|
|
169
167
|
children.each do |c|
|
@@ -181,13 +179,13 @@ module Plist
|
|
181
179
|
|
182
180
|
class PKey < PTag
|
183
181
|
def to_ruby
|
184
|
-
CGI
|
182
|
+
CGI.unescapeHTML(text || '')
|
185
183
|
end
|
186
184
|
end
|
187
185
|
|
188
186
|
class PString < PTag
|
189
187
|
def to_ruby
|
190
|
-
CGI
|
188
|
+
CGI.unescapeHTML(text || '')
|
191
189
|
end
|
192
190
|
end
|
193
191
|
|
data/lib/plist/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: plist
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Bleything
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2017-
|
12
|
+
date: 2017-12-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -95,7 +95,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
95
95
|
version: '0'
|
96
96
|
requirements: []
|
97
97
|
rubyforge_project:
|
98
|
-
rubygems_version: 2.
|
98
|
+
rubygems_version: 2.7.3
|
99
99
|
signing_key:
|
100
100
|
specification_version: 4
|
101
101
|
summary: All-purpose Property List manipulation library
|