plist4r 0.2.2 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/.yardopts +11 -0
- data/LICENSE +3 -1
- data/README.rdoc +25 -122
- data/Rakefile +14 -0
- data/VERSION +1 -1
- data/bin/plist4r +2 -0
- data/ext/osx_plist/Makefile +157 -0
- data/ext/osx_plist/extconf.rb +9 -0
- data/ext/osx_plist/plist.c +606 -0
- data/ext/osx_plist/plist.o +0 -0
- data/lib/plist4r.rb +6 -3
- data/lib/plist4r/application.rb +1 -2
- data/lib/plist4r/backend.rb +102 -34
- data/lib/plist4r/backend/c_f_property_list.rb +65 -0
- data/lib/plist4r/backend/c_f_property_list/LICENSE +19 -0
- data/lib/plist4r/backend/c_f_property_list/README +34 -0
- data/lib/plist4r/backend/c_f_property_list/cfpropertylist.rb +6 -0
- data/lib/plist4r/backend/c_f_property_list/rbBinaryCFPropertyList.rb +663 -0
- data/lib/plist4r/backend/c_f_property_list/rbCFPlistError.rb +26 -0
- data/lib/plist4r/backend/c_f_property_list/rbCFPropertyList.rb +348 -0
- data/lib/plist4r/backend/c_f_property_list/rbCFTypes.rb +241 -0
- data/lib/plist4r/backend/c_f_property_list/rbXMLCFPropertyList.rb +116 -0
- data/lib/plist4r/backend/example.rb +37 -52
- data/lib/plist4r/backend/haml.rb +47 -36
- data/lib/plist4r/backend/libxml4r.rb +24 -20
- data/lib/plist4r/backend/osx_plist.rb +82 -0
- data/lib/plist4r/backend/ruby_cocoa.rb +172 -54
- data/lib/plist4r/backend/test/data_types.rb +163 -0
- data/lib/plist4r/backend/test/harness.rb +255 -0
- data/lib/plist4r/backend/test/output.rb +47 -0
- data/lib/plist4r/backend_base.rb +4 -2
- data/lib/plist4r/{options.rb → cli.rb} +2 -1
- data/lib/plist4r/commands.rb +13 -8
- data/lib/plist4r/config.rb +36 -9
- data/lib/plist4r/docs/Backends.html +59 -0
- data/lib/plist4r/docs/DeveloperGuide.rdoc +53 -0
- data/lib/plist4r/docs/EditingPlistFiles.rdoc +88 -0
- data/lib/plist4r/docs/InfoPlistExample.rdoc +33 -0
- data/lib/plist4r/docs/LaunchdPlistExample.rdoc +33 -0
- data/lib/plist4r/docs/PlistKeyNames.rdoc +47 -0
- data/lib/plist4r/mixin/array_dict.rb +61 -0
- data/lib/plist4r/mixin/data_methods.rb +178 -54
- data/lib/plist4r/mixin/haml4r.rb +4 -0
- data/lib/plist4r/mixin/haml4r/css_attributes.rb +19 -0
- data/lib/plist4r/mixin/haml4r/examples.rb +261 -0
- data/lib/plist4r/mixin/haml4r/haml_table_example.rb +79 -0
- data/lib/plist4r/mixin/haml4r/table.rb +157 -0
- data/lib/plist4r/mixin/haml4r/table_cell.rb +160 -0
- data/lib/plist4r/mixin/haml4r/table_cells.rb +485 -0
- data/lib/plist4r/mixin/haml4r/table_section.rb +101 -0
- data/lib/plist4r/mixin/ordered_hash.rb +9 -1
- data/lib/plist4r/mixin/popen4.rb +1 -1
- data/lib/plist4r/mixin/ruby_stdlib.rb +154 -1
- data/lib/plist4r/mixin/script.rb +133 -0
- data/lib/plist4r/mixin/table.rb +435 -0
- data/lib/plist4r/plist.rb +272 -94
- data/lib/plist4r/plist_cache.rb +42 -43
- data/lib/plist4r/plist_type.rb +31 -74
- data/lib/plist4r/plist_type/info.rb +157 -3
- data/lib/plist4r/plist_type/launchd.rb +54 -48
- data/lib/plist4r/plist_type/plist.rb +1 -3
- data/plist4r.gemspec +74 -14
- data/spec/{examples.rb → launchd_examples.rb} +131 -139
- data/spec/plist4r/application_spec.rb +37 -0
- data/spec/plist4r/backend_spec.rb +256 -0
- data/spec/plist4r/cli_spec.rb +25 -0
- data/spec/plist4r/commands_spec.rb +20 -0
- data/spec/plist4r/config_spec.rb +38 -0
- data/spec/plist4r/mixin/array_dict_spec.rb +120 -0
- data/spec/plist4r/mixin/data_methods_spec.rb +96 -0
- data/spec/plist4r/mixin/haml4r/examples.rb +261 -0
- data/spec/plist4r/mixin/ruby_stdlib_spec.rb +228 -0
- data/spec/plist4r/plist_cache_spec.rb +261 -0
- data/spec/plist4r/plist_spec.rb +841 -23
- data/spec/plist4r/plist_type_spec.rb +126 -0
- data/spec/plist4r_spec.rb +53 -27
- data/spec/scratchpad.rb +226 -0
- data/spec/spec_helper.rb +5 -1
- metadata +109 -23
- data/lib/plist4r/backend/plutil.rb +0 -25
- data/lib/plist4r/mixin.rb +0 -7
- data/plists/array_mini.xml +0 -14
- data/plists/example_big_binary.plist +0 -0
- data/plists/example_medium_binary_launchd.plist +0 -0
- data/plists/example_medium_launchd.xml +0 -53
- data/plists/mini.xml +0 -12
- data/test.rb +0 -40
@@ -0,0 +1,435 @@
|
|
1
|
+
|
2
|
+
require 'plist4r/mixin/ruby_stdlib'
|
3
|
+
|
4
|
+
module Plist4r
|
5
|
+
|
6
|
+
# A data type representation for tables. The underlying store is an array of arrays (2d).
|
7
|
+
# The addressing scheme is based on (column, row) order, with Range objects to specify
|
8
|
+
# the bounds of any rectangle of elements withing the table.
|
9
|
+
#
|
10
|
+
# A variety of methods are provided for manipulating the table data, including flipping,
|
11
|
+
# inserting, replacing and deleting. Operations can be column-based, row-based, or both.
|
12
|
+
class Table
|
13
|
+
class << self
|
14
|
+
# This class only understands a range addressing scheme, which is used to specify
|
15
|
+
# table locations in a [columns, rows] caresian system starting at col 0, row 0.
|
16
|
+
#
|
17
|
+
# Convert any Integer numbers into range objects. Check that all input ranges are
|
18
|
+
# positive, starting (and including) zero as the first index.
|
19
|
+
def sanitize_ranges *ranges
|
20
|
+
sanitized_ranges = []
|
21
|
+
ranges.flatten.each do |range|
|
22
|
+
case range
|
23
|
+
when Range
|
24
|
+
if range.exclude_end?
|
25
|
+
range = range.first..(range.last - 1)
|
26
|
+
end
|
27
|
+
when Integer
|
28
|
+
range = (range..range)
|
29
|
+
else
|
30
|
+
raise "Unsupported type"
|
31
|
+
end
|
32
|
+
if range.first < 0 || range.last < 0
|
33
|
+
raise "range cannot cover negative values"
|
34
|
+
end
|
35
|
+
sanitized_ranges << range
|
36
|
+
end
|
37
|
+
sanitized_ranges
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# The value to assign to an empty cell
|
42
|
+
EmptyCell = nil
|
43
|
+
|
44
|
+
# The range of valid values for which match the empty cell criteria (for which the cell are ignored)
|
45
|
+
EmptyCells = [nil, false]
|
46
|
+
|
47
|
+
# When allocating the arrays for a new table, the minimum size to pad around with empty cells.
|
48
|
+
MinPadSize = 10
|
49
|
+
|
50
|
+
OptionsHash = %w[ size array pad_all fill_all ]
|
51
|
+
|
52
|
+
def initialize *args, &blk
|
53
|
+
@array = []
|
54
|
+
|
55
|
+
case args[0]
|
56
|
+
when nil
|
57
|
+
resize 0..0, 0..0
|
58
|
+
|
59
|
+
when Hash
|
60
|
+
parse_opts args[0]
|
61
|
+
|
62
|
+
when Plist4r::Table
|
63
|
+
%w[ col_range row_range array ].each do |a|
|
64
|
+
self.send a.to_sym, args[0].send(a.to_sym).deep_clone
|
65
|
+
end
|
66
|
+
|
67
|
+
else
|
68
|
+
raise "unsupported type"
|
69
|
+
end
|
70
|
+
|
71
|
+
resize 0..0, 0..0 unless @cr && @rr
|
72
|
+
end
|
73
|
+
|
74
|
+
# Sets up those valid (settable) attributes as found the options hash.
|
75
|
+
# Normally we dont call this method directly. Called from {#initialize}.
|
76
|
+
# @param [Hash <OptionsHash>] opts The options hash, containing keys of {OptionsHash}
|
77
|
+
# @see #initialize
|
78
|
+
def parse_opts opts
|
79
|
+
self.class::OptionsHash.each do |opt|
|
80
|
+
if opts[opt.to_sym]
|
81
|
+
value = opts[opt.to_sym]
|
82
|
+
eval "self.#{opt}(value)"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def ascii_col_width
|
88
|
+
lines = self.inspect.split "\n"
|
89
|
+
lines[0].length
|
90
|
+
end
|
91
|
+
|
92
|
+
def inspect start_col=0
|
93
|
+
cell_width = Plist4r::Table.new :size => [@cr, 0..0], :fill_all => 5
|
94
|
+
@cr.each do |col|
|
95
|
+
@rr.each do |row|
|
96
|
+
cell_size = @array[col][row].inspect.size
|
97
|
+
cell_width.cell(col, 0, cell_size) if cell_size > cell_width.cell(col,0)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
col_pad_pre = " "
|
102
|
+
col_pad_post = " "
|
103
|
+
|
104
|
+
vert_border = "|"
|
105
|
+
horz_border = "-"
|
106
|
+
|
107
|
+
row_sep = ""
|
108
|
+
row_sep << " " * start_col
|
109
|
+
@cr.each do |col|
|
110
|
+
row_sep << vert_border + horz_border * (col_pad_pre.size + cell_width.cell(col,0) + col_pad_post.size)
|
111
|
+
end
|
112
|
+
row_sep << vert_border
|
113
|
+
|
114
|
+
o = ""
|
115
|
+
o << row_sep << "\n"
|
116
|
+
@rr.each do |row|
|
117
|
+
o << " " * start_col
|
118
|
+
@cr.each do |col|
|
119
|
+
cell_str = vert_border + col_pad_pre + " " * cell_width.cell(col,0) + col_pad_post
|
120
|
+
cell_str[vert_border.size+col_pad_pre.size,@array[col][row].inspect.size] = @array[col][row].inspect
|
121
|
+
o << cell_str
|
122
|
+
end
|
123
|
+
o << vert_border
|
124
|
+
o << "\n"
|
125
|
+
o << row_sep << "\n"
|
126
|
+
end
|
127
|
+
return o
|
128
|
+
end
|
129
|
+
|
130
|
+
def col_range
|
131
|
+
@cr
|
132
|
+
end
|
133
|
+
|
134
|
+
def row_range
|
135
|
+
@rr
|
136
|
+
end
|
137
|
+
|
138
|
+
def cell col, row, value=nil
|
139
|
+
raise "unsupported type" unless col.is_a?(Integer) && row.is_a?(Integer)
|
140
|
+
return nil if col < 0 || row < 0
|
141
|
+
|
142
|
+
case value
|
143
|
+
when nil
|
144
|
+
@array[col][row]
|
145
|
+
else
|
146
|
+
if value.is_a? Plist4r::Table
|
147
|
+
@array[col][row] = value.cell col, row
|
148
|
+
else
|
149
|
+
@array[col][row] = value
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def first value=nil
|
155
|
+
cell @cr.first, @rr.first, value
|
156
|
+
end
|
157
|
+
|
158
|
+
def map col_range=nil, row_range=nil, &blk
|
159
|
+
col_range = @cr if col_range.nil? ; row_range = @rr if row_range.nil?
|
160
|
+
col_range, row_range = Plist4r::Table.sanitize_ranges col_range, row_range
|
161
|
+
|
162
|
+
t = Plist4r::Table.new :size => [col_range, row_range]
|
163
|
+
row_range.each do |row|
|
164
|
+
col_range.each do |col|
|
165
|
+
t.cell col, row, yield(cell(col, row))
|
166
|
+
end
|
167
|
+
end
|
168
|
+
t
|
169
|
+
end
|
170
|
+
|
171
|
+
def each col_range=nil, row_range=nil, &blk
|
172
|
+
col_range = @cr if col_range.nil? ; row_range = @rr if row_range.nil?
|
173
|
+
col_range, row_range = Plist4r::Table.sanitize_ranges col_range, row_range
|
174
|
+
row_range.each do |row|
|
175
|
+
col_range.each do |col|
|
176
|
+
yield cell(col, row)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def array array=nil
|
182
|
+
case array
|
183
|
+
when nil
|
184
|
+
@array
|
185
|
+
when Array
|
186
|
+
if array.multidim?
|
187
|
+
@array = array
|
188
|
+
auto_size unless @cr && @rr
|
189
|
+
else
|
190
|
+
raise "array type not supported"
|
191
|
+
end
|
192
|
+
else
|
193
|
+
raise "Unsupported type"
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def size *args
|
198
|
+
if args.empty?
|
199
|
+
[@cr, @rr]
|
200
|
+
else
|
201
|
+
col_range, row_range = args.flatten
|
202
|
+
resize col_range, row_range
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def resize col_range, row_range
|
207
|
+
col_range, row_range = Plist4r::Table.sanitize_ranges col_range, row_range
|
208
|
+
|
209
|
+
@cr = col_range
|
210
|
+
@rr = row_range
|
211
|
+
pad @cr, @rr, EmptyCell
|
212
|
+
end
|
213
|
+
|
214
|
+
def auto_size
|
215
|
+
ce = @array.size - 1
|
216
|
+
unless @cr && (0..ce).include_range?(@cr)
|
217
|
+
@cr = 0..ce
|
218
|
+
end
|
219
|
+
|
220
|
+
re = 0
|
221
|
+
@array.each do |col|
|
222
|
+
re = col.size - 1 if col.size - 1 > re
|
223
|
+
end
|
224
|
+
|
225
|
+
unless @rr && (0..re).include_range?(@rr)
|
226
|
+
@rr = 0..re
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
def pad col_range, row_range, data
|
231
|
+
col_range, row_range = Plist4r::Table.sanitize_ranges col_range, row_range
|
232
|
+
|
233
|
+
if EmptyCells.include? data
|
234
|
+
if col_range.end < MinPadSize - 1
|
235
|
+
col_range = 0..(MinPadSize - 1)
|
236
|
+
else
|
237
|
+
col_range = 0..(col_range.end)
|
238
|
+
end
|
239
|
+
|
240
|
+
if row_range.end < MinPadSize - 1
|
241
|
+
row_range = 0..(MinPadSize - 1)
|
242
|
+
else
|
243
|
+
row_range = 0..(row_range.end)
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
(col_range.end - @array.size + 1).times do
|
248
|
+
@array << []
|
249
|
+
end
|
250
|
+
|
251
|
+
col_range.each do |col|
|
252
|
+
row_range.each do |row|
|
253
|
+
@array[col][row] = data.deep_clone if EmptyCells.include? @array[col][row]
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
def pad_all data
|
259
|
+
pad @cr, @rr, data
|
260
|
+
end
|
261
|
+
|
262
|
+
def crop col_range, row_range
|
263
|
+
col_range, row_range = Plist4r::Table.sanitize_ranges col_range, row_range
|
264
|
+
|
265
|
+
pad col_range, row_range, EmptyCell
|
266
|
+
crop_obj = self.class.new :size => [0..(col_range.size - 1), 0..(row_range.size - 1)]
|
267
|
+
|
268
|
+
col_range.each do |col|
|
269
|
+
row_range.each do |row|
|
270
|
+
crop_obj.array[col-col_range.first][row-row_range.first] = @array[col][row].deep_clone
|
271
|
+
end
|
272
|
+
end
|
273
|
+
crop_obj
|
274
|
+
end
|
275
|
+
|
276
|
+
def fill col_range, row_range, data=nil
|
277
|
+
col_range, row_range = Plist4r::Table.sanitize_ranges col_range, row_range
|
278
|
+
data = EmptyCell unless data
|
279
|
+
|
280
|
+
pad col_range, row_range, EmptyCell
|
281
|
+
col_range.each do |c|
|
282
|
+
row_range.each do |r|
|
283
|
+
@array[c][r] = data.deep_clone
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
def fill_all data
|
289
|
+
fill @cr, @rr, data
|
290
|
+
end
|
291
|
+
|
292
|
+
def inverse_fill col_range, row_range, data=nil
|
293
|
+
col_range, row_range = Plist4r::Table.sanitize_ranges col_range, row_range
|
294
|
+
data = EmptyCell unless data
|
295
|
+
|
296
|
+
crop_obj = crop col_range, row_range
|
297
|
+
fill @cr, @rr, data
|
298
|
+
replace col_range, row_range, crop_obj
|
299
|
+
end
|
300
|
+
|
301
|
+
def transpose col_range=nil, row_range=nil, keep_bounds=false
|
302
|
+
col_range = @cr if col_range.nil? ; row_range = @rr if row_range.nil?
|
303
|
+
col_range, row_range = Plist4r::Table.sanitize_ranges col_range, row_range
|
304
|
+
|
305
|
+
if col_range == @cr && row_range == @rr && @cr.first == @rr.first
|
306
|
+
@array = @array.transpose
|
307
|
+
if keep_bounds
|
308
|
+
@cr,@rr = [[@cr,@rr].min,[@cr,@rr].min]
|
309
|
+
else
|
310
|
+
@cr,@rr = [@rr, @cr]
|
311
|
+
end
|
312
|
+
self
|
313
|
+
else
|
314
|
+
col_range, row_range = Plist4r::Table.sanitize_ranges col_range, row_range
|
315
|
+
|
316
|
+
crop_obj = crop col_range, row_range
|
317
|
+
crop_obj.transpose
|
318
|
+
fill col_range, row_range, EmptyCell
|
319
|
+
|
320
|
+
ocr,orr = [col_range,row_range]
|
321
|
+
col_range = (ocr.begin)..(ocr.begin+orr.size-1)
|
322
|
+
row_range = (orr.begin)..(orr.begin+ocr.size-1)
|
323
|
+
|
324
|
+
if keep_bounds && col_range.size != row_range.size
|
325
|
+
if ocr.size > orr.size
|
326
|
+
row_range = (row_range.begin)..(orr.end)
|
327
|
+
else
|
328
|
+
col_range = (col_range.begin)..(ocr.end)
|
329
|
+
end
|
330
|
+
end
|
331
|
+
replace col_range, row_range, crop_obj
|
332
|
+
end
|
333
|
+
self
|
334
|
+
end
|
335
|
+
|
336
|
+
def data_replace col_range, row_range, other_data
|
337
|
+
col_range, row_range = Plist4r::Table.sanitize_ranges col_range, row_range
|
338
|
+
|
339
|
+
self.pad col_range, row_range, EmptyCell
|
340
|
+
o = other_data.deep_clone
|
341
|
+
|
342
|
+
if o.col_range.size < col_range.size
|
343
|
+
col_range = (col_range.first)..(row_range.first + o.col_range.size - 1)
|
344
|
+
end
|
345
|
+
|
346
|
+
if o.row_range.size < row_range.size
|
347
|
+
row_range = (row_range.first)..(row_range.first + o.row_range.size - 1)
|
348
|
+
end
|
349
|
+
|
350
|
+
col_range.each do |col|
|
351
|
+
row_range.each do |row|
|
352
|
+
# @array[col][row] = o.array[col-col_range.first+o.col_range.first][row-row_range.first+o.row_range.first].deep_clone
|
353
|
+
cell col, row, o.cell(col-col_range.first+o.col_range.first,row-row_range.first+o.row_range.first).deep_clone
|
354
|
+
end
|
355
|
+
end
|
356
|
+
end
|
357
|
+
|
358
|
+
def replace col_range, row_range, data
|
359
|
+
col_range, row_range = Plist4r::Table.sanitize_ranges col_range, row_range
|
360
|
+
|
361
|
+
case data
|
362
|
+
when Plist4r::Table
|
363
|
+
data_replace col_range, row_range, data
|
364
|
+
else
|
365
|
+
fill col_range, row_range, data
|
366
|
+
end
|
367
|
+
self
|
368
|
+
end
|
369
|
+
|
370
|
+
def col_replace col_range, data
|
371
|
+
col_range = Plist4r::Table.sanitize_ranges col_range
|
372
|
+
replace col_range, @rr.first..@rr.last, data
|
373
|
+
end
|
374
|
+
|
375
|
+
def row_replace row_range, data
|
376
|
+
row_range = Plist4r::Table.sanitize_ranges row_range
|
377
|
+
replace @cr.first..@cr.last, row_range, data
|
378
|
+
end
|
379
|
+
|
380
|
+
def translate col_range, row_range, vector
|
381
|
+
col_range, row_range = Plist4r::Table.sanitize_ranges col_range, row_range
|
382
|
+
|
383
|
+
crop_obj = crop col_range, row_range
|
384
|
+
fill col_range, row_range, EmptyCell
|
385
|
+
col_range = (col_range.begin+vector[0])..(col_range.end+vector[0])
|
386
|
+
row_range = (row_range.begin+vector[1])..(row_range.end+vector[1])
|
387
|
+
replace col_range, row_range, crop_obj
|
388
|
+
end
|
389
|
+
|
390
|
+
def col_insert col_range, row_range, other_data, resize=true
|
391
|
+
col_range, row_range = Plist4r::Table.sanitize_ranges col_range, row_range
|
392
|
+
translate col_range.first..@cr.last, @rr, [col_range.size, 0]
|
393
|
+
replace col_range, row_range, other_data
|
394
|
+
@cr = @cr.first..(@cr.last + col_range.size) if resize
|
395
|
+
end
|
396
|
+
|
397
|
+
def row_insert col_range, row_range, other_data, resize=true
|
398
|
+
col_range, row_range = Plist4r::Table.sanitize_ranges col_range, row_range
|
399
|
+
translate @cr, row_range.first..@rr.last, [0, row_range.size]
|
400
|
+
replace col_range, row_range, other_data
|
401
|
+
@rr = @rr.first..(@rr.last + row_range.size) if resize
|
402
|
+
end
|
403
|
+
|
404
|
+
def cells col_range=nil, row_range=nil, value=nil
|
405
|
+
col_range = @cr if col_range.nil? ; row_range = @rr if row_range.nil?
|
406
|
+
col_range, row_range = Plist4r::Table.sanitize_ranges col_range, row_range
|
407
|
+
|
408
|
+
replace col_range, row_range, value if value
|
409
|
+
self.class.new :array => @array, :size => [col_range, row_range]
|
410
|
+
end
|
411
|
+
|
412
|
+
def col col_range, value=nil
|
413
|
+
col_range = Plist4r::Table.sanitize_ranges col_range
|
414
|
+
|
415
|
+
case value
|
416
|
+
when nil
|
417
|
+
cells col_range, @rr
|
418
|
+
else
|
419
|
+
col_replace col_range, value
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
423
|
+
def row row_range, value=nil
|
424
|
+
row_range = Plist4r::Table.sanitize_ranges row_range
|
425
|
+
|
426
|
+
case value
|
427
|
+
when nil
|
428
|
+
cells @cr, row_range
|
429
|
+
else
|
430
|
+
row_replace row_range, value
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
end
|
435
|
+
end
|
data/lib/plist4r/plist.rb
CHANGED
@@ -3,18 +3,20 @@ require 'plist4r/mixin/ordered_hash'
|
|
3
3
|
require 'plist4r/mixin/ruby_stdlib'
|
4
4
|
require 'plist4r/plist_cache'
|
5
5
|
require 'plist4r/plist_type'
|
6
|
-
Dir.glob(File.dirname(__FILE__) + "/plist_type
|
7
|
-
require 'plist4r/backend'
|
6
|
+
Dir.glob(File.dirname(__FILE__) + "/plist_type/*.rb").each {|t| require File.expand_path t}
|
7
|
+
# require 'plist4r/backend'
|
8
8
|
|
9
9
|
module Plist4r
|
10
|
+
# See {file:README} and {file:InfoPlistExample} for usage examples. Also see {file:EditingPlistFiles}
|
10
11
|
class Plist
|
11
12
|
# Recognised keys of the options hash. Passed when instantiating a new Plist Object
|
12
13
|
# @see #initialize
|
13
14
|
# @see #parse_opts
|
14
|
-
|
15
|
-
|
15
|
+
OptionsHash = %w[filename path file_format plist_type strict_keys backends from_string]
|
16
|
+
|
17
|
+
# The plist file formats, written as symbols.
|
16
18
|
# @see #file_format
|
17
|
-
FileFormats = %w[binary xml
|
19
|
+
FileFormats = %w[binary xml gnustep]
|
18
20
|
|
19
21
|
# Instantiate a new Plist4r::Plist object. We usually set our per-application defaults in {Plist4r::Config} beforehand.
|
20
22
|
#
|
@@ -33,9 +35,10 @@ module Plist4r
|
|
33
35
|
# Plist4r::Plist.new({ :filename => "example.plist", :path => plist_working_dir, :backends => ["libxml4r","ruby_cocoa"]})
|
34
36
|
# => #<Plist4r::Plist:0x111546c @file_format=nil, ...>
|
35
37
|
# @return [Plist4r::Plist] The new Plist object
|
38
|
+
# @yield An optional block to instance_eval &blk, and apply an edit on creation
|
36
39
|
def initialize *args, &blk
|
37
40
|
@hash = ::Plist4r::OrderedHash.new
|
38
|
-
|
41
|
+
plist_type :plist
|
39
42
|
|
40
43
|
@strict_keys = Config[:strict_keys]
|
41
44
|
@backends = Config[:backends]
|
@@ -57,6 +60,8 @@ module Plist4r
|
|
57
60
|
end
|
58
61
|
|
59
62
|
@plist_cache ||= PlistCache.new self
|
63
|
+
|
64
|
+
edit(&blk) if block_given?
|
60
65
|
end
|
61
66
|
|
62
67
|
# Reinitialize plist object from string (overwrites the current contents). Usually called from {Plist#initialize}
|
@@ -64,7 +69,7 @@ module Plist4r
|
|
64
69
|
# plist = Plist4r::Plist.new
|
65
70
|
# => #<Plist4r::Plist:0x11e161c @file_format=nil, ...>
|
66
71
|
# plist.from_string "{ \"key1\" = \"value1\"; \"key2\" = \"value2\"; }"
|
67
|
-
# => #<Plist4r::Plist:0x11e161c @file_format="
|
72
|
+
# => #<Plist4r::Plist:0x11e161c @file_format="gnustep", ...>
|
68
73
|
def from_string string=nil
|
69
74
|
case string
|
70
75
|
when String
|
@@ -83,7 +88,7 @@ module Plist4r
|
|
83
88
|
end
|
84
89
|
end
|
85
90
|
|
86
|
-
# Set or return the filename attribute of the plist object.
|
91
|
+
# Set or return the filename attribute of the plist object. Used in cojunction with the {#path} attribute
|
87
92
|
# @param [String] filename either a relative path or absolute
|
88
93
|
# @return The plist's filename
|
89
94
|
# @see Plist::Plist#open
|
@@ -122,7 +127,7 @@ module Plist4r
|
|
122
127
|
# @see filename
|
123
128
|
# @see path
|
124
129
|
def filename_path filename_path=nil
|
125
|
-
case
|
130
|
+
case filename_path
|
126
131
|
when String
|
127
132
|
@filename = File.basename filename_path
|
128
133
|
@path = File.dirname filename_path
|
@@ -135,7 +140,7 @@ module Plist4r
|
|
135
140
|
|
136
141
|
# The file format of the plist file we are loading / saving. Written as a symbol.
|
137
142
|
# One of {Plist4r::Plist.FileFormats}. Defaults to :xml
|
138
|
-
# @param [Symbol, String] file_format Can be :binary, :xml, :
|
143
|
+
# @param [Symbol, String] file_format Can be :binary, :xml, :gnustep
|
139
144
|
# @return The file format associated to this current plist object
|
140
145
|
# @see Plist4r::Plist.FileFormats
|
141
146
|
def file_format file_format=nil
|
@@ -157,7 +162,7 @@ module Plist4r
|
|
157
162
|
# using an algorithm that stats the plist data. The plist types with the highest stat (score)
|
158
163
|
# is chosen to be the object's "Plist Type".
|
159
164
|
# @see Plist4r::PlistType
|
160
|
-
# @return
|
165
|
+
# @return The plist's known type, written as a symbol. Will be a sublcass of Plist4r::PlistType. Defaults to :plist
|
161
166
|
def detect_plist_type
|
162
167
|
stat_m = {}
|
163
168
|
stat_r = {}
|
@@ -167,6 +172,7 @@ module Plist4r
|
|
167
172
|
t = eval "::Plist4r::PlistType::#{t.to_s.camelcase}"
|
168
173
|
when Class
|
169
174
|
t = t
|
175
|
+
when nil
|
170
176
|
else
|
171
177
|
raise "Unrecognized plist type: #{t.inspect}"
|
172
178
|
end
|
@@ -190,7 +196,6 @@ module Plist4r
|
|
190
196
|
else
|
191
197
|
plist_type stat_m[most_matches]
|
192
198
|
end
|
193
|
-
return true
|
194
199
|
end
|
195
200
|
|
196
201
|
# Set or return the plist_type of the current object. We can use this to override the automatic type detection.
|
@@ -202,7 +207,8 @@ module Plist4r
|
|
202
207
|
begin
|
203
208
|
case plist_type
|
204
209
|
when Class
|
205
|
-
unless plist_type.is_a? ::Plist4r::PlistType
|
210
|
+
# unless plist_type.is_a? ::Plist4r::PlistType # .is_a? returns false in spec
|
211
|
+
unless plist_type.ancestors.include? Plist4r::PlistType
|
206
212
|
raise "Unrecognized Plist type. Class #{plist_type.inspect} isnt inherited from ::Plist4r::PlistType"
|
207
213
|
end
|
208
214
|
when Symbol, String
|
@@ -236,16 +242,26 @@ module Plist4r
|
|
236
242
|
|
237
243
|
# An array of strings, symbols or class names which correspond to the active Plist4r::Backends for this object.
|
238
244
|
# The priority order in which backends are executed is determined by the in sequence array order.
|
239
|
-
# @param [Array] backends
|
240
|
-
# @return The backends
|
241
|
-
#
|
245
|
+
# @param [Array <Symbol,String>] A new list of backends to use, in Priority order
|
246
|
+
# @return [Array <Symbol>] The plist's backends, each written as a symbol. Must be a sublcass of Plist4r::Backend
|
247
|
+
# Defaults to {Plist4r::Config}[:backends]
|
248
|
+
# @example
|
242
249
|
# plist.backends [:haml, :ruby_cocoa]
|
243
250
|
# @see Plist4r::Backend
|
244
251
|
# @see Plist4r::Backend::Example
|
245
252
|
def backends backends=nil
|
246
253
|
case backends
|
247
254
|
when Array
|
248
|
-
@backends = backends
|
255
|
+
@backends = backends.collect do |b|
|
256
|
+
case b
|
257
|
+
when Symbol, String
|
258
|
+
eval "Plist4r::Backend::#{b.to_s.camelcase}"
|
259
|
+
b.to_sym
|
260
|
+
when nil
|
261
|
+
else
|
262
|
+
raise "Backend #{b.inspect} is of unsupported type: #{b.class}"
|
263
|
+
end
|
264
|
+
end
|
249
265
|
when nil
|
250
266
|
@backends
|
251
267
|
else
|
@@ -254,21 +270,21 @@ module Plist4r
|
|
254
270
|
end
|
255
271
|
|
256
272
|
# Sets up those valid (settable) plist attributes as found the options hash.
|
257
|
-
# Normally we dont call this method
|
258
|
-
# @param [Hash <
|
273
|
+
# Normally we dont call this method directly. Called from {#initialize}.
|
274
|
+
# @param [Hash <OptionsHash>] opts The options hash, containing keys of {OptionsHash}
|
259
275
|
# @see #initialize
|
260
276
|
def parse_opts opts
|
261
|
-
|
277
|
+
OptionsHash.each do |opt|
|
262
278
|
if opts[opt.to_sym]
|
263
279
|
value = opts[opt.to_sym]
|
264
|
-
|
280
|
+
self.send opt, value
|
265
281
|
end
|
266
282
|
end
|
267
283
|
end
|
268
284
|
|
269
285
|
# Opens a plist file
|
270
286
|
#
|
271
|
-
# @param [String] filename plist file to load. Uses the
|
287
|
+
# @param [String] filename plist file to load. Uses the {#filename} attribute when nil
|
272
288
|
# @return [Plist4r::Plist] The loaded Plist object
|
273
289
|
# @example Load from file
|
274
290
|
# plist = Plist4r.new
|
@@ -282,7 +298,7 @@ module Plist4r
|
|
282
298
|
# An alias of {#edit}
|
283
299
|
# @example
|
284
300
|
# plist.<< do
|
285
|
-
#
|
301
|
+
# store "PFReleaseVersion" "0.1.1"
|
286
302
|
# end
|
287
303
|
# @see #edit
|
288
304
|
def << *args, &blk
|
@@ -291,36 +307,35 @@ module Plist4r
|
|
291
307
|
|
292
308
|
# Edit a plist object. Set or return plist keys. Add or remove a selection of keys.
|
293
309
|
# Plist key accessor methods are snake-cased versions of the key string.
|
294
|
-
# @example
|
310
|
+
# @example Edit some keys and values with {#[]} and {#store}
|
295
311
|
# plist.edit do
|
296
|
-
#
|
297
|
-
#
|
312
|
+
# store "PFInstance" "4982394823"
|
313
|
+
# store "PFReleaseVersion" "0.1.1"
|
298
314
|
# end
|
299
|
-
#
|
315
|
+
#
|
300
316
|
# plist.edit do
|
301
|
-
# new_ver =
|
302
|
-
#
|
317
|
+
# new_ver = self["PFReleaseVersion"] + 0.1
|
318
|
+
# store "PFReleaseVersion" new_ver
|
303
319
|
# end
|
304
|
-
# @example
|
320
|
+
# @example Edit with implicit methods. Calls method_missing()
|
305
321
|
# plist.edit do
|
306
|
-
# new_ver =
|
307
|
-
#
|
322
|
+
# new_ver = p_f_release_version + 0.1
|
323
|
+
# p_f_release_version(new_ver)
|
308
324
|
# end
|
309
325
|
def edit *args, &blk
|
310
326
|
@plist_type.hash @hash
|
311
327
|
instance_eval *args, &blk
|
312
|
-
detect_plist_type
|
313
|
-
@plist_cache.update_checksum
|
328
|
+
detect_plist_type if plist_type == :plist
|
314
329
|
end
|
315
330
|
|
316
331
|
# Pass down unknown method calls to the selected plist_type, to set or return plist keys.
|
317
332
|
# All plist data manipulation API is called through method_missing -> PlistType -> DataMethods.
|
318
|
-
# @example This will actually call {DataMethods#
|
319
|
-
# plist.
|
333
|
+
# @example This will actually call {DataMethods#method_missing}
|
334
|
+
# plist.store "CFBundleVersion" "0.1.0"
|
320
335
|
# @see Plist4r::DataMethods#method_missing
|
321
336
|
# @see #plist_type
|
322
337
|
def method_missing method_sym, *args, &blk
|
323
|
-
@plist_type.
|
338
|
+
@plist_type.method_missing method_sym, *args, &blk
|
324
339
|
end
|
325
340
|
|
326
341
|
# Backend method to set or return all new plist data resulting from a backend API. Used in load operations.
|
@@ -337,11 +352,204 @@ module Plist4r
|
|
337
352
|
raise "Please use ::Plist4r::OrderedHash.new for your hashes"
|
338
353
|
end
|
339
354
|
end
|
340
|
-
|
341
|
-
#
|
355
|
+
|
356
|
+
# Element Reference — Retrieve the value object corresponding to the key object. If not found, returns nil
|
357
|
+
# @param [Symbol, String] key The plist key name, either a snake-cased symbol, or literal string
|
358
|
+
# @return The value associated with the plist key
|
359
|
+
# @example
|
360
|
+
# plist["CFBundleIdentifier"] # => "com.apple.myapp"
|
361
|
+
# @example
|
362
|
+
# plist[:c_f_bundle_identifier] # => "com.apple.myapp"
|
363
|
+
def [] key
|
364
|
+
@plist_type.set_or_return key
|
365
|
+
end
|
366
|
+
|
367
|
+
|
368
|
+
# Element Assignment — Assign a value to the given plist key
|
369
|
+
# @param [Symbol, String] key The plist key name, either a snake-cased symbol, or literal string
|
370
|
+
# @param value The value to store under the plist key name
|
371
|
+
# @example
|
372
|
+
# plist["CFBundleIdentifier"] = "com.apple.myapp"
|
373
|
+
# @example
|
374
|
+
# plist[:c_f_bundle_identifier] = "com.apple.myapp"
|
375
|
+
def []= key, value
|
376
|
+
store key, value
|
377
|
+
end
|
378
|
+
|
379
|
+
# Element Assignment — Assign a value to the given plist key
|
380
|
+
# @param [Symbol, String] key The plist key name, either a snake-cased symbol, or literal string
|
381
|
+
# @param value The value to store under the plist key name
|
382
|
+
# @example
|
383
|
+
# plist.store "CFBundleIdentifier", "com.apple.myapp"
|
384
|
+
# @example
|
385
|
+
# plist.store :c_f_bundle_identifier, "com.apple.myapp"
|
386
|
+
def store key, value
|
387
|
+
@plist_type.set_or_return key, value
|
388
|
+
end
|
389
|
+
|
390
|
+
# Element selection - Keep selected plist keys and discard others.
|
391
|
+
# @param [Array, *args] keys List of Plist Keys to keep. Can be an array, or method argument list
|
392
|
+
# @yield Keep every key-value pair for which the passed block evaluates to true. Works as per the ruby core classes Hash#select method
|
393
|
+
def select *keys, &blk
|
394
|
+
if block_given?
|
395
|
+
a = @hash.select &blk
|
396
|
+
old_hash = @hash.deep_clone
|
397
|
+
clear
|
398
|
+
a.each do |pair|
|
399
|
+
store pair[0], pair[1]
|
400
|
+
end
|
401
|
+
keys.each do |k|
|
402
|
+
store k, old_hash[k]
|
403
|
+
end
|
404
|
+
else
|
405
|
+
@plist_type.array_dict :select, *keys
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
# Invokes block &blk once for each key-value pair in plist. Similar to the ruby core classes Array#map.
|
410
|
+
# Replaces the plist keys and values with the [key,value] pairs returned by &blk.
|
411
|
+
# @yield For each iteration of the block, must return a 2-element Array which is a [key,value] pair to replace the original [key,value] pair from the plist.
|
412
|
+
# Key names can be given as either snake_case'd Symbol or camelcased String
|
413
|
+
def map &blk
|
414
|
+
if block_given?
|
415
|
+
old_hash = @hash.deep_clone
|
416
|
+
clear
|
417
|
+
|
418
|
+
old_hash.each do |k,v|
|
419
|
+
pair = yield k,v
|
420
|
+
case pair
|
421
|
+
when Array
|
422
|
+
store pair[0], pair[1]
|
423
|
+
when nil
|
424
|
+
else
|
425
|
+
raise "The supplied block must return plist [key, value] pairs, or nil"
|
426
|
+
end
|
427
|
+
end
|
428
|
+
else
|
429
|
+
raise "No block given"
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
# Alias for {#map}
|
434
|
+
def collect &blk
|
435
|
+
map &blk
|
436
|
+
end
|
437
|
+
|
438
|
+
# Alias for {#delete}
|
439
|
+
def unselect *keys
|
440
|
+
delete *keys
|
441
|
+
end
|
442
|
+
|
443
|
+
# Delete plist keys from the object.
|
444
|
+
# @param [Array, *args] keys The list of Plist Keys to delete unconditionally. Can be an array, or argument list
|
445
|
+
# Key names can be given as either snake_case'd Symbol or camelcased String
|
446
|
+
# @example
|
447
|
+
# plist.delete :c_f_bundle_identifier
|
448
|
+
def delete *keys
|
449
|
+
@plist_type.array_dict :unselect, *keys
|
450
|
+
end
|
451
|
+
|
452
|
+
# Conditionally delete plist keys from the object.
|
453
|
+
# @param [Array, *args] keys The list of Plist Keys to delete unconditionally. Can be an array, or argument list
|
454
|
+
# @yield Delete a key-value pair if block evaluates to true.
|
455
|
+
# @example
|
456
|
+
# plist.delete_if "CFBundleIdentifier"
|
457
|
+
# @example
|
458
|
+
# plist.delete_if { |k,v| k.length > 20 }
|
459
|
+
# @example
|
460
|
+
# plist.delete_if { |k,v| k =~ /Identifier/ }
|
461
|
+
def delete_if *keys, &blk
|
462
|
+
delete *keys
|
463
|
+
@hash.delete_if &blk
|
464
|
+
@plist_type.hash @hash
|
465
|
+
end
|
466
|
+
|
467
|
+
# Clears all plist keys and their contents
|
468
|
+
# @example
|
469
|
+
# plist.clear
|
470
|
+
# plist.size # => 0
|
471
|
+
def clear
|
472
|
+
@plist_type.array_dict :unselect_all
|
473
|
+
end
|
474
|
+
|
475
|
+
# Merge together plist objects.
|
476
|
+
# Adds the contents of other_plist to the current object, overwriting any entries of the same key name with those from other_plist.
|
477
|
+
# Other attributes (filename, plist_type, file_format, etc) remain unaffected
|
478
|
+
# @param [Plist4r::Plist] other_plist The other plist to merge with
|
479
|
+
def merge! other_plist
|
480
|
+
if plist_type == other_plist.plist_type
|
481
|
+
@hash.merge! other_plist.to_hash
|
482
|
+
@plist_type.hash @hash
|
483
|
+
else
|
484
|
+
raise "plist_type differs, one is #{plist_type.inspect}, and the other is #{plist.plist_type.inspect}"
|
485
|
+
end
|
486
|
+
self
|
487
|
+
end
|
488
|
+
|
489
|
+
# Check if key exists in plist
|
490
|
+
# This is equivalent to the ruby core classes method Hash#include?
|
491
|
+
# @param [String, Symbol] key The plist key name
|
492
|
+
# @return [true,false] True if the plist has the specified key
|
493
|
+
def include? key
|
494
|
+
key.to_s.camelcase if key.class == Symbol
|
495
|
+
@hash.include? key
|
496
|
+
end
|
497
|
+
|
498
|
+
# Alias of {#include?}
|
499
|
+
# @param [String, Symbol] key The plist key name
|
500
|
+
# @return [true,false] True if the plist has the specified key
|
501
|
+
def has_key? key
|
502
|
+
key.to_s.camelcase if key.class == Symbol
|
503
|
+
@hash.has_key? key
|
504
|
+
end
|
505
|
+
|
506
|
+
# This is equivalent to the ruby core classes method Array#empty?
|
507
|
+
def empty?
|
508
|
+
@hash.empty?
|
509
|
+
end
|
510
|
+
|
511
|
+
# This is equivalent to the ruby core classes method Hash#each
|
512
|
+
# @yield A block to execute for each key, value pair in plist
|
513
|
+
# @example
|
514
|
+
# plist.each do |k,v|
|
515
|
+
# puts "key = #{k.inspect}, value = #{v.inspect}"
|
516
|
+
# end
|
517
|
+
def each &blk
|
518
|
+
@hash.each &blk
|
519
|
+
end
|
520
|
+
|
521
|
+
# This is equivalent to the ruby core classes method Array#length
|
522
|
+
# @example
|
523
|
+
# plist.length # => 14
|
524
|
+
def length
|
525
|
+
@hash.length
|
526
|
+
end
|
527
|
+
|
528
|
+
# This is equivalent to the ruby core classes method Array#size
|
529
|
+
# plist.size # => 14
|
530
|
+
def size
|
531
|
+
@hash.size
|
532
|
+
end
|
533
|
+
|
534
|
+
# This is equivalent to the ruby core classes method Hash#keys
|
535
|
+
# @example
|
536
|
+
# plist.keys # => ["Key1", "Key2", "Key3", "etc.."]
|
537
|
+
# @return [Array <String, Symbol>] The keys of the plist
|
538
|
+
def keys
|
539
|
+
@hash.keys
|
540
|
+
end
|
541
|
+
|
542
|
+
# The internal data storage object for the plist data
|
543
|
+
#
|
544
|
+
# This is a pretty standard (either ActiveSupport or Ruby 1.9) ordered hash.
|
545
|
+
# Key names - regular ruby strings of arbitrary length.
|
342
546
|
#
|
343
|
-
#
|
344
|
-
#
|
547
|
+
# Values - Must only store generic Ruby objects data such as TrueClass, FalseClass, Integer, Float, String, Time, Array, Hash, and Data
|
548
|
+
#
|
549
|
+
# Data (NSData / CFData) - see {file:EditingPlistFiles}
|
550
|
+
#
|
551
|
+
# @return [Plist4r::OrderedHash] Nested hash of ruby objects. The raw Plist data
|
552
|
+
# @see Plist4r::OrderedHash
|
345
553
|
# @example
|
346
554
|
# plist = "{ \"key1\" = \"value1\"; \"key2\" = \"value2\"; }".to_plist
|
347
555
|
# plist.to_hash => {"key1"=>"value1", "key2"=>"value2"}
|
@@ -349,7 +557,17 @@ module Plist4r
|
|
349
557
|
@hash
|
350
558
|
end
|
351
559
|
|
352
|
-
#
|
560
|
+
# # The internal ruby data representation for the plist data.
|
561
|
+
# # This is a pretty standard (either ActiveSupport or Ruby 1.9) ordered hash.
|
562
|
+
# # Key names - regular ruby strings of arbitrary length.
|
563
|
+
# # Values - Must only store generic Ruby objects data such as TrueClass, FalseClass, Integer, Float, String, Time, Array, Hash, and Data
|
564
|
+
# # @return [Plist4r::OrderedHash] Nested hash of ruby objects. The raw Plist data
|
565
|
+
# def hash
|
566
|
+
# @hash
|
567
|
+
# end
|
568
|
+
|
569
|
+
# Export the plist to xml string representation.
|
570
|
+
# Calls through the plist cache
|
353
571
|
#
|
354
572
|
# @return [String] An xml string which represents the entire plist, as would be the plist xml file
|
355
573
|
# @example
|
@@ -359,8 +577,12 @@ module Plist4r
|
|
359
577
|
def to_xml
|
360
578
|
@plist_cache.to_xml
|
361
579
|
end
|
362
|
-
|
363
|
-
#
|
580
|
+
|
581
|
+
# Write out a binary string representation of the plist
|
582
|
+
#
|
583
|
+
# Looking for how to store a bytestream in CFData / NSData? See {file:EditingPlistFiles}
|
584
|
+
#
|
585
|
+
# @example
|
364
586
|
# plist = "{ \"key1\" = \"value1\"; \"key2\" = \"value2\"; }".to_plist
|
365
587
|
# plist.to_binary
|
366
588
|
# => "bplist00\322\001\002\003\004Tkey2Tkey1Vvalue2Vvalue1\b\r\022\027\036\000\000\000\000\000\000\001\001\000\000\000\000\000\000\000\005\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000%"
|
@@ -368,23 +590,21 @@ module Plist4r
|
|
368
590
|
@plist_cache.to_binary
|
369
591
|
end
|
370
592
|
|
371
|
-
#
|
372
|
-
|
373
|
-
|
374
|
-
@plist_cache.to_next_step
|
593
|
+
# We are missing a backend for writing out plist strings in Gnustep / Nextstep / Openstep format. Contributions appreciated.
|
594
|
+
def to_gnustep
|
595
|
+
@plist_cache.to_gnustep
|
375
596
|
end
|
376
597
|
|
377
|
-
# Save plist to #
|
598
|
+
# Save plist to {#filename_path}
|
378
599
|
# @raise [RuntimeError] if the {#filename} attribute is nil
|
379
|
-
# @see #
|
380
|
-
# @see #path
|
600
|
+
# @see #filename_path
|
381
601
|
def save
|
382
602
|
raise "No filename specified" unless @filename
|
383
603
|
@plist_cache.save
|
384
604
|
end
|
385
605
|
|
386
606
|
# Save the plist under a new filename
|
387
|
-
# @param [String] filename The new file name to save as. If
|
607
|
+
# @param [String] filename The new file name to save as. If relative, will be appended to {#path}
|
388
608
|
# @see #save
|
389
609
|
def save_as filename
|
390
610
|
@filename = filename
|
@@ -393,47 +613,5 @@ module Plist4r
|
|
393
613
|
end
|
394
614
|
end
|
395
615
|
|
396
|
-
module Plist4r
|
397
|
-
# @private
|
398
|
-
class OldPlist
|
399
|
-
|
400
|
-
def initialize path_prefix, plist_str, &blk
|
401
|
-
plist_str << ".plist" unless plist_str =~ /\.plist$/
|
402
|
-
|
403
|
-
@filename = nil
|
404
|
-
if plist_str =~ /^\//
|
405
|
-
@filename = plist_str
|
406
|
-
else
|
407
|
-
@filename = "#{path_prefix}/#{plist_str}"
|
408
|
-
end
|
409
|
-
|
410
|
-
@label = @filename.match(/^.*\/(.*)\.plist$/)[1]
|
411
|
-
@shortname = @filename.match(/^.*\.(.*)$/)[1]
|
412
|
-
|
413
|
-
@block = blk
|
414
|
-
@hash = @orig = ::Plist4r::OrderedHash.new
|
415
|
-
|
416
|
-
instance_eval(&@block) if @block
|
417
|
-
end
|
418
|
-
|
419
|
-
def override_plist_keys?
|
420
|
-
return true unless @label == @filename.match(/^.*\/(.*)\.plist$/)[1]
|
421
|
-
vars = self.instance_variables - ["@filename","@label","@shortname","@block","@hash","@obj"]
|
422
|
-
return true unless vars.empty?
|
423
|
-
end
|
424
|
-
|
425
|
-
def finalize
|
426
|
-
if File.exists? @filename
|
427
|
-
if override_plist_keys?
|
428
|
-
# @hash = @obj = ::LibxmlLaunchdPlistParser.new(@filename).plist_struct
|
429
|
-
# eval_plist_block(&@block) if @block
|
430
|
-
# write_plist
|
431
|
-
end
|
432
|
-
else
|
433
|
-
# write_plist
|
434
|
-
end
|
435
|
-
end
|
436
|
-
end
|
437
|
-
end
|
438
616
|
|
439
617
|
|