axlsx 2.0.1 → 3.0.0.pre

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 (180) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/README.md +23 -23
  4. data/Rakefile +9 -11
  5. data/examples/auto_filter.rb +10 -1
  6. data/examples/conditional_formatting/example_conditional_formatting.rb +18 -3
  7. data/examples/example.rb +102 -4
  8. data/examples/merge_cells.rb +17 -0
  9. data/examples/no_grid_with_borders.rb +18 -0
  10. data/examples/pivot_test.rb +63 -0
  11. data/examples/split.rb +16 -0
  12. data/lib/axlsx/content_type/abstract_content_type.rb +1 -1
  13. data/lib/axlsx/content_type/content_type.rb +1 -1
  14. data/lib/axlsx/doc_props/app.rb +1 -1
  15. data/lib/axlsx/doc_props/core.rb +5 -5
  16. data/lib/axlsx/drawing/area_chart.rb +99 -0
  17. data/lib/axlsx/drawing/area_series.rb +110 -0
  18. data/lib/axlsx/drawing/axes.rb +1 -1
  19. data/lib/axlsx/drawing/axis.rb +12 -9
  20. data/lib/axlsx/drawing/bar_3D_chart.rb +13 -13
  21. data/lib/axlsx/drawing/bar_chart.rb +143 -0
  22. data/lib/axlsx/drawing/bar_series.rb +9 -9
  23. data/lib/axlsx/drawing/bubble_chart.rb +59 -0
  24. data/lib/axlsx/drawing/bubble_series.rb +63 -0
  25. data/lib/axlsx/drawing/cat_axis.rb +5 -5
  26. data/lib/axlsx/drawing/chart.rb +52 -8
  27. data/lib/axlsx/drawing/d_lbls.rb +3 -3
  28. data/lib/axlsx/drawing/drawing.rb +6 -1
  29. data/lib/axlsx/drawing/graphic_frame.rb +3 -3
  30. data/lib/axlsx/drawing/hyperlink.rb +1 -3
  31. data/lib/axlsx/drawing/line_3D_chart.rb +2 -2
  32. data/lib/axlsx/drawing/line_chart.rb +10 -10
  33. data/lib/axlsx/drawing/line_series.rb +32 -3
  34. data/lib/axlsx/drawing/marker.rb +1 -1
  35. data/lib/axlsx/drawing/num_data.rb +4 -4
  36. data/lib/axlsx/drawing/num_data_source.rb +6 -6
  37. data/lib/axlsx/drawing/num_val.rb +3 -1
  38. data/lib/axlsx/drawing/one_cell_anchor.rb +3 -2
  39. data/lib/axlsx/drawing/pic.rb +25 -19
  40. data/lib/axlsx/drawing/picture_locking.rb +1 -3
  41. data/lib/axlsx/drawing/pie_3D_chart.rb +5 -6
  42. data/lib/axlsx/drawing/pie_series.rb +6 -6
  43. data/lib/axlsx/drawing/scaling.rb +6 -6
  44. data/lib/axlsx/drawing/scatter_chart.rb +10 -10
  45. data/lib/axlsx/drawing/scatter_series.rb +40 -7
  46. data/lib/axlsx/drawing/ser_axis.rb +2 -2
  47. data/lib/axlsx/drawing/series.rb +3 -3
  48. data/lib/axlsx/drawing/series_title.rb +2 -2
  49. data/lib/axlsx/drawing/str_data.rb +3 -3
  50. data/lib/axlsx/drawing/str_val.rb +3 -1
  51. data/lib/axlsx/drawing/title.rb +22 -4
  52. data/lib/axlsx/drawing/two_cell_anchor.rb +6 -1
  53. data/lib/axlsx/drawing/val_axis.rb +1 -1
  54. data/lib/axlsx/drawing/view_3D.rb +2 -2
  55. data/lib/axlsx/drawing/vml_drawing.rb +1 -1
  56. data/lib/axlsx/package.rb +34 -32
  57. data/lib/axlsx/rels/relationship.rb +1 -1
  58. data/lib/axlsx/rels/relationships.rb +7 -4
  59. data/lib/axlsx/stylesheet/border_pr.rb +2 -2
  60. data/lib/axlsx/stylesheet/cell_alignment.rb +1 -3
  61. data/lib/axlsx/stylesheet/cell_protection.rb +1 -3
  62. data/lib/axlsx/stylesheet/cell_style.rb +1 -3
  63. data/lib/axlsx/stylesheet/color.rb +1 -3
  64. data/lib/axlsx/stylesheet/font.rb +1 -1
  65. data/lib/axlsx/stylesheet/gradient_stop.rb +1 -1
  66. data/lib/axlsx/stylesheet/num_fmt.rb +10 -3
  67. data/lib/axlsx/stylesheet/pattern_fill.rb +1 -1
  68. data/lib/axlsx/stylesheet/styles.rb +7 -7
  69. data/lib/axlsx/stylesheet/table_style_element.rb +1 -3
  70. data/lib/axlsx/util/accessors.rb +6 -6
  71. data/lib/axlsx/util/constants.rb +107 -99
  72. data/lib/axlsx/util/mime_type_utils.rb +11 -0
  73. data/lib/axlsx/util/options_parser.rb +2 -1
  74. data/lib/axlsx/util/parser.rb +4 -4
  75. data/lib/axlsx/util/serialized_attributes.rb +16 -6
  76. data/lib/axlsx/util/simple_typed_list.rb +28 -52
  77. data/lib/axlsx/util/storage.rb +4 -4
  78. data/lib/axlsx/util/validators.rb +29 -17
  79. data/lib/axlsx/version.rb +1 -1
  80. data/lib/axlsx/workbook/defined_name.rb +11 -12
  81. data/lib/axlsx/workbook/defined_names.rb +2 -2
  82. data/lib/axlsx/workbook/shared_strings_table.rb +5 -5
  83. data/lib/axlsx/workbook/workbook.rb +36 -11
  84. data/lib/axlsx/workbook/workbook_view.rb +80 -0
  85. data/lib/axlsx/workbook/workbook_views.rb +22 -0
  86. data/lib/axlsx/workbook/worksheet/auto_filter/auto_filter.rb +2 -2
  87. data/lib/axlsx/workbook/worksheet/auto_filter/filters.rb +1 -3
  88. data/lib/axlsx/workbook/worksheet/break.rb +1 -3
  89. data/lib/axlsx/workbook/worksheet/cell.rb +136 -74
  90. data/lib/axlsx/workbook/worksheet/cell_serializer.rb +63 -43
  91. data/lib/axlsx/workbook/worksheet/cfvo.rb +1 -3
  92. data/lib/axlsx/workbook/worksheet/cfvos.rb +4 -1
  93. data/lib/axlsx/workbook/worksheet/col.rb +7 -10
  94. data/lib/axlsx/workbook/worksheet/col_breaks.rb +2 -2
  95. data/lib/axlsx/workbook/worksheet/cols.rb +5 -2
  96. data/lib/axlsx/workbook/worksheet/comment.rb +5 -6
  97. data/lib/axlsx/workbook/worksheet/comments.rb +9 -12
  98. data/lib/axlsx/workbook/worksheet/conditional_formatting.rb +1 -1
  99. data/lib/axlsx/workbook/worksheet/conditional_formatting_rule.rb +1 -1
  100. data/lib/axlsx/workbook/worksheet/data_bar.rb +4 -6
  101. data/lib/axlsx/workbook/worksheet/data_validation.rb +6 -4
  102. data/lib/axlsx/workbook/worksheet/dimension.rb +2 -2
  103. data/lib/axlsx/workbook/worksheet/header_footer.rb +6 -8
  104. data/lib/axlsx/workbook/worksheet/icon_set.rb +3 -5
  105. data/lib/axlsx/workbook/worksheet/merged_cells.rb +4 -2
  106. data/lib/axlsx/workbook/worksheet/outline_pr.rb +33 -0
  107. data/lib/axlsx/workbook/worksheet/page_margins.rb +1 -3
  108. data/lib/axlsx/workbook/worksheet/page_set_up_pr.rb +1 -1
  109. data/lib/axlsx/workbook/worksheet/page_setup.rb +21 -23
  110. data/lib/axlsx/workbook/worksheet/pane.rb +1 -3
  111. data/lib/axlsx/workbook/worksheet/pivot_table.rb +44 -28
  112. data/lib/axlsx/workbook/worksheet/pivot_table_cache_definition.rb +4 -4
  113. data/lib/axlsx/workbook/worksheet/print_options.rb +1 -3
  114. data/lib/axlsx/workbook/worksheet/protected_range.rb +1 -3
  115. data/lib/axlsx/workbook/worksheet/protected_ranges.rb +5 -2
  116. data/lib/axlsx/workbook/worksheet/rich_text.rb +55 -0
  117. data/lib/axlsx/workbook/worksheet/rich_text_run.rb +250 -0
  118. data/lib/axlsx/workbook/worksheet/row.rb +40 -51
  119. data/lib/axlsx/workbook/worksheet/row_breaks.rb +2 -2
  120. data/lib/axlsx/workbook/worksheet/selection.rb +1 -3
  121. data/lib/axlsx/workbook/worksheet/sheet_data.rb +3 -1
  122. data/lib/axlsx/workbook/worksheet/sheet_pr.rb +21 -3
  123. data/lib/axlsx/workbook/worksheet/sheet_protection.rb +1 -3
  124. data/lib/axlsx/workbook/worksheet/table.rb +6 -6
  125. data/lib/axlsx/workbook/worksheet/table_style_info.rb +1 -3
  126. data/lib/axlsx/workbook/worksheet/tables.rb +4 -1
  127. data/lib/axlsx/workbook/worksheet/worksheet.rb +64 -78
  128. data/lib/axlsx/workbook/worksheet/worksheet_drawing.rb +10 -10
  129. data/lib/axlsx/workbook/worksheet/worksheet_hyperlinks.rb +3 -3
  130. data/lib/axlsx.rb +34 -15
  131. data/test/drawing/tc_area_chart.rb +39 -0
  132. data/test/drawing/tc_area_series.rb +71 -0
  133. data/test/drawing/tc_axis.rb +27 -0
  134. data/test/drawing/tc_bar_chart.rb +71 -0
  135. data/test/drawing/tc_bubble_chart.rb +44 -0
  136. data/test/drawing/tc_bubble_series.rb +21 -0
  137. data/test/drawing/tc_chart.rb +23 -10
  138. data/test/drawing/tc_data_source.rb +6 -0
  139. data/test/drawing/tc_drawing.rb +2 -2
  140. data/test/drawing/tc_line_chart.rb +5 -5
  141. data/test/drawing/tc_line_series.rb +47 -6
  142. data/test/drawing/tc_pic.rb +11 -15
  143. data/test/drawing/tc_scatter_series.rb +36 -1
  144. data/test/drawing/tc_str_val.rb +9 -0
  145. data/test/drawing/tc_title.rb +5 -0
  146. data/test/stylesheet/tc_styles.rb +2 -2
  147. data/test/tc_axlsx.rb +31 -0
  148. data/test/tc_helper.rb +2 -0
  149. data/test/tc_package.rb +19 -1
  150. data/test/util/tc_mime_type_utils.rb +13 -0
  151. data/test/util/tc_simple_typed_list.rb +2 -3
  152. data/test/util/tc_validators.rb +34 -10
  153. data/test/workbook/tc_defined_name.rb +12 -4
  154. data/test/workbook/tc_shared_strings_table.rb +16 -1
  155. data/test/workbook/tc_workbook.rb +38 -3
  156. data/test/workbook/tc_workbook_view.rb +50 -0
  157. data/test/workbook/worksheet/auto_filter/tc_filters.rb +1 -1
  158. data/test/workbook/worksheet/tc_break.rb +1 -1
  159. data/test/workbook/worksheet/tc_cell.rb +76 -8
  160. data/test/workbook/worksheet/tc_col.rb +2 -2
  161. data/test/workbook/worksheet/tc_conditional_formatting.rb +2 -2
  162. data/test/workbook/worksheet/tc_data_bar.rb +1 -1
  163. data/test/workbook/worksheet/tc_data_validation.rb +11 -11
  164. data/test/workbook/worksheet/tc_header_footer.rb +2 -2
  165. data/test/workbook/worksheet/tc_icon_set.rb +1 -1
  166. data/test/workbook/worksheet/tc_outline_pr.rb +19 -0
  167. data/test/workbook/worksheet/tc_page_setup.rb +3 -3
  168. data/test/workbook/worksheet/tc_pivot_table.rb +21 -6
  169. data/test/workbook/worksheet/tc_print_options.rb +1 -1
  170. data/test/workbook/worksheet/tc_rich_text.rb +44 -0
  171. data/test/workbook/worksheet/tc_rich_text_run.rb +172 -0
  172. data/test/workbook/worksheet/tc_row.rb +7 -2
  173. data/test/workbook/worksheet/tc_sheet_calc_pr.rb +1 -1
  174. data/test/workbook/worksheet/tc_sheet_format_pr.rb +4 -4
  175. data/test/workbook/worksheet/tc_sheet_pr.rb +26 -4
  176. data/test/workbook/worksheet/tc_sheet_protection.rb +5 -5
  177. data/test/workbook/worksheet/tc_sheet_view.rb +4 -4
  178. data/test/workbook/worksheet/tc_table.rb +2 -3
  179. data/test/workbook/worksheet/tc_worksheet.rb +99 -45
  180. metadata +142 -64
@@ -4,14 +4,10 @@ module Axlsx
4
4
  # The Worksheet class represents a worksheet in the workbook.
5
5
  class Worksheet
6
6
  include Axlsx::OptionsParser
7
-
7
+ include Axlsx::SerializedAttributes
8
8
  # definition of characters which are less than the maximum width of 0-9 in the default font for use in String#count.
9
9
  # This is used for autowidth calculations
10
- # @return [String]
11
- def self.thin_chars
12
- # removed 'e' and 'y' from this list - as a GUESS
13
- @thin_chars ||= "^.acfijklrstxzFIJL()-"
14
- end
10
+ THIN_CHARS = '^.acfijklrstxzFIJL()-'.freeze
15
11
 
16
12
  # Creates a new worksheet.
17
13
  # @note the recommended way to manage worksheets is Workbook#add_worksheet
@@ -24,12 +20,15 @@ module Axlsx
24
20
  def initialize(wb, options={})
25
21
  self.workbook = wb
26
22
  @sheet_protection = nil
27
-
28
23
  initialize_page_options(options)
29
24
  parse_options options
30
25
  @workbook.worksheets << self
26
+ @sheet_id = index + 1
27
+ yield self if block_given?
31
28
  end
32
29
 
30
+ serializable_attributes :sheet_id, :state
31
+
33
32
  # Initalizes page margin, setup and print options
34
33
  # @param [Hash] options Options passed in from the initializer
35
34
  def initialize_page_options(options)
@@ -44,7 +43,23 @@ module Axlsx
44
43
  # The name of the worksheet
45
44
  # @return [String]
46
45
  def name
47
- @name ||= "Sheet" + (index+1).to_s
46
+ @name ||= "Sheet" + (index+1).to_s
47
+ end
48
+
49
+ # Specifies the visible state of this sheet. Allowed states are
50
+ # :visible, :hidden or :very_hidden. The default value is :visible.
51
+ #
52
+ # Worksheets in the :hidden state can be shown using the sheet formatting properties in excel.
53
+ # :very_hidden sheets should be inaccessible to end users.
54
+ # @param [Symbol] sheet_state The visible state for this sheet.
55
+ def state=(sheet_state)
56
+ RestrictionValidator.validate :worksheet_state, [:visible, :hidden, :very_hidden], sheet_state
57
+ @state = sheet_state
58
+ end
59
+
60
+ # The visibility of this sheet
61
+ def state
62
+ @state ||= :visible
48
63
  end
49
64
 
50
65
  # The sheet calculation properties
@@ -76,7 +91,7 @@ module Axlsx
76
91
  # @see [SheetFormatPr]
77
92
  def sheet_format_pr
78
93
  @sheet_format_pr ||= SheetFormatPr.new
79
- yeild @sheet_format_pr if block_given?
94
+ yield @sheet_format_pr if block_given?
80
95
  @sheet_format_pr
81
96
  end
82
97
 
@@ -129,7 +144,7 @@ module Axlsx
129
144
  # @return [SimpleTypedList]
130
145
  # @see Worksheet#add_row
131
146
  def rows
132
- @rows ||= SimpleTypedList.new Row
147
+ @rows ||= SimpleTypedList.new Row
133
148
  end
134
149
 
135
150
  # returns the sheet data as columns
@@ -137,12 +152,12 @@ module Axlsx
137
152
  # cell at a specific index. The block will be called with the row and column
138
153
  # index in the missing cell was found.
139
154
  # @example
140
- # cols { |row_index, column_index| p "warn - row #{row_index} is does not have a cell at #{column_index}
155
+ # cols { |row_index, column_index| puts "warn - row #{row_index} does not have a cell at #{column_index}" }
141
156
  def cols(&block)
142
157
  @rows.transpose(&block)
143
158
  end
144
159
 
145
- # An range that excel will apply an auto-filter to "A1:B3"
160
+ # A range that excel will apply an auto-filter to "A1:B3"
146
161
  # This will turn filtering on for the cells in the range.
147
162
  # The first row is considered the header, while subsequent rows are considered to be data.
148
163
  # @return String
@@ -249,7 +264,7 @@ module Axlsx
249
264
  @header_footer
250
265
  end
251
266
 
252
- # convinience method to access all cells in this worksheet
267
+ # convenience method to access all cells in this worksheet
253
268
  # @return [Array] cells
254
269
  def cells
255
270
  rows.flatten
@@ -290,50 +305,6 @@ module Axlsx
290
305
  @sheet_pr ||= SheetPr.new self
291
306
  end
292
307
 
293
- # Indicates if gridlines should be shown in the sheet.
294
- # This is true by default.
295
- # @return [Boolean]
296
- # @deprecated Use SheetView#show_grid_lines= instead.
297
- def show_gridlines=(v)
298
- warn('axlsx::DEPRECIATED: Worksheet#show_gridlines= has been depreciated. This value can be set over SheetView#show_grid_lines=.')
299
- Axlsx::validate_boolean v
300
- sheet_view.show_grid_lines = v
301
- end
302
-
303
- # @see selected
304
- # @return [Boolean]
305
- # @deprecated Use SheetView#tab_selected= instead.
306
- def selected=(v)
307
- warn('axlsx::DEPRECIATED: Worksheet#selected= has been depreciated. This value can be set over SheetView#tab_selected=.')
308
- Axlsx::validate_boolean v
309
- sheet_view.tab_selected = v
310
- end
311
-
312
- # Indicates if the worksheet should show gridlines or not
313
- # @return Boolean
314
- # @deprecated Use SheetView#show_grid_lines instead.
315
- def show_gridlines
316
- warn('axlsx::DEPRECIATED: Worksheet#show_gridlines has been depreciated. This value can get over SheetView#show_grid_lines.')
317
- sheet_view.show_grid_lines
318
- end
319
-
320
- # Indicates if the worksheet is selected in the workbook
321
- # It is possible to have more than one worksheet selected, however it might cause issues
322
- # in some older versions of excel when using copy and paste.
323
- # @return Boolean
324
- # @deprecated Use SheetView#tab_selected instead.
325
- def selected
326
- warn('axlsx::DEPRECIATED: Worksheet#selected has been depreciated. This value can get over SheetView#tab_selected.')
327
- sheet_view.tab_selected
328
- end
329
-
330
- # (see #fit_to_page)
331
- # @return [Boolean]
332
- def fit_to_page=(v)
333
- warn('axlsx::DEPRECIATED: Worksheet#fit_to_page has been depreciated. This value will automatically be set for you when you use PageSetup#fit_to.')
334
- fit_to_page?
335
- end
336
-
337
308
  # The name of the worksheet
338
309
  # The name of a worksheet must be unique in the workbook, and must not exceed 31 characters
339
310
  # @param [String] name
@@ -346,7 +317,7 @@ module Axlsx
346
317
  # @param [String] v
347
318
  # @see auto_filter
348
319
  def auto_filter=(v)
349
- DataTypeValidator.validate "Worksheet.auto_filter", String, v
320
+ DataTypeValidator.validate :worksheet_auto_filter, String, v
350
321
  auto_filter.range = v
351
322
  end
352
323
 
@@ -427,10 +398,10 @@ module Axlsx
427
398
  # @option options [Array] widths each member of the widths array will affect how auto_fit behavies.
428
399
  # @option options [Float] height the row's height (in points)
429
400
  def add_row(values=[], options={})
430
- Row.new(self, values, options)
431
- update_column_info @rows.last.cells, options.delete(:widths) || []
432
- yield @rows.last if block_given?
433
- @rows.last
401
+ row = Row.new(self, values, options)
402
+ update_column_info row, options.delete(:widths)
403
+ yield row if block_given?
404
+ row
434
405
  end
435
406
 
436
407
  alias :<< :add_row
@@ -522,7 +493,7 @@ module Axlsx
522
493
  # @example
523
494
  # ws.add_page_break("A4")
524
495
  def add_page_break(cell)
525
- DataTypeValidator.validate "Worksheet#add_page_break cell", [String, Cell], cell
496
+ DataTypeValidator.validate :worksheet_page_break, [String, Cell], cell
526
497
  column_index, row_index = if cell.is_a?(String)
527
498
  Axlsx.name_to_indices(cell)
528
499
  else
@@ -535,12 +506,12 @@ module Axlsx
535
506
  end
536
507
 
537
508
  # This is a helper method that Lets you specify a fixed width for multiple columns in a worksheet in one go.
538
- # Axlsx is sparse, so if you have not set data for a column, you cannot set the width.
509
+ # Note that you must call column_widths AFTER adding data, otherwise the width will not be set successfully.
539
510
  # Setting a fixed column width to nil will revert the behaviour back to calculating the width for you on the next call to add_row.
540
511
  # @example This would set the first and third column widhts but leave the second column in autofit state.
541
512
  # ws.column_widths 7.2, nil, 3
542
513
  # @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
543
- # @param [Integer|Float|Fixnum|nil] widths
514
+ # @param [Integer|Float|nil] widths
544
515
  def column_widths(*widths)
545
516
  widths.each_with_index do |value, index|
546
517
  next if value == nil
@@ -559,7 +530,7 @@ module Axlsx
559
530
  # @see README.md for an example
560
531
  def col_style(index, style, options={})
561
532
  offset = options.delete(:row_offset) || 0
562
- cells = @rows[(offset..-1)].map { |row| row.cells[index] }.flatten.compact
533
+ cells = @rows[(offset..-1)].map { |row| row[index] }.flatten.compact
563
534
  cells.each { |cell| cell.style = style }
564
535
  end
565
536
 
@@ -577,18 +548,27 @@ module Axlsx
577
548
  cells.each { |cell| cell.style = style }
578
549
  end
579
550
 
551
+ # Returns a sheet node serialization for this sheet in the workbook.
552
+ def to_sheet_node_xml_string(str='')
553
+ add_autofilter_defined_name_to_workbook
554
+ str << '<sheet '
555
+ serialized_attributes str
556
+ str << ('name="' << name << '" ')
557
+ str << ('r:id="' << rId << '"></sheet>')
558
+ end
559
+
580
560
  # Serializes the worksheet object to an xml string
581
561
  # This intentionally does not use nokogiri for performance reasons
582
562
  # @return [String]
583
- def to_xml_string
563
+ def to_xml_string str=''
564
+ add_autofilter_defined_name_to_workbook
584
565
  auto_filter.apply if auto_filter.range
585
- str = '<?xml version="1.0" encoding="UTF-8"?>'
566
+ str << '<?xml version="1.0" encoding="UTF-8"?>'
586
567
  str << worksheet_node
587
568
  serializable_parts.each do |item|
588
569
  item.to_xml_string(str) if item
589
570
  end
590
571
  str << '</worksheet>'
591
- Axlsx::sanitize(str)
592
572
  end
593
573
 
594
574
  # The worksheet relationships. This is managed automatically by the worksheet
@@ -606,7 +586,7 @@ module Axlsx
606
586
  # Returns the cell or cells defined using excel style A1:B3 references.
607
587
  # @param [String|Integer] cell_def the string defining the cell or range of cells, or the rownumber
608
588
  # @return [Cell, Array]
609
- def [] (cell_def)
589
+ def [](cell_def)
610
590
  return rows[cell_def] if cell_def.is_a?(Integer)
611
591
  parts = cell_def.split(':').map{ |part| name_to_cell part }
612
592
  if parts.size == 1
@@ -622,7 +602,7 @@ module Axlsx
622
602
  def name_to_cell(name)
623
603
  col_index, row_index = *Axlsx::name_to_indices(name)
624
604
  r = rows[row_index]
625
- r.cells[col_index] if r
605
+ r[col_index] if r
626
606
  end
627
607
 
628
608
  # shortcut method to access styles direclty from the worksheet
@@ -675,7 +655,7 @@ module Axlsx
675
655
  end
676
656
 
677
657
  def validate_sheet_name(name)
678
- DataTypeValidator.validate "Worksheet.name", String, name
658
+ DataTypeValidator.validate :worksheet_name, String, name
679
659
  raise ArgumentError, (ERR_SHEET_NAME_TOO_LONG % name) if name.size > 31
680
660
  raise ArgumentError, (ERR_SHEET_NAME_CHARACTER_FORBIDDEN % name) if '[]*/\?:'.chars.any? { |char| name.include? char }
681
661
  name = Axlsx::coder.encode(name)
@@ -695,8 +675,8 @@ module Axlsx
695
675
  def range(*cell_def)
696
676
  first, last = cell_def
697
677
  cells = []
698
- rows[(first.row.index..last.row.index)].each do |r|
699
- r.cells[(first.index..last.index)].each do |c|
678
+ rows[(first.row.row_index..last.row.row_index)].each do |r|
679
+ r[(first.index..last.index)].each do |c|
700
680
  cells << c
701
681
  end
702
682
  end
@@ -734,7 +714,7 @@ module Axlsx
734
714
  # Helper method for parsingout the root node for worksheet
735
715
  # @return [String]
736
716
  def worksheet_node
737
- "<worksheet xmlns=\"%s\" xmlns:r=\"%s\" xml:space=\"#{xml_space}\">" % [XML_NS, XML_NS_R]
717
+ "<worksheet xmlns=\"#{XML_NS}\" xmlns:r=\"#{XML_NS_R}\" xml:space=\"#{xml_space}\">"
738
718
  end
739
719
 
740
720
  def sheet_data
@@ -753,11 +733,12 @@ module Axlsx
753
733
 
754
734
  def workbook=(v) DataTypeValidator.validate "Worksheet.workbook", Workbook, v; @workbook = v; end
755
735
 
756
- def update_column_info(cells, widths=[])
736
+ def update_column_info(cells, widths=nil)
757
737
  cells.each_with_index do |cell, index|
738
+ width = widths ? widths[index] : nil
758
739
  col = find_or_create_column_info(index)
759
- next if widths[index] == :ignore
760
- col.update_width(cell, widths[index], workbook.use_autowidth)
740
+ next if width == :ignore
741
+ col.update_width(cell, width, workbook.use_autowidth)
761
742
  end
762
743
  end
763
744
 
@@ -765,5 +746,10 @@ module Axlsx
765
746
  column_info[index] ||= Col.new(index + 1, index + 1)
766
747
  end
767
748
 
749
+ def add_autofilter_defined_name_to_workbook
750
+ return if !auto_filter.range
751
+ workbook.add_defined_name auto_filter.defined_name, name: '_xlnm._FilterDatabase', local_sheet_id: index, hidden: 1
752
+ end
753
+
768
754
  end
769
755
  end
@@ -1,5 +1,5 @@
1
1
  module Axlsx
2
-
2
+
3
3
  # This is a utility class for serialing the drawing node in a
4
4
  # worksheet. Drawing objects have their own serialization that exports
5
5
  # a drawing document. This is only for the single node in the
@@ -17,7 +17,7 @@ module Axlsx
17
17
  attr_reader :worksheet
18
18
 
19
19
  attr_reader :drawing
20
-
20
+
21
21
  # adds a chart to the drawing object
22
22
  # @param [Class] chart_type The type of chart to add
23
23
  # @param [Hash] options Options to pass on to the drawing and chart
@@ -26,17 +26,17 @@ module Axlsx
26
26
  @drawing ||= Drawing.new worksheet
27
27
  drawing.add_chart(chart_type, options)
28
28
  end
29
-
29
+
30
30
  # adds an image to the drawing object
31
- # @param [Hash] options Options to pass on to the drawing and image
31
+ # @param [Hash] options Options to pass on to the drawing and image
32
32
  # @see Worksheet#add_image
33
33
  def add_image(options)
34
- @drawing ||= Drawing.new worksheet
34
+ @drawing ||= Drawing.new(worksheet)
35
35
  drawing.add_image(options)
36
- end
37
-
36
+ end
37
+
38
38
  # helper method to tell us if the drawing has something in it or not
39
- # @return [Boolean]
39
+ # @return [Boolean]
40
40
  def has_drawing?
41
41
  @drawing.is_a? Drawing
42
42
  end
@@ -45,13 +45,13 @@ module Axlsx
45
45
  # @return [Relationship]
46
46
  def relationship
47
47
  return unless has_drawing?
48
- Relationship.new(self, DRAWING_R, "../#{drawing.pn}")
48
+ Relationship.new(self, DRAWING_R, "../#{drawing.pn}")
49
49
  end
50
50
 
51
51
  # Serialize the drawing for the worksheet
52
52
  # @param [String] str
53
53
  def to_xml_string(str = '')
54
- return unless has_drawing?
54
+ return unless has_drawing?
55
55
  str << "<drawing r:id='#{relationship.Id}'/>"
56
56
  end
57
57
  end
@@ -15,8 +15,8 @@ module Axlsx
15
15
  # @see WorksheetHyperlink#initialize
16
16
  # @return [WorksheetHyperlink]
17
17
  def add(options)
18
- @list << WorksheetHyperlink.new(@worksheet, options)
19
- @list.last
18
+ self << WorksheetHyperlink.new(@worksheet, options)
19
+ last
20
20
  end
21
21
 
22
22
  # The relationships required by this collection's hyperlinks
@@ -31,7 +31,7 @@ module Axlsx
31
31
  def to_xml_string(str='')
32
32
  return if empty?
33
33
  str << '<hyperlinks>'
34
- @list.each { |hyperlink| hyperlink.to_xml_string(str) }
34
+ each { |hyperlink| hyperlink.to_xml_string(str) }
35
35
  str << '</hyperlinks>'
36
36
  end
37
37
  end
data/lib/axlsx.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # encoding: UTF-8
2
2
  require 'htmlentities'
3
3
  require 'axlsx/version.rb'
4
+ require 'mimemagic'
4
5
 
5
6
  require 'axlsx/util/simple_typed_list.rb'
6
7
  require 'axlsx/util/constants.rb'
@@ -10,6 +11,7 @@ require 'axlsx/util/serialized_attributes'
10
11
  require 'axlsx/util/options_parser'
11
12
  # to be included with parsable intitites.
12
13
  #require 'axlsx/util/parser.rb'
14
+ require 'axlsx/util/mime_type_utils'
13
15
 
14
16
  require 'axlsx/stylesheet/styles.rb'
15
17
 
@@ -53,7 +55,7 @@ module Axlsx
53
55
  cells = sort_cells(cells)
54
56
  reference = "#{cells.first.reference(absolute)}:#{cells.last.reference(absolute)}"
55
57
  if absolute
56
- escaped_name = cells.first.row.worksheet.name.gsub "&apos;", "''"
58
+ escaped_name = cells.first.row.worksheet.name.gsub '&apos;', "''"
57
59
  "'#{escaped_name}'!#{reference}"
58
60
  else
59
61
  reference
@@ -65,7 +67,7 @@ module Axlsx
65
67
  # @param [Array] cells
66
68
  # @return [Array]
67
69
  def self.sort_cells(cells)
68
- cells.sort { |x, y| [x.index, x.row.index] <=> [y.index, y.row.index] }
70
+ cells.sort { |x, y| [x.index, x.row.row_index] <=> [y.index, y.row.row_index] }
69
71
  end
70
72
 
71
73
  #global reference html entity encoding
@@ -88,20 +90,21 @@ module Axlsx
88
90
  # @note This follows the standard spreadsheet convention of naming columns A to Z, followed by AA to AZ etc.
89
91
  # @return [String]
90
92
  def self.col_ref(index)
91
- chars = []
93
+ chars = ''
92
94
  while index >= 26 do
93
- chars << ((index % 26) + 65).chr
94
- index = (index / 26).to_i - 1
95
+ index, char = index.divmod(26)
96
+ chars.prepend((char + 65).chr)
97
+ index -= 1
95
98
  end
96
- chars << (index + 65).chr
97
- chars.reverse.join
99
+ chars.prepend((index + 65).chr)
100
+ chars
98
101
  end
99
102
 
100
103
  # @return [String] The alpha(column)numeric(row) reference for this sell.
101
104
  # @example Relative Cell Reference
102
105
  # ws.rows.first.cells.first.r #=> "A1"
103
106
  def self.cell_r(c_index, r_index)
104
- Axlsx::col_ref(c_index).to_s << (r_index+1).to_s
107
+ col_ref(c_index) << (r_index+1).to_s
105
108
  end
106
109
 
107
110
  # Creates an array of individual cell references based on an excel reference range.
@@ -113,7 +116,7 @@ module Axlsx
113
116
  end_col, end_row = name_to_indices($2)
114
117
  (start_row..end_row).to_a.map do |row_num|
115
118
  (start_col..end_col).to_a.map do |col_num|
116
- "#{col_ref(col_num)}#{row_num+1}"
119
+ cell_r(col_num, row_num)
117
120
  end
118
121
  end
119
122
  end
@@ -127,14 +130,30 @@ module Axlsx
127
130
  s.gsub(/_(.)/){ $1.upcase }
128
131
  end
129
132
 
130
- # returns the provided string with all invalid control charaters
131
- # removed.
132
- # @param [String] str The sting to process
133
- # @return [String]
134
- def self.sanitize(str)
135
- str.gsub(CONTROL_CHAR_REGEX, '')
133
+ # returns the provided string with all invalid control charaters
134
+ # removed.
135
+ # @param [String] str The string to process
136
+ # @return [String]
137
+ def self.sanitize(str)
138
+ if str.frozen?
139
+ str.delete(CONTROL_CHARS)
140
+ else
141
+ str.delete!(CONTROL_CHARS)
142
+ str
136
143
  end
144
+ end
137
145
 
146
+ # If value is boolean return 1 or 0
147
+ # else return the value
148
+ # @param [Object] value The value to process
149
+ # @return [Object]
150
+ def self.booleanize(value)
151
+ if value == true || value == false
152
+ value ? 1 : 0
153
+ else
154
+ value
155
+ end
156
+ end
138
157
 
139
158
  # Instructs the serializer to not try to escape cell value input.
140
159
  # This will give you a huge speed bonus, but if you content has <, > or other xml character data
@@ -0,0 +1,39 @@
1
+ require 'tc_helper.rb'
2
+
3
+ class TestAreaChart < 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::AreaChart, :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::AreaSeries, "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
@@ -0,0 +1,71 @@
1
+ require 'tc_helper.rb'
2
+
3
+ class TestAreaSeries < Test::Unit::TestCase
4
+
5
+ def setup
6
+ p = Axlsx::Package.new
7
+ @ws = p.workbook.add_worksheet :name=>"hmmm"
8
+ chart = @ws.add_chart Axlsx::AreaChart, :title => "fishery"
9
+ @series = chart.add_series(
10
+ :data => [0,1,2],
11
+ :labels => ["zero", "one", "two"],
12
+ :title => "bob",
13
+ :color => "#FF0000",
14
+ :show_marker => true,
15
+ :smooth => true
16
+ )
17
+ end
18
+
19
+ def test_initialize
20
+ assert_equal(@series.title.text, "bob", "series title has been applied")
21
+ assert_equal(@series.labels.class, Axlsx::AxDataSource)
22
+ assert_equal(@series.data.class, Axlsx::NumDataSource)
23
+ end
24
+
25
+ def test_show_marker
26
+ assert_equal(true, @series.show_marker)
27
+ @series.show_marker = false
28
+ assert_equal(false, @series.show_marker)
29
+ end
30
+
31
+ def test_smooth
32
+ assert_equal(true, @series.smooth)
33
+ @series.smooth = false
34
+ assert_equal(false, @series.smooth)
35
+ end
36
+
37
+ def test_marker_symbol
38
+ assert_equal(:default, @series.marker_symbol)
39
+ @series.marker_symbol = :circle
40
+ assert_equal(:circle, @series.marker_symbol)
41
+ end
42
+
43
+ def test_to_xml_string
44
+ doc = Nokogiri::XML(wrap_with_namespaces(@series))
45
+ assert(doc.xpath("//srgbClr[@val='#{@series.color}']"))
46
+ assert_equal(xpath_with_namespaces(doc, "//c:marker").size, 0)
47
+ assert(doc.xpath("//smooth"))
48
+
49
+ @series.marker_symbol = :diamond
50
+ doc = Nokogiri::XML(wrap_with_namespaces(@series))
51
+ assert_equal(xpath_with_namespaces(doc, "//c:marker/c:symbol[@val='diamond']").size, 1)
52
+
53
+ @series.show_marker = false
54
+ doc = Nokogiri::XML(wrap_with_namespaces(@series))
55
+ assert_equal(xpath_with_namespaces(doc, "//c:marker/c:symbol[@val='none']").size, 1)
56
+ end
57
+
58
+ def wrap_with_namespaces(series)
59
+ '<c:chartSpace xmlns:c="' <<
60
+ Axlsx::XML_NS_C <<
61
+ '" xmlns:a="' <<
62
+ Axlsx::XML_NS_A <<
63
+ '">' <<
64
+ series.to_xml_string <<
65
+ '</c:chartSpace>'
66
+ end
67
+
68
+ def xpath_with_namespaces(doc, xpath)
69
+ doc.xpath(xpath, "a" => Axlsx::XML_NS_A, "c" => Axlsx::XML_NS_C)
70
+ end
71
+ end
@@ -61,6 +61,33 @@ class TestAxis < Test::Unit::TestCase
61
61
  assert_nothing_raised("accepts valid format code") { @axis.format_code = "00.##" }
62
62
  end
63
63
 
64
+ def create_chart_with_formatting(format_string=nil)
65
+ p = Axlsx::Package.new
66
+ p.workbook.add_worksheet(:name => "Formatting Test") do |sheet|
67
+ sheet.add_row(['test', 20])
68
+ sheet.add_chart(Axlsx::Bar3DChart, :start_at => [0,5], :end_at => [10, 20], :title => "Test Formatting") do |chart|
69
+ chart.add_series :data => sheet["B1:B1"], :labels => sheet["A1:A1"]
70
+ chart.val_axis.format_code = format_string if format_string
71
+ doc = Nokogiri::XML(chart.to_xml_string)
72
+ yield doc
73
+ end
74
+ end
75
+ end
76
+
77
+ def test_format_code_resets_source_linked
78
+ create_chart_with_formatting("#,##0.00") do |doc|
79
+ assert_equal(doc.xpath("//c:valAx/c:numFmt[@formatCode='#,##0.00']").size, 1)
80
+ assert_equal(doc.xpath("//c:valAx/c:numFmt[@sourceLinked='0']").size, 1)
81
+ end
82
+ end
83
+
84
+ def test_no_format_code_keeps_source_linked
85
+ create_chart_with_formatting do |doc|
86
+ assert_equal(doc.xpath("//c:valAx/c:numFmt[@formatCode='General']").size, 1)
87
+ assert_equal(doc.xpath("//c:valAx/c:numFmt[@sourceLinked='1']").size, 1)
88
+ end
89
+ end
90
+
64
91
  def test_crosses
65
92
  assert_raise(ArgumentError, "requires valid crosses") { @axis.crosses = 1 }
66
93
  assert_nothing_raised("accepts valid crosses") { @axis.crosses = :min }