axlsx 1.2.3 → 1.3.1

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 (65) hide show
  1. data/.yardopts +3 -2
  2. data/CHANGELOG.md +34 -1
  3. data/README.md +26 -37
  4. data/Rakefile +1 -1
  5. data/examples/auto_filter.rb +16 -0
  6. data/examples/auto_filter.xlsx +0 -0
  7. data/examples/example.rb +3 -2
  8. data/examples/example.xlsx +0 -0
  9. data/examples/example_streamed.xlsx +0 -0
  10. data/examples/no-use_autowidth.xlsx +0 -0
  11. data/examples/shared_strings_example.xlsx +0 -0
  12. data/examples/skydrive/real_example.rb +6 -6
  13. data/examples/sprk2012/Screen Shot 2012-09-11 at 10.42.06 PM.png +0 -0
  14. data/examples/sprk2012/Screen Shot 2012-09-11 at 11.07.48 PM.png +0 -0
  15. data/examples/sprk2012/Screen Shot 2012-09-11 at 8.31.50 PM.png +0 -0
  16. data/examples/sprk2012/Screen Shot 2012-09-11 at 9.23.27 PM.png +0 -0
  17. data/examples/sprk2012/Screen Shot 2012-09-11 at 9.32.06 PM.png +0 -0
  18. data/examples/sprk2012/Screen Shot 2012-09-11 at 9.33.35 PM.png +0 -0
  19. data/examples/sprk2012/Screen Shot 2012-09-11 at 9.46.44 PM.png +0 -0
  20. data/examples/sprk2012/Screen Shot 2012-09-12 at 5.07.23 PM.png +0 -0
  21. data/examples/sprk2012/basics.rb +1 -0
  22. data/examples/sprk2012/basics.xlsx +0 -0
  23. data/examples/sprk2012/gravatar.jpeg +0 -0
  24. data/examples/sprk2012/hair_club.jpg +0 -0
  25. data/examples/sprk2012/images.rb +7 -12
  26. data/examples/sprk2012/images.xlsx +0 -0
  27. data/examples/sprk2012/line_chart.rb +56 -0
  28. data/examples/sprk2012/line_chart.xlsx +0 -0
  29. data/examples/sprk2012/sprk2012.key +0 -0
  30. data/examples/sprk2012/styles.rb +13 -12
  31. data/examples/sprk2012/styles.xlsx +0 -0
  32. data/examples/styles.rb +62 -0
  33. data/examples/styles.xlsx +0 -0
  34. data/lib/axlsx.rb +8 -1
  35. data/lib/axlsx/stylesheet/styles.rb +4 -0
  36. data/lib/axlsx/util/constants.rb +90 -5
  37. data/lib/axlsx/util/validators.rb +26 -8
  38. data/lib/axlsx/version.rb +2 -2
  39. data/lib/axlsx/workbook/workbook.rb +4 -1
  40. data/lib/axlsx/workbook/worksheet/auto_filter/auto_filter.rb +77 -0
  41. data/lib/axlsx/workbook/worksheet/auto_filter/filter_column.rb +102 -0
  42. data/lib/axlsx/workbook/worksheet/auto_filter/filters.rb +253 -0
  43. data/lib/axlsx/workbook/worksheet/cell.rb +9 -4
  44. data/lib/axlsx/workbook/worksheet/date_time_converter.rb +1 -1
  45. data/lib/axlsx/workbook/worksheet/page_set_up_pr.rb +47 -0
  46. data/lib/axlsx/workbook/worksheet/sheet_calc_pr.rb +49 -0
  47. data/lib/axlsx/workbook/worksheet/sheet_pr.rb +87 -4
  48. data/lib/axlsx/workbook/worksheet/table.rb +8 -1
  49. data/lib/axlsx/workbook/worksheet/table_style_info.rb +68 -0
  50. data/lib/axlsx/workbook/worksheet/worksheet.rb +18 -3
  51. data/test/stylesheet/tc_styles.rb +13 -0
  52. data/test/util/tc_validators.rb +8 -1
  53. data/test/workbook/worksheet/auto_filter/tc_auto_filter.rb +38 -0
  54. data/test/workbook/worksheet/auto_filter/tc_filter_column.rb +76 -0
  55. data/test/workbook/worksheet/auto_filter/tc_filters.rb +50 -0
  56. data/test/workbook/worksheet/tc_cell.rb +5 -0
  57. data/test/workbook/worksheet/tc_page_set_up_pr.rb +15 -0
  58. data/test/workbook/worksheet/tc_sheet_calc_pr.rb +18 -0
  59. data/test/workbook/worksheet/tc_sheet_pr.rb +27 -0
  60. data/test/workbook/worksheet/{table/tc_table.rb → tc_table.rb} +6 -1
  61. data/test/workbook/worksheet/tc_table_style_info.rb +53 -0
  62. data/test/workbook/worksheet/tc_worksheet.rb +17 -3
  63. metadata +45 -7
  64. data/examples/~$extractive.xlsx +0 -0
  65. data/lib/axlsx/workbook/worksheet/auto_filter.rb +0 -35
@@ -28,6 +28,7 @@ module Axlsx
28
28
  @sheet = sheet
29
29
  @style = nil
30
30
  @sheet.workbook.tables << self
31
+ @table_style_info = TableStyleInfo.new(options[:style_info]) if options[:style_info]
31
32
  @name = "Table#{index+1}"
32
33
  options.each do |o|
33
34
  self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
@@ -62,6 +63,12 @@ module Axlsx
62
63
  @name = v
63
64
  end
64
65
  end
66
+
67
+ # TableStyleInfo for the table.
68
+ # initialization can be fed via the :style_info option
69
+ def table_style_info
70
+ @table_style_info ||= TableStyleInfo.new
71
+ end
65
72
 
66
73
  # Serializes the object
67
74
  # @param [String] str
@@ -77,7 +84,7 @@ module Axlsx
77
84
  end
78
85
  str << '</tableColumns>'
79
86
  #TODO implement tableStyleInfo
80
- str << '<tableStyleInfo showFirstColumn="0" showLastColumn="0" showRowStripes="1" showColumnStripes="0" name="TableStyleMedium9" />'
87
+ table_style_info.to_xml_string(str) # '<tableStyleInfo showFirstColumn="0" showLastColumn="0" showRowStripes="1" showColumnStripes="0" name="TableStyleMedium9" />'
81
88
  str << '</table>'
82
89
  end
83
90
 
@@ -0,0 +1,68 @@
1
+ module Axlsx
2
+
3
+ # The table style info class manages style attributes for defined tables in
4
+ # a worksheet
5
+ class TableStyleInfo
6
+
7
+ # boolean attributes for this object
8
+ BOOLEAN_ATTRIBUTES = %w(show_first_column show_last_column show_row_stripes show_column_stripes)
9
+
10
+ # creates a new TableStyleInfo instance
11
+ # @param [Hash] options
12
+ # @option [Boolean] show_first_column indicates if the first column should
13
+ # be shown
14
+ # @option [Boolean] show_last_column indicates if the last column should
15
+ # be shown
16
+ # @option [Boolean] show_column_stripes indicates if column stripes should
17
+ # be shown
18
+ # @option [Boolean] show_row_stripes indicates if row stripes should be shown
19
+ # @option [String] name The name of the style to apply to your table.
20
+ # Only predefined styles are currently supported.
21
+ # @see Annex G. (normative) Predefined SpreadsheetML Style Definitions in part 1 of the specification.
22
+ def initialize(options = {})
23
+ initialize_defaults
24
+ @name = 'TableStyleMedium9'
25
+ options.each do |k, v|
26
+ send("#{k}=", v) if respond_to? "#{k}="
27
+ end
28
+ end
29
+
30
+ # Dynamically create accessors for boolean attriubtes
31
+ BOOLEAN_ATTRIBUTES.each do |attr|
32
+ class_eval %{
33
+ # The #{attr} attribute reader
34
+ # @return [Boolean]
35
+ attr_reader :#{attr}
36
+
37
+ # The #{attr} writer
38
+ # @param [Boolean] value The value to assign to #{attr}
39
+ # @return [Boolean]
40
+ def #{attr}=(value)
41
+ Axlsx::validate_boolean(value)
42
+ @#{attr} = value
43
+ end
44
+ }
45
+ end
46
+
47
+ # Initialize all the values to false as Excel requires them to
48
+ # explicitly be disabled or all will show.
49
+ def initialize_defaults
50
+ BOOLEAN_ATTRIBUTES.each do |attr|
51
+ self.send("#{attr}=", 0)
52
+ end
53
+ end
54
+
55
+ # The name of the table style.
56
+ attr_accessor :name
57
+
58
+ # seralizes this object to an xml string
59
+ # @param [String] str the string to contact this objects serialization to.
60
+ def to_xml_string(str = '')
61
+ str << '<tableStyleInfo '
62
+ instance_values.each do |key, value|
63
+ str << Axlsx::camel(key, false) << "='#{value}' "
64
+ end
65
+ str << '/>'
66
+ end
67
+ end
68
+ end
@@ -42,6 +42,12 @@ module Axlsx
42
42
  def name
43
43
  @name ||= "Sheet" + (index+1).to_s
44
44
  end
45
+
46
+ # The sheet calculation properties
47
+ # @return [SheetCalcPr]
48
+ def sheet_calc_pr
49
+ @sheet_calc_pr ||= SheetCalcPr.new
50
+ end
45
51
 
46
52
  # The sheet protection object for this workbook
47
53
  # @return [SheetProtection]
@@ -491,15 +497,24 @@ module Axlsx
491
497
  # This intentionally does not use nokogiri for performance reasons
492
498
  # @return [String]
493
499
  def to_xml_string
500
+ auto_filter.apply if auto_filter.range
494
501
  str = '<?xml version="1.0" encoding="UTF-8"?>'
495
502
  str << worksheet_node
496
503
  serializable_parts.each do |item|
497
504
  item.to_xml_string(str) if item
498
505
  end
499
506
  str << '</worksheet>'
500
- str.gsub(/[[:cntrl:]]/,'')
507
+ sanitize(str)
501
508
  end
502
509
 
510
+ # returns the provided string with all invalid control charaters
511
+ # removed.
512
+ # @param [String] str The sting to process
513
+ # @return [String]
514
+ def sanitize(str)
515
+ str.gsub(CONTROL_CHAR_REGEX, '')
516
+ end
517
+
503
518
  # The worksheet relationships. This is managed automatically by the worksheet
504
519
  # @return [Relationships]
505
520
  def relationships
@@ -556,7 +571,7 @@ module Axlsx
556
571
 
557
572
 
558
573
  private
559
-
574
+
560
575
  def validate_sheet_name(name)
561
576
  DataTypeValidator.validate "Worksheet.name", String, name
562
577
  raise ArgumentError, (ERR_SHEET_NAME_TOO_LONG % name) if name.size > 31
@@ -569,7 +584,7 @@ module Axlsx
569
584
 
570
585
  def serializable_parts
571
586
  [sheet_pr, dimension, sheet_view, column_info,
572
- sheet_data, @sheet_protection, protected_ranges,
587
+ sheet_data, sheet_calc_pr, @sheet_protection, protected_ranges,
573
588
  auto_filter, merged_cells, conditional_formattings,
574
589
  data_validations, hyperlinks, print_options, page_margins,
575
590
  page_setup, worksheet_drawing, worksheet_comments,
@@ -105,6 +105,19 @@ class TestStyles < Test::Unit::TestCase
105
105
  assert(@styles.parse_alignment_options(:alignment => {}).is_a?(Axlsx::CellAlignment))
106
106
  end
107
107
 
108
+ def test_parse_font_using_defaults
109
+ original = @styles.fonts.first
110
+ @styles.add_style :b => 1, :sz => 99
111
+ created = @styles.fonts.last
112
+ original_attributes = original.instance_values
113
+ assert_equal(1, created.b)
114
+ assert_equal(99, created.sz)
115
+ copied = original_attributes.reject{ |key, value| %w(b sz).include? key }
116
+ copied.each do |key, value|
117
+ assert_equal(created.instance_values[key], value)
118
+ end
119
+ end
120
+
108
121
  def test_parse_font_options
109
122
  options = {
110
123
  :fg_color => "FF050505",
@@ -158,4 +158,11 @@ class TestValidators < Test::Unit::TestCase
158
158
  assert_raise(ArgumentError) { Axlsx.validate_split_state_type 'frozen_split' }
159
159
  assert_raise(ArgumentError) { Axlsx.validate_split_state_type 0 }
160
160
  end
161
- end
161
+
162
+ def test_range_validation
163
+ # exclusive
164
+ assert_raise(ArgumentError) { Axlsx::RangeValidator.validate('foo', 1, 10, 10, false) }
165
+ # inclusive by default
166
+ assert_nothing_raised { Axlsx::RangeValidator.validate('foo', 1, 10, 10) }
167
+ end
168
+ end
@@ -0,0 +1,38 @@
1
+ require 'tc_helper.rb'
2
+
3
+ class TestAutoFilter < Test::Unit::TestCase
4
+
5
+ def setup
6
+ ws = Axlsx::Package.new.workbook.add_worksheet
7
+ 3.times { |index| ws.add_row [1*index,2*index,3*index] }
8
+ @auto_filter = ws.auto_filter
9
+ @auto_filter.range = 'A1:C3'
10
+ @auto_filter.add_column 0, :filters, :filter_items => [1]
11
+ end
12
+
13
+ def test_defined_name
14
+ assert_equal("'Sheet1'!$A$1:$C$3", @auto_filter.defined_name)
15
+ end
16
+
17
+ def test_to_xml_string
18
+ doc = Nokogiri::XML(@auto_filter.to_xml_string)
19
+ assert(doc.xpath("autoFilter[@ref='#{@auto_filter.range}']"))
20
+ end
21
+
22
+ def test_columns
23
+ assert @auto_filter.columns.is_a?(Axlsx::SimpleTypedList)
24
+ assert_equal @auto_filter.columns.allowed_types, [Axlsx::FilterColumn]
25
+ end
26
+
27
+ def test_add_column
28
+ @auto_filter.add_column(0, :filters) do |column|
29
+ assert column.is_a? FilterColumn
30
+ end
31
+ end
32
+
33
+ def test_applya
34
+ assert_equal nil, @auto_filter.worksheet.rows.last.hidden
35
+ @auto_filter.apply
36
+ assert_equal true, @auto_filter.worksheet.rows.last.hidden
37
+ end
38
+ end
@@ -0,0 +1,76 @@
1
+ require 'tc_helper.rb'
2
+
3
+ class TestFilterColumn < Test::Unit::TestCase
4
+
5
+ def setup
6
+ @filter_column = Axlsx::FilterColumn.new(0, :filters, :filter_items => [200])
7
+ end
8
+
9
+
10
+ def test_initialize_col_id
11
+ assert_raise ArgumentError do
12
+ Axlsx::FilterColumn.new(0, :bobs_house_of_filter)
13
+ end
14
+ assert_raise ArgumentError do
15
+ Axlsx::FilterColumn.new(:penut, :filters)
16
+ end
17
+ end
18
+
19
+ def test_initailize_filter_type
20
+ assert @filter_column.filter.is_a?(Axlsx::Filters)
21
+ assert_equal 1, @filter_column.filter.filter_items.size
22
+ end
23
+
24
+ def test_initialize_filter_type_filters_with_options
25
+ assert_equal 200, @filter_column.filter.filter_items.first.val
26
+ end
27
+
28
+ def test_initialize_with_block
29
+ filter_column = Axlsx::FilterColumn.new(0, :filters) do |filters|
30
+ filters.filter_items = [700, 100, 5]
31
+ end
32
+ assert_equal 3, filter_column.filter.filter_items.size
33
+ assert_equal 700, filter_column.filter.filter_items.first.val
34
+ assert_equal 5, filter_column.filter.filter_items.last.val
35
+ end
36
+
37
+ def test_default_show_button
38
+ assert_equal true, @filter_column.show_button
39
+ end
40
+
41
+ def test_default_hidden_button
42
+ assert_equal false, @filter_column.hidden_button
43
+ end
44
+
45
+ def test_show_button
46
+ assert_raise ArgumentError do
47
+ @filter_column.show_button = :foo
48
+ end
49
+ assert_nothing_raised { @filter_column.show_button = false }
50
+ end
51
+
52
+ def test_hidden_button
53
+ assert_raise ArgumentError do
54
+ @filter_column.hidden_button = :hoge
55
+ end
56
+ assert_nothing_raised { @filter_column.hidden_button = true }
57
+ end
58
+
59
+ def test_col_id=
60
+ assert_raise ArgumentError do
61
+ @filter_column.col_id = :bar
62
+ end
63
+ assert_nothing_raised { @filter_column.col_id = 7 }
64
+ end
65
+
66
+ def test_to_xml_string
67
+ doc = Nokogiri::XML(@filter_column.to_xml_string)
68
+ assert doc.xpath("//filterColumn[@colId=#{@filter_column.col_id}]")
69
+ assert doc.xpath("//filterColumn[@hiddenButton=#{@filter_column.hidden_button}]")
70
+ assert doc.xpath("//filterColumn[@showButton=#{@filter_column.show_button}]")
71
+
72
+
73
+
74
+ assert doc.xpath("//filterColumn/filters")
75
+ end
76
+ end
@@ -0,0 +1,50 @@
1
+ require 'tc_helper.rb'
2
+
3
+ class TestFilters < Test::Unit::TestCase
4
+ def setup
5
+ @filters = Axlsx::Filters.new(:filter_items => [1, 'a'],
6
+ :date_group_items =>[ { :date_time_grouping => :year, :year => 2011, :month => 11, :day => 11, :hour => 0, :minute => 0, :second => 0 } ] ,
7
+ :blank => true)
8
+ end
9
+
10
+ def test_blank
11
+ assert_equal true, @filters.blank
12
+ assert_raise(ArgumentError) { @filters.blank = :only_if_you_want_it }
13
+ @filters.blank = true
14
+ assert_equal true, @filters.blank
15
+ end
16
+
17
+ def test_calendar_type
18
+ assert_raise(ArgumentError) { @filters.calendar_type = 'monkey calendar' }
19
+ @filters.calendar_type = 'japan'
20
+ assert_equal('japan', @filters.calendar_type)
21
+ end
22
+
23
+ def test_filters_items
24
+ assert @filters.filter_items.is_a?(Array)
25
+ assert_equal 2, @filters.filter_items.size
26
+ end
27
+
28
+ def test_date_group_items
29
+ assert @filters.date_group_items.is_a?(Array)
30
+ assert_equal 1, @filters.date_group_items.size
31
+ end
32
+
33
+ def test_apply_is_false_for_matching_values
34
+ keeper = Object.new
35
+ def keeper.value; 'a'; end
36
+ assert_equal false, @filters.apply(keeper)
37
+ end
38
+
39
+ def test_apply_is_true_for_non_matching_values
40
+ hidden = Object.new
41
+ def hidden.value; 'b'; end
42
+ assert_equal true, @filters.apply(hidden)
43
+ end
44
+
45
+ def test_to_xml_string
46
+ doc = Nokogiri::XML(@filters.to_xml_string)
47
+ assert_equal(1, doc.xpath('//filters[@blank="true"]').size)
48
+ end
49
+ end
50
+
@@ -275,6 +275,11 @@ class TestCell < Test::Unit::TestCase
275
275
  assert_equal(sz, @c.row.worksheet.workbook.styles.fonts.first.sz)
276
276
  end
277
277
 
278
+ def test_font_size_with_bolding
279
+ @c.style = @c.row.worksheet.workbook.styles.add_style :b => true
280
+ assert_equal(@c.row.worksheet.workbook.styles.fonts.first.sz * 1.5, @c.send(:font_size))
281
+ end
282
+
278
283
  def test_font_size_with_custom_sz
279
284
  @c.style = @c.row.worksheet.workbook.styles.add_style :sz => 52
280
285
  sz = @c.send(:font_size)
@@ -0,0 +1,15 @@
1
+ require 'tc_helper.rb'
2
+
3
+ class TestPageSetUpPr < Test::Unit::TestCase
4
+ def setup
5
+ @page_setup_pr = Axlsx::PageSetUpPr.new(:fit_to_page => true, :auto_page_breaks => true)
6
+ end
7
+
8
+ def test_fit_to_page
9
+ assert_equal true, @page_setup_pr.fit_to_page
10
+ end
11
+
12
+ def test_auto_page_breaks
13
+ assert_equal true, @page_setup_pr.auto_page_breaks
14
+ end
15
+ end
@@ -0,0 +1,18 @@
1
+ require 'tc_helper'
2
+
3
+ class TestSheetCalcPr < Test::Unit::TestCase
4
+
5
+ def setup
6
+ @sheet_calc_pr = Axlsx::SheetCalcPr.new(:full_calc_on_load => false)
7
+ end
8
+
9
+ def test_full_calc_on_load
10
+ assert_equal false, @sheet_calc_pr.full_calc_on_load
11
+ assert Axlsx::SheetCalcPr.new.full_calc_on_load
12
+ end
13
+
14
+ def test_to_xml_string
15
+ doc = Nokogiri::XML(@sheet_calc_pr.to_xml_string)
16
+ assert_equal 1, doc.xpath('//sheetCalcPr[@fullCalcOnLoad="false"]').size
17
+ end
18
+ end
@@ -0,0 +1,27 @@
1
+ require 'tc_helper.rb'
2
+
3
+
4
+ class TestSheetPr < Test::Unit::TestCase
5
+
6
+ def setup
7
+ worksheet = Axlsx::Package.new.workbook.add_worksheet
8
+ @options = {
9
+ :sync_horizontal => false,
10
+ :sync_vertical => false,
11
+ :transtion_evaluation => true,
12
+ :transition_entry => true,
13
+ :published => false,
14
+ :filter_mode => true,
15
+ :enable_format_conditions_calculation => false,
16
+ :code_name => '007',
17
+ :sync_ref => 'foo'
18
+ }
19
+ @sheet_pr = Axlsx::SheetPr.new(worksheet, @options)
20
+ end
21
+
22
+ def test_initialization
23
+ @options.each do |key, value|
24
+ assert_equal value, @sheet_pr.send(key)
25
+ end
26
+ end
27
+ end
@@ -15,6 +15,12 @@ class TestTable < Test::Unit::TestCase
15
15
 
16
16
  end
17
17
 
18
+ def test_table_style_info
19
+ table = @ws.add_table('A1:D5', :name => 'foo', :style_info => { :show_row_stripes => true, :name => "TableStyleMedium25" })
20
+ assert_equal('TableStyleMedium25', table.table_style_info.name)
21
+ assert_equal(true, table.table_style_info.show_row_stripes)
22
+ end
23
+
18
24
  def test_add_table
19
25
  name = "test"
20
26
  table = @ws.add_table("A1:D5", :name => name)
@@ -22,7 +28,6 @@ class TestTable < Test::Unit::TestCase
22
28
  assert_equal(@ws.workbook.tables.last, table, "must be added to workbook table collection")
23
29
  assert_equal(@ws.tables.last, table, "must be added to worksheet table collection")
24
30
  assert_equal(table.name, name, "options for name are applied")
25
-
26
31
  end
27
32
 
28
33
  def test_pn