plist4r 0.2.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. data/.gitignore +4 -0
  2. data/.yardopts +11 -0
  3. data/LICENSE +3 -1
  4. data/README.rdoc +25 -122
  5. data/Rakefile +14 -0
  6. data/VERSION +1 -1
  7. data/bin/plist4r +2 -0
  8. data/ext/osx_plist/Makefile +157 -0
  9. data/ext/osx_plist/extconf.rb +9 -0
  10. data/ext/osx_plist/plist.c +606 -0
  11. data/ext/osx_plist/plist.o +0 -0
  12. data/lib/plist4r.rb +6 -3
  13. data/lib/plist4r/application.rb +1 -2
  14. data/lib/plist4r/backend.rb +102 -34
  15. data/lib/plist4r/backend/c_f_property_list.rb +65 -0
  16. data/lib/plist4r/backend/c_f_property_list/LICENSE +19 -0
  17. data/lib/plist4r/backend/c_f_property_list/README +34 -0
  18. data/lib/plist4r/backend/c_f_property_list/cfpropertylist.rb +6 -0
  19. data/lib/plist4r/backend/c_f_property_list/rbBinaryCFPropertyList.rb +663 -0
  20. data/lib/plist4r/backend/c_f_property_list/rbCFPlistError.rb +26 -0
  21. data/lib/plist4r/backend/c_f_property_list/rbCFPropertyList.rb +348 -0
  22. data/lib/plist4r/backend/c_f_property_list/rbCFTypes.rb +241 -0
  23. data/lib/plist4r/backend/c_f_property_list/rbXMLCFPropertyList.rb +116 -0
  24. data/lib/plist4r/backend/example.rb +37 -52
  25. data/lib/plist4r/backend/haml.rb +47 -36
  26. data/lib/plist4r/backend/libxml4r.rb +24 -20
  27. data/lib/plist4r/backend/osx_plist.rb +82 -0
  28. data/lib/plist4r/backend/ruby_cocoa.rb +172 -54
  29. data/lib/plist4r/backend/test/data_types.rb +163 -0
  30. data/lib/plist4r/backend/test/harness.rb +255 -0
  31. data/lib/plist4r/backend/test/output.rb +47 -0
  32. data/lib/plist4r/backend_base.rb +4 -2
  33. data/lib/plist4r/{options.rb → cli.rb} +2 -1
  34. data/lib/plist4r/commands.rb +13 -8
  35. data/lib/plist4r/config.rb +36 -9
  36. data/lib/plist4r/docs/Backends.html +59 -0
  37. data/lib/plist4r/docs/DeveloperGuide.rdoc +53 -0
  38. data/lib/plist4r/docs/EditingPlistFiles.rdoc +88 -0
  39. data/lib/plist4r/docs/InfoPlistExample.rdoc +33 -0
  40. data/lib/plist4r/docs/LaunchdPlistExample.rdoc +33 -0
  41. data/lib/plist4r/docs/PlistKeyNames.rdoc +47 -0
  42. data/lib/plist4r/mixin/array_dict.rb +61 -0
  43. data/lib/plist4r/mixin/data_methods.rb +178 -54
  44. data/lib/plist4r/mixin/haml4r.rb +4 -0
  45. data/lib/plist4r/mixin/haml4r/css_attributes.rb +19 -0
  46. data/lib/plist4r/mixin/haml4r/examples.rb +261 -0
  47. data/lib/plist4r/mixin/haml4r/haml_table_example.rb +79 -0
  48. data/lib/plist4r/mixin/haml4r/table.rb +157 -0
  49. data/lib/plist4r/mixin/haml4r/table_cell.rb +160 -0
  50. data/lib/plist4r/mixin/haml4r/table_cells.rb +485 -0
  51. data/lib/plist4r/mixin/haml4r/table_section.rb +101 -0
  52. data/lib/plist4r/mixin/ordered_hash.rb +9 -1
  53. data/lib/plist4r/mixin/popen4.rb +1 -1
  54. data/lib/plist4r/mixin/ruby_stdlib.rb +154 -1
  55. data/lib/plist4r/mixin/script.rb +133 -0
  56. data/lib/plist4r/mixin/table.rb +435 -0
  57. data/lib/plist4r/plist.rb +272 -94
  58. data/lib/plist4r/plist_cache.rb +42 -43
  59. data/lib/plist4r/plist_type.rb +31 -74
  60. data/lib/plist4r/plist_type/info.rb +157 -3
  61. data/lib/plist4r/plist_type/launchd.rb +54 -48
  62. data/lib/plist4r/plist_type/plist.rb +1 -3
  63. data/plist4r.gemspec +74 -14
  64. data/spec/{examples.rb → launchd_examples.rb} +131 -139
  65. data/spec/plist4r/application_spec.rb +37 -0
  66. data/spec/plist4r/backend_spec.rb +256 -0
  67. data/spec/plist4r/cli_spec.rb +25 -0
  68. data/spec/plist4r/commands_spec.rb +20 -0
  69. data/spec/plist4r/config_spec.rb +38 -0
  70. data/spec/plist4r/mixin/array_dict_spec.rb +120 -0
  71. data/spec/plist4r/mixin/data_methods_spec.rb +96 -0
  72. data/spec/plist4r/mixin/haml4r/examples.rb +261 -0
  73. data/spec/plist4r/mixin/ruby_stdlib_spec.rb +228 -0
  74. data/spec/plist4r/plist_cache_spec.rb +261 -0
  75. data/spec/plist4r/plist_spec.rb +841 -23
  76. data/spec/plist4r/plist_type_spec.rb +126 -0
  77. data/spec/plist4r_spec.rb +53 -27
  78. data/spec/scratchpad.rb +226 -0
  79. data/spec/spec_helper.rb +5 -1
  80. metadata +109 -23
  81. data/lib/plist4r/backend/plutil.rb +0 -25
  82. data/lib/plist4r/mixin.rb +0 -7
  83. data/plists/array_mini.xml +0 -14
  84. data/plists/example_big_binary.plist +0 -0
  85. data/plists/example_medium_binary_launchd.plist +0 -0
  86. data/plists/example_medium_launchd.xml +0 -53
  87. data/plists/mini.xml +0 -12
  88. data/test.rb +0 -40
@@ -0,0 +1,160 @@
1
+
2
+ require 'plist4r/mixin/haml4r/css_attributes'
3
+
4
+ module Haml4r
5
+ class TableCell
6
+
7
+ class InnerCell
8
+ Attributes = Haml4r::CssAttributes + %w[ content ]
9
+
10
+ def initialize *args, &blk
11
+ @content = nil
12
+ end
13
+
14
+ def respond_to? method_sym
15
+ return true if Attributes.include? method_sym.to_s
16
+ return true if Attributes.include? method_sym.to_s.chomp('=')
17
+ super
18
+ end
19
+
20
+ def method_missing method_sym, *args, &blk
21
+ if Attributes.include? method_sym.to_s.chomp('=')
22
+ set_or_return method_sym.to_s, *args, &blk
23
+ end
24
+ end
25
+
26
+ def set attribute, value
27
+ eval "@#{attribute} = value"
28
+ end
29
+
30
+ def value_for attribute
31
+ eval "@#{attribute}"
32
+ end
33
+
34
+ def set_or_return attribute, value=nil
35
+ case attribute
36
+ when /\=$/
37
+ set attribute.to_s.chomp('='), value
38
+ else
39
+ value_for attribute.to_s
40
+ end
41
+ end
42
+ end
43
+
44
+ Attributes = InnerCell::Attributes
45
+
46
+ def initialize *args, &blk
47
+
48
+ @inner_cell = InnerCell.new
49
+ @table_section = nil
50
+
51
+ case args[0]
52
+ when nil
53
+
54
+ when Hash, Haml4r::TableCell
55
+ merge! args[0]
56
+
57
+ else
58
+ raise "unsupported type"
59
+ end
60
+ end
61
+
62
+ def attributes_hash
63
+ h = {}
64
+ CssAttributes.Attributes.each do |a|
65
+ v = self.send a
66
+ h[a] = v if v
67
+ end
68
+ h
69
+ end
70
+
71
+ def merge! obj
72
+ case obj
73
+ when Hash
74
+ Attributes.each do |a|
75
+ hash = obj
76
+ if hash[a.to_sym]
77
+ value = hash[a.to_sym].deep_clone
78
+ self.send( (a+'=').to_sym, value)
79
+ end
80
+ end
81
+ when Haml4r::TableCell
82
+ Attributes.each do |a|
83
+ value = args[0].send(a.to_sym).deep_clone
84
+ self.send( (a+'=').to_sym, value)
85
+ end
86
+ else
87
+ raise "unsupported type"
88
+ end
89
+ end
90
+
91
+ def to_hash
92
+ @hash ||= {}
93
+ Attributes.each do |a|
94
+ @hash[a.to_sym] = eval "#{a}"
95
+ end
96
+ @hash
97
+ end
98
+
99
+ def inspect
100
+ content ? content.inspect : super.match(/TableCell:[\w]*/)[0]
101
+ # spanee ? "spanee" : ( content ? content.inspect : super.match(/TableCell:[\w]*/)[0] )
102
+ end
103
+
104
+ def inner_cell= inner_cell
105
+ case inner_cell
106
+ when InnerCell
107
+ @inner_cell = inner_cell
108
+ else
109
+ raise "unsupported type"
110
+ end
111
+ end
112
+
113
+ def inner_cell
114
+ @inner_cell
115
+ end
116
+
117
+ def method_missing method_sym, *args, &blk
118
+ if @inner_cell.class::Attributes.include? method_sym.to_s.chomp('=')
119
+ @inner_cell.send method_sym, *args, &blk
120
+ end
121
+ end
122
+
123
+ def spanee
124
+ @spanee ||= false
125
+ end
126
+
127
+ def spanee= spanee
128
+ case spanee
129
+ when true, false
130
+ @spanee = spanee
131
+ else
132
+ raise "unsupported type"
133
+ end
134
+ end
135
+
136
+ def spaner
137
+ @spaner ||= false
138
+ end
139
+
140
+ def spaner= spaner
141
+ case spaner
142
+ when true, false
143
+ @spaner = spaner
144
+ else
145
+ raise "unsupported type"
146
+ end
147
+ end
148
+
149
+ def dissolve_span!
150
+ if spanee
151
+ @inner_cell = @inner_cell.deep_clone
152
+ @spanee = false
153
+ else
154
+ @spaner = false
155
+ end
156
+ end
157
+
158
+ end
159
+
160
+ end
@@ -0,0 +1,485 @@
1
+
2
+ require 'plist4r/mixin/table'
3
+ require 'plist4r/mixin/haml4r/table_cell'
4
+
5
+ module Haml4r
6
+ # TableCells object holds its table data in a 2-dimensional array.
7
+ # TableCells inherits from Plist4r::Table, a generic table class.
8
+ #
9
+ # We access cell locations in a col,row cartesian format (x,y).
10
+ # Ie increasing columns numbers across to the right, and rows down.
11
+ #
12
+ # To specify multiple cells, we use ranges to mark out a rectangle.
13
+ # Any integer is translated to a range. For example row 3 => (3..3)
14
+ #
15
+ # To specify a 2x2 square, we might write [(0..1),(0..1)], or
16
+ # [(3..4),(5..6)] if the rectangle were to start at location [3,5]
17
+ # and extend to [4,6] inclusive.
18
+ #
19
+ # Internal table data always starts writing at index 0, and unused areas
20
+ # padded with EmptyCell. We cannot store negative index locations.
21
+ #
22
+ # For a table starting at a higher (non-zero) index, lower values are then ignored.
23
+ #
24
+ # TableCells class includes spanning functionality, to accomodate the html
25
+ # colspan= and rowspan= attributes. Spanning data are held in a special @spans
26
+ # array, and individual cells are marked as spanning cells.
27
+ #
28
+ # Certain table operations will change groups of cells at once. If a spanning
29
+ # cell falls on the area of cells being changed, the span will try to be
30
+ # re-located, or operated upon in-place accordingly. However if the operation
31
+ # breaks the boundaries of the spanning cell, it must be dissolved.
32
+ #
33
+ # This is expecially true for functions such as transpose, which will flip the
34
+ # orientation of cells across the x-y axis. Other operations, such as fill and
35
+ # and col_insert imply that any existing spans in those areas not be preserved.
36
+ #
37
+ # :-----------------------------------------:
38
+ # | :------------------:------------------: |
39
+ # | | | | |
40
+ # | | | | |
41
+ # | | TableCell | TableCell | |
42
+ # | | | | |
43
+ # | | | | |
44
+ # | :------------------:------------------: |
45
+ # | | | | |
46
+ # | | | | |
47
+ # | | TableCell | TableCell | |
48
+ # | | | | |
49
+ # | | | | |
50
+ # | :- @array ---------:------------------: |
51
+ # | TableCells |
52
+ # :-----------------------------------------:
53
+ #
54
+ class TableCells < Plist4r::Table
55
+
56
+ def examples
57
+ @table.cell(0,3).spanee
58
+ @table.cell(0,3).css_class = "highline"
59
+ @table.cells.cell(0,3).css_class = "highline"
60
+
61
+ @table.cells
62
+ # => TableCells obj (0,0) -> (max,max)
63
+
64
+ @table.cell(0,0).attributes(:css_class, "highlighted")
65
+ # => TableCell obj (0,0) -> (0,0)
66
+
67
+ @table.cells(0,(0..3)).class = "highline"
68
+ # => TableCells obj (0,0) -> (0,3)
69
+
70
+ @table.cells.class = "highline"
71
+ @table.cells.resize(5,5)
72
+
73
+ @table.cell(2, 5, cell)
74
+
75
+ quarant_a = @table.cells(0,(0..3))
76
+ # => TableCells obj
77
+ end
78
+
79
+ OptionsHash += %w[ spans ]
80
+ EmptyCell = TableCell.new
81
+
82
+ def initialize *args, &blk
83
+ @spans = nil
84
+ super
85
+ pad @cr, @rr, EmptyCell
86
+ # puts "@spans = #{@spans.inspect}"
87
+ # puts "args = #{args.inspect}"
88
+ @spans ||= []
89
+ refresh_spans
90
+ end
91
+
92
+ def empty?
93
+ if @cr == (0..0) && @rr == (0..0)
94
+ c = cell(0,0)
95
+ TableCell::Attributes.each do |a|
96
+ return false if eval("c.#{a}")
97
+ end
98
+ return true
99
+ else
100
+ return false
101
+ end
102
+ end
103
+
104
+ def inspect start_col=0
105
+ cell_width = Plist4r::Table.new :size => [@cr, 0..0], :fill_all => 5
106
+ @cr.each do |col|
107
+ @rr.each do |row|
108
+ cell_size = @array[col][row].inspect.size
109
+ cell_width.cell(col, 0, cell_size) if cell_size > cell_width.cell(col,0)
110
+ end
111
+ end
112
+
113
+ col_pad_pre = " "
114
+ col_pad_post = " "
115
+
116
+ vert_border = "|"
117
+ horz_border = "-"
118
+
119
+ # row_sep = ""
120
+ # row_sep << " " * start_col
121
+ # @cr.each do |col|
122
+ # row_sep << ":" + horz_border * (col_pad_pre.size + cell_width.cell(col,0) + col_pad_post.size)
123
+ # end
124
+ # row_sep << ":"
125
+
126
+ o = ""
127
+ # o << row_sep << "\n"
128
+ @rr.each do |row|
129
+ row_sep = ""
130
+ row_sep << " " * start_col
131
+ @cr.each do |col|
132
+ last = cell(col,row-1)
133
+ if last.is_a?(TableCell) && ( last.inner_cell == cell(col,row).inner_cell )
134
+ row_sep << ":" + " " * (col_pad_pre.size + cell_width.cell(col,0) + col_pad_post.size)
135
+ else
136
+ row_sep << ":" + horz_border * (col_pad_pre.size + cell_width.cell(col,0) + col_pad_post.size)
137
+ end
138
+ end
139
+ row_sep << ":"
140
+ o << row_sep << "\n"
141
+
142
+
143
+
144
+ o << " " * start_col
145
+ @cr.each do |col|
146
+ last = cell(col-1,row)
147
+ if last.is_a?(TableCell) && ( last.inner_cell == cell(col,row).inner_cell )
148
+ cell_str = " " * vert_border.size + col_pad_pre + " " * cell_width.cell(col,0) + col_pad_post
149
+ else
150
+ cell_str = vert_border + col_pad_pre + " " * cell_width.cell(col,0) + col_pad_post
151
+ end
152
+ cell_str[vert_border.size+col_pad_pre.size,@array[col][row].inspect.size] = @array[col][row].inspect
153
+ o << cell_str
154
+ end
155
+ o << vert_border
156
+ o << "\n"
157
+
158
+ end
159
+ row_sep = ""
160
+ row_sep << " " * start_col
161
+ @cr.each do |col|
162
+ row_sep << ":" + horz_border * (col_pad_pre.size + cell_width.cell(col,0) + col_pad_post.size)
163
+ end
164
+ row_sep << ":"
165
+
166
+ o << row_sep << "\n"
167
+ return o
168
+ end
169
+
170
+ def resize col_range, row_range
171
+ super
172
+ pad @cr, @rr, EmptyCell
173
+ inverse_unspan_cells if @spans
174
+ self
175
+ end
176
+
177
+ def array array=nil
178
+ result = super
179
+ @spans.slice!(0,@spans.size) if @spans
180
+ result
181
+ end
182
+
183
+ def spans spans=nil
184
+ case spans
185
+ when nil
186
+ @spans
187
+ when Array
188
+ @spans = spans
189
+ else
190
+ raise "unsupported type"
191
+ end
192
+ end
193
+
194
+ def colspan col, row
195
+ @spans.each do |span|
196
+ if span.col_range.first == col && span.row_range.first == row
197
+ if span.col_range.size > 1
198
+ return span.col_range.size
199
+ end
200
+ end
201
+ end
202
+ return nil
203
+ end
204
+
205
+ def rowspan col, row
206
+ @spans.each do |span|
207
+ if span.col_range.first == col && span.row_range.first == row
208
+ if span.row_range.size > 1
209
+ return span.row_range.size
210
+ end
211
+ end
212
+ end
213
+ return nil
214
+ end
215
+
216
+ def cell col, row, value=nil
217
+ case value
218
+ when Hash
219
+ super col, row, TableCell.new(value)
220
+ when nil, TableCell, Plist4r::Table
221
+ super col, row, value
222
+ else
223
+ raise "unsupported type"
224
+ end
225
+ end
226
+
227
+ def cells col_range=nil, row_range=nil, value=nil
228
+ col_range = @cr if col_range.nil? ; row_range = @rr if row_range.nil?
229
+ col_range, row_range = Plist4r::Table.sanitize_ranges col_range, row_range
230
+
231
+ replace col_range, row_range, value if value
232
+ Haml4r::TableCells.new :array => @array, :size => [col_range, row_range], :spans => @spans
233
+ end
234
+
235
+ def span_cells col_range=nil, row_range=nil, data=nil
236
+ col_range = @cr if col_range.nil? ; row_range = @rr if row_range.nil?
237
+ col_range, row_range = Plist4r::Table.sanitize_ranges col_range, row_range
238
+
239
+ puts "returning nil" unless col_range.size > 1 || row_range.size > 1
240
+ return nil unless col_range.size > 1 || row_range.size > 1
241
+
242
+ unspan_cells col_range, row_range
243
+
244
+ if data
245
+ cell col_range.first, row_range.first, data
246
+ end
247
+
248
+ first_cell = cell col_range.first, row_range.first
249
+ first_cell.spaner = true
250
+ spanning_inner_cell = first_cell.inner_cell
251
+
252
+ new_span = cells col_range, row_range
253
+ new_span.each do |c|
254
+ unless c.spaner
255
+ c.inner_cell = spanning_inner_cell
256
+ c.spanee = true
257
+ end
258
+ end
259
+ @spans << new_span
260
+ self
261
+ end
262
+
263
+ def refresh_spans
264
+ @spans.each do |span|
265
+ first_cell = cell span.col_range.first, span.row_range.first
266
+ first_cell.spaner = true
267
+ spanning_inner_cell = first_cell.inner_cell
268
+
269
+ span.each do |c|
270
+ unless c.spaner
271
+ c.inner_cell = spanning_inner_cell
272
+ c.spanee = true
273
+ end
274
+ end
275
+ end
276
+ self
277
+ end
278
+
279
+ def crop col_range, row_range
280
+ crop_obj = super
281
+ cs = col_range.first
282
+ rs = row_range.first
283
+
284
+ @spans.each do |span|
285
+ scr, srr = [span.col_range, span.row_range]
286
+ cf, cl = [scr.first - cs, scr.last - cs]
287
+ rf, rl = [srr.first - rs, srr.last - rs]
288
+
289
+ if cf < 0 || rf < 0
290
+ crop_cr = ([cf,0].max)..([cl,0].max)
291
+ crop_rr = ([rf,0].max)..([rl,0].max)
292
+ crop_obj.each(crop_cr, crop_rr) do |c|
293
+ c.dissolve_span!
294
+ end
295
+ else
296
+ crop_obj.span_cells cf..cl, rf..rl
297
+ end
298
+ end
299
+ crop_obj.inverse_unspan_cells
300
+ return crop_obj
301
+ end
302
+
303
+ def fill col_range, row_range, data
304
+ super
305
+ unspan_cells col_range, row_range
306
+ self
307
+ end
308
+
309
+ def inverse_fill col_range, row_range, data=nil
310
+ super
311
+ inverse_unspan_cells col_range, row_range
312
+ self
313
+ end
314
+
315
+ def transpose col_range=nil, row_range=nil, keep_bounds=false
316
+ col_range = @cr if col_range.nil? ; row_range = @rr if row_range.nil?
317
+ col_range, row_range = Plist4r::Table.sanitize_ranges col_range, row_range
318
+
319
+ super_cr, super_rr = [col_range, row_range]
320
+
321
+ ocr,orr = [col_range,row_range]
322
+ col_range = (ocr.begin)..(ocr.begin+orr.size-1)
323
+ row_range = (orr.begin)..(orr.begin+ocr.size-1)
324
+
325
+ if keep_bounds && col_range.size != row_range.size
326
+ if ocr.size > orr.size
327
+ row_range = (row_range.begin)..(orr.end)
328
+ else
329
+ col_range = (col_range.begin)..(ocr.end)
330
+ end
331
+ end
332
+
333
+ transposed_spans = []
334
+ @spans.each do |span|
335
+ ocr,orr = [span.col_range,span.row_range]
336
+ nscr = (ocr.begin)..(ocr.begin+orr.size-1)
337
+ nsrr = (orr.begin)..(orr.begin+ocr.size-1)
338
+ if ( nscr & col_range == nscr ) && ( nsrr & row_range == nsrr )
339
+ transposed_spans << [nscr,nsrr]
340
+ end
341
+ end
342
+
343
+ unspan_cells col_range, row_range
344
+ super super_cr, super_rr
345
+ pad super_cr, super_rr, EmptyCell
346
+
347
+ transposed_spans.each do |ts|
348
+ span_cells ts[0], ts[1]
349
+ end
350
+
351
+ self
352
+ end
353
+
354
+ def data_replace col_range, row_range, other_data
355
+ super
356
+ unspan_cells col_range, row_range
357
+
358
+ col_adjust = col_range.first-other_data.col_range.first
359
+ row_adjust = row_range.first-other_data.row_range.first
360
+
361
+ o_spans = other_data.spans
362
+ o_spans.each do |span|
363
+ scr, srr = [span.col_range, span.row_range]
364
+ sacr = (scr.first+col_adjust)..(scr.last+col_adjust)
365
+ sarr = (srr.first+row_adjust)..(srr.last+row_adjust)
366
+
367
+ col_multiply = col_range & sacr
368
+ row_multiply = row_range & sarr
369
+
370
+ span_cells sacr, sarr if col_multiply == sacr && row_multiply == sarr
371
+ end
372
+ self
373
+ end
374
+
375
+ def unspan_cells col_range=nil, row_range=nil
376
+ col_range = @cr if col_range.nil? ; row_range = @rr if row_range.nil?
377
+ col_range, row_range = Plist4r::Table.sanitize_ranges col_range, row_range
378
+
379
+ conflicting_spans = []
380
+ @spans.each do |span|
381
+ col_overlap = col_range & span.col_range
382
+ row_overlap = row_range & span.row_range
383
+ conflicting_spans << span if col_overlap && row_overlap
384
+ end
385
+
386
+ conflicting_spans.each do |span|
387
+ span.each do |c|
388
+ c.dissolve_span!
389
+ end
390
+ @spans.delete span
391
+ end
392
+
393
+ self
394
+ end
395
+
396
+ def inverse_unspan_cells col_range=nil, row_range=nil
397
+ col_range = @cr if col_range.nil? ; row_range = @rr if row_range.nil?
398
+ col_range, row_range = Plist4r::Table.sanitize_ranges col_range, row_range
399
+
400
+ conflicting_spans = []
401
+ @spans.each do |span|
402
+ col_multiply = col_range & span.col_range
403
+ row_multiply = row_range & span.row_range
404
+ conflicting_spans << span unless col_multiply == span.col_range && row_multiply == span.row_range
405
+ end
406
+
407
+ conflicting_spans.each do |span|
408
+ span.each do |c|
409
+ c.dissolve_span!
410
+ end
411
+ @spans.delete span
412
+ end
413
+ self
414
+ end
415
+
416
+ def respond_to? method_sym
417
+ return true if TableCell::Attributes.include? method_sym.to_s.chomp('=')
418
+ super
419
+ end
420
+
421
+ def method_missing method_sym, *args, &blk
422
+ if TableCell::Attributes.include? method_sym.to_s.chomp('=')
423
+ set_or_return method_sym.to_s.chomp('='), *args, &blk
424
+ end
425
+ end
426
+
427
+ def map col_range=nil, row_range=nil, &blk
428
+ col_range = @cr if col_range.nil? ; row_range = @rr if row_range.nil?
429
+ col_range, row_range = Plist4r::Table.sanitize_ranges col_range, row_range
430
+
431
+ t = Plist4r::Table.new :size => [col_range, row_range]
432
+
433
+ row_range.each do |row|
434
+ col_range.each do |col|
435
+ element = yield(cell(col, row).deep_clone)
436
+ t.cell col, row, element
437
+ end
438
+ end
439
+ refresh_spans
440
+ t
441
+ end
442
+
443
+ def map! col_range=nil, row_range=nil, &blk
444
+ col_range = @cr if col_range.nil? ; row_range = @rr if row_range.nil?
445
+ col_range, row_range = Plist4r::Table.sanitize_ranges col_range, row_range
446
+
447
+ row_range.each do |row|
448
+ col_range.each do |col|
449
+ c = cell(col, row).deep_clone
450
+ element = yield c
451
+ if element.is_a? TableCell
452
+ cell col, row, element
453
+ else
454
+ cell col, row, c
455
+ end
456
+ end
457
+ end
458
+ refresh_spans
459
+ t
460
+ end
461
+
462
+ def set attribute, value
463
+ set_or_return attribute, value
464
+ end
465
+
466
+ def value_for attribute
467
+ set_or_return attribute
468
+ end
469
+
470
+ def set_or_return attribute, value=nil
471
+ case value
472
+ when nil
473
+ map do |cell|
474
+ eval "cell.#{attribute}"
475
+ end
476
+ else
477
+ each do |cell|
478
+ eval "cell.#{attribute} = value"
479
+ end
480
+ end
481
+ end
482
+
483
+ end
484
+
485
+ end