lib/rspreadsheet/worksheet.rb in rspreadsheet-0.1.1 vs lib/rspreadsheet/worksheet.rb in rspreadsheet-0.2.0
- old
+ new
@@ -1,17 +1,18 @@
require 'rspreadsheet/row'
require 'rspreadsheet/tools'
# require 'forwardable'
-module Rspreadsheet
+module Rspreadsheet
class Worksheet
attr_accessor :name, :xmlnode
# extend Forwardable
# def_delegators :nonemptycells
def initialize(xmlnode_or_sheet_name)
+ @rowcache=[]
# set up the @xmlnode according to parameter
case xmlnode_or_sheet_name
when LibXML::XML::Node
@xmlnode = xmlnode_or_sheet_name
when String
@@ -19,22 +20,131 @@
ns = LibXML::XML::Namespace.new(@xmlnode, 'table', 'urn:oasis:names:tc:opendocument:xmlns:table:1.0')
@xmlnode .namespaces.namespace = ns
@xmlnode['table:name'] = xmlnode_or_sheet_name
else raise 'Provide name or xml node to create a Worksheet object'
end
-
- ## initialize rows
- @spredsheetrows=RowArray.new(self,@xmlnode)
end
+
+ def rowxmlnode(rowi)
+ find_subnode_respect_repeated(@xmlnode, rowi, {:xml_items_node_name => 'table-row', :xml_repeated_attribute => 'number-rows-repeated'})
+ end
+
+ def rowrange(rowi)
+ find_subnode_range_respect_repeated(@xmlnode, rowi, {:xml_items_node_name => 'table-row', :xml_repeated_attribute => 'number-rows-repeated'})
+ end
+
+ def row_nonempty_cells_col_indexes(rowi)
+ arowxmlnode = rowxmlnode(rowi)
+ if arowxmlnode.nil?
+ []
+ else
+ find_nonempty_subnode_indexes(arowxmlnode, {:xml_items_node_name => 'table-cell', :xml_repeated_attribute => 'number-columns-repeated'})
+ end
+ end
+
+ def cellxmlnode(rowi,coli)
+ arowxmlnode = rowxmlnode(rowi)
+ if arowxmlnode.nil?
+ nil
+ else
+ find_subnode_respect_repeated(arowxmlnode, coli, {:xml_items_node_name => 'table-cell', :xml_repeated_attribute => 'number-columns-repeated'})
+ end
+ end
+
+ def cellrange(coli)
+ find_subnode_range_respect_repeated(@xmlnode, rowi, {:xml_items_node_name => 'table-row', :xml_repeated_attribute => 'number-rows-repeated'})
+ end
+
+ def first_unused_row_index
+ find_first_unused_index_respect_repeated(xmlnode, {:xml_items_node_name => 'table-row', :xml_repeated_attribute => 'number-rows-repeated'})
+ end
+
+ def detach_row_in_xml(rowi)
+ return detach_subnode_respect_repeated(xmlnode, rowi, {:xml_items_node_name => 'table-row', :xml_repeated_attribute => 'number-rows-repeated'})
+ end
+ def detach_cell_in_xml(rowi,coli)
+ rownode = detach_row_in_xml(rowi)
+ return detach_subnode_respect_repeated(rownode, coli, {:xml_items_node_name => 'table-cell', :xml_repeated_attribute => 'number-columns-repeated'})
+ end
+
+ def detach_subnode_respect_repeated(axmlnode,aindex, options)
+ index = 0
+ axmlnode.elements.select{|node| node.name == options[:xml_items_node_name]}.each do |node|
+ repeated = (node.attributes[options[:xml_repeated_attribute]] || 1).to_i
+ oldindex = index
+ index = index+repeated
+ if index>= aindex # found the node, now do the detachement
+ ranges = [oldindex+1..aindex-1,aindex..aindex,aindex+1..index].reject {|range| range.size<1}
+ ranges.each do |range|
+ newnode = node.copy(true)
+ Tools.set_ns_attribute(newnode,'table',options[:xml_repeated_attribute],range.size,1)
+ node.prev = newnode
+ end
+ node.remove!
+ return find_subnode_respect_repeated(axmlnode, aindex, options)
+ end
+ end
+ # add outbound xmlnode
+ [index+1..aindex-1,aindex..aindex].reject {|range| range.size<1}.each do |range|
+ node = LibXML::XML::Node.new(options[:xml_items_node_name],nil, Tools.get_namespace('table'))
+ Tools.set_ns_attribute(node,'table',options[:xml_repeated_attribute],range.size, 1)
+ axmlnode << node
+ end
+ find_subnode_respect_repeated(axmlnode, aindex, options)
+ end
+
+ def find_subnode_respect_repeated(axmlnode, aindex, options)
+ index = 0
+ axmlnode.elements.select{|node| node.name == options[:xml_items_node_name]}.each do |node|
+ repeated = (node.attributes[options[:xml_repeated_attribute]] || 1).to_i
+ index = index+repeated
+ return node if index>= aindex
+ end
+ return nil
+ end
+ def find_subnode_range_respect_repeated(axmlnode, aindex, options)
+ index = 0
+ axmlnode.elements.select{|node| node.name == options[:xml_items_node_name]}.each do |node|
+ repeated = (node.attributes[options[:xml_repeated_attribute]] || 1).to_i
+ if index+repeated >= aindex
+ return (index+1..index+repeated)
+ else
+ index = index+repeated
+ end
+ end
+ return (index+1..Float::INFINITY)
+ end
+
+ def find_nonempty_subnode_indexes(axmlnode, options)
+ index = 0
+ result = []
+ axmlnode.elements.select{|node| node.name == options[:xml_items_node_name]}.each do |node|
+ repeated = (node.attributes[options[:xml_repeated_attribute]] || 1).to_i
+ index = index + repeated
+ if !(node.content.nil? or node.content.empty? or node.content =='') and (repeated==1)
+ result << index
+ end
+ end
+ return result
+ end
+ def find_first_unused_index_respect_repeated(axmlnode, options)
+ index = 0
+ axmlnode.elements.select{|node| node.name == options[:xml_items_node_name]}.each do |node|
+ repeated = (node.attributes[options[:xml_repeated_attribute]] || 1).to_i
+ index = index+repeated
+ end
+ return index+1
+ end
+
def cells(r,c)
rows(r).andand.cells(c)
end
def nonemptycells
used_rows_range.collect{ |rowi| rows(rowi) }.collect { |row| row.nonemptycells }.flatten
end
def rows(rowi)
- @spredsheetrows.get_row(rowi)
+ @rowcache[rowi] ||= Row.new(self,rowi) unless rowi<=0
end
## syntactic sugar follows
def [](r,c)
cells(r,c).andand.value
end
@@ -42,11 +152,11 @@
cells(r,c).andand.value=avalue
end
# allows syntax like sheet.F15
def method_missing method_name, *args, &block
if method_name.to_s.match(/^([A-Z]{1,3})(\d{1,8})(=?)$/)
- row,col = Rspreadsheet::Tools.convert_cell_address($~[1],$~[2])
+ row,col = Rspreadsheet::Tools.convert_cell_address_to_coordinates($~[1],$~[2])
assignchar = $~[3]
if assignchar == '='
self.cells(row,col).value = args.first
else
self.cells(row,col).value
@@ -54,10 +164,10 @@
else
super
end
end
def used_rows_range
- 1..@spredsheetrows.first_unused_row_index-1
+ 1..self.first_unused_row_index-1
end
end
end