Created
May 8, 2010 20:28
-
-
Save dreamcat4/394757 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Object | |
def deep_clone; Marshal::load(Marshal.dump(self)); end | |
end | |
class Array | |
def multidim? | |
case self.size | |
when 0 | |
false | |
else | |
each do |e| | |
return false unless e.class == Array | |
end | |
true | |
end | |
end | |
end | |
class Integer | |
def to_r | |
self..self | |
end | |
end | |
class Range | |
def size | |
last - first | |
end | |
def to_r | |
self | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'plist4r/mixin/ruby_stdlib' | |
module Plist4r | |
# A data type representation for tables. The underlying store is an array of arrays (2d). | |
# The addressing scheme is based on (column, row) order, with Range objects to specify | |
# the bounds of any rectangle of elements withing the table. | |
# | |
# A variety of methods are provided for manipulating the table data, including flipping, | |
# inserting, replacing and deleting. Operations can be column-based, row-based, or both. | |
class Table | |
# The value to assign to an empty cell | |
EmptyCell = nil | |
# The range of valid values for which match the empty cell criteria (for which the cell are ignored) | |
EmptyCells = [nil, false, 0] | |
# When allocating the arrays for a new table, the minimum size to pad around with empty cells. | |
MinPadSize = 10 | |
def examples | |
d = Plist4r::Table.new(5,4) | |
d = Plist4r::Table.new(0..5,0..4) | |
d = Plist4r::Table.new | |
d = Plist4r::Table.new [5,4] | |
d.crop(3..5, 2..4) | |
# => Plist4r::Table.new(0..2,0..2) | |
d.rows # => (2..4) | |
end | |
# def foo *args | |
def initialize data, opts={}, ranges, *args, &blk | |
case args[0] | |
when Array | |
array = args[0] | |
case array.size | |
when 0 | |
resize 0..0, 0..0 | |
when 2 | |
dimensions = array.map do |d| | |
case d | |
when Integer | |
0..d | |
when Range | |
d | |
else | |
raise "unsupported type" | |
end | |
end | |
else | |
if array.multidim? | |
@array = array | |
# we should grap a range here and mask the input | |
auto_size | |
else | |
raise "array type not supported" | |
end | |
end | |
when Integer, Range | |
raise "args not supported" unless [Integer, Range].include? args[1].class | |
resize args[0].to_r, args[1].to_r | |
when Hash | |
parse_opts! args.first | |
when Plist4r::Table | |
replace args.first | |
when nil | |
resize 0..0, 0..0 | |
else | |
raise "unsupported type" | |
end | |
@array ||= [] | |
end | |
def auto_size | |
rs = 0 | |
@array.each_index do |col| | |
rs = col.size if col.size > rs | |
end | |
@cr = 0..@array.size | |
@rr = 0..rs | |
end | |
def resize col_range, row_range | |
@cr = col_range | |
@rr = row_range | |
pad @cr, @rr, EmptyCell | |
end | |
def pad col_range, row_range, data | |
if EmptyCells.include? data | |
col_range = col_range.start..MinPadSize if col_range.end < MinPadSize | |
row_range = row_range.start..MinPadSize if row_range.end < MinPadSize | |
end | |
@array.fill [], @array.size, col_range.end - @array.size | |
@array.each do |col| | |
col.each do |cell| | |
cell = data if EmptyCells.include? cell | |
end | |
col.fill data, col.size, row_range.end - col.size | |
end | |
end | |
def fill col_range, row_range, data | |
pad col_range, row_range, EmptyCell | |
col_range.each do |c| | |
row_range.each do |r| | |
@array[c][r] = data | |
end | |
end | |
end | |
def inverse_fill col_range, row_range, data | |
crop_obj = crop col_range, row_range | |
fill @cr, @rr, EmptyCell | |
replace col_range, row_range, crop_obj | |
end | |
def replace col_range, row_range, data | |
case data | |
when Plist4r::Table | |
data_replace col_range, row_range, data | |
else | |
fill col_range, row_range, data | |
end | |
end | |
def col_range | |
@cr | |
end | |
def row_range | |
@rr | |
end | |
def row_replace row_range, data | |
replace @cr.first..@cr.last, row_range, data | |
end | |
def col_replace col_range, data | |
replace col_range, @rr.first..@rr.last, data | |
end | |
def crop! col_range, row_range | |
pad col_range, row_range, EmptyCell | |
new_array = [] | |
col_range.each_index do |col| | |
new_array << [] | |
@array[col][row_range].each_index do |row| | |
new_array[col-col_range.first][row-row_range.first] = @array[col][row].deep_clone | |
end | |
end | |
@array = new_array | |
@cr = 0..col_range.size | |
@rr = 0..row_range.size | |
self | |
end | |
def crop col_range, row_range | |
pad col_range, row_range, EmptyCell | |
new_array = [] | |
col_range.each_index do |col| | |
new_array << [] | |
@array[col][row_range].each_index do |row| | |
new_array[col-col_range.first][row-row_range.first] = @array[col][row].deep_clone | |
end | |
end | |
new_obj = Plist4r::Table.new new_array | |
end | |
def data_replace col_range, row_range, other_data | |
self.pad col_range, row_range, EmptyCell | |
o = other_data.deep_clone | |
o.pad (o.col_range.first)..(o.col_range.first+col_range.size), (o.row_range.first)..(o.row_range.first+row_range.size), EmptyCell | |
col_range.each do |col| | |
row_range.each do |row| | |
@array[col][row] = o.to_a[col][row].deep_clone unless EmptyCells.include? o.to_a[col][row] | |
end | |
end | |
end | |
def col_insert col_range, row_range, other_data | |
translate col_range.first..@cr.last, @rr, [col_range.size, 0] | |
replace col_range, row_range, other_data | |
end | |
def row_insert col_range, row_range, other_data | |
translate @cr, row_range.first..@rr.last, [0, row_range.size] | |
replace col_range, row_range, other_data | |
end | |
def translate col_range, row_range, vector | |
crop_obj = crop col_range, row_range | |
fill col_range, row_range, EmptyCell | |
col_range = (col_range.start+vector[0])..(col_range.end+vector[0]) | |
row_range = (row_range.start+vector[1])..(row_range.end+vector[1]) | |
replace col_range, row_range, crop_obj | |
end | |
def transpose col_range=nil, row_range=nil, keep_bounds=true | |
if col_range.nil? | |
if row_range.nil? | |
@array.transpose | |
@cr,@rr = [@rr, @cr] | |
else | |
raise "col_range and row_range must both be nil, or an instance of Range" | |
end | |
else | |
crop_obj = crop col_range, row_range | |
fill col_range, row_range, EmptyCell | |
crop_obj.flip | |
if keep_bounds && col_range.size != row_range.size | |
if col_range.size > row_range.size | |
col_range = (col_range.start)..(col_range.start+row_range.size) | |
else | |
row_range = (row_range.start)..(row_range.start+col_range.size) | |
end | |
end | |
replace col_range, row_range, crop_obj | |
end | |
end | |
def column col_range, value=nil | |
case value | |
when nil | |
crop col_range, @rr | |
else | |
col_replace col_range, value | |
end | |
end | |
def row row_range, value=nil | |
case value | |
when nil | |
crop @cr, row_range | |
else | |
row_replace row_range, value | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment