nixenvironment 0.0.118 → 0.0.119
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/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
|