lib/axlsx/workbook/worksheet/cell.rb in axlsx-1.3.4 vs lib/axlsx/workbook/worksheet/cell.rb in axlsx-1.3.5

- old
+ new

@@ -26,23 +26,29 @@ # @option options [Boolean] extend # @option options [Boolean] u # @option options [Symbol] vertAlign must be one of :baseline, :subscript, :superscript # @option options [Integer] sz # @option options [String] color an 8 letter rgb specification + # @option options [Number] formula_value The value to cache for a formula cell. # @option options [Symbol] scheme must be one of :none, major, :minor def initialize(row, value="", options={}) self.row=row - @value = @font_name = @charset = @family = @b = @i = @strike = @outline = @shadow = nil - @condense = @u = @vertAlign = @sz = @color = @scheme = @extend = @ssti = nil + @value = nil + #@value = @font_name = @charset = @family = @b = @i = @strike = @outline = @shadow = nil + #@formula_value = @condense = @u = @vertAlign = @sz = @color = @scheme = @extend = @ssti = nil @styles = row.worksheet.workbook.styles @row.cells << self parse_options options @style ||= 0 @type ||= cell_type_from_value(value) @value = cast_value(value) end + # this is the cached value for formula cells. If you want the values to render in iOS/Mac OSX preview + # you need to set this. + attr_accessor :formula_value + # An array of available inline styes. # TODO change this to a hash where each key defines attr name and validator (and any info the validator requires) # then move it out to a module so we can re-use in in other classes. # needs to define bla=(v) and bla methods on the class that hook into a # set_attr method that kicks the suplied validator and updates the instance_variable @@ -73,18 +79,18 @@ # :string, :integer, or :float to :time conversions always return the original value as a string and set the cells type to :string. # No support is currently implemented for parsing time strings. attr_reader :type # @see type def type=(v) - RestrictionValidator.validate "Cell.type", [:date, :time, :float, :integer, :string, :boolean], v + RestrictionValidator.validate "Cell.type", [:date, :time, :float, :integer, :string, :boolean, :iso_8601], v @type=v self.value = @value unless @value.nil? end # The value of this cell. - # @return [String, Integer, Float, Time] casted value based on cell's type attribute. + # @return [String, Integer, Float, Time, Boolean] casted value based on cell's type attribute. attr_reader :value # @see value def value=(v) #TODO: consider doing value based type determination first? @value = cast_value(v) @@ -212,11 +218,11 @@ @color = v.is_a?(Color) ? v : Color.new(:rgb=>v) @is_text_run = true end # The inline sz property for the cell - # @return [Boolean] + # @return [Inteter] attr_reader :sz # @see sz def sz=(v) set_run_style :validate_unsigned_int, :sz, v; end # The inline vertical alignment property for the cell @@ -286,71 +292,19 @@ target.r end self.row.worksheet.merge_cells "#{self.r}:#{range_end}" unless range_end.nil? end - # builds an xml text run based on this cells attributes. - # @param [String] str The string instance this run will be concated to. - # @return [String] - def run_xml_string(str = '') - if is_text_run? - data = instance_values.reject{|key, value| value == nil || key == 'value' || key == 'type' } - keys = data.keys & INLINE_STYLES - str << "<r><rPr>" - keys.each do |key| - case key - when 'font_name' - str << "<rFont val='"<< @font_name << "'/>" - when 'color' - str << data[key].to_xml_string - else - str << "<" << key.to_s << " val='" << data[key].to_s << "'/>" - end - end - str << "</rPr>" << "<t>" << value.to_s << "</t></r>" - else - str << "<t>" << value.to_s << "</t>" - end - str - end - # Serializes the cell # @param [Integer] r_index The row index for the cell # @param [Integer] c_index The cell index in the row. # @param [String] str The string index the cell content will be appended to. Defaults to empty string. # @return [String] xml text for the cell def to_xml_string(r_index, c_index, str = '') - str << '<c r="' << Axlsx::cell_r(c_index, r_index) << '" s="' << @style.to_s << '" ' - return str << '/>' if @value.nil? - - case @type - - when :string - #parse formula - if @value.start_with?('=') - str << 't="str"><f>' << @value.to_s.sub('=', '') << '</f>' - else - #parse shared - if @ssti - str << 't="s"><v>' << @ssti.to_s << '</v>' - else - str << 't="inlineStr"><is>' << run_xml_string << '</is>' - end - end - when :date - # TODO: See if this is subject to the same restriction as Time below - str << '><v>' << DateTimeConverter::date_to_serial(@value).to_s << '</v>' - when :time - str << '><v>' << DateTimeConverter::time_to_serial(@value).to_s << '</v>' - when :boolean - str << 't="b"><v>' << @value.to_s << '</v>' - else - str << '><v>' << @value.to_s << '</v>' - end - str << '</c>' + CellSerializer.to_xml_string r_index, c_index, self, str end - + def is_formula? @type == :string && @value.to_s.start_with?('=') end # This is still not perfect... @@ -413,22 +367,27 @@ :date elsif v.is_a?(Time) :time elsif v.is_a?(TrueClass) || v.is_a?(FalseClass) :boolean - elsif v.to_s.match(/\A[+-]?\d+?\Z/) #numeric + elsif v.to_s =~ /\A[+-]?\d+?\Z/ #numeric :integer - elsif v.to_s.match(/\A[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?\Z/) #float + elsif v.to_s =~ /\A[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?\Z/ #float :float + # \A(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[0-1]|0[1-9]|[1-2][0-9]) + # T(2[0-3]|[0-1][0-9]):([0-5][0-9]):([0-5][0-9])(\.[0-9]+)? + # (Z|[+-](?:2[0-3]|[0-1][0-9]):[0-5][0-9])?\Z + elsif v.to_s =~/\A(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[0-1]|0[1-9]|[1-2][0-9])T(2[0-3]|[0-1][0-9]):([0-5][0-9]):([0-5][0-9])(\.[0-9]+)?(Z|[+-](?:2[0-3]|[0-1][0-9]):[0-5][0-9])?\Z/ + :iso_8601 else :string end end # Cast the value into this cells data type. # @note - # About Time - Time in OOXML is *different* from what you might expect. The history as to why is interesting, but you can safely assume that if you are generating docs on a mac, you will want to specify Workbook.1904 as true when using time typed values. + # About Time - Time in OOXML is *different* from what you might expect. The history as to why is interesting, but you can safely assume that if you are generating docs on a mac, you will want to specify Workbook.1904 as true when using time typed values. # @see Axlsx#date1904 def cast_value(v) return nil if v.nil? if @type == :date self.style = STYLE_DATE if self.style == 0 @@ -440,15 +399,18 @@ v.to_f elsif @type == :integer v.to_i elsif @type == :boolean v ? 1 : 0 + elsif @type == :iso_8601 + #consumer is responsible for ensuring the iso_8601 format when specifying this type + v else @type = :string - v.to_s # TODO find a better way to do this as it accounts for 30% of # processing time in benchmarking... - ::CGI.escapeHTML(v.to_s) + Axlsx::trust_input ? v.to_s : ::CGI.escapeHTML(v.to_s) end end + end end