lib/rspreadsheet/cell.rb in rspreadsheet-0.0.5 vs lib/rspreadsheet/cell.rb in rspreadsheet-0.0.6
- old
+ new
@@ -1,54 +1,166 @@
require 'andand'
module Rspreadsheet
+
class Cell
- attr_reader :value,:col,:row, :source_node
- def initialize(arow,acol,source_node=nil)
- @col = acol
- @row = arow
- @source_node = source_node
- unless @source_node.nil?
- @type = @source_node.attributes['value-type'].to_s
- if (@source_node.children.size == 0) and (not @source_node.attributes?)
- @value = nil
- else
- # here you also ned to read style not only value
- @value = case @type
- when 'float'
- @source_node.attributes['value'].to_f
- when 'string'
- @source_node.elements.first.andand.content.to_s
- when 'date'
- Date.strptime(@source_node.attributes['date-value'].to_s, '%Y-%m-%d')
- when 'percentage'
- @source_node.attributes['value'].to_f
- else
- if @source_node.children.size == 0
- nil
- else
- nil
-# raise "Unknown type from #{@source_node.to_s} / children size=#{@source_node.children.size.to_s} / type=#{@type}"
- end
- end
+ attr_reader :col, :xmlnode
+ attr_reader :parent_row # for debug only
+ attr_accessor :mode
+ def self.empty_cell_node
+ LibXML::XML::Node.new('table-cell',nil, Tools.get_namespace('table'))
+ end
+ def initialize(aparent_row,coli,asource_node=nil)
+ raise "First parameter should be Row object not #{aparent_row.class}" unless aparent_row.kind_of?(Rspreadsheet::Row)
+ @mode = :regular
+ @parent_row = aparent_row
+ if asource_node.nil?
+ asource_node = Cell.empty_cell_node
+ end
+ @xmlnode = asource_node
+ @col = coli
+ end
+ def ns_table; @parent_row.xmlnode.doc.root.namespaces.find_by_prefix('table') end
+ def ns_office; @parent_row.xmlnode.doc.root.namespaces.find_by_prefix('office') end
+ def ns_text; @parent_row.xmlnode.doc.root.namespaces.find_by_prefix('text') end
+ def to_s; value end
+ def xml; self.source_node.to_s; end
+ def value_xml; self.source_node.children.first.children.first.to_s; end
+ def coordinates; [row,col]; end
+ def row; @parent_row.row; end
+ def value
+ gt = guess_cell_type
+ if (@mode == :regular) or (@mode == @repeated)
+ case
+ when gt == nil then nil
+ when gt == Float then @xmlnode.attributes['value'].to_f
+ when gt == String then @xmlnode.elements.first.andand.content.to_s
+ when gt == Date then Date.strptime(@xmlnode.attributes['date-value'].to_s, '%Y-%m-%d')
+ when gt == 'percentage' then @xmlnode.attributes['value'].to_f
end
+ elsif @mode == :outbound # needs to check whether it is still unbound
+ if parent_row.still_out_of_used_range?
+ nil
+ else
+ parent_row.normalize.cells(@col).value
+ end
+ else
+ raise "Unknown cell mode #{@mode}"
end
end
- def to_s
- value
- end
def value=(avalue)
- @value=avalue
- self
+ if @mode == :regular
+ gt = guess_cell_type(avalue)
+ case
+ when gt == nil then raise 'This value type is not storable to cell'
+ when gt == Float
+ set_type_attribute('float')
+ remove_all_value_attributes_and_content(@xmlnode)
+ Tools.set_ns_attribute(@xmlnode,'office','value', avalue.to_s)
+ @xmlnode << LibXML::XML::Node.new('p', avalue.to_f.to_s, ns_text)
+ when gt == String then
+ set_type_attribute('string')
+ remove_all_value_attributes_and_content(@xmlnode)
+ @xmlnode << LibXML::XML::Node.new('p', avalue.to_s, ns_text)
+ when gt == Date then
+ set_type_attribute('date')
+ remove_all_value_attributes_and_content(@xmlnode)
+ Tools.set_ns_attribute(@xmlnode,'office','date-value', avalue.strftime('%Y-%m-%d'))
+ @xmlnode << LibXML::XML::Node.new('p', avalue.strftime('%Y-%m-%d'), ns_text)
+ when gt == 'percentage'
+ set_type_attribute('float')
+ remove_all_value_attributes_and_content(@xmlnode)
+ Tools.set_ns_attribute(@xmlnode,'office','value', avalue.to_f.to_s)
+ @xmlnode << LibXML::XML::Node.new('p', (avalue.to_f*100).round.to_s+'%', ns_text)
+ end
+ elsif (@mode == :repeated) or (@mode == :outbound ) # Cell did not exist individually yet, detach row and create editable cell
+ row = @parent_row.detach
+ row.cells(@col).value = avalue
+ else
+ raise "Unknown cell mode #{@mode}"
+ end
end
- def xml
- self.source_node.to_s
+ def remove_all_value_attributes_and_content(node)
+ if att = Tools.get_ns_attribute(@xmlnode, 'office','value') then att.remove! end
+ if att = Tools.get_ns_attribute(@xmlnode, 'office','date-value') then att.remove! end
+ @xmlnode.content=''
end
- def value_xml
-# self.source_node.children.first.to_s
- self.source_node.children.first.children.first.to_s
+ def set_type_attribute(typestring)
+ Tools.set_ns_attribute(@xmlnode,'office','value-type',typestring)
end
- def coordinates
- [row,col]
+
+ # based on @xmlnode and optionally value which is about to be assigned, guesses which type the result should be
+ def guess_cell_type(avalue=nil)
+ # try guessing by value
+ valueguess = case avalue
+ when Numeric then Float
+ when Date then Date
+ when String,nil then nil
+ else nil
+ end
+ result = valueguess
+
+ if valueguess.nil? # valueguess is most important
+ # if not succesfull then try guessing by type
+ type = @xmlnode.attributes['value-type'].to_s
+ typeguess = case type
+ when 'float' then Float
+ when 'string' then String
+ when 'date' then Date
+ when 'percentage' then 'percentage'
+ else
+ if @xmlnode.children.size == 0
+ nil
+ else
+ raise "Unknown type from #{@xmlnode.to_s} / children size=#{@xmlnode.children.size.to_s} / type=#{type}"
+ end
+ end
+
+ result =
+ if !typeguess.nil? # if not certain by value, but have a typeguess
+ if !avalue.nil? # with value we may try converting
+ if (typeguess(avalue) rescue false) # if convertible then it is typeguess
+ typeguess
+ elsif (String(avalue) rescue false) # otherwise try string
+ String
+ else # if not convertible to anyhing concious then nil
+ nil
+ end
+ else # without value we just beleive typeguess
+ typeguess
+ end
+ else # it not have a typeguess
+ if (String(avalue) rescue false) # convertible to String
+ String
+ else
+ nil
+ end
+ end
+ end
+ result
end
+ def inspect
+ "#<Cell:[#{row},#{col}]=#{value}(#{guess_cell_type.to_s})"
+ end
end
+
end
+
+# ## initialize cells
+# @cells = Hash.new do |hash, coords|
+# # we create empty cell and place it to hash, we do not have to check whether there is a cell in XML already, because it would be in hash as well
+# hash[coords]=Cell.new(coords[0],coords[1])
+# # TODO: create XML empty node here or upon save?
+# end
+# rowi = 1
+# unless @xmlnode.nil?
+# @xmlnode.elements.select{ |node| node.name == 'table-row'}.each do |row_source_node|
+# coli = 1
+# row_source_node.elements.select{ |node| node.name == 'table-cell'}.each do |cell_source_node|
+# initialize_cell(rowi,coli,cell_source_node)
+# coli += 1
+# end
+# rowi += 1
+# end
+# end
+
+