diff options
33 files changed, 303 insertions, 65 deletions
diff --git a/.travis.yml b/.travis.yml index 8371fef4..657f9173 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,28 +1,41 @@ language: ruby -sudo: false +sudo: required +dist: trusty +group: beta cache: bundler bundler_args: --without profile -env: - - JRUBY_OPTS="-Xcli.debug=true --debug" + notifications: irc: "irc.freenode.org#axlsx" email: recipients: on_success: always -rvm: - - 1.9.2 - - 1.9.3 - - 2.0 - - 2.1 - - 2.2 - - rbx - - jruby-19mode - - jruby-9.0.0.0 - - ruby-head - - jruby-head + matrix: + include: + - rvm: 2.1 + - rvm: 2.2.8 + - rvm: 2.3.5 + - rvm: 2.0.0 + - rvm: 2.4.2 + - rvm: rbx-3 + - rvm: jruby-19mode + env: JRUBY_OPTS="-Xcli.debug=true --debug" + - rvm: jruby-9.1.8.0 + env: JRUBY_OPTS="-Xcli.debug=true --debug" + - rvm: ruby-head + - rvm: jruby-head + env: JRUBY_OPTS="-Xcli.debug=true --debug" allow_failures: + - rvm: rbx-3 - rvm: ruby-head - - rvm: jruby-9.0.0.0 + - rvm: jruby-9.1.8.0 - rvm: jruby-head + +# https://github.com/jruby/jruby/wiki/FAQs#why-is-jruby-so-slow-to-install-via-rvm +# https://docs.travis-ci.com/user/installing-dependencies#Installing-Packages-with-the-APT-Addon +addons: + apt: + packages: + - haveged @@ -2,18 +2,23 @@ source 'https://rubygems.org' gemspec group :test do - gem 'rake', '>= 0.8.7' + if RUBY_VERSION.to_i < 2 + gem 'rake', '>= 0.8.7', '< 11' + gem 'json', '< 2' + else + gem 'rake' + end gem 'simplecov' gem 'test-unit' end group :profile do - gem 'ruby-prof' + gem 'ruby-prof', :platforms => :ruby end platforms :rbx do gem 'rubysl' gem 'rubysl-test-unit' gem 'racc' - gem 'rubinius-coverage', '~> 2.0' + gem 'rubinius-coverage', '~> 2.0' end @@ -1,6 +1,6 @@ Axlsx: Office Open XML Spreadsheet Generation ==================================== -[](http://travis-ci.org/randym/axlsx/) +[](http://travis-ci.org/randym/axlsx/) If you are using axlsx for commercial purposes, or just want to show your appreciation for the gem, please don't hesitate to make a donation. diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 00000000..0d7d5fce --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,23 @@ +version: 2.1.0.{build}-{branch} + +environment: + matrix: + - RUBY_VERSION: 23 + - RUBY_VERSION: 22 + - RUBY_VERSION: 21 + - RUBY_VERSION: 200 + - RUBY_VERSION: 193 + +install: + - set PATH=C:\Ruby%RUBY_VERSION%\bin;%PATH% + - bundle install + +build: off + +before_test: + - ruby -v + - gem -v + - bundle -v + +test_script: + - bundle exec rake diff --git a/axlsx.gemspec b/axlsx.gemspec index b4cec557..228d5a98 100644 --- a/axlsx.gemspec +++ b/axlsx.gemspec @@ -18,7 +18,7 @@ Gem::Specification.new do |s| s.test_files = Dir.glob("{test/**/*}") s.add_runtime_dependency 'nokogiri', '>= 1.6.6' - s.add_runtime_dependency 'rubyzip', '~> 1.1.7' + s.add_runtime_dependency 'rubyzip', '>= 1.2.1' s.add_runtime_dependency "htmlentities", "~> 4.3.4" s.add_runtime_dependency "mimemagic", "~> 0.3" diff --git a/lib/axlsx/drawing/pic.rb b/lib/axlsx/drawing/pic.rb index 275a6d06..5a418df0 100644 --- a/lib/axlsx/drawing/pic.rb +++ b/lib/axlsx/drawing/pic.rb @@ -53,7 +53,7 @@ module Axlsx attr_reader :hyperlink # Picture opacity - # @return [Fixnum] + # @return [Integer] attr_reader :opacity # sets or updates a hyperlink for this image. diff --git a/lib/axlsx/drawing/scaling.rb b/lib/axlsx/drawing/scaling.rb index fcbea9f8..4c9d6888 100644 --- a/lib/axlsx/drawing/scaling.rb +++ b/lib/axlsx/drawing/scaling.rb @@ -6,7 +6,7 @@ module Axlsx include Axlsx::OptionsParser # creates a new Scaling object - # @option options [Integer, Fixnum] logBase + # @option options [Integer] logBase # @option options [Symbol] orientation # @option options [Float] max # @option options [Float] min @@ -35,7 +35,7 @@ module Axlsx attr_reader :min # @see logBase - def logBase=(v) DataTypeValidator.validate "Scaling.logBase", [Integer, Fixnum], v, lambda { |arg| arg >= 2 && arg <= 1000}; @logBase = v; end + def logBase=(v) DataTypeValidator.validate "Scaling.logBase", [Integer], v, lambda { |arg| arg >= 2 && arg <= 1000}; @logBase = v; end # @see orientation def orientation=(v) RestrictionValidator.validate "Scaling.orientation", [:minMax, :maxMin], v; @orientation = v; end # @see max diff --git a/lib/axlsx/drawing/view_3D.rb b/lib/axlsx/drawing/view_3D.rb index 9c320b4a..55bbc6c3 100644 --- a/lib/axlsx/drawing/view_3D.rb +++ b/lib/axlsx/drawing/view_3D.rb @@ -86,12 +86,12 @@ module Axlsx alias :rAngAx= :r_ang_ax= # @see perspective - def perspective=(v) + def perspective=(v) RangeValidator.validate "View3D.perspective", 0, 240, v @perspective = v end - # DataTypeValidator.validate "#{self.class}.perspective", [Integer, Fixnum], v, lambda {|arg| arg >= 0 && arg <= 240 }; @perspective = v; end + # DataTypeValidator.validate "#{self.class}.perspective", [Integer], v, lambda {|arg| arg >= 0 && arg <= 240 }; @perspective = v; end # Serializes the object # @param [String] str diff --git a/lib/axlsx/package.rb b/lib/axlsx/package.rb index 8a4f29dc..5b5ea14a 100644 --- a/lib/axlsx/package.rb +++ b/lib/axlsx/package.rb @@ -1,4 +1,4 @@ -# encoding: UTF-8 +# encoding: utf-8 module Axlsx # Package is responsible for managing all the bits and peices that Open Office XML requires to make a valid # xlsx document including valdation and serialization. @@ -253,7 +253,9 @@ module Axlsx parts << {:entry => "xl/#{sheet.rels_pn}", :doc => sheet.relationships, :schema => RELS_XSD} parts << {:entry => "xl/#{sheet.pn}", :doc => sheet, :schema => SML_XSD} end - parts + + # Sort parts for correct MIME detection + parts.sort_by { |part| part[:entry] } end # Performs xsd validation for a signle document diff --git a/lib/axlsx/stylesheet/num_fmt.rb b/lib/axlsx/stylesheet/num_fmt.rb index 8276ba18..1072d18a 100644 --- a/lib/axlsx/stylesheet/num_fmt.rb +++ b/lib/axlsx/stylesheet/num_fmt.rb @@ -73,5 +73,14 @@ module Axlsx serialized_tag('numFmt', str) end + # Override to avoid removing underscores + def serialized_attributes(str = '', additional_attributes = {}) + attributes = declared_attributes.merge! additional_attributes + attributes.each do |key, value| + str << "#{Axlsx.camel(key, false)}=\"#{Axlsx.booleanize(value)}\" " + end + str + end + end end diff --git a/lib/axlsx/util/constants.rb b/lib/axlsx/util/constants.rb index ea9b1ceb..64bae270 100644 --- a/lib/axlsx/util/constants.rb +++ b/lib/axlsx/util/constants.rb @@ -67,7 +67,7 @@ module Axlsx APP_R = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties".freeze # core rels namespace - CORE_R = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/metadata/core-properties".freeze + CORE_R = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties".freeze # digital signature rels namespace DIGITAL_SIGNATURE_R = "http://schemas.openxmlformats.org/package/2006/relationships/digital- signature/signature".freeze diff --git a/lib/axlsx/util/simple_typed_list.rb b/lib/axlsx/util/simple_typed_list.rb index 95f5b3f2..77bed775 100644 --- a/lib/axlsx/util/simple_typed_list.rb +++ b/lib/axlsx/util/simple_typed_list.rb @@ -147,7 +147,7 @@ module Axlsx # determines if the index is protected # @param [Integer] index def protected? index - return false unless locked_at.is_a? Fixnum + return false unless locked_at.is_a? Integer index < locked_at end diff --git a/lib/axlsx/util/validators.rb b/lib/axlsx/util/validators.rb index 9c6f34aa..2b4afd8d 100644 --- a/lib/axlsx/util/validators.rb +++ b/lib/axlsx/util/validators.rb @@ -80,16 +80,16 @@ module Axlsx end UINT_VALIDATOR = lambda { |arg| arg.respond_to?(:>=) && arg >= 0 } - - # Requires that the value is a Fixnum or Integer and is greater or equal to 0 + + # Requires that the value is a Integer and is greater or equal to 0 # @param [Any] v The value validated - # @raise [ArgumentError] raised if the value is not a Fixnum or Integer value greater or equal to 0 + # @raise [ArgumentError] raised if the value is not a Integer value greater or equal to 0 # @return [Boolean] true if the data is valid def self.validate_unsigned_int(v) DataTypeValidator.validate(:unsigned_int, Integer, v, UINT_VALIDATOR) end - # Requires that the value is a Fixnum Integer or Float and is greater or equal to 0 + # Requires that the value is a Integer or Float and is greater or equal to 0 # @param [Any] v The value validated # @raise [ArgumentError] raised if the value is not a Fixnun, Integer, Float value greater or equal to 0 # @return [Boolean] true if the data is valid @@ -104,7 +104,7 @@ module Axlsx end # Requires that the value is a form that can be evaluated as a boolean in an xml document. - # The value must be an instance of Fixnum, String, Integer, Symbol, TrueClass or FalseClass and + # The value must be an instance of String, Integer, Symbol, TrueClass or FalseClass and # it must be one of 0, 1, "true", "false", :true, :false, true, false, "0", or "1" # @param [Any] v The value validated def self.validate_boolean(v) diff --git a/lib/axlsx/workbook/workbook.rb b/lib/axlsx/workbook/workbook.rb index ddb13600..4ba44adb 100644 --- a/lib/axlsx/workbook/workbook.rb +++ b/lib/axlsx/workbook/workbook.rb @@ -11,6 +11,7 @@ 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' +require 'axlsx/workbook/worksheet/outline_pr.rb' require 'axlsx/workbook/worksheet/page_setup.rb' require 'axlsx/workbook/worksheet/header_footer.rb' require 'axlsx/workbook/worksheet/print_options.rb' diff --git a/lib/axlsx/workbook/worksheet/cell.rb b/lib/axlsx/workbook/worksheet/cell.rb index cd832f7b..777b7812 100644 --- a/lib/axlsx/workbook/worksheet/cell.rb +++ b/lib/axlsx/workbook/worksheet/cell.rb @@ -66,7 +66,7 @@ module Axlsx :vertAlign, :sz, :color, :scheme].freeze CELL_TYPES = [:date, :time, :float, :integer, :richtext, - :string, :boolean, :iso_8601].freeze + :string, :boolean, :iso_8601, :text].freeze # The index of the cellXfs item to be applied to this cell. # @return [Integer] @@ -123,7 +123,7 @@ module Axlsx # Indicates if the cell is good for shared string table def plain_string? - type == :string && # String typed + (type == :string || type == :text) && # String typed !is_text_run? && # No inline styles [email protected]? && # Not nil [email protected]? && # Not empty @@ -368,7 +368,7 @@ module Axlsx # TODO find a better way to do this as it accounts for 30% of # processing time in benchmarking... def clean_value - if type == :string && !Axlsx::trust_input + if (type == :string || type == :text) && !Axlsx::trust_input Axlsx::sanitize(::CGI.escapeHTML(@value.to_s)) else @value.to_s diff --git a/lib/axlsx/workbook/worksheet/cell_serializer.rb b/lib/axlsx/workbook/worksheet/cell_serializer.rb index 9a9f9465..76a3c386 100644 --- a/lib/axlsx/workbook/worksheet/cell_serializer.rb +++ b/lib/axlsx/workbook/worksheet/cell_serializer.rb @@ -14,7 +14,7 @@ module Axlsx method = cell.type self.send(method, cell, str) str << '</c>' - end + end # builds an xml text run based on this cells attributes. # @param [String] str The string instance this run will be concated to. @@ -22,7 +22,7 @@ module Axlsx def run_xml_string(cell, str = '') if cell.is_text_run? valid = RichTextRun::INLINE_STYLES - [:value, :type] - data = Hash[cell.instance_values.map{ |k, v| [k.to_sym, v] }] + data = Hash[cell.instance_values.map{ |k, v| [k.to_sym, v] }] data = data.select { |key, value| valid.include?(key) && !value.nil? } RichText.new(cell.value.to_s, data).to_xml_string(str) elsif cell.contains_rich_text? @@ -124,7 +124,7 @@ module Axlsx inline_string_serialization cell, str end end - + # Serializes cells that are of the type richtext # @param [Cell] cell The cell that is being serialized # @param [String] str The string the serialized content will be appended to. @@ -137,6 +137,18 @@ module Axlsx end end + # Serializes cells that are of the type text + # @param [Cell] cell The cell that is being serialized + # @param [String] str The string the serialized content will be appended to. + # @return [String] + def text(cell, str) + if cell.ssti.nil? + inline_string_serialization cell, str + else + value_serialization 's', cell.ssti, str + end + end + private def numeric(cell, str = '') diff --git a/lib/axlsx/workbook/worksheet/merged_cells.rb b/lib/axlsx/workbook/worksheet/merged_cells.rb index 6ea1edc9..67753bd3 100644 --- a/lib/axlsx/workbook/worksheet/merged_cells.rb +++ b/lib/axlsx/workbook/worksheet/merged_cells.rb @@ -19,6 +19,8 @@ module Axlsx cells elsif cells.is_a?(Array) Axlsx::cell_range(cells, false) + elsif cells.is_a?(Row) + Axlsx::cell_range(cells, false) end end diff --git a/lib/axlsx/workbook/worksheet/outline_pr.rb b/lib/axlsx/workbook/worksheet/outline_pr.rb new file mode 100644 index 00000000..ae9ccf38 --- /dev/null +++ b/lib/axlsx/workbook/worksheet/outline_pr.rb @@ -0,0 +1,33 @@ +module Axlsx + + # The OutlinePr class manages serialization of a worksheet's outlinePr element, which provides various + # options to control outlining. + class OutlinePr + include Axlsx::OptionsParser + include Axlsx::Accessors + include Axlsx::SerializedAttributes + + serializable_attributes :summary_below, + :summary_right, + :apply_styles + + # These attributes are all boolean so I'm doing a bit of a hand + # waving magic show to set up the attriubte accessors + boolean_attr_accessor :summary_below, + :summary_right, + :apply_styles + + # Creates a new OutlinePr object + # @param [Worksheet] worksheet The worksheet that owns this OutlinePr object + def initialize(options = {}) + parse_options options + end + + # Serialize the object + # @param [String] str serialized output will be appended to this object if provided. + # @return [String] + def to_xml_string(str = '') + str << "<outlinePr #{serialized_attributes} />" + end + end +end diff --git a/lib/axlsx/workbook/worksheet/pivot_table.rb b/lib/axlsx/workbook/worksheet/pivot_table.rb index 0d5f34e8..fffced0b 100644 --- a/lib/axlsx/workbook/worksheet/pivot_table.rb +++ b/lib/axlsx/workbook/worksheet/pivot_table.rb @@ -25,10 +25,20 @@ module Axlsx @data = [] @pages = [] @subtotal = nil + @no_subtotals_on_headers = [] + @style_info = {} parse_options options yield self if block_given? end + # Defines the headers in which subtotals are not to be included + # @return[Array] + attr_accessor :no_subtotals_on_headers + + # Style info for the pivot table + # @return[Hash] + attr_accessor :style_info + # The reference to the table data # @return [String] attr_reader :ref @@ -163,7 +173,7 @@ module Axlsx str << ( '<location firstDataCol="1" firstDataRow="1" firstHeaderRow="1" ref="' << ref << '"/>') str << ( '<pivotFields count="' << header_cells_count.to_s << '">') header_cell_values.each do |cell_value| - str << pivot_field_for(cell_value) + str << pivot_field_for(cell_value,!no_subtotals_on_headers.include?(cell_value)) end str << '</pivotFields>' if rows.empty? @@ -200,12 +210,21 @@ module Axlsx unless data.empty? str << "<dataFields count=\"#{data.size}\">" data.each do |datum_value| - str << "<dataField name='#{@subtotal} of #{datum_value[:ref]}' fld='#{header_index_of(datum_value[:ref])}' baseField='0' baseItem='0'" + # The correct name prefix in ["Sum","Average", etc...] + str << "<dataField name='#{(datum_value[:subtotal]||'')} of #{datum_value[:ref]}' fld='#{header_index_of(datum_value[:ref])}' baseField='0' baseItem='0'" str << " subtotal='#{datum_value[:subtotal]}' " if datum_value[:subtotal] str << "/>" end str << '</dataFields>' end + # custom pivot table style + unless style_info.empty? + str << '<pivotTableStyleInfo' + style_info.each do |k,v| + str << ' ' << k.to_s << '="' << v.to_s << '"' + end + str << ' />' + end str << '</pivotTableDefinition>' end @@ -241,13 +260,17 @@ module Axlsx private - def pivot_field_for(cell_ref) + def pivot_field_for(cell_ref, subtotal=true) if rows.include? cell_ref - '<pivotField axis="axisRow" compact="0" outline="0" subtotalTop="0" showAll="0" includeNewItemsInFilter="1">' + '<items count="1"><item t="default"/></items>' + '</pivotField>' + if subtotal + '<pivotField axis="axisRow" compact="0" outline="0" subtotalTop="0" showAll="0" includeNewItemsInFilter="1">' + '<items count="1"><item t="default"/></items>' + '</pivotField>' + else + '<pivotField axis="axisRow" compact="0" outline="0" subtotalTop="0" showAll="0" includeNewItemsInFilter="1" defaultSubtotal="0">' + '</pivotField>' + end elsif columns.include? cell_ref '<pivotField axis="axisCol" compact="0" outline="0" subtotalTop="0" showAll="0" includeNewItemsInFilter="1">' + '<items count="1"><item t="default"/></items>' + '</pivotField>' elsif pages.include? cell_ref - '<pivotField axis="axisCol" compact="0" outline="0" subtotalTop="0" showAll="0" includeNewItemsInFilter="1">' + '<items count="1"><item t="default"/></items>' + '</pivotField>' + '<pivotField axis="axisPage" compact="0" outline="0" subtotalTop="0" showAll="0" includeNewItemsInFilter="1">' + '<items count="1"><item t="default"/></items>' + '</pivotField>' elsif data_refs.include? cell_ref '<pivotField dataField="1" compact="0" outline="0" subtotalTop="0" showAll="0" includeNewItemsInFilter="1">' + '</pivotField>' else diff --git a/lib/axlsx/workbook/worksheet/row.rb b/lib/axlsx/workbook/worksheet/row.rb index 078e281f..b394279f 100644 --- a/lib/axlsx/workbook/worksheet/row.rb +++ b/lib/axlsx/workbook/worksheet/row.rb @@ -103,6 +103,13 @@ module Axlsx c end + # sets the color for every cell in this row + def color=(color) + each_with_index do | cell, index | + cell.color = color.is_a?(Array) ? color[index] : color + end + end + # sets the style for every cell in this row def style=(style) each_with_index do | cell, index | diff --git a/lib/axlsx/workbook/worksheet/sheet_pr.rb b/lib/axlsx/workbook/worksheet/sheet_pr.rb index a299bc0f..fd6dad2b 100644 --- a/lib/axlsx/workbook/worksheet/sheet_pr.rb +++ b/lib/axlsx/workbook/worksheet/sheet_pr.rb @@ -1,6 +1,6 @@ module Axlsx - # The SheetPr class manages serialization fo a worksheet's sheetPr element. + # The SheetPr class manages serialization of a worksheet's sheetPr element. class SheetPr include Axlsx::OptionsParser include Axlsx::Accessors @@ -33,6 +33,7 @@ module Axlsx def initialize(worksheet, options={}) raise ArgumentError, "you must provide a worksheet" unless worksheet.is_a?(Worksheet) @worksheet = worksheet + @outline_pr = nil parse_options options end @@ -51,6 +52,7 @@ module Axlsx update_properties str << "<sheetPr #{serialized_attributes}>" tab_color.to_xml_string(str, 'tabColor') if tab_color + outline_pr.to_xml_string(str) if @outline_pr page_setup_pr.to_xml_string(str) str << "</sheetPr>" end @@ -60,6 +62,12 @@ module Axlsx def page_setup_pr @page_setup_pr ||= PageSetUpPr.new end + + # The OutlinePr for this sheet pr object + # @return [OutlinePr] + def outline_pr + @outline_pr ||= OutlinePr.new + end # @see tab_color def tab_color=(v) diff --git a/lib/axlsx/workbook/worksheet/worksheet.rb b/lib/axlsx/workbook/worksheet/worksheet.rb index dc8da53f..f094c5cd 100644 --- a/lib/axlsx/workbook/worksheet/worksheet.rb +++ b/lib/axlsx/workbook/worksheet/worksheet.rb @@ -27,7 +27,7 @@ module Axlsx yield self if block_given? end - serializable_attributes :sheet_id, :name, :state + serializable_attributes :sheet_id, :state # Initalizes page margin, setup and print options # @param [Hash] options Options passed in from the initializer @@ -264,7 +264,7 @@ module Axlsx @header_footer end - # convinience method to access all cells in this worksheet + # convenience method to access all cells in this worksheet # @return [Array] cells def cells rows.flatten @@ -555,7 +555,7 @@ module Axlsx # @example This would set the first and third column widhts but leave the second column in autofit state. # ws.column_widths 7.2, nil, 3 # @note For updating only a single column it is probably easier to just set the width of the ws.column_info[col_index].width directly - # @param [Integer|Float|Fixnum|nil] widths + # @param [Integer|Float|nil] widths def column_widths(*widths) widths.each_with_index do |value, index| next if value == nil @@ -597,6 +597,7 @@ module Axlsx add_autofilter_defined_name_to_workbook str << '<sheet ' serialized_attributes str + str << ('name="' << name << '" ') str << ('r:id="' << rId << '"></sheet>') end diff --git a/test/stylesheet/tc_styles.rb b/test/stylesheet/tc_styles.rb index 98c8e3ef..eb1680ad 100644 --- a/test/stylesheet/tc_styles.rb +++ b/test/stylesheet/tc_styles.rb @@ -133,7 +133,7 @@ class TestStyles < Test::Unit::TestCase :font_name => "woot font" } assert_equal(@styles.parse_font_options {}, nil, "noop if no font keys are set") - assert_equal(@styles.parse_font_options(:b=>1).class, Fixnum, "return index of font if not :dxf type") + assert(@styles.parse_font_options(:b=>1).is_a?(Integer), "return index of font if not :dxf type") assert_equal(@styles.parse_font_options(:b=>1, :type => :dxf).class, Axlsx::Font, "return font object if :dxf type") f = @styles.parse_font_options(options.merge(:type => :dxf)) @@ -147,7 +147,7 @@ class TestStyles < Test::Unit::TestCase def test_parse_fill_options assert_equal(@styles.parse_fill_options {}, nil, "noop if no fill keys are set") - assert_equal(@styles.parse_fill_options(:bg_color => "DE").class, Fixnum, "return index of fill if not :dxf type") + assert(@styles.parse_fill_options(:bg_color => "DE").is_a?(Integer), "return index of fill if not :dxf type") assert_equal(@styles.parse_fill_options(:bg_color => "DE", :type => :dxf).class, Axlsx::Fill, "return fill object if :dxf type") f = @styles.parse_fill_options(:bg_color => "DE", :type => :dxf) assert(f.fill_type.bgColor.rgb == "FFDEDEDE") diff --git a/test/tc_axlsx.rb b/test/tc_axlsx.rb index 1be9166c..99832f63 100644 --- a/test/tc_axlsx.rb +++ b/test/tc_axlsx.rb @@ -45,6 +45,16 @@ class TestAxlsx < Test::Unit::TestCase assert_equal(Axlsx.cell_range([c2, c1], true), "'Sheet <''>" 1'!$A$1:$B$1") end + def test_cell_range_row + p = Axlsx::Package.new + ws = p.workbook.add_worksheet + row = ws.add_row + row.add_cell + row.add_cell + row.add_cell + assert_equal("A1:C1", Axlsx.cell_range(row, false)) + end + def test_name_to_indices setup_wide @wide_test_points.each do |key, value| diff --git a/test/tc_helper.rb b/test/tc_helper.rb index 96f545cd..396f19b2 100644 --- a/test/tc_helper.rb +++ b/test/tc_helper.rb @@ -7,4 +7,6 @@ end require 'test/unit' require "timecop" -require "axlsx.rb"
\ No newline at end of file +require "axlsx.rb" +# MIME detection for Microsoft Office 2007+ formats +require 'mimemagic/overlay' diff --git a/test/tc_package.rb b/test/tc_package.rb index 0ad27f7d..58ff53b0 100644 --- a/test/tc_package.rb +++ b/test/tc_package.rb @@ -154,6 +154,11 @@ class TestPackage < Test::Unit::TestCase assert package_1.to_stream.string == package_2.to_stream.string, "zip files are not identical" end + def test_serialization_creates_files_with_excel_mime_type + assert_equal(MimeMagic.by_magic(@package.to_stream).type, + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') + end + def test_validation assert_equal(@package.validate.size, 0, @package.validate) Axlsx::Workbook.send(:class_variable_set, :@@date1904, 9900) diff --git a/test/util/tc_simple_typed_list.rb b/test/util/tc_simple_typed_list.rb index 1596ac13..72bd6246 100644 --- a/test/util/tc_simple_typed_list.rb +++ b/test/util/tc_simple_typed_list.rb @@ -1,7 +1,7 @@ require 'tc_helper.rb' class TestSimpleTypedList < Test::Unit::TestCase def setup - @list = Axlsx::SimpleTypedList.new Fixnum + @list = Axlsx::SimpleTypedList.new Integer end def teardown diff --git a/test/workbook/tc_workbook.rb b/test/workbook/tc_workbook.rb index 51dd01f4..ab400db1 100644 --- a/test/workbook/tc_workbook.rb +++ b/test/workbook/tc_workbook.rb @@ -136,4 +136,10 @@ class TestWorkbook < Test::Unit::TestCase doc = Nokogiri::XML(@wb.to_xml_string) assert_equal pivot_table.cache_definition.rId, doc.xpath("//xmlns:pivotCache").first["r:id"] end + + def test_worksheet_name_is_intact_after_serialized_into_xml + sheet = @wb.add_worksheet(:name => '_Example') + wb_xml = Nokogiri::XML(@wb.to_xml_string) + assert_equal sheet.name, wb_xml.xpath('//xmlns:workbook/xmlns:sheets/*[1]/@name').to_s + end end diff --git a/test/workbook/worksheet/tc_cell.rb b/test/workbook/worksheet/tc_cell.rb index 5ae2a51f..f61a254f 100644 --- a/test/workbook/worksheet/tc_cell.rb +++ b/test/workbook/worksheet/tc_cell.rb @@ -238,7 +238,7 @@ class TestCell < Test::Unit::TestCase @c.merge @row.cells.last assert_equal(@c.row.worksheet.send(:merged_cells).last, "A1:C1") end - + def test_reverse_merge_with_cell @c.row.add_cell 2 @c.row.add_cell 3 @@ -284,7 +284,7 @@ class TestCell < Test::Unit::TestCase c_xml = Nokogiri::XML(@c.to_xml_string(1,1)) assert_equal(c_xml.xpath("/c[@s=1]").size, 1) end - + def test_to_xml_string_with_run # Actually quite a number of similar run styles # but the processing should be the same @@ -294,7 +294,7 @@ class TestCell < Test::Unit::TestCase @c.font_name = 'arial' @c.color = 'FF0000' c_xml = Nokogiri::XML(@c.to_xml_string(1,1)) - assert(c_xml.xpath("//b")) + assert(c_xml.xpath("//b").any?) end def test_to_xml_string_formula @@ -303,8 +303,8 @@ class TestCell < Test::Unit::TestCase sheet.add_row ["=IF(2+2=4,4,5)"] end doc = Nokogiri::XML(ws.to_xml_string) - assert(doc.xpath("//f[@text()='IF(2+2=4,4,5)']")) - + doc.remove_namespaces! + assert(doc.xpath("//f[text()='IF(2+2=4,4,5)']").any?) end def test_to_xml_string_array_formula @@ -314,9 +314,24 @@ class TestCell < Test::Unit::TestCase end doc = Nokogiri::XML(ws.to_xml_string) doc.remove_namespaces! - assert(doc.xpath("//f[text()='SUM(C2:C11*D2:D11)']")) - assert(doc.xpath("//f[@t='array']")) - assert(doc.xpath("//f[@ref='A1']")) + assert(doc.xpath("//f[text()='SUM(C2:C11*D2:D11)']").any?) + assert(doc.xpath("//f[@t='array']").any?) + assert(doc.xpath("//f[@ref='A1']").any?) + end + + def test_to_xml_string_text_formula + p = Axlsx::Package.new + ws = p.workbook.add_worksheet do |sheet| + sheet.add_row ["=1+1", "-1+1"], type: :text + end + doc = Nokogiri::XML(ws.to_xml_string) + doc.remove_namespaces! + + assert(doc.xpath("//f[text()='1+1']").empty?) + assert(doc.xpath("//t[text()='=1+1']").any?) + + assert(doc.xpath("//f[text()='1+1']").empty?) + assert(doc.xpath("//t[text()='-1+1']").any?) end def test_font_size_with_custom_style_and_no_sz @@ -335,17 +350,17 @@ class TestCell < Test::Unit::TestCase sz = @c.send(:font_size) assert_equal(sz, 52) end - + def test_cell_with_sz @c.sz = 25 assert_equal(25, @c.send(:font_size)) end - + def test_to_xml # TODO This could use some much more stringent testing related to the xml content generated! @ws.add_row [Time.now, Date.today, true, 1, 1.0, "text", "=sum(A1:A2)", "2013-01-13T13:31:25.123"] @ws.rows.last.cells[5].u = true - + schema = Nokogiri::XML::Schema(File.open(Axlsx::SML_XSD)) doc = Nokogiri::XML(@ws.to_xml_string) errors = [] diff --git a/test/workbook/worksheet/tc_outline_pr.rb b/test/workbook/worksheet/tc_outline_pr.rb new file mode 100644 index 00000000..41a2b4ca --- /dev/null +++ b/test/workbook/worksheet/tc_outline_pr.rb @@ -0,0 +1,19 @@ +require 'tc_helper.rb' + +class TestOutlinePr < Test::Unit::TestCase + def setup + @outline_pr = Axlsx::OutlinePr.new(:summary_below => false, :summary_right => true, :apply_styles => false) + end + + def test_summary_below + assert_equal false, @outline_pr.summary_below + end + + def test_summary_right + assert_equal true, @outline_pr.summary_right + end + + def test_apply_styles + assert_equal false, @outline_pr.apply_styles + end +end diff --git a/test/workbook/worksheet/tc_pivot_table.rb b/test/workbook/worksheet/tc_pivot_table.rb index 3c42d605..ff7f8b92 100644 --- a/test/workbook/worksheet/tc_pivot_table.rb +++ b/test/workbook/worksheet/tc_pivot_table.rb @@ -67,6 +67,26 @@ class TestPivotTable < Test::Unit::TestCase assert_equal([{:ref=>"Sales", :subtotal => 'average'}], pivot_table.data) end + def test_add_pivot_table_with_style_info + style_info_data = { :name=>"PivotStyleMedium9", :showRowHeaders=>"1", :showLastColumn=>"0"} + pivot_table = @ws.add_pivot_table('G5:G6', 'A1:E5', {:style_info=>style_info_data}) do |pt| + pt.rows = ['Year', 'Month'] + pt.columns = ['Type'] + pt.data = ['Sales'] + pt.pages = ['Region'] + end + assert_equal(style_info_data, pivot_table.style_info) + shared_test_pivot_table_xml_validity(pivot_table) + end + + def test_add_pivot_table_with_row_without_subtotals + pivot_table = @ws.add_pivot_table('G5:G6', 'A1:D5', {:no_subtotals_on_headers=>['Year']}) do |pt| + pt.data = ['Sales'] + pt.rows = ['Year','Month'] + end + assert_equal(['Year'], pivot_table.no_subtotals_on_headers) + end + def test_header_indices pivot_table = @ws.add_pivot_table('G5:G6', 'A1:E5') assert_equal(0, pivot_table.header_index_of('Year' )) diff --git a/test/workbook/worksheet/tc_row.rb b/test/workbook/worksheet/tc_row.rb index 808e0138..43e7d23f 100644 --- a/test/workbook/worksheet/tc_row.rb +++ b/test/workbook/worksheet/tc_row.rb @@ -27,6 +27,11 @@ class TestRow < Test::Unit::TestCase r.cells.each { |c| assert_equal(c.style,1) } end + def test_color + r = @ws.add_row([1,2,3,4,5]) + r.color = "FF00FF00" + r.cells.each { |c| assert_equal(c.color.rgb, "FF00FF00") } + end def test_index assert_equal(@row.row_index, @row.worksheet.rows.index(@row)) diff --git a/test/workbook/worksheet/tc_worksheet.rb b/test/workbook/worksheet/tc_worksheet.rb index eb668d7f..166850e5 100644 --- a/test/workbook/worksheet/tc_worksheet.rb +++ b/test/workbook/worksheet/tc_worksheet.rb @@ -323,6 +323,13 @@ class TestWorksheet < Test::Unit::TestCase assert_equal(doc.xpath('//xmlns:worksheet/xmlns:mergeCells/xmlns:mergeCell[@ref="E1:F1"]').size, 1) end + def test_to_xml_string_merge_cells_row + row = @ws.add_row [1, "two"] + @ws.merge_cells row + doc = Nokogiri::XML(@ws.to_xml_string) + assert_equal(doc.xpath('//xmlns:worksheet/xmlns:mergeCells/xmlns:mergeCell[@ref="A1:B1"]').size, 1) + end + def test_to_xml_string_row_breaks @ws.add_page_break("A1") doc = Nokogiri::XML(@ws.to_xml_string) @@ -476,7 +483,7 @@ class TestWorksheet < Test::Unit::TestCase @ws.column_widths nil, 0.5 assert_equal(@ws.column_info[1].width, 0.5, 'eat my width') assert_raise(ArgumentError, 'only accept unsigned ints') { @ws.column_widths 2, 7, -1 } - assert_raise(ArgumentError, 'only accept Integer, Float or Fixnum') { @ws.column_widths 2, 7, "-1" } + assert_raise(ArgumentError, 'only accept Integer or Float') { @ws.column_widths 2, 7, "-1" } end def test_protect_range @@ -573,5 +580,15 @@ class TestWorksheet < Test::Unit::TestCase assert_raise(ArgumentError) { @wb.add_worksheet(:name => 'Sheet1') } assert_equal(1, @wb.worksheets.size) end + + def test_worksheet_only_includes_outline_pr_when_set + doc = Nokogiri::XML(@ws.to_xml_string) + assert_equal(doc.xpath('//xmlns:worksheet/xmlns:sheetPr/xmlns:outlinePr').size, 0) + @ws.sheet_pr.outline_pr.summary_below = false + @ws.sheet_pr.outline_pr.summary_right = true + doc = Nokogiri::XML(@ws.to_xml_string) + assert_equal(doc.xpath('//xmlns:worksheet/xmlns:sheetPr/xmlns:outlinePr').size, 1) + assert_equal(doc.xpath('//xmlns:worksheet/xmlns:sheetPr/xmlns:outlinePr[@summaryBelow=0][@summaryRight=1]').size, 1) + end end |
