Skip to content

Instantly share code, notes, and snippets.

@dreamcat4
Created May 8, 2010 20:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dreamcat4/394757 to your computer and use it in GitHub Desktop.
Save dreamcat4/394757 to your computer and use it in GitHub Desktop.
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
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