nixenvironment 0.0.118 → 0.0.119
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/nixenvironment +0 -17
- data/lib/nixenvironment/CFPropertyList228/README +44 -0
- data/lib/nixenvironment/CFPropertyList228/lib/cfpropertylist.rb +6 -0
- data/lib/nixenvironment/CFPropertyList228/lib/cfpropertylist/rbBinaryCFPropertyList.rb +605 -0
- data/lib/nixenvironment/CFPropertyList228/lib/cfpropertylist/rbCFPlistError.rb +28 -0
- data/lib/nixenvironment/CFPropertyList228/lib/cfpropertylist/rbCFPropertyList.rb +432 -0
- data/lib/nixenvironment/CFPropertyList228/lib/cfpropertylist/rbCFTypes.rb +266 -0
- data/lib/nixenvironment/CFPropertyList228/lib/cfpropertylist/rbLibXMLParser.rb +147 -0
- data/lib/nixenvironment/CFPropertyList228/lib/cfpropertylist/rbNokogiriParser.rb +151 -0
- data/lib/nixenvironment/CFPropertyList228/lib/cfpropertylist/rbREXMLParser.rb +147 -0
- data/lib/nixenvironment/plist.rb +12 -11
- data/lib/nixenvironment/version.rb +1 -1
- metadata +10 -1
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Exceptions used:
|
4
|
+
# CFPlistError:: General base exception
|
5
|
+
# CFFormatError:: Format error
|
6
|
+
# CFTypeError:: Type error
|
7
|
+
#
|
8
|
+
# Easy and simple :-)
|
9
|
+
#
|
10
|
+
# Author:: Christian Kruse (mailto:cjk@wwwtech.de)
|
11
|
+
# Copyright:: Copyright (c) 2010
|
12
|
+
# License:: MIT License
|
13
|
+
|
14
|
+
module CFPropertyList228
|
15
|
+
# general plist error. All exceptions thrown are derived from this class.
|
16
|
+
class CFPlistError < Exception
|
17
|
+
end
|
18
|
+
|
19
|
+
# Exception thrown when format errors occur
|
20
|
+
class CFFormatError < CFPlistError
|
21
|
+
end
|
22
|
+
|
23
|
+
# Exception thrown when type errors occur
|
24
|
+
class CFTypeError < CFPlistError
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# eof
|
@@ -0,0 +1,432 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'kconv'
|
4
|
+
require 'date'
|
5
|
+
require 'time'
|
6
|
+
|
7
|
+
#
|
8
|
+
# CFPropertyList228 implementation
|
9
|
+
#
|
10
|
+
# class to read, manipulate and write both XML and binary property list
|
11
|
+
# files (plist(5)) as defined by Apple. Have a look at CFPropertyList228::List
|
12
|
+
# for more documentation.
|
13
|
+
#
|
14
|
+
# == Example
|
15
|
+
# require 'CFPropertyList228'
|
16
|
+
#
|
17
|
+
# # create a arbitrary data structure of basic data types
|
18
|
+
# data = {
|
19
|
+
# 'name' => 'John Doe',
|
20
|
+
# 'missing' => true,
|
21
|
+
# 'last_seen' => Time.now,
|
22
|
+
# 'friends' => ['Jane Doe','Julian Doe'],
|
23
|
+
# 'likes' => {
|
24
|
+
# 'me' => false
|
25
|
+
# }
|
26
|
+
# }
|
27
|
+
#
|
28
|
+
# # create CFPropertyList228::List object
|
29
|
+
# plist = CFPropertyList228::List.new
|
30
|
+
#
|
31
|
+
# # call CFPropertyList228.guess() to create corresponding CFType values
|
32
|
+
# # pass in optional :convert_unknown_to_string => true to convert things like symbols into strings.
|
33
|
+
# plist.value = CFPropertyList228.guess(data)
|
34
|
+
#
|
35
|
+
# # write plist to file
|
36
|
+
# plist.save("example.plist", CFPropertyList228::List::FORMAT_BINARY)
|
37
|
+
#
|
38
|
+
# # … later, read it again
|
39
|
+
# plist = CFPropertyList228::List.new(:file => "example.plist")
|
40
|
+
# data = CFPropertyList228.native_types(plist.value)
|
41
|
+
#
|
42
|
+
# Author:: Christian Kruse (mailto:cjk@wwwtech.de)
|
43
|
+
# Copyright:: Copyright (c) 2010
|
44
|
+
# License:: MIT License
|
45
|
+
module CFPropertyList228
|
46
|
+
class << self
|
47
|
+
attr_accessor :xml_parser_interface
|
48
|
+
end
|
49
|
+
|
50
|
+
# interface class for PList parsers
|
51
|
+
class ParserInterface
|
52
|
+
# load a plist
|
53
|
+
def load(opts={})
|
54
|
+
return ""
|
55
|
+
end
|
56
|
+
|
57
|
+
# convert a plist to string
|
58
|
+
def to_str(opts={})
|
59
|
+
return true
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class XMLParserInterface < ParserInterface
|
64
|
+
def new_node(name)
|
65
|
+
end
|
66
|
+
|
67
|
+
def new_text(val)
|
68
|
+
end
|
69
|
+
|
70
|
+
def append_node(parent, child)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class String
|
76
|
+
unless("".respond_to?(:bytesize)) then
|
77
|
+
def bytesize
|
78
|
+
self.length
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
dirname = File.dirname(__FILE__)
|
84
|
+
require dirname + '/rbCFPlistError.rb'
|
85
|
+
require dirname + '/rbCFTypes.rb'
|
86
|
+
require dirname + '/rbBinaryCFPropertyList.rb'
|
87
|
+
|
88
|
+
require 'iconv' unless "".respond_to?("encode")
|
89
|
+
|
90
|
+
# ensure that the module and class exist
|
91
|
+
module Enumerable
|
92
|
+
class Enumerator
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
begin
|
97
|
+
require dirname + '/rbLibXMLParser.rb'
|
98
|
+
temp = LibXML::XML::Parser::Options::NOBLANKS; # check if we have a version with parser options
|
99
|
+
try_nokogiri = false
|
100
|
+
CFPropertyList228.xml_parser_interface = CFPropertyList228::LibXMLParser
|
101
|
+
rescue LoadError, NameError
|
102
|
+
try_nokogiri = true
|
103
|
+
end
|
104
|
+
|
105
|
+
if try_nokogiri then
|
106
|
+
begin
|
107
|
+
require dirname + '/rbNokogiriParser.rb'
|
108
|
+
CFPropertyList228.xml_parser_interface = CFPropertyList228::NokogiriXMLParser
|
109
|
+
rescue LoadError => e
|
110
|
+
require dirname + '/rbREXMLParser.rb'
|
111
|
+
CFPropertyList228.xml_parser_interface = CFPropertyList228::ReXMLParser
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
module CFPropertyList228
|
117
|
+
# Create CFType hierarchy by guessing the correct CFType, e.g.
|
118
|
+
#
|
119
|
+
# x = {
|
120
|
+
# 'a' => ['b','c','d']
|
121
|
+
# }
|
122
|
+
# cftypes = CFPropertyList228.guess(x)
|
123
|
+
#
|
124
|
+
# pass optional options hash. Only possible value actually:
|
125
|
+
# +convert_unknown_to_string+:: Convert unknown objects to string calling to_str()
|
126
|
+
# +converter_method+:: Convert unknown objects to known objects calling +method_name+
|
127
|
+
#
|
128
|
+
# cftypes = CFPropertyList228.guess(x,:convert_unknown_to_string => true,:converter_method => :to_hash, :converter_with_opts => true)
|
129
|
+
def guess(object, options = {})
|
130
|
+
case object
|
131
|
+
when Fixnum, Integer then CFInteger.new(object)
|
132
|
+
when UidFixnum then CFUid.new(object)
|
133
|
+
when Float then CFReal.new(object)
|
134
|
+
when TrueClass, FalseClass then CFBoolean.new(object)
|
135
|
+
|
136
|
+
when Blob
|
137
|
+
CFData.new(object, CFData::DATA_RAW)
|
138
|
+
|
139
|
+
when String
|
140
|
+
CFString.new(object)
|
141
|
+
|
142
|
+
when Time, DateTime, Date then CFDate.new(object)
|
143
|
+
|
144
|
+
when Array, Enumerator, Enumerable::Enumerator
|
145
|
+
ary = Array.new
|
146
|
+
object.each do |o|
|
147
|
+
ary.push CFPropertyList228.guess(o, options)
|
148
|
+
end
|
149
|
+
CFArray.new(ary)
|
150
|
+
|
151
|
+
when Hash
|
152
|
+
hsh = Hash.new
|
153
|
+
object.each_pair do |k,v|
|
154
|
+
k = k.to_s if k.is_a?(Symbol)
|
155
|
+
hsh[k] = CFPropertyList228.guess(v, options)
|
156
|
+
end
|
157
|
+
CFDictionary.new(hsh)
|
158
|
+
else
|
159
|
+
case
|
160
|
+
when Object.const_defined?('BigDecimal') && object.is_a?(BigDecimal)
|
161
|
+
CFReal.new(object)
|
162
|
+
when object.respond_to?(:read)
|
163
|
+
raw_data = object.read
|
164
|
+
# treat the data as a bytestring (ASCII-8BIT) if Ruby supports it. Do this by forcing
|
165
|
+
# the encoding, on the assumption that the bytes were read correctly, and just tagged with
|
166
|
+
# an inappropriate encoding, rather than transcoding.
|
167
|
+
raw_data.force_encoding(Encoding::ASCII_8BIT) if raw_data.respond_to?(:force_encoding)
|
168
|
+
CFData.new(raw_data, CFData::DATA_RAW)
|
169
|
+
when options[:converter_method] && object.respond_to?(options[:converter_method])
|
170
|
+
if options[:converter_with_opts]
|
171
|
+
CFPropertyList228.guess(object.send(options[:converter_method],options),options)
|
172
|
+
else
|
173
|
+
CFPropertyList228.guess(object.send(options[:converter_method]),options)
|
174
|
+
end
|
175
|
+
when options[:convert_unknown_to_string]
|
176
|
+
CFString.new(object.to_s)
|
177
|
+
else
|
178
|
+
raise CFTypeError.new("Unknown class #{object.class.to_s}. Try using :convert_unknown_to_string if you want to use unknown object types!")
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
# Converts a CFType hiercharchy to native Ruby types
|
184
|
+
def native_types(object,keys_as_symbols=false)
|
185
|
+
return if object.nil?
|
186
|
+
|
187
|
+
if(object.is_a?(CFDate) || object.is_a?(CFString) || object.is_a?(CFInteger) || object.is_a?(CFReal) || object.is_a?(CFBoolean)) || object.is_a?(CFUid) then
|
188
|
+
return object.value
|
189
|
+
elsif(object.is_a?(CFData)) then
|
190
|
+
return CFPropertyList228::Blob.new(object.decoded_value)
|
191
|
+
elsif(object.is_a?(CFArray)) then
|
192
|
+
ary = []
|
193
|
+
object.value.each do
|
194
|
+
|v|
|
195
|
+
ary.push CFPropertyList228.native_types(v)
|
196
|
+
end
|
197
|
+
|
198
|
+
return ary
|
199
|
+
elsif(object.is_a?(CFDictionary)) then
|
200
|
+
hsh = {}
|
201
|
+
object.value.each_pair do
|
202
|
+
|k,v|
|
203
|
+
k = k.to_sym if keys_as_symbols
|
204
|
+
hsh[k] = CFPropertyList228.native_types(v)
|
205
|
+
end
|
206
|
+
|
207
|
+
return hsh
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
module_function :guess, :native_types
|
212
|
+
|
213
|
+
# Class representing a CFPropertyList228. Instanciate with #new
|
214
|
+
class List
|
215
|
+
# Format constant for binary format
|
216
|
+
FORMAT_BINARY = 1
|
217
|
+
|
218
|
+
# Format constant for XML format
|
219
|
+
FORMAT_XML = 2
|
220
|
+
|
221
|
+
# Format constant for automatic format recognizing
|
222
|
+
FORMAT_AUTO = 0
|
223
|
+
|
224
|
+
@@parsers = [Binary, CFPropertyList228.xml_parser_interface]
|
225
|
+
|
226
|
+
# Path of PropertyList
|
227
|
+
attr_accessor :filename
|
228
|
+
# the original format of the PropertyList
|
229
|
+
attr_accessor :format
|
230
|
+
# the root value in the plist file
|
231
|
+
attr_accessor :value
|
232
|
+
# default value for XML generation; if true generate formatted XML
|
233
|
+
attr_accessor :formatted
|
234
|
+
|
235
|
+
# initialize a new CFPropertyList228, arguments are:
|
236
|
+
#
|
237
|
+
# :file:: Parse a file
|
238
|
+
# :format:: Format is one of FORMAT_BINARY or FORMAT_XML. Defaults to FORMAT_AUTO
|
239
|
+
# :data:: Parse a string
|
240
|
+
#
|
241
|
+
# All arguments are optional
|
242
|
+
def initialize(opts={})
|
243
|
+
@filename = opts[:file]
|
244
|
+
@format = opts[:format] || FORMAT_AUTO
|
245
|
+
@data = opts[:data]
|
246
|
+
@formatted = opts[:formatted]
|
247
|
+
|
248
|
+
load(@filename) unless @filename.nil?
|
249
|
+
load_str(@data) unless @data.nil?
|
250
|
+
end
|
251
|
+
|
252
|
+
# returns a list of registered parsers
|
253
|
+
def self.parsers
|
254
|
+
@@parsers
|
255
|
+
end
|
256
|
+
|
257
|
+
# set a list of parsers
|
258
|
+
def self.parsers=(val)
|
259
|
+
@@parsers = val
|
260
|
+
end
|
261
|
+
|
262
|
+
# Load an XML PropertyList
|
263
|
+
# filename = nil:: The filename to read from; if nil, read from the file defined by instance variable +filename+
|
264
|
+
def load_xml(filename=nil)
|
265
|
+
load(filename,List::FORMAT_XML)
|
266
|
+
end
|
267
|
+
|
268
|
+
# read a binary plist file
|
269
|
+
# filename = nil:: The filename to read from; if nil, read from the file defined by instance variable +filename+
|
270
|
+
def load_binary(filename=nil)
|
271
|
+
load(filename,List::FORMAT_BINARY)
|
272
|
+
end
|
273
|
+
|
274
|
+
# load a plist from a XML string
|
275
|
+
# str:: The string containing the plist
|
276
|
+
def load_xml_str(str=nil)
|
277
|
+
load_str(str,List::FORMAT_XML)
|
278
|
+
end
|
279
|
+
|
280
|
+
# load a plist from a binary string
|
281
|
+
# str:: The string containing the plist
|
282
|
+
def load_binary_str(str=nil)
|
283
|
+
load_str(str,List::FORMAT_BINARY)
|
284
|
+
end
|
285
|
+
|
286
|
+
# load a plist from a string
|
287
|
+
# str = nil:: The string containing the plist
|
288
|
+
# format = nil:: The format of the plist
|
289
|
+
def load_str(str=nil,format=nil)
|
290
|
+
str = @data if str.nil?
|
291
|
+
format = @format if format.nil?
|
292
|
+
|
293
|
+
@value = {}
|
294
|
+
case format
|
295
|
+
when List::FORMAT_BINARY, List::FORMAT_XML then
|
296
|
+
prsr = @@parsers[format-1].new
|
297
|
+
@value = prsr.load({:data => str})
|
298
|
+
|
299
|
+
when List::FORMAT_AUTO then # what we now do is ugly, but neccessary to recognize the file format
|
300
|
+
filetype = str[0..5]
|
301
|
+
version = str[6..7]
|
302
|
+
|
303
|
+
prsr = nil
|
304
|
+
if filetype == "bplist" then
|
305
|
+
raise CFFormatError.new("Wrong file version #{version}") unless version == "00"
|
306
|
+
prsr = Binary.new
|
307
|
+
@format = List::FORMAT_BINARY
|
308
|
+
else
|
309
|
+
prsr = CFPropertyList228.xml_parser_interface.new
|
310
|
+
@format = List::FORMAT_XML
|
311
|
+
end
|
312
|
+
|
313
|
+
@value = prsr.load({:data => str})
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
# Read a plist file
|
318
|
+
# file = nil:: The filename of the file to read. If nil, use +filename+ instance variable
|
319
|
+
# format = nil:: The format of the plist file. Auto-detect if nil
|
320
|
+
def load(file=nil,format=nil)
|
321
|
+
file = @filename if file.nil?
|
322
|
+
format = @format if format.nil?
|
323
|
+
@value = {}
|
324
|
+
|
325
|
+
raise IOError.new("File #{file} not readable!") unless File.readable? file
|
326
|
+
|
327
|
+
case format
|
328
|
+
when List::FORMAT_BINARY, List::FORMAT_XML then
|
329
|
+
prsr = @@parsers[format-1].new
|
330
|
+
@value = prsr.load({:file => file})
|
331
|
+
|
332
|
+
when List::FORMAT_AUTO then # what we now do is ugly, but neccessary to recognize the file format
|
333
|
+
magic_number = IO.read(file,8)
|
334
|
+
raise IOError.new("File #{file} is empty.") unless magic_number
|
335
|
+
filetype = magic_number[0..5]
|
336
|
+
version = magic_number[6..7]
|
337
|
+
|
338
|
+
prsr = nil
|
339
|
+
if filetype == "bplist" then
|
340
|
+
raise CFFormatError.new("Wong file version #{version}") unless version == "00"
|
341
|
+
prsr = Binary.new
|
342
|
+
@format = List::FORMAT_BINARY
|
343
|
+
else
|
344
|
+
prsr = CFPropertyList228.xml_parser_interface.new
|
345
|
+
@format = List::FORMAT_XML
|
346
|
+
end
|
347
|
+
|
348
|
+
@value = prsr.load({:file => file})
|
349
|
+
end
|
350
|
+
|
351
|
+
raise CFFormatError.new("Invalid format or parser error!") if @value.nil?
|
352
|
+
end
|
353
|
+
|
354
|
+
# Serialize CFPropertyList228 object to specified format and write it to file
|
355
|
+
# file = nil:: The filename of the file to write to. Uses +filename+ instance variable if nil
|
356
|
+
# format = nil:: The format to save in. Uses +format+ instance variable if nil
|
357
|
+
def save(file=nil,format=nil,opts={})
|
358
|
+
format = @format if format.nil?
|
359
|
+
file = @filename if file.nil?
|
360
|
+
|
361
|
+
raise CFFormatError.new("Format #{format} not supported, use List::FORMAT_BINARY or List::FORMAT_XML") if format != FORMAT_BINARY && format != FORMAT_XML
|
362
|
+
|
363
|
+
if(!File.exists?(file)) then
|
364
|
+
raise IOError.new("File #{file} not writable!") unless File.writable?(File.dirname(file))
|
365
|
+
elsif(!File.writable?(file)) then
|
366
|
+
raise IOError.new("File #{file} not writable!")
|
367
|
+
end
|
368
|
+
|
369
|
+
opts[:root] = @value
|
370
|
+
opts[:formatted] = @formatted unless opts.has_key?(:formatted)
|
371
|
+
|
372
|
+
prsr = @@parsers[format-1].new
|
373
|
+
|
374
|
+
content = prsr.to_str(opts)
|
375
|
+
|
376
|
+
File.open(file, 'wb') {
|
377
|
+
|fd|
|
378
|
+
fd.write content
|
379
|
+
}
|
380
|
+
end
|
381
|
+
|
382
|
+
# convert plist to string
|
383
|
+
# format = List::FORMAT_BINARY:: The format to save the plist
|
384
|
+
# opts={}:: Pass parser options
|
385
|
+
def to_str(format=List::FORMAT_BINARY,opts={})
|
386
|
+
raise CFFormatError.new("Format #{format} not supported, use List::FORMAT_BINARY or List::FORMAT_XML") if format != FORMAT_BINARY && format != FORMAT_XML
|
387
|
+
|
388
|
+
prsr = @@parsers[format-1].new
|
389
|
+
|
390
|
+
opts[:root] = @value
|
391
|
+
opts[:formatted] = @formatted unless opts.has_key?(:formatted)
|
392
|
+
|
393
|
+
return prsr.to_str(opts)
|
394
|
+
end
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
|
399
|
+
class Array
|
400
|
+
# convert an array to plist format
|
401
|
+
def to_plist(options={})
|
402
|
+
options[:plist_format] ||= CFPropertyList228::List::FORMAT_BINARY
|
403
|
+
|
404
|
+
plist = CFPropertyList228::List.new
|
405
|
+
plist.value = CFPropertyList228.guess(self, options)
|
406
|
+
plist.to_str(options[:plist_format], options)
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
class Enumerator
|
411
|
+
# convert an array to plist format
|
412
|
+
def to_plist(options={})
|
413
|
+
options[:plist_format] ||= CFPropertyList228::List::FORMAT_BINARY
|
414
|
+
|
415
|
+
plist = CFPropertyList228::List.new
|
416
|
+
plist.value = CFPropertyList228.guess(self, options)
|
417
|
+
plist.to_str(options[:plist_format], options)
|
418
|
+
end
|
419
|
+
end
|
420
|
+
|
421
|
+
class Hash
|
422
|
+
# convert a hash to plist format
|
423
|
+
def to_plist(options={})
|
424
|
+
options[:plist_format] ||= CFPropertyList228::List::FORMAT_BINARY
|
425
|
+
|
426
|
+
plist = CFPropertyList228::List.new
|
427
|
+
plist.value = CFPropertyList228.guess(self, options)
|
428
|
+
plist.to_str(options[:plist_format], options)
|
429
|
+
end
|
430
|
+
end
|
431
|
+
|
432
|
+
# eof
|