summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--README.md8
-rw-r--r--cd1
-rw-r--r--examples/underline.rb13
-rw-r--r--exclusive.rb32
-rw-r--r--lib/axlsx/doc_props/core.rb7
-rw-r--r--lib/axlsx/drawing/axes.rb10
-rw-r--r--lib/axlsx/drawing/bar_3D_chart.rb4
-rw-r--r--lib/axlsx/drawing/chart.rb18
-rw-r--r--lib/axlsx/package.rb14
-rw-r--r--lib/axlsx/util/validators.rb7
-rw-r--r--lib/axlsx/workbook/worksheet/conditional_formatting_rule.rb2
-rw-r--r--lib/axlsx/workbook/worksheet/worksheet.rb9
-rw-r--r--test/doc_props/tc_core.rb7
-rw-r--r--test/drawing/tc_axes.rb8
-rw-r--r--test/drawing/tc_bar_3D_chart.rb6
-rw-r--r--test/drawing/tc_chart.rb14
-rw-r--r--test/tc_package.rb6
-rw-r--r--test/workbook/worksheet/tc_conditional_formatting.rb6
-rw-r--r--test/workbook/worksheet/tc_worksheet.rb7
19 files changed, 158 insertions, 21 deletions
diff --git a/README.md b/README.md
index 20f67088..ff3fe557 100644
--- a/README.md
+++ b/README.md
@@ -21,7 +21,7 @@ appreciation for the gem, please don't hesitate to make a donation.
**License**: MIT License
-**Latest Version**: 1.3.6
+**Latest Version**: 1.3.7
**Ruby Version**: 1.8.7 (soon to be depreciated!!!), 1.9.2, 1.9.3, 2.0.0
@@ -29,7 +29,7 @@ appreciation for the gem, please don't hesitate to make a donation.
**Rubinius Version**: rubinius 2.0.0dev * lower versions may run, this gem always tests against head.
-**Release Date**: April 24th 2013
+**Release Date**: June ? 2013
If you are working in rails, or with active record see:
[acts_as_xlsx](http://github.com/randym/acts_as_xlsx)
@@ -160,7 +160,9 @@ This gem has 100% test coverage using test/unit. To execute tests for this gem,
#Change log
---------
-- **April.??.13**:1.37
+- **June.?.13**:1.3.7
+ - Bugfix: transposition of cells for Worksheet#cols now supports
+ incongruent column counts.counts
- Added space preservation for cell text. This will allow whitespace
in cell text both when using shared strings and when serializing
directly to the cell.
diff --git a/cd b/cd
new file mode 100644
index 00000000..8588caed
--- /dev/null
+++ b/cd
@@ -0,0 +1 @@
+/opt/boxen/rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/gems/axlsx-1.3.6/lib/axlsx.rb
diff --git a/examples/underline.rb b/examples/underline.rb
new file mode 100644
index 00000000..ccd1b394
--- /dev/null
+++ b/examples/underline.rb
@@ -0,0 +1,13 @@
+$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib"
+require 'axlsx'
+p = Axlsx::Package.new
+p.workbook do |wb|
+ wb.styles do |s|
+ no_underline = s.add_style :sz => 10, :b => true, :u => false, :alignment => { :horizontal=> :right }
+ wb.add_worksheet(:name => 'wunderlinen') do |sheet|
+ sheet.add_row %w{a b c really?}, :style => no_underline
+ end
+ end
+end
+p.serialize 'no_underline.xlsx'
+
diff --git a/exclusive.rb b/exclusive.rb
new file mode 100644
index 00000000..71339146
--- /dev/null
+++ b/exclusive.rb
@@ -0,0 +1,32 @@
+
+def exclusively_true(hash, key)
+ #clone = hash.clone
+ return false unless hash.delete(key) == true
+ !hash.has_value? true
+end
+
+require 'test/unit'
+class TestExclusive < Test::Unit::TestCase
+ def setup
+ @test_hash = {foo: true, bar: false, hoge: false}
+ end
+ def test_exclusive
+ assert_equal(true, exclusively_true(@test_hash, :foo))
+ end
+ def test_inexclusive
+ @test_hash[:bar] = true
+ assert_equal(false, exclusively_true(@test_hash, :foo))
+ end
+end
+
+require 'benchmark'
+
+h = {foo: true}
+999.times {|i| h["a#{i}"] = false}
+Benchmark.bmbm(30) do |x|
+ x.report('exclusively_true') do
+ 1000.times do
+ exclusively_true(h, :foo)
+ end
+ end
+end
diff --git a/lib/axlsx/doc_props/core.rb b/lib/axlsx/doc_props/core.rb
index d71300e0..a74031f2 100644
--- a/lib/axlsx/doc_props/core.rb
+++ b/lib/axlsx/doc_props/core.rb
@@ -8,14 +8,19 @@ module Axlsx
# Creates a new Core object.
# @option options [String] creator
+ # @option options [Time] created
def initialize(options={})
@creator = options[:creator] || 'axlsx'
+ @created = options[:created]
end
# The author of the document. By default this is 'axlsx'
# @return [String]
attr_accessor :creator
+ # Creation time of the document. If nil, the current time will be used.
+ attr_accessor :created
+
# serializes the core.xml document
# @return [String]
def to_xml_string(str = '')
@@ -24,7 +29,7 @@ module Axlsx
str << 'xmlns:dcmitype="' << CORE_NS_DCMIT << '" xmlns:dcterms="' << CORE_NS_DCT << '" '
str << 'xmlns:xsi="' << CORE_NS_XSI << '">'
str << '<dc:creator>' << self.creator << '</dc:creator>'
- str << '<dcterms:created xsi:type="dcterms:W3CDTF">' << Time.now.strftime('%Y-%m-%dT%H:%M:%S') << 'Z</dcterms:created>'
+ str << '<dcterms:created xsi:type="dcterms:W3CDTF">' << (created || Time.now).strftime('%Y-%m-%dT%H:%M:%S') << 'Z</dcterms:created>'
str << '<cp:revision>0</cp:revision>'
str << '</cp:coreProperties>'
end
diff --git a/lib/axlsx/drawing/axes.rb b/lib/axlsx/drawing/axes.rb
index c3a8dd85..bc40e532 100644
--- a/lib/axlsx/drawing/axes.rb
+++ b/lib/axlsx/drawing/axes.rb
@@ -5,9 +5,11 @@ module Axlsx
class Axes
# @param [Hash] options options used to generate axis each key
- # should be an axis name like :val_axix and its value should be the
- # class of the axis type to construct.
+ # should be an axis name like :val_axis and its value should be the
+ # class of the axis type to construct. The :cat_axis, if there is one,
+ # must come first (we assume a Ruby 1.9+ Hash or an OrderedHash).
def initialize(options={})
+ raise(ArgumentError, "CatAxis must come first") if options.keys.include?(:cat_axis) && options.keys.first != :cat_axis
options.each do |name, axis_class|
add_axis(name, axis_class)
end
@@ -28,7 +30,9 @@ module Axlsx
# serialized. Otherwise, each axis is serialized in full.
def to_xml_string(str = '', options = {})
if options[:ids]
- axes.inject(str) { |string, axis| string << '<c:axId val="' << axis[1].id.to_s << '"/>' }
+ # CatAxis must come first in the XML (for Microsoft Excel at least)
+ sorted = axes.sort_by { |name, axis| axis.kind_of?(CatAxis) ? 0 : 1 }
+ sorted.inject(str) { |string, axis| string << '<c:axId val="' << axis[1].id.to_s << '"/>' }
else
axes.each { |axis| axis[1].to_xml_string(str) }
end
diff --git a/lib/axlsx/drawing/bar_3D_chart.rb b/lib/axlsx/drawing/bar_3D_chart.rb
index 3315ad80..755f334c 100644
--- a/lib/axlsx/drawing/bar_3D_chart.rb
+++ b/lib/axlsx/drawing/bar_3D_chart.rb
@@ -142,10 +142,10 @@ module Axlsx
end
# A hash of axes used by this chart. Bar charts have a value and
- # category axes specified via axex[:val_axes] and axes[:cat_axis]
+ # category axes specified via axes[:val_axes] and axes[:cat_axis]
# @return [Axes]
def axes
- @axes ||= Axes.new(:val_axis => ValAxis, :cat_axis => CatAxis)
+ @axes ||= Axes.new(:cat_axis => CatAxis, :val_axis => ValAxis)
end
end
end
diff --git a/lib/axlsx/drawing/chart.rb b/lib/axlsx/drawing/chart.rb
index 79019a0a..1da3a253 100644
--- a/lib/axlsx/drawing/chart.rb
+++ b/lib/axlsx/drawing/chart.rb
@@ -20,6 +20,7 @@ module Axlsx
@graphic_frame.anchor.drawing.worksheet.workbook.charts << self
@series = SimpleTypedList.new Series
@show_legend = true
+ @display_blanks_as = :gap
@series_type = Series
@title = Title.new
parse_options options
@@ -70,6 +71,15 @@ module Axlsx
# @return [Boolean]
attr_reader :show_legend
+ # How to display blank values
+ # Options are
+ # * gap: Display nothing
+ # * span: Not sure what this does
+ # * zero: Display as if the value were zero, not blank
+ # @return [Symbol]
+ # Default :gap (although this really should vary by chart type and grouping)
+ attr_reader :display_blanks_as
+
# returns a relationship object for the chart
# @return [Axlsx::Relationship]
def relationship
@@ -105,6 +115,12 @@ module Axlsx
# @return [Boolean]
def show_legend=(v) Axlsx::validate_boolean(v); @show_legend = v; end
+ # How to display blank values
+ # @see display_blanks_as
+ # @param [Symbol] v
+ # @return [Symbol]
+ def display_blanks_as=(v) Axlsx::validate_display_blanks_as(v); @display_blanks_as = v; end
+
# The style for the chart.
# see ECMA Part 1 ยง21.2.2.196
# @param [Integer] v must be between 1 and 48
@@ -157,7 +173,7 @@ module Axlsx
str << '</c:legend>'
end
str << '<c:plotVisOnly val="1"/>'
- str << '<c:dispBlanksAs val="zero"/>'
+ str << '<c:dispBlanksAs val="' << display_blanks_as.to_s << '"/>'
str << '<c:showDLblsOverMax val="1"/>'
str << '</c:chart>'
str << '<c:printSettings>'
diff --git a/lib/axlsx/package.rb b/lib/axlsx/package.rb
index df87ed12..37620b48 100644
--- a/lib/axlsx/package.rb
+++ b/lib/axlsx/package.rb
@@ -17,12 +17,14 @@ module Axlsx
#
# @param [Hash] options A hash that you can use to specify the author and workbook for this package.
# @option options [String] :author The author of the document
+ # @option options [Time] :created_at Timestamp in the document properties (defaults to current time).
# @option options [Boolean] :use_shared_strings This is passed to the workbook to specify that shared strings should be used when serializing the package.
# @example Package.new :author => 'you!', :workbook => Workbook.new
def initialize(options={})
@workbook = nil
@core, @app = Core.new, App.new
@core.creator = options[:author] || @core.creator
+ @core.created = options[:created_at]
parse_options options
yield self if block_given?
end
@@ -35,12 +37,6 @@ module Axlsx
end
- # Shortcut to specify that the workbook should use shared strings
- # @see Workbook#use_shared_strings
- def use_shared_strings=(v)
- Axlsx::validate_boolean(v);
- workbook.use_shared_strings = v
- end
# Shortcut to determine if the workbook is configured to use shared strings
# @see Workbook#use_shared_strings
@@ -48,6 +44,12 @@ module Axlsx
workbook.use_shared_strings
end
+ # Shortcut to specify that the workbook should use shared strings
+ # @see Workbook#use_shared_strings
+ def use_shared_strings=(v)
+ Axlsx::validate_boolean(v);
+ workbook.use_shared_strings = v
+ end
# The workbook this package will serialize or validate.
# @return [Workbook] If no workbook instance has been assigned with this package a new Workbook instance is returned.
# @raise ArgumentError if workbook parameter is not a Workbook instance.
diff --git a/lib/axlsx/util/validators.rb b/lib/axlsx/util/validators.rb
index 739a4de2..a161f0d9 100644
--- a/lib/axlsx/util/validators.rb
+++ b/lib/axlsx/util/validators.rb
@@ -290,4 +290,11 @@ module Axlsx
def self.validate_split_state_type(v)
RestrictionValidator.validate :split_state_type, [:frozen, :frozen_split, :split], v
end
+
+ # Requires that the value is a valid "display blanks as" type.
+ # valid types must be one of gap, span, zero
+ # @param [Any] v The value validated
+ def self.validate_display_blanks_as(v)
+ RestrictionValidator.validate :display_blanks_as, [:gap, :span, :zero], v
+ end
end
diff --git a/lib/axlsx/workbook/worksheet/conditional_formatting_rule.rb b/lib/axlsx/workbook/worksheet/conditional_formatting_rule.rb
index 9db091be..916b31c2 100644
--- a/lib/axlsx/workbook/worksheet/conditional_formatting_rule.rb
+++ b/lib/axlsx/workbook/worksheet/conditional_formatting_rule.rb
@@ -182,7 +182,7 @@ module Axlsx
# @see timePeriod
def timePeriod=(v); Axlsx::validate_time_period_type(v); @timePeriod = v end
# @see formula
- def formula=(v); [*v].each {|x| Axlsx::validate_string(x) }; @formula = v end
+ def formula=(v); [*v].each {|x| Axlsx::validate_string(x) }; @formula = [*v].map { |form| ::CGI.escapeHTML(form) } end
# @see color_scale
def color_scale=(v)
diff --git a/lib/axlsx/workbook/worksheet/worksheet.rb b/lib/axlsx/workbook/worksheet/worksheet.rb
index 1187bf83..7324181a 100644
--- a/lib/axlsx/workbook/worksheet/worksheet.rb
+++ b/lib/axlsx/workbook/worksheet/worksheet.rb
@@ -115,8 +115,13 @@ module Axlsx
end
# returns the sheet data as columns
- def cols
- @rows.transpose
+ # If you pass a block, it will be evaluated whenever a row does not have a
+ # cell at a specific index. The block will be called with the row and column
+ # index in the missing cell was found.
+ # @example
+ # cols { |row_index, column_index| p "warn - row #{row_index} is does not have a cell at #{column_index}
+ def cols(&block)
+ @rows.transpose(&block)
end
# An range that excel will apply an auto-filter to "A1:B3"
diff --git a/test/doc_props/tc_core.rb b/test/doc_props/tc_core.rb
index cfff4d59..0eddfed7 100644
--- a/test/doc_props/tc_core.rb
+++ b/test/doc_props/tc_core.rb
@@ -23,6 +23,13 @@ class TestCore < Test::Unit::TestCase
assert_equal(@doc.xpath('//dcterms:created').text, @time, "dcterms:created incorrect")
end
+ def test_created_as_option
+ time = Time.utc(2013, 1, 1, 12, 00)
+ c = Axlsx::Core.new :created => time
+ doc = Nokogiri::XML(c.to_xml_string)
+ assert_equal(doc.xpath('//dcterms:created').text, time.xmlschema, "dcterms:created incorrect")
+ end
+
def test_populates_default_name
assert_equal(@doc.xpath('//dc:creator').text, "axlsx", "Default name not populated")
end
diff --git a/test/drawing/tc_axes.rb b/test/drawing/tc_axes.rb
new file mode 100644
index 00000000..e3c26936
--- /dev/null
+++ b/test/drawing/tc_axes.rb
@@ -0,0 +1,8 @@
+require 'tc_helper.rb'
+
+class TestAxes < Test::Unit::TestCase
+ def test_constructor_requires_cat_axis_first
+ assert_raise(ArgumentError) { Axlsx::Axes.new(:val_axis => Axlsx::ValAxis, :cat_axis => Axlsx::CatAxis) }
+ assert_nothing_raised { Axlsx::Axes.new(:cat_axis => Axlsx::CatAxis, :val_axis => Axlsx::ValAxis) }
+ end
+end \ No newline at end of file
diff --git a/test/drawing/tc_bar_3D_chart.rb b/test/drawing/tc_bar_3D_chart.rb
index 3e1ff342..0cae7af6 100644
--- a/test/drawing/tc_bar_3D_chart.rb
+++ b/test/drawing/tc_bar_3D_chart.rb
@@ -62,4 +62,10 @@ class TestBar3DChart < Test::Unit::TestCase
assert(errors.empty?, "error free validation")
end
+ def test_to_xml_string_has_axes_in_correct_order
+ str = @chart.to_xml_string
+ cat_axis_position = str.index(@chart.axes[:cat_axis].id.to_s)
+ val_axis_position = str.index(@chart.axes[:val_axis].id.to_s)
+ assert(cat_axis_position < val_axis_position, "cat_axis must occur earlier than val_axis in the XML")
+ end
end
diff --git a/test/drawing/tc_chart.rb b/test/drawing/tc_chart.rb
index 03e4fd6f..751d2ae4 100644
--- a/test/drawing/tc_chart.rb
+++ b/test/drawing/tc_chart.rb
@@ -45,6 +45,14 @@ class TestChart < Test::Unit::TestCase
assert_equal(false, @chart.vary_colors)
end
+ def test_display_blanks_as
+ assert_equal(:gap, @chart.display_blanks_as, "default is not :gap")
+ assert_raise(ArgumentError, "did not validate possible values") { @chart.display_blanks_as = :hole }
+ assert_nothing_raised { @chart.display_blanks_as = :zero }
+ assert_nothing_raised { @chart.display_blanks_as = :span }
+ assert_equal(:span, @chart.display_blanks_as)
+ end
+
def test_start_at
@chart.start_at 15, 25
assert_equal(@chart.graphic_frame.anchor.from.col, 15)
@@ -94,4 +102,10 @@ class TestChart < Test::Unit::TestCase
assert(errors.empty?, "error free validation")
end
+ def test_to_xml_string_for_display_blanks_as
+ schema = Nokogiri::XML::Schema(File.open(Axlsx::DRAWING_XSD))
+ @chart.display_blanks_as = :span
+ doc = Nokogiri::XML(@chart.to_xml_string)
+ assert_equal("span", doc.xpath("//c:dispBlanksAs").attr("val").value, "did not use the display_blanks_as configuration")
+ end
end
diff --git a/test/tc_package.rb b/test/tc_package.rb
index 5fd411e0..df096a31 100644
--- a/test/tc_package.rb
+++ b/test/tc_package.rb
@@ -105,6 +105,12 @@ class TestPackage < Test::Unit::TestCase
assert(Axlsx::Package.new.workbook.worksheets.size == 0, 'Workbook should not have sheets by default')
end
+ def test_created_at_is_propagated_to_core
+ time = Time.utc(2013, 1, 1, 12, 0)
+ p = Axlsx::Package.new :created_at => time
+ assert_equal(time, p.core.created)
+ end
+
def test_serialization
assert_nothing_raised do
begin
diff --git a/test/workbook/worksheet/tc_conditional_formatting.rb b/test/workbook/worksheet/tc_conditional_formatting.rb
index 42e29fa6..9e5e01cf 100644
--- a/test/workbook/worksheet/tc_conditional_formatting.rb
+++ b/test/workbook/worksheet/tc_conditional_formatting.rb
@@ -131,9 +131,11 @@ class TestConditionalFormatting < Test::Unit::TestCase
end
def test_multiple_formulas
- @ws.add_conditional_formatting "B3:B3", { :type => :cellIs, :dxfId => 0, :priority => 1, :operator => :between, :formula => ["1","5"] }
+ @ws.add_conditional_formatting "B3:B3", { :type => :cellIs, :dxfId => 0, :priority => 1, :operator => :between, :formula => ["1 <> 2","5"] }
doc = Nokogiri::XML.parse(@ws.to_xml_string)
- assert doc.xpath("//xmlns:worksheet/xmlns:conditionalFormatting//xmlns:cfRule[@type='cellIs'][@dxfId=0][@priority=1][@operator='between']//xmlns:formula='1'")
+ p doc.xpath("//xmlns:worksheet/xmlns:conditionalFormatting//xmlns:cfRule[@type='cellIs'][@dxfId=0][@priority=1][@operator='between']")
+
+ assert doc.xpath("//xmlns:worksheet/xmlns:conditionalFormatting//xmlns:cfRule[@type='cellIs'][@dxfId=0][@priority=1][@operator='between']//xmlns:formula='1 <> 2'")
assert doc.xpath("//xmlns:worksheet/xmlns:conditionalFormatting//xmlns:cfRule[@type='cellIs'][@dxfId=0][@priority=1][@operator='between']//xmlns:formula='5'")
end
diff --git a/test/workbook/worksheet/tc_worksheet.rb b/test/workbook/worksheet/tc_worksheet.rb
index b05a1c56..980c9e01 100644
--- a/test/workbook/worksheet/tc_worksheet.rb
+++ b/test/workbook/worksheet/tc_worksheet.rb
@@ -212,6 +212,13 @@ class TestWorksheet < Test::Unit::TestCase
assert_equal(c[0].value, 2)
end
+ def test_cols_with_block
+ @ws.add_row [1,2,3]
+ @ws.add_row [1]
+ cols = @ws.cols {|row, column| :foo }
+ assert_equal(:foo, cols[1][1])
+ end
+
def test_row_style
@ws.add_row [1,2,3,4]
@ws.add_row [1,2,3,4]