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.
@@ -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