axlsx 1.3.5 → 1.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +9 -1
  3. data/README.md +26 -17
  4. data/examples/conditional_formatting/example_conditional_formatting.rb +4 -2
  5. data/examples/example.rb +22 -9
  6. data/examples/pivot_table.rb +0 -2
  7. data/lib/axlsx/drawing/axes.rb +57 -0
  8. data/lib/axlsx/drawing/axis.rb +16 -13
  9. data/lib/axlsx/drawing/bar_3D_chart.rb +16 -12
  10. data/lib/axlsx/drawing/cat_axis.rb +2 -10
  11. data/lib/axlsx/drawing/d_lbls.rb +1 -1
  12. data/lib/axlsx/drawing/drawing.rb +2 -0
  13. data/lib/axlsx/drawing/line_3D_chart.rb +27 -70
  14. data/lib/axlsx/drawing/line_chart.rb +99 -0
  15. data/lib/axlsx/drawing/line_series.rb +20 -2
  16. data/lib/axlsx/drawing/scatter_chart.rb +27 -17
  17. data/lib/axlsx/drawing/ser_axis.rb +15 -16
  18. data/lib/axlsx/drawing/val_axis.rb +14 -13
  19. data/lib/axlsx/drawing/vml_shape.rb +18 -77
  20. data/lib/axlsx/util/serialized_attributes.rb +0 -1
  21. data/lib/axlsx/version.rb +1 -1
  22. data/lib/axlsx/workbook/worksheet/comment.rb +10 -23
  23. data/lib/axlsx/workbook/worksheet/conditional_formatting_rule.rb +5 -3
  24. data/test/benchmark.rb +0 -1
  25. data/test/drawing/tc_axis.rb +15 -17
  26. data/test/drawing/tc_cat_axis.rb +9 -9
  27. data/test/drawing/tc_line_chart.rb +39 -0
  28. data/test/drawing/tc_line_series.rb +8 -2
  29. data/test/drawing/tc_ser_axis.rb +13 -12
  30. data/test/drawing/tc_val_axis.rb +6 -6
  31. data/test/drawing/tc_vml_shape.rb +9 -3
  32. data/test/profile.rb +5 -11
  33. data/test/tc_helper.rb +1 -0
  34. data/test/util/tc_validators.rb +5 -1
  35. data/test/workbook/worksheet/tc_comment.rb +5 -1
  36. data/test/workbook/worksheet/tc_comments.rb +2 -2
  37. data/test/workbook/worksheet/tc_conditional_formatting.rb +7 -0
  38. metadata +21 -55
@@ -4,95 +4,35 @@ module Axlsx
4
4
  class VmlShape
5
5
 
6
6
  include Axlsx::OptionsParser
7
+ include Axlsx::Accessors
7
8
 
8
9
  # Creates a new VmlShape
9
- # @option options [Integer|String] left_column
10
- # @option options [Integer|String] left_offset
11
- # @option options [Integer|String] top_row
12
- # @option options [Integer|String] top_offset
13
- # @option options [Integer|String] right_column
14
- # @option options [Integer|String] right_offset
15
- # @option options [Integer|String] bottom_row
16
- # @option options [Integer|String] bottom_offset
10
+ # @option options [Integer] row
11
+ # @option options [Integer] column
12
+ # @option options [Integer] left_column
13
+ # @option options [Integer] left_offset
14
+ # @option options [Integer] top_row
15
+ # @option options [Integer] top_offset
16
+ # @option options [Integer] right_column
17
+ # @option options [Integer] right_offset
18
+ # @option options [Integer] bottom_row
19
+ # @option options [Integer] bottom_offset
17
20
  def initialize(options={})
18
21
  @row = @column = @left_column = @top_row = @right_column = @bottom_row = 0
19
22
  @left_offset = 15
20
23
  @top_offset = 2
21
24
  @right_offset = 50
22
25
  @bottom_offset = 5
26
+ @visible = true
23
27
  @id = (0...8).map{65.+(rand(25)).chr}.join
24
28
  parse_options options
25
29
  yield self if block_given?
26
30
  end
27
31
 
28
- # The row anchor position for this shape determined by the comment's ref value
29
- # @return [Integer]
30
- attr_reader :row
32
+ unsigned_int_attr_accessor :row, :column, :left_column, :left_offset, :top_row, :top_offset,
33
+ :right_column, :right_offset, :bottom_row, :bottom_offset
31
34
 
32
- # The column anchor position for this shape determined by the comment's ref value
33
- # @return [Integer]
34
- attr_reader :column
35
-
36
- # The left column for this shape
37
- # @return [Integer]
38
- attr_reader :left_column
39
-
40
- # The left offset for this shape
41
- # @return [Integer]
42
- attr_reader :left_offset
43
-
44
- # The top row for this shape
45
- # @return [Integer]
46
- attr_reader :top_row
47
-
48
- # The top offset for this shape
49
- # @return [Integer]
50
- attr_reader :top_offset
51
-
52
- # The right column for this shape
53
- # @return [Integer]
54
- attr_reader :right_column
55
-
56
- # The right offset for this shape
57
- # @return [Integer]
58
- attr_reader :right_offset
59
-
60
- # The botttom row for this shape
61
- # @return [Integer]
62
- attr_reader :bottom_row
63
-
64
- # The bottom offset for this shape
65
- # @return [Integer]
66
- attr_reader :bottom_offset
67
-
68
- # @see column
69
- def column=(v); Axlsx::validate_integerish(v); @column = v.to_i end
70
-
71
- # @see row
72
- def row=(v); Axlsx::validate_integerish(v); @row = v.to_i end
73
- # @see left_column
74
- def left_column=(v); Axlsx::validate_integerish(v); @left_column = v.to_i end
75
-
76
- # @see left_offset
77
- def left_offset=(v); Axlsx::validate_integerish(v); @left_offset = v.to_i end
78
-
79
- # @see top_row
80
- def top_row=(v); Axlsx::validate_integerish(v); @top_row = v.to_i end
81
-
82
- # @see top_offset
83
- def top_offset=(v); Axlsx::validate_integerish(v); @top_offset = v.to_i end
84
-
85
- # @see right_column
86
- def right_column=(v); Axlsx::validate_integerish(v); @right_column = v.to_i end
87
-
88
- # @see right_offset
89
- def right_offset=(v); Axlsx::validate_integerish(v); @right_offset = v.to_i end
90
-
91
- # @see bottom_row
92
- def bottom_row=(v); Axlsx::validate_integerish(v); @bottom_row = v.to_i end
93
-
94
- # @see bottom_offset
95
- def bottom_offset=(v); Axlsx::validate_integerish(v); @bottom_offset = v.to_i end
35
+ boolean_attr_accessor :visible
96
36
 
97
37
  # serialize the shape to a string
98
38
  # @param [String] str
@@ -100,7 +40,8 @@ module Axlsx
100
40
  def to_xml_string(str ='')
101
41
  str << <<SHAME_ON_YOU
102
42
 
103
- <v:shape id="#{@id}" type="#_x0000_t202" fillcolor="#ffffa1 [80]" o:insetmode="auto">
43
+ <v:shape id="#{@id}" type="#_x0000_t202" fillcolor="#ffffa1 [80]" o:insetmode="auto"
44
+ style="visibility:#{@visible ? 'visible' : 'hidden'}">
104
45
  <v:fill color2="#ffffa1 [80]"/>
105
46
  <v:shadow on="t" obscured="t"/>
106
47
  <v:path o:connecttype="none"/>
@@ -115,7 +56,7 @@ str << <<SHAME_ON_YOU
115
56
  <x:AutoFill>False</x:AutoFill>
116
57
  <x:Row>#{row}</x:Row>
117
58
  <x:Column>#{column}</x:Column>
118
- <x:Visible/>
59
+ #{@visible ? '<x:Visible/>' : ''}
119
60
  </x:ClientData>
120
61
  </v:shape>
121
62
  SHAME_ON_YOU
@@ -59,7 +59,6 @@ module Axlsx
59
59
  # break the xml and 1.8.7 does not support ordered hashes.
60
60
  # @param [String] str The string instance to which serialized data is appended
61
61
  # @param [Array] additional_attributes An array of additional attribute names.
62
- # @param [Proc] block A which will be called with the value for each element.
63
62
  # @return [String] The serialized output.
64
63
  def serialized_element_attributes(str='', additional_attributes=[], &block)
65
64
  attrs = self.class.xml_element_attributes + additional_attributes
@@ -1,5 +1,5 @@
1
1
  module Axlsx
2
2
 
3
3
  # The current version
4
- VERSION = "1.3.5"
4
+ VERSION = "1.3.6"
5
5
  end
@@ -4,35 +4,33 @@ module Axlsx
4
4
  class Comment
5
5
 
6
6
  include Axlsx::OptionsParser
7
+ include Axlsx::Accessors
7
8
 
8
9
  # Creates a new comment object
9
- # @param [Comments] comments
10
+ # @param [Comments] comments The comment collection this comment belongs to
10
11
  # @param [Hash] options
11
12
  # @option [String] author the author of the comment
12
13
  # @option [String] text The text for the comment
14
+ # @option [String] ref The refence (e.g. 'A3' where this comment will be anchored.
15
+ # @option [Boolean] visible This controls the visiblity of the associated vml_shape.
13
16
  def initialize(comments, options={})
14
17
  raise ArgumentError, "A comment needs a parent comments object" unless comments.is_a?(Comments)
18
+ @visible = true
15
19
  @comments = comments
16
20
  parse_options options
17
21
  yield self if block_given?
18
22
  end
19
23
 
20
- # The text to render
21
- # @return [String]
22
- attr_reader :text
23
-
24
- # The author of this comment
25
- # @see Comments
26
- # @return [String]
27
- attr_reader :author
24
+ string_attr_accessor :text, :author
25
+ boolean_attr_accessor :visible
28
26
 
29
- # The owning Comments object
27
+ # The owning Comments object
30
28
  # @return [Comments]
31
29
  attr_reader :comments
32
30
 
33
31
 
34
32
  # The string based cell position reference (e.g. 'A1') that determines the positioning of this comment
35
- # @return [String]
33
+ # @return [String|Cell]
36
34
  attr_reader :ref
37
35
 
38
36
  # TODO
@@ -60,17 +58,6 @@ module Axlsx
60
58
  @ref = v.r if v.is_a?(Cell)
61
59
  end
62
60
 
63
- # @see text
64
- def text=(v)
65
- Axlsx::validate_string(v)
66
- @text = v
67
- end
68
-
69
- # @see author
70
- def author=(v)
71
- @author = v
72
- end
73
-
74
61
  # serialize the object
75
62
  # @param [String] str
76
63
  # @return [String]
@@ -93,7 +80,7 @@ module Axlsx
93
80
  # by default, all columns are 5 columns wide and 5 rows high
94
81
  def initialize_vml_shape
95
82
  pos = Axlsx::name_to_indices(ref)
96
- @vml_shape = VmlShape.new(:row => pos[1], :column => pos[0]) do |vml|
83
+ @vml_shape = VmlShape.new(:row => pos[1], :column => pos[0], :visible => @visible) do |vml|
97
84
  vml.left_column = vml.column
98
85
  vml.right_column = vml.column + 2
99
86
  vml.top_row = vml.row
@@ -25,7 +25,7 @@ module Axlsx
25
25
  # @option options [Integer] stdDev The number of standard deviations above or below the average to match
26
26
  # @option options [Boolean] stopIfTrue Stop evaluating rules after this rule matches
27
27
  # @option options [Symbol] timePeriod The time period in a date occuring... rule
28
- # @option options [String] formula The formula to match against in i.e. an equal rule
28
+ # @option options [String] formula The formula to match against in i.e. an equal rule. Use a [minimum, maximum] array for cellIs between/notBetween conditionals.
29
29
  def initialize(options={})
30
30
  @color_scale = @data_bar = @icon_set = @formula = nil
31
31
  parse_options options
@@ -36,6 +36,8 @@ module Axlsx
36
36
  :stopIfTrue, :timePeriod
37
37
 
38
38
  # Formula
39
+ # The formula or value to match against (e.g. 5 with an operator of :greaterThan to specify cell_value > 5).
40
+ # If the operator is :between or :notBetween, use an array to specify [minimum, maximum]
39
41
  # @return [String]
40
42
  attr_reader :formula
41
43
 
@@ -180,7 +182,7 @@ module Axlsx
180
182
  # @see timePeriod
181
183
  def timePeriod=(v); Axlsx::validate_time_period_type(v); @timePeriod = v end
182
184
  # @see formula
183
- def formula=(v); Axlsx::validate_string(v); @formula = v end
185
+ def formula=(v); [*v].each {|x| Axlsx::validate_string(x) }; @formula = v end
184
186
 
185
187
  # @see color_scale
186
188
  def color_scale=(v)
@@ -208,7 +210,7 @@ module Axlsx
208
210
  str << '<cfRule '
209
211
  serialized_attributes str
210
212
  str << '>'
211
- str << '<formula>' << self.formula << '</formula>' if @formula
213
+ str << '<formula>' << [*self.formula].join('</formula><formula>') << '</formula>' if @formula
212
214
  @color_scale.to_xml_string(str) if @color_scale && @type == :colorScale
213
215
  @data_bar.to_xml_string(str) if @data_bar && @type == :dataBar
214
216
  @icon_set.to_xml_string(str) if @icon_set && @type == :iconSet
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env ruby -s
2
- # -*- coding: utf-8 -*-
3
2
  $:.unshift "#{File.dirname(__FILE__)}/../lib"
4
3
  require 'axlsx'
5
4
  require 'csv'
@@ -2,25 +2,22 @@ require 'tc_helper.rb'
2
2
 
3
3
  class TestAxis < Test::Unit::TestCase
4
4
  def setup
5
-
6
- @axis = Axlsx::Axis.new 12345, 54321, :gridlines => false, :title => 'Foo'
5
+ @axis = Axlsx::Axis.new :gridlines => false, :title => 'Foo'
7
6
  end
8
7
 
9
- def teardown
10
- end
11
8
 
12
9
  def test_initialization
13
- assert_equal(@axis.axPos, :b, "axis position default incorrect")
14
- assert_equal(@axis.tickLblPos, :nextTo, "tick label position default incorrect")
15
- assert_equal(@axis.tickLblPos, :nextTo, "tick label position default incorrect")
10
+ assert_equal(@axis.ax_pos, :b, "axis position default incorrect")
11
+ assert_equal(@axis.tick_lbl_pos, :nextTo, "tick label position default incorrect")
12
+ assert_equal(@axis.tick_lbl_pos, :nextTo, "tick label position default incorrect")
16
13
  assert_equal(@axis.crosses, :autoZero, "tick label position default incorrect")
17
14
  assert(@axis.scaling.is_a?(Axlsx::Scaling) && @axis.scaling.orientation == :minMax, "scaling default incorrect")
18
- assert_raise(ArgumentError) { Axlsx::Axis.new( -1234, 'abcd') }
19
15
  assert_equal('Foo', @axis.title.text)
20
16
  end
21
17
 
22
18
  def test_color
23
19
  @axis.color = "00FF00"
20
+ @axis.cross_axis = Axlsx::CatAxis.new
24
21
  str = '<?xml version="1.0" encoding="UTF-8"?>'
25
22
  str << '<c:chartSpace xmlns:c="' << Axlsx::XML_NS_C << '" xmlns:a="' << Axlsx::XML_NS_A << '">'
26
23
  doc = Nokogiri::XML(@axis.to_xml_string(str))
@@ -35,15 +32,15 @@ class TestAxis < Test::Unit::TestCase
35
32
  sheet.add_row ['cat', 7, 9, 10]
36
33
  sheet.add_chart(Axlsx::Line3DChart) do |chart|
37
34
  chart.add_series :data => sheet['B2:D2'], :labels => sheet['B1']
38
- chart.valAxis.title = sheet['A1']
39
- assert_equal('battle victories', chart.valAxis.title.text)
35
+ chart.val_axis.title = sheet['A1']
36
+ assert_equal('battle victories', chart.val_axis.title.text)
40
37
  end
41
38
  end
42
39
  end
43
40
 
44
41
  def test_axis_position
45
- assert_raise(ArgumentError, "requires valid axis position") { @axis.axPos = :nowhere }
46
- assert_nothing_raised("accepts valid axis position") { @axis.axPos = :r }
42
+ assert_raise(ArgumentError, "requires valid axis position") { @axis.ax_pos = :nowhere }
43
+ assert_nothing_raised("accepts valid axis position") { @axis.ax_pos = :r }
47
44
  end
48
45
 
49
46
  def test_label_rotation
@@ -55,13 +52,13 @@ class TestAxis < Test::Unit::TestCase
55
52
  end
56
53
 
57
54
  def test_tick_label_position
58
- assert_raise(ArgumentError, "requires valid tick label position") { @axis.tickLblPos = :nowhere }
59
- assert_nothing_raised("accepts valid tick label position") { @axis.tickLblPos = :high }
55
+ assert_raise(ArgumentError, "requires valid tick label position") { @axis.tick_lbl_pos = :nowhere }
56
+ assert_nothing_raised("accepts valid tick label position") { @axis.tick_lbl_pos = :high }
60
57
  end
61
58
 
62
59
  def test_format_code
63
- assert_raise(ArgumentError, "requires valid format code") { @axis.format_code = 1 }
64
- assert_nothing_raised("accepts valid format code") { @axis.tickLblPos = :high }
60
+ assert_raise(ArgumentError, "requires valid format code") { @axis.format_code = :high }
61
+ assert_nothing_raised("accepts valid format code") { @axis.format_code = "00.##" }
65
62
  end
66
63
 
67
64
  def test_crosses
@@ -75,12 +72,13 @@ class TestAxis < Test::Unit::TestCase
75
72
  end
76
73
 
77
74
  def test_to_xml_string
75
+ @axis.cross_axis = Axlsx::CatAxis.new
78
76
  str = '<?xml version="1.0" encoding="UTF-8"?>'
79
77
  str << '<c:chartSpace xmlns:c="' << Axlsx::XML_NS_C << '" xmlns:a="' << Axlsx::XML_NS_A << '">'
80
78
  doc = Nokogiri::XML(@axis.to_xml_string(str))
81
79
  assert(doc.xpath('//a:noFill'))
82
80
  assert(doc.xpath("//c:crosses[@val='#{@axis.crosses.to_s}']"))
83
- assert(doc.xpath("//c:crossAx[@val='#{@axis.crossAx.to_s}']"))
81
+ assert(doc.xpath("//c:crossAx[@val='#{@axis.cross_axis.to_s}']"))
84
82
  assert(doc.xpath("//a:bodyPr[@rot='#{@axis.label_rotation.to_s}']"))
85
83
  assert(doc.xpath("//a:t[text()='Foo']"))
86
84
  end
@@ -2,15 +2,15 @@ require 'tc_helper.rb'
2
2
 
3
3
  class TestCatAxis < Test::Unit::TestCase
4
4
  def setup
5
- @axis = Axlsx::CatAxis.new 12345, 54321
5
+ @axis = Axlsx::CatAxis.new
6
6
  end
7
7
  def teardown
8
8
  end
9
9
 
10
10
  def test_initialization
11
11
  assert_equal(@axis.auto, 1, "axis auto default incorrect")
12
- assert_equal(@axis.lblAlgn, :ctr, "label align default incorrect")
13
- assert_equal(@axis.lblOffset, "100", "label offset default incorrect")
12
+ assert_equal(@axis.lbl_algn, :ctr, "label align default incorrect")
13
+ assert_equal(@axis.lbl_offset, "100", "label offset default incorrect")
14
14
  end
15
15
 
16
16
  def test_auto
@@ -18,14 +18,14 @@ class TestCatAxis < Test::Unit::TestCase
18
18
  assert_nothing_raised("accepts valid auto") { @axis.auto = false }
19
19
  end
20
20
 
21
- def test_lblAlgn
22
- assert_raise(ArgumentError, "requires valid label alignment") { @axis.lblAlgn = :nowhere }
23
- assert_nothing_raised("accepts valid label alignment") { @axis.lblAlgn = :r }
21
+ def test_lbl_algn
22
+ assert_raise(ArgumentError, "requires valid label alignment") { @axis.lbl_algn = :nowhere }
23
+ assert_nothing_raised("accepts valid label alignment") { @axis.lbl_algn = :r }
24
24
  end
25
25
 
26
- def test_lblOffset
27
- assert_raise(ArgumentError, "requires valid label offset") { @axis.lblOffset = 'foo' }
28
- assert_nothing_raised("accepts valid label offset") { @axis.lblOffset = "20" }
26
+ def test_lbl_offset
27
+ assert_raise(ArgumentError, "requires valid label offset") { @axis.lbl_offset = 'foo' }
28
+ assert_nothing_raised("accepts valid label offset") { @axis.lbl_offset = "20" }
29
29
  end
30
30
 
31
31
  end
@@ -0,0 +1,39 @@
1
+ require 'tc_helper.rb'
2
+
3
+ class TestLineChart < Test::Unit::TestCase
4
+
5
+ def setup
6
+ @p = Axlsx::Package.new
7
+ ws = @p.workbook.add_worksheet
8
+ @row = ws.add_row ["one", 1, Time.now]
9
+ @chart = ws.add_chart Axlsx::LineChart, :title => "fishery"
10
+ end
11
+
12
+ def teardown
13
+ end
14
+
15
+ def test_initialization
16
+ assert_equal(@chart.grouping, :standard, "grouping defualt incorrect")
17
+ assert_equal(@chart.series_type, Axlsx::LineSeries, "series type incorrect")
18
+ assert(@chart.cat_axis.is_a?(Axlsx::CatAxis), "category axis not created")
19
+ assert(@chart.val_axis.is_a?(Axlsx::ValAxis), "value access not created")
20
+ end
21
+
22
+ def test_grouping
23
+ assert_raise(ArgumentError, "require valid grouping") { @chart.grouping = :inverted }
24
+ assert_nothing_raised("allow valid grouping") { @chart.grouping = :stacked }
25
+ assert(@chart.grouping == :stacked)
26
+ end
27
+
28
+ def test_to_xml
29
+ schema = Nokogiri::XML::Schema(File.open(Axlsx::DRAWING_XSD))
30
+ doc = Nokogiri::XML(@chart.to_xml_string)
31
+ errors = []
32
+ schema.validate(doc).each do |error|
33
+ errors.push error
34
+ puts error.message
35
+ end
36
+ assert(errors.empty?, "error free validation")
37
+ end
38
+
39
+ end
@@ -6,7 +6,7 @@ class TestLineSeries < Test::Unit::TestCase
6
6
  p = Axlsx::Package.new
7
7
  @ws = p.workbook.add_worksheet :name=>"hmmm"
8
8
  chart = @ws.add_chart Axlsx::Line3DChart, :title => "fishery"
9
- @series = chart.add_series :data=>[0,1,2], :labels=>["zero", "one", "two"], :title=>"bob", :color => "#FF0000"
9
+ @series = chart.add_series :data=>[0,1,2], :labels=>["zero", "one", "two"], :title=>"bob", :color => "#FF0000", :show_marker => true
10
10
  end
11
11
 
12
12
  def test_initialize
@@ -15,10 +15,16 @@ class TestLineSeries < Test::Unit::TestCase
15
15
  assert_equal(@series.data.class, Axlsx::NumDataSource)
16
16
 
17
17
  end
18
-
18
+
19
+ def test_show_marker
20
+ assert_equal(true, @series.show_marker)
21
+ @series.show_marker = false
22
+ assert_equal(false, @series.show_marker)
23
+ end
19
24
  def test_to_xml_string
20
25
  doc = Nokogiri::XML(@series.to_xml_string)
21
26
  assert(doc.xpath("//srgbClr[@val='#{@series.color}']"))
27
+ assert(doc.xpath("//marker"))
22
28
  end
23
29
  #TODO serialization testing
24
30
  end