diff options
| author | Randy Morgan <[email protected]> | 2013-01-10 18:27:27 +0900 |
|---|---|---|
| committer | Randy Morgan <[email protected]> | 2013-01-10 18:27:27 +0900 |
| commit | 58e8dd8a2b1a4a85ac77bf680914daf16eb695f1 (patch) | |
| tree | 980bf825b4b5c5fb55ef55b1b7f0ea2eb9b13533 | |
| parent | f7eeb07abfa1c58552847b2b38787f44cd3e2d24 (diff) | |
| download | caxlsx-58e8dd8a2b1a4a85ac77bf680914daf16eb695f1.tar.gz caxlsx-58e8dd8a2b1a4a85ac77bf680914daf16eb695f1.zip | |
reduced processing of 3000 rows from 3+ seconds to just under 2
| -rw-r--r-- | lib/axlsx.rb | 7 | ||||
| -rw-r--r-- | lib/axlsx/util/validators.rb | 13 | ||||
| -rw-r--r-- | lib/axlsx/workbook/shared_strings_table.rb | 2 | ||||
| -rw-r--r-- | lib/axlsx/workbook/workbook.rb | 1 | ||||
| -rw-r--r-- | lib/axlsx/workbook/worksheet/cell.rb | 81 | ||||
| -rw-r--r-- | lib/axlsx/workbook/worksheet/cell_serializer.rb | 94 | ||||
| -rw-r--r-- | lib/axlsx/workbook/worksheet/col.rb | 4 | ||||
| -rw-r--r-- | test/benchmark.rb | 1 | ||||
| -rw-r--r-- | test/profile.rb | 1 |
9 files changed, 121 insertions, 83 deletions
diff --git a/lib/axlsx.rb b/lib/axlsx.rb index 91391db5..c5fcfed0 100644 --- a/lib/axlsx.rb +++ b/lib/axlsx.rb @@ -124,5 +124,10 @@ module Axlsx s = s.capitalize if all_caps s.gsub(/_(.)/){ $1.upcase } end - + def self.trust_input + @trust_input ||= false + end + def self.trust_input=(v) + @trust_input=v + end end diff --git a/lib/axlsx/util/validators.rb b/lib/axlsx/util/validators.rb index aa8eb1ac..739a4de2 100644 --- a/lib/axlsx/util/validators.rb +++ b/lib/axlsx/util/validators.rb @@ -51,17 +51,18 @@ module Axlsx # @raise [ArugumentError] Raised if the class of the value provided is not in the specified array of types or the block passed returns false # @return [Boolean] true if validation succeeds. # @see validate_boolean - def self.validate(name, types, v, other= lambda{|arg| true }) + def self.validate(name, types, v, other=false) types = [types] unless types.is_a? Array - valid_type = false + if other.is_a?(Proc) + raise ArgumentError, (ERR_TYPE % [v.inspect, name, types.inspect]) unless other.call(v) + end if v.class == Class - types.each { |t| valid_type = true if v.ancestors.include?(t) } + types.each { |t| return if v.ancestors.include?(t) } else - types.each { |t| valid_type = true if v.is_a?(t) } + types.each { |t| return if v.is_a?(t) } end - raise ArgumentError, (ERR_TYPE % [v.inspect, name, types.inspect]) unless (other.call(v) && valid_type) + raise ArgumentError, (ERR_TYPE % [v.inspect, name, types.inspect]) end - true end diff --git a/lib/axlsx/workbook/shared_strings_table.rb b/lib/axlsx/workbook/shared_strings_table.rb index 61402aec..43e8a1a8 100644 --- a/lib/axlsx/workbook/shared_strings_table.rb +++ b/lib/axlsx/workbook/shared_strings_table.rb @@ -58,7 +58,7 @@ module Axlsx cell.send :ssti=, index else cell.send :ssti=, @index - @shared_xml_string << '<si>' << cell.run_xml_string << '</si>' + @shared_xml_string << '<si>' << CellSerializer.run_xml_string(cell) << '</si>' @unique_cells[cell_hash] = @index @index += 1 end diff --git a/lib/axlsx/workbook/workbook.rb b/lib/axlsx/workbook/workbook.rb index 576367ba..e329ae74 100644 --- a/lib/axlsx/workbook/workbook.rb +++ b/lib/axlsx/workbook/workbook.rb @@ -5,6 +5,7 @@ require 'axlsx/workbook/worksheet/auto_filter/auto_filter.rb' require 'axlsx/workbook/worksheet/date_time_converter.rb' require 'axlsx/workbook/worksheet/protected_range.rb' require 'axlsx/workbook/worksheet/protected_ranges.rb' +require 'axlsx/workbook/worksheet/cell_serializer.rb' require 'axlsx/workbook/worksheet/cell.rb' require 'axlsx/workbook/worksheet/page_margins.rb' require 'axlsx/workbook/worksheet/page_set_up_pr.rb' diff --git a/lib/axlsx/workbook/worksheet/cell.rb b/lib/axlsx/workbook/worksheet/cell.rb index 626b0969..7617bb0f 100644 --- a/lib/axlsx/workbook/worksheet/cell.rb +++ b/lib/axlsx/workbook/worksheet/cell.rb @@ -32,8 +32,9 @@ module Axlsx # @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 - @formula_value = @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 @@ -293,42 +294,13 @@ module Axlsx 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? - method = (@type.to_s << '_type_serialization').to_sym - self.send(method, str) - str << '</c>' + CellSerializer.to_xml_string r_index, c_index, self, str end def is_formula? @@ -397,9 +369,9 @@ module Axlsx :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 else :string @@ -428,46 +400,7 @@ module Axlsx @type = :string # TODO find a better way to do this as it accounts for 30% of # processing time in benchmarking... - ::CGI.escapeHTML(v.to_s) - end - end - - def date_type_serialization(str='') - value_serialization 'd', DateTimeConverter::date_to_serial(@value).to_s, str - end - - def time_type_serialization(str='') - value_serialization 'd', DateTimeConverter::time_to_serial(@value).to_s, str - end - - def boolean_type_serialization(str='') - value_serialization 'b', @value.to_s, str - end - - def float_type_serialization(str='') - numeric_type_serialization str - end - - def integer_type_serialization(str = '') - numeric_type_serialization str - end - - def numeric_type_serialization(str = '') - value_serialization('n', @value.to_s, str) - end - - def value_serialization(serialization_type, serialization_value, str = '') - str << 't="' << serialization_type << '"><v>' << serialization_value << '</v>' - end - - def string_type_serialization(str='') - if is_formula? - str << 't="str">' << '<f>' << value.to_s.sub('=', '') << '</f>' - str << '<v>' << formula_value.to_s << '</v>' unless formula_value.nil? - elsif [email protected]? - value_serialization 's', @ssti.to_s, str - else - str << 't="inlineStr">' << '<is>' << run_xml_string << '</is>' + Axlsx::trust_input ? v.to_s : ::CGI.escapeHTML(v.to_s) end end diff --git a/lib/axlsx/workbook/worksheet/cell_serializer.rb b/lib/axlsx/workbook/worksheet/cell_serializer.rb new file mode 100644 index 00000000..c7f43f45 --- /dev/null +++ b/lib/axlsx/workbook/worksheet/cell_serializer.rb @@ -0,0 +1,94 @@ +module Axlsx + class CellSerializer + class << self + def to_xml_string(row_index, column_index, cell, str='') + str << '<c r="' << Axlsx::cell_r(column_index, row_index) << '" s="' << cell.style.to_s << '" ' + return str << '/>' if cell.value.nil? + method = (cell.type.to_s << '_type_serialization').to_sym + self.send(method, cell, str) + str << '</c>' + 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(cell, str = '') + if cell.is_text_run? + data = cell.instance_values.reject{|key, value| value == nil || key == 'value' || key == 'type' } + keys = data.keys & Cell::INLINE_STYLES + str << "<r><rPr>" + keys.each do |key| + case key + when 'font_name' + str << "<rFont val='"<< cell.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>" << cell.value.to_s << "</t></r>" + else + str << "<t>" << cell.value.to_s << "</t>" + end + str + end + + + def iso_8601_type_serialization(cell, str='') + value_serialization 'd', cell.value, str + end + + def date_type_serialization(cell, str='') + value_serialization false, DateTimeConverter::date_to_serial(cell.value).to_s, str + end + + def time_type_serialization(cell, str='') + value_serialization false, DateTimeConverter::time_to_serial(cell.value).to_s, str + end + + def boolean_type_serialization(cell, str='') + value_serialization 'b', cell.value.to_s, str + end + + def float_type_serialization(cell, str='') + numeric_type_serialization cell, str + end + + def integer_type_serialization(cell, str = '') + numeric_type_serialization cell, str + end + + def numeric_type_serialization(cell, str = '') + value_serialization 'n', cell.value.to_s, str + end + + def value_serialization(serialization_type, serialization_value, str = '') + str << 't="' << serialization_type << '"' if serialization_type + str << '><v>' << serialization_value << '</v>' + end + + def formula_serialization(cell, str='') + str << 't="str">' << '<f>' << cell.value.to_s.sub('=', '') << '</f>' + str << '<v>' << cell.formula_value.to_s << '</v>' unless cell.formula_value.nil? + end + + def inline_string_serialization(cell, str = '') + str << 't="inlineStr">' << '<is>' + run_xml_string cell, str + str << '</is>' + end + + def string_type_serialization(cell, str='') + if cell.is_formula? + formula_serialization cell, str + elsif !cell.ssti.nil? + value_serialization 's', cell.ssti.to_s, str + else + inline_string_serialization cell, str + end + end + end + end +end diff --git a/lib/axlsx/workbook/worksheet/col.rb b/lib/axlsx/workbook/worksheet/col.rb index 42997a2b..0a3edf87 100644 --- a/lib/axlsx/workbook/worksheet/col.rb +++ b/lib/axlsx/workbook/worksheet/col.rb @@ -125,7 +125,9 @@ module Axlsx if fixed_width.is_a? Numeric self.width = fixed_width elsif use_autowidth - self.width = [width || 0, cell.autowidth || 0].max + cell_width = cell.autowidth + self.width = cell_width unless (width || 0) > (cell_width || 0) + #self.width = [width || 0, cell.autowidth || 0].max end end diff --git a/test/benchmark.rb b/test/benchmark.rb index 33bf7d2c..2ef82eaf 100644 --- a/test/benchmark.rb +++ b/test/benchmark.rb @@ -4,6 +4,7 @@ $:.unshift "#{File.dirname(__FILE__)}/../lib" require 'axlsx' require 'csv' require 'benchmark' +Axlsx::trust_input = true row = [] input = (32..126).to_a.pack('U*').chars.to_a 20.times { row << input.shuffle.join} diff --git a/test/profile.rb b/test/profile.rb index 0190dc16..8e4218fd 100644 --- a/test/profile.rb +++ b/test/profile.rb @@ -8,6 +8,7 @@ $:.unshift "#{File.dirname(__FILE__)}/../lib" require 'axlsx' require 'perftools' +Axlsx.trust_input = true row = [] # Taking worst case scenario of all string data input = (32..126).to_a.pack('U*').chars.to_a |
