plist 3.5.0 → 3.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/plist.rb +3 -3
- data/lib/plist/generator.rb +91 -141
- data/lib/plist/parser.rb +14 -3
- data/lib/plist/version.rb +1 -1
- metadata +10 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2a76784a6b7e953d1cd9b6deaf390eb7556fd0df83e8970db7ac4640c71493b4
|
4
|
+
data.tar.gz: 8324c2b332839aa772eb77a4a760b24e43e24c363c99d01c2b2b4b11e311938a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c33686b606d723821333314b4a18fe6ac39d65a3712aa1cd43896dbbd4bfb95130aa0a1f62b4a3b260c2a633d44681eec0766fef5651ae70580340a905e4f6e4
|
7
|
+
data.tar.gz: 5b63b55469235ec79f14af6f25c05cbc8e6088ce9532e9dfc5aa0887e533a7ee67424953d62e0b3dfe046c7745d9a2add1e0b8ddf07c34f46c5a551c92a9a158
|
data/lib/plist.rb
CHANGED
data/lib/plist/generator.rb
CHANGED
@@ -26,13 +26,11 @@ module Plist
|
|
26
26
|
|
27
27
|
# Helper method for injecting into classes. Calls <tt>Plist::Emit.dump</tt> with +self+.
|
28
28
|
def to_plist(envelope = true, options = {})
|
29
|
-
|
30
|
-
return Plist::Emit.dump(self, envelope, options)
|
29
|
+
Plist::Emit.dump(self, envelope, options)
|
31
30
|
end
|
32
31
|
|
33
32
|
# Helper method for injecting into classes. Calls <tt>Plist::Emit.save_plist</tt> with +self+.
|
34
33
|
def save_plist(filename, options = {})
|
35
|
-
options = { :indent => DEFAULT_INDENT }.merge(options)
|
36
34
|
Plist::Emit.save_plist(self, filename, options)
|
37
35
|
end
|
38
36
|
|
@@ -46,177 +44,129 @@ module Plist
|
|
46
44
|
# 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
45
|
def self.dump(obj, envelope = true, options = {})
|
48
46
|
options = { :indent => DEFAULT_INDENT }.merge(options)
|
49
|
-
output = plist_node(obj, options)
|
50
47
|
|
48
|
+
output = PlistBuilder.new(options[:indent]).build(obj)
|
51
49
|
output = wrap(output) if envelope
|
52
50
|
|
53
|
-
|
51
|
+
output
|
54
52
|
end
|
55
53
|
|
56
54
|
# Writes the serialized object's plist to the specified filename.
|
57
55
|
def self.save_plist(obj, filename, options = {})
|
58
|
-
options = { :indent => DEFAULT_INDENT }.merge(options)
|
59
56
|
File.open(filename, 'wb') do |f|
|
60
57
|
f.write(obj.to_plist(true, options))
|
61
58
|
end
|
62
59
|
end
|
63
60
|
|
64
61
|
private
|
65
|
-
def self.plist_node(element, options = {})
|
66
|
-
options = { :indent => DEFAULT_INDENT }.merge(options)
|
67
|
-
output = ''
|
68
|
-
|
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
|
-
}
|
80
|
-
end
|
81
|
-
when Hash
|
82
|
-
if element.empty?
|
83
|
-
output << "<dict/>\n"
|
84
|
-
else
|
85
|
-
inner_tags = []
|
86
62
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
end
|
63
|
+
class PlistBuilder
|
64
|
+
def initialize(indent_str)
|
65
|
+
@indent_str = indent_str.to_s
|
66
|
+
end
|
92
67
|
|
93
|
-
|
94
|
-
|
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)
|
68
|
+
def build(element, level=0)
|
69
|
+
if element.respond_to? :to_plist_node
|
70
|
+
element.to_plist_node
|
115
71
|
else
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
72
|
+
case element
|
73
|
+
when Array
|
74
|
+
if element.empty?
|
75
|
+
tag('array', nil, level)
|
76
|
+
else
|
77
|
+
tag('array', nil, level) {
|
78
|
+
element.collect {|e| build(e, level + 1) }.join
|
79
|
+
}
|
80
|
+
end
|
81
|
+
when Hash
|
82
|
+
if element.empty?
|
83
|
+
tag('dict', nil, level)
|
84
|
+
else
|
85
|
+
tag('dict', '', level) do
|
86
|
+
element.sort_by{|k,v| k.to_s }.collect do |k,v|
|
87
|
+
tag('key', CGI.escapeHTML(k.to_s), level + 1) +
|
88
|
+
build(v, level + 1)
|
89
|
+
end.join
|
90
|
+
end
|
91
|
+
end
|
92
|
+
when true, false
|
93
|
+
tag(element, nil, level)
|
94
|
+
when Time
|
95
|
+
tag('date', element.utc.strftime('%Y-%m-%dT%H:%M:%SZ'), level)
|
96
|
+
when Date # also catches DateTime
|
97
|
+
tag('date', element.strftime('%Y-%m-%dT%H:%M:%SZ'), level)
|
98
|
+
when String, Symbol, Integer, Float
|
99
|
+
tag(element_type(element), CGI.escapeHTML(element.to_s), level)
|
100
|
+
when IO, StringIO
|
101
|
+
data = element.tap(&:rewind).read
|
102
|
+
data_tag(data, level)
|
103
|
+
else
|
104
|
+
data = Marshal.dump(element)
|
105
|
+
comment_tag('The <data> element below contains a Ruby object which has been serialized with Marshal.dump.') +
|
106
|
+
data_tag(data, level)
|
107
|
+
end
|
120
108
|
end
|
121
109
|
end
|
122
110
|
|
123
|
-
|
124
|
-
end
|
125
|
-
|
126
|
-
def self.comment(content)
|
127
|
-
return "<!-- #{content} -->\n"
|
128
|
-
end
|
111
|
+
private
|
129
112
|
|
130
|
-
|
131
|
-
|
132
|
-
|
113
|
+
def tag(type, contents, level, &block)
|
114
|
+
if block_given?
|
115
|
+
indent("<#{type}>\n", level) +
|
116
|
+
block.call +
|
117
|
+
indent("</#{type}>\n", level)
|
118
|
+
elsif contents.to_s.empty?
|
119
|
+
indent("<#{type}/>\n", level)
|
120
|
+
else
|
121
|
+
indent("<#{type}>#{contents.to_s}</#{type}>\n", level)
|
122
|
+
end
|
123
|
+
end
|
133
124
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
125
|
+
def data_tag(data, level)
|
126
|
+
# note that apple plists are wrapped at a different length then
|
127
|
+
# what ruby's base64 wraps by default.
|
128
|
+
# I used #encode64 instead of #b64encode (which allows a length arg)
|
129
|
+
# because b64encode is b0rked and ignores the length arg.
|
130
|
+
tag('data', nil, level) do
|
131
|
+
Base64.encode64(data)
|
132
|
+
.gsub(/\s+/, '')
|
133
|
+
.scan(/.{1,68}/o)
|
134
|
+
.collect { |line| indent(line, level) }
|
135
|
+
.join("\n")
|
136
|
+
.concat("\n")
|
137
|
+
end
|
138
|
+
end
|
138
139
|
|
139
|
-
|
140
|
+
def indent(str, level)
|
141
|
+
@indent_str.to_s * level + str
|
142
|
+
end
|
140
143
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
144
|
+
def element_type(item)
|
145
|
+
case item
|
146
|
+
when String, Symbol
|
147
|
+
'string'
|
148
|
+
when Integer
|
149
|
+
'integer'
|
150
|
+
when Float
|
151
|
+
'real'
|
152
|
+
else
|
153
|
+
raise "Don't know about this data type... something must be wrong!"
|
154
|
+
end
|
145
155
|
end
|
146
156
|
|
147
|
-
|
157
|
+
def comment_tag(content)
|
158
|
+
return "<!-- #{content} -->\n"
|
159
|
+
end
|
148
160
|
end
|
149
161
|
|
150
162
|
def self.wrap(contents)
|
151
|
-
output = '
|
152
|
-
|
153
|
-
output << '<?xml version="1.0" encoding="UTF-8"?>' + "\n"
|
163
|
+
output = '<?xml version="1.0" encoding="UTF-8"?>' + "\n"
|
154
164
|
output << '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">' + "\n"
|
155
165
|
output << '<plist version="1.0">' + "\n"
|
156
|
-
|
157
166
|
output << contents
|
158
|
-
|
159
167
|
output << '</plist>' + "\n"
|
160
168
|
|
161
|
-
|
162
|
-
end
|
163
|
-
|
164
|
-
def self.element_type(item)
|
165
|
-
case item
|
166
|
-
when String, Symbol
|
167
|
-
'string'
|
168
|
-
|
169
|
-
when Integer
|
170
|
-
'integer'
|
171
|
-
|
172
|
-
when Float
|
173
|
-
'real'
|
174
|
-
|
175
|
-
else
|
176
|
-
raise "Don't know about this data type... something must be wrong!"
|
177
|
-
end
|
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
|
188
|
-
|
189
|
-
def to_s
|
190
|
-
return @contents
|
191
|
-
end
|
192
|
-
|
193
|
-
def raise_indent
|
194
|
-
@indent_level += 1
|
195
|
-
end
|
196
|
-
|
197
|
-
def lower_indent
|
198
|
-
@indent_level -= 1 if @indent_level > 0
|
199
|
-
end
|
200
|
-
|
201
|
-
def <<(val)
|
202
|
-
if val.is_a? Array
|
203
|
-
val.each do |f|
|
204
|
-
self << f
|
205
|
-
end
|
206
|
-
else
|
207
|
-
# if it's already indented, don't bother indenting further
|
208
|
-
unless val =~ /\A#{@indent_string}/
|
209
|
-
indent = @indent_string * @indent_level
|
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
|
219
|
-
end
|
169
|
+
output
|
220
170
|
end
|
221
171
|
end
|
222
172
|
end
|
data/lib/plist/parser.rb
CHANGED
@@ -13,6 +13,9 @@
|
|
13
13
|
#
|
14
14
|
# r = Plist.parse_xml(filename_or_xml)
|
15
15
|
module Plist
|
16
|
+
# Raised when an element is not implemented
|
17
|
+
class UnimplementedElementError < RuntimeError; end
|
18
|
+
|
16
19
|
# Note that I don't use these two elements much:
|
17
20
|
#
|
18
21
|
# + Date elements are returned as DateTime objects.
|
@@ -46,7 +49,10 @@ module Plist
|
|
46
49
|
end
|
47
50
|
|
48
51
|
def text(contents)
|
49
|
-
|
52
|
+
if @open.last
|
53
|
+
@open.last.text ||= ''
|
54
|
+
@open.last.text.concat(contents)
|
55
|
+
end
|
50
56
|
end
|
51
57
|
|
52
58
|
def tag_end(name)
|
@@ -72,11 +78,14 @@ module Plist
|
|
72
78
|
@listener = listener
|
73
79
|
end
|
74
80
|
|
75
|
-
TEXT
|
81
|
+
TEXT = /([^<]+)/
|
82
|
+
CDATA = /<!\[CDATA\[(.*?)\]\]>/
|
76
83
|
XMLDECL_PATTERN = /<\?xml\s+(.*?)\?>*/m
|
77
84
|
DOCTYPE_PATTERN = /\s*<!DOCTYPE\s+(.*?)(\[|>)/m
|
78
85
|
COMMENT_START = /\A<!--/
|
79
86
|
COMMENT_END = /.*?-->/m
|
87
|
+
UNIMPLEMENTED_ERROR = 'Unimplemented element. ' \
|
88
|
+
'Consider reporting via https://github.com/patsplat/plist/issues'
|
80
89
|
|
81
90
|
def parse
|
82
91
|
plist_tags = PTag.mappings.keys.join('|')
|
@@ -105,10 +114,12 @@ module Plist
|
|
105
114
|
end
|
106
115
|
elsif @scanner.scan(TEXT)
|
107
116
|
@listener.text(@scanner[1])
|
117
|
+
elsif @scanner.scan(CDATA)
|
118
|
+
@listener.text(@scanner[1])
|
108
119
|
elsif @scanner.scan(end_tag)
|
109
120
|
@listener.tag_end(@scanner[1])
|
110
121
|
else
|
111
|
-
raise
|
122
|
+
raise UnimplementedElementError.new(UNIMPLEMENTED_ERROR)
|
112
123
|
end
|
113
124
|
end
|
114
125
|
end
|
data/lib/plist/version.rb
CHANGED
metadata
CHANGED
@@ -1,28 +1,28 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: plist
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Bleything
|
8
8
|
- Patrick May
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2020-12-30 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
|
-
- - "
|
18
|
+
- - ">="
|
19
19
|
- !ruby/object:Gem::Version
|
20
20
|
version: '1.14'
|
21
21
|
type: :development
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
|
-
- - "
|
25
|
+
- - ">="
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: '1.14'
|
28
28
|
- !ruby/object:Gem::Dependency
|
@@ -56,7 +56,7 @@ dependencies:
|
|
56
56
|
description: Plist is a library to manipulate Property List files, also known as plists.
|
57
57
|
It can parse plist files into native Ruby data structures as well as generating
|
58
58
|
new plist files from your Ruby objects.
|
59
|
-
email:
|
59
|
+
email:
|
60
60
|
executables: []
|
61
61
|
extensions: []
|
62
62
|
extra_rdoc_files: []
|
@@ -70,7 +70,7 @@ homepage: https://github.com/patsplat/plist
|
|
70
70
|
licenses:
|
71
71
|
- MIT
|
72
72
|
metadata: {}
|
73
|
-
post_install_message:
|
73
|
+
post_install_message:
|
74
74
|
rdoc_options: []
|
75
75
|
require_paths:
|
76
76
|
- lib
|
@@ -78,16 +78,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
78
78
|
requirements:
|
79
79
|
- - ">="
|
80
80
|
- !ruby/object:Gem::Version
|
81
|
-
version:
|
81
|
+
version: 1.9.3
|
82
82
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
83
|
requirements:
|
84
84
|
- - ">="
|
85
85
|
- !ruby/object:Gem::Version
|
86
86
|
version: '0'
|
87
87
|
requirements: []
|
88
|
-
|
89
|
-
|
90
|
-
signing_key:
|
88
|
+
rubygems_version: 3.2.3
|
89
|
+
signing_key:
|
91
90
|
specification_version: 4
|
92
91
|
summary: All-purpose Property List manipulation library
|
93
92
|
test_files: []
|