caxlsx 3.1.1 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (154) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +43 -1
  3. data/README.md +4 -11
  4. data/lib/axlsx/content_type/abstract_content_type.rb +1 -1
  5. data/lib/axlsx/doc_props/app.rb +1 -1
  6. data/lib/axlsx/drawing/chart.rb +25 -2
  7. data/lib/axlsx/drawing/d_lbls.rb +3 -2
  8. data/lib/axlsx/drawing/scatter_series.rb +31 -0
  9. data/lib/axlsx/drawing/title.rb +11 -1
  10. data/lib/axlsx/drawing/view_3D.rb +1 -1
  11. data/lib/axlsx/package.rb +15 -5
  12. data/lib/axlsx/rels/relationship.rb +1 -1
  13. data/lib/axlsx/stylesheet/border.rb +2 -0
  14. data/lib/axlsx/stylesheet/font.rb +1 -1
  15. data/lib/axlsx/stylesheet/styles.rb +139 -24
  16. data/lib/axlsx/util/constants.rb +16 -1
  17. data/lib/axlsx/util/serialized_attributes.rb +2 -2
  18. data/lib/axlsx/util/storage.rb +9 -9
  19. data/lib/axlsx/version.rb +1 -1
  20. data/lib/axlsx/workbook/workbook.rb +55 -0
  21. data/lib/axlsx/workbook/worksheet/border_creator.rb +76 -0
  22. data/lib/axlsx/workbook/worksheet/cell.rb +29 -2
  23. data/lib/axlsx/workbook/worksheet/cell_serializer.rb +1 -1
  24. data/lib/axlsx/workbook/worksheet/col.rb +4 -4
  25. data/lib/axlsx/workbook/worksheet/data_validation.rb +26 -5
  26. data/lib/axlsx/workbook/worksheet/pivot_table.rb +55 -14
  27. data/lib/axlsx/workbook/worksheet/rich_text_run.rb +1 -1
  28. data/lib/axlsx/workbook/worksheet/worksheet.rb +68 -7
  29. data/lib/axlsx.rb +43 -10
  30. metadata +6 -253
  31. data/test/benchmark.rb +0 -72
  32. data/test/content_type/tc_content_type.rb +0 -76
  33. data/test/content_type/tc_default.rb +0 -16
  34. data/test/content_type/tc_override.rb +0 -14
  35. data/test/doc_props/tc_app.rb +0 -43
  36. data/test/doc_props/tc_core.rb +0 -42
  37. data/test/drawing/tc_area_chart.rb +0 -39
  38. data/test/drawing/tc_area_series.rb +0 -71
  39. data/test/drawing/tc_axes.rb +0 -8
  40. data/test/drawing/tc_axis.rb +0 -112
  41. data/test/drawing/tc_bar_3D_chart.rb +0 -86
  42. data/test/drawing/tc_bar_chart.rb +0 -86
  43. data/test/drawing/tc_bar_series.rb +0 -46
  44. data/test/drawing/tc_bubble_chart.rb +0 -44
  45. data/test/drawing/tc_bubble_series.rb +0 -21
  46. data/test/drawing/tc_cat_axis.rb +0 -31
  47. data/test/drawing/tc_cat_axis_data.rb +0 -27
  48. data/test/drawing/tc_chart.rb +0 -123
  49. data/test/drawing/tc_d_lbls.rb +0 -57
  50. data/test/drawing/tc_data_source.rb +0 -23
  51. data/test/drawing/tc_drawing.rb +0 -80
  52. data/test/drawing/tc_graphic_frame.rb +0 -27
  53. data/test/drawing/tc_hyperlink.rb +0 -64
  54. data/test/drawing/tc_line_3d_chart.rb +0 -47
  55. data/test/drawing/tc_line_chart.rb +0 -39
  56. data/test/drawing/tc_line_series.rb +0 -71
  57. data/test/drawing/tc_marker.rb +0 -44
  58. data/test/drawing/tc_named_axis_data.rb +0 -27
  59. data/test/drawing/tc_num_data.rb +0 -31
  60. data/test/drawing/tc_num_val.rb +0 -29
  61. data/test/drawing/tc_one_cell_anchor.rb +0 -66
  62. data/test/drawing/tc_pic.rb +0 -103
  63. data/test/drawing/tc_picture_locking.rb +0 -72
  64. data/test/drawing/tc_pie_3D_chart.rb +0 -28
  65. data/test/drawing/tc_pie_series.rb +0 -33
  66. data/test/drawing/tc_scaling.rb +0 -36
  67. data/test/drawing/tc_scatter_chart.rb +0 -48
  68. data/test/drawing/tc_scatter_series.rb +0 -56
  69. data/test/drawing/tc_ser_axis.rb +0 -31
  70. data/test/drawing/tc_series.rb +0 -23
  71. data/test/drawing/tc_series_title.rb +0 -54
  72. data/test/drawing/tc_str_data.rb +0 -18
  73. data/test/drawing/tc_str_val.rb +0 -30
  74. data/test/drawing/tc_title.rb +0 -70
  75. data/test/drawing/tc_two_cell_anchor.rb +0 -36
  76. data/test/drawing/tc_val_axis.rb +0 -24
  77. data/test/drawing/tc_view_3D.rb +0 -54
  78. data/test/drawing/tc_vml_drawing.rb +0 -25
  79. data/test/drawing/tc_vml_shape.rb +0 -106
  80. data/test/fixtures/image1.gif +0 -0
  81. data/test/fixtures/image1.jpeg +0 -0
  82. data/test/fixtures/image1.jpg +0 -0
  83. data/test/fixtures/image1.png +0 -0
  84. data/test/fixtures/image1_fake.jpg +0 -0
  85. data/test/profile.rb +0 -24
  86. data/test/rels/tc_relationship.rb +0 -52
  87. data/test/rels/tc_relationships.rb +0 -37
  88. data/test/stylesheet/tc_border.rb +0 -37
  89. data/test/stylesheet/tc_border_pr.rb +0 -32
  90. data/test/stylesheet/tc_cell_alignment.rb +0 -81
  91. data/test/stylesheet/tc_cell_protection.rb +0 -29
  92. data/test/stylesheet/tc_cell_style.rb +0 -57
  93. data/test/stylesheet/tc_color.rb +0 -43
  94. data/test/stylesheet/tc_dxf.rb +0 -81
  95. data/test/stylesheet/tc_fill.rb +0 -18
  96. data/test/stylesheet/tc_font.rb +0 -133
  97. data/test/stylesheet/tc_gradient_fill.rb +0 -72
  98. data/test/stylesheet/tc_gradient_stop.rb +0 -31
  99. data/test/stylesheet/tc_num_fmt.rb +0 -30
  100. data/test/stylesheet/tc_pattern_fill.rb +0 -43
  101. data/test/stylesheet/tc_styles.rb +0 -261
  102. data/test/stylesheet/tc_table_style.rb +0 -44
  103. data/test/stylesheet/tc_table_style_element.rb +0 -45
  104. data/test/stylesheet/tc_table_styles.rb +0 -29
  105. data/test/stylesheet/tc_xf.rb +0 -120
  106. data/test/tc_axlsx.rb +0 -109
  107. data/test/tc_helper.rb +0 -10
  108. data/test/tc_package.rb +0 -314
  109. data/test/util/tc_mime_type_utils.rb +0 -13
  110. data/test/util/tc_serialized_attributes.rb +0 -19
  111. data/test/util/tc_simple_typed_list.rb +0 -77
  112. data/test/util/tc_validators.rb +0 -210
  113. data/test/workbook/tc_defined_name.rb +0 -49
  114. data/test/workbook/tc_shared_strings_table.rb +0 -59
  115. data/test/workbook/tc_workbook.rb +0 -160
  116. data/test/workbook/tc_workbook_view.rb +0 -50
  117. data/test/workbook/worksheet/auto_filter/tc_auto_filter.rb +0 -38
  118. data/test/workbook/worksheet/auto_filter/tc_filter_column.rb +0 -76
  119. data/test/workbook/worksheet/auto_filter/tc_filters.rb +0 -50
  120. data/test/workbook/worksheet/tc_break.rb +0 -49
  121. data/test/workbook/worksheet/tc_cell.rb +0 -453
  122. data/test/workbook/worksheet/tc_cfvo.rb +0 -31
  123. data/test/workbook/worksheet/tc_col.rb +0 -93
  124. data/test/workbook/worksheet/tc_color_scale.rb +0 -58
  125. data/test/workbook/worksheet/tc_comment.rb +0 -72
  126. data/test/workbook/worksheet/tc_comments.rb +0 -57
  127. data/test/workbook/worksheet/tc_conditional_formatting.rb +0 -224
  128. data/test/workbook/worksheet/tc_data_bar.rb +0 -46
  129. data/test/workbook/worksheet/tc_data_validation.rb +0 -265
  130. data/test/workbook/worksheet/tc_date_time_converter.rb +0 -124
  131. data/test/workbook/worksheet/tc_header_footer.rb +0 -151
  132. data/test/workbook/worksheet/tc_icon_set.rb +0 -45
  133. data/test/workbook/worksheet/tc_outline_pr.rb +0 -19
  134. data/test/workbook/worksheet/tc_page_margins.rb +0 -97
  135. data/test/workbook/worksheet/tc_page_set_up_pr.rb +0 -15
  136. data/test/workbook/worksheet/tc_page_setup.rb +0 -143
  137. data/test/workbook/worksheet/tc_pane.rb +0 -54
  138. data/test/workbook/worksheet/tc_pivot_table.rb +0 -143
  139. data/test/workbook/worksheet/tc_pivot_table_cache_definition.rb +0 -62
  140. data/test/workbook/worksheet/tc_print_options.rb +0 -72
  141. data/test/workbook/worksheet/tc_protected_range.rb +0 -17
  142. data/test/workbook/worksheet/tc_rich_text.rb +0 -44
  143. data/test/workbook/worksheet/tc_rich_text_run.rb +0 -173
  144. data/test/workbook/worksheet/tc_row.rb +0 -160
  145. data/test/workbook/worksheet/tc_selection.rb +0 -55
  146. data/test/workbook/worksheet/tc_sheet_calc_pr.rb +0 -18
  147. data/test/workbook/worksheet/tc_sheet_format_pr.rb +0 -88
  148. data/test/workbook/worksheet/tc_sheet_pr.rb +0 -49
  149. data/test/workbook/worksheet/tc_sheet_protection.rb +0 -117
  150. data/test/workbook/worksheet/tc_sheet_view.rb +0 -214
  151. data/test/workbook/worksheet/tc_table.rb +0 -77
  152. data/test/workbook/worksheet/tc_table_style_info.rb +0 -53
  153. data/test/workbook/worksheet/tc_worksheet.rb +0 -601
  154. data/test/workbook/worksheet/tc_worksheet_hyperlink.rb +0 -55
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ef44b04d373e873848cd74d5bebae4d327cd0d9cba06ee74de6d0aac35b51ab9
4
- data.tar.gz: b54abdd82f277253216da4ad9d938c2508c9f1ed54abd080d4437e5523c470e1
3
+ metadata.gz: 4f5803740b82493118fd7fe6787c90dd0eb8e2f7908736597026d03c4255597b
4
+ data.tar.gz: 3bf010de6171b2862cd27ea12df265162071801b0cac7172cee4d1629e856835
5
5
  SHA512:
6
- metadata.gz: bce9d28013a2ec3ffec4be335a2b933ba38fb508dbc4f486a3df135dc81122a236ff9439792ac8bc64c4150e523af261deea02c5a86b9f3838a38b2a26e0d537
7
- data.tar.gz: 1bca0d82c582818a822feefbb499caef3b622f8d4203543a1c6d11f57876944df01db0bafb30d6238f9a268d731a0a78de0ed4efa97a205db43465d73dab7d74
6
+ metadata.gz: 40af150a59e4aacb3f1d385117d0c21b1b2d8ca3c36e12592f23464b35270ac07af826c2494c9922510603e96933de82dafb4819b8ac31b892c7ce842eb190cc
7
+ data.tar.gz: bd16de0493f11a225fd7e376cdce5b10433f253431e2d00f9ecfeca464f96336499d35806781de77ad5c1dad62a63bb2545deb7e00cfef6fc0a4a1f0657103e1
data/CHANGELOG.md CHANGED
@@ -1,16 +1,53 @@
1
1
  CHANGELOG
2
2
  ---------
3
+ - **Unreleased**
4
+
5
+ - **October.21.22**: 3.3.0
6
+ - [PR #168](https://github.com/caxlsx/caxlsx/pull/168) - Merge in the gem [`axlsx_styler`](https://github.com/axlsx-styler-gem/axlsx_styler)
7
+ - Add ability to both apply or append to existing styles after rows have been created using `worksheet.add_style`
8
+ - `worksheet.add_style "A1", {b: true}`
9
+ - `worksheet.add_style "A1:B2", {b: true}`
10
+ - `worksheet.add_style ["A1", "B2:C7", "D8:E9"], {b: true}`
11
+ - Add ability to create borders upon specific areas of the page using `worksheet.add_border`
12
+ - `worksheet.add_border "A1", {style: :thin}`
13
+ - `worksheet.add_border "A1:B2", {style: :thin}`
14
+ - `worksheet.add_border ["A1", "B2:C7", "D8:E9"], {style: :thin}`
15
+ - Add `Axlsx::BorderCreator` the class used under the hood for `worksheet.add_border`
16
+ - Allow specifying `:all` in `border: {edges: :all}` which is a shortcut for `border: {edges: [:left, :right, :top, :bottom]}`
17
+ - [PR #156](https://github.com/caxlsx/caxlsx/pull/156) - Prevent Excel from crashing when multiple data columns added to PivotTable
18
+ - [PR #155](https://github.com/caxlsx/caxlsx/pull/155) - Add `hideDropDown` alias for `showDropDown` setting, as the latter is confusing to use (because its logic seems inverted).
19
+ - [PR #143](https://github.com/caxlsx/caxlsx/pull/143) - Add setting `sort_on_headers` for pivot tables
20
+ - [PR #132](https://github.com/caxlsx/caxlsx/pull/132) - Remove monkey patch from Object#instance_values
21
+ - [PR #139](https://github.com/caxlsx/caxlsx/pull/139) - Sort archive entries for correct MIME detection with `file` command
22
+ - [PR #140](https://github.com/caxlsx/caxlsx/pull/140) - Update gemspec to recent styles - it reduced the size of the gem
23
+ - [PR #147](https://github.com/caxlsx/caxlsx/pull/147) - Implement “rounded corners” setting for charts.
24
+ - [PR #145](https://github.com/caxlsx/caxlsx/pull/145) - Implement “plot visible only” setting for charts.
25
+ - [PR #144](https://github.com/caxlsx/caxlsx/pull/144) - Completely hide chart titles if blank; Fix missing cell reference for chart title when cell empty.
26
+
27
+ - **February.23.22**: 3.2.0
28
+ - [PR #75](https://github.com/caxlsx/caxlsx/pull/85) - Added manageable markers for scatter series
29
+ - [PR #116](https://github.com/caxlsx/caxlsx/pull/116) - Validate name option to be non-empty string when passed.
30
+ - [PR #117](https://github.com/caxlsx/caxlsx/pull/117) - Allow passing an Array of border hashes to the `border` style. Change previous behaviour where `border_top`, `border_*` styles would not be applied unless `border` style was also defined.
31
+ - [PR #122](https://github.com/caxlsx/caxlsx/pull/122) - Improve error messages when incorrect ranges are provided to `Worksheet#[]`
32
+ - [PR #123](https://github.com/caxlsx/caxlsx/pull/123) - Fix invalid xml when pivot table created with more than one column in data field. Solves [Issue #110](https://github.com/caxlsx/caxlsx/issues/110)
33
+ - [PR #127](https://github.com/caxlsx/caxlsx/pull/127) - Possibility to configure the calculation of the autowidth mechanism with `font_scale_divisor` and `bold_font_multiplier`. Example: [Fine tuned autowidth](examples/fine_tuned_autowidth_example.md)
34
+ - [PR #85](https://github.com/caxlsx/caxlsx/pull/85) - Manageable markers for scatter series
35
+ - [PR #120](https://github.com/caxlsx/caxlsx/pull/120) - Return output stream in binmode
3
36
 
4
37
  - **September.22.21**: 3.1.1
5
38
  - [PR #107](https://github.com/caxlsx/caxlsx/pull/107) - Add overlap to bar charts
6
39
  - [PR #108](https://github.com/caxlsx/caxlsx/pull/108) - Fix gap depth and gap depth validators for bar charts and 3D bar charts
40
+ - [PR #94](https://github.com/caxlsx/caxlsx/pull/94) - Major performance improvement for charts with large amounts of data
41
+ - [PR #81](https://github.com/caxlsx/caxlsx/pull/81) - Add option to define a color for the BarSeries
7
42
 
8
43
  - **March.27.21**: 3.1.0
9
- - [PR #95](https://github.com/caxlsx/caxlsx/pull/95) - Replace mimemagic with marcel
44
+ - [PR #95](https://github.com/caxlsx/caxlsx/pull/95) - Replace mimemagic with marcel
10
45
  - [PR #87](https://github.com/caxlsx/caxlsx/pull/87) - Implement :offset option for worksheet#add_row
11
46
  - [PR #79](https://github.com/caxlsx/caxlsx/pull/79) - Add support for format in pivot tables
12
47
  - [PR #77](https://github.com/caxlsx/caxlsx/pull/77) - Fix special characters in table header
13
48
  - [PR #57](https://github.com/caxlsx/caxlsx/pull/57) - Deprecate using #serialize with boolean argument: Calls like `Package#serialize("name.xlsx", false)` should be replaced with `Package#serialize("name.xlsx", confirm_valid: false)`.
49
+ - [PR #78](https://github.com/caxlsx/caxlsx/pull/78) - Fix special characters in pivot table cache definition
50
+ - [PR #84](https://github.com/caxlsx/caxlsx/pull/84) - Add JRuby 9.2 to the CI
14
51
 
15
52
  - **January.5.21**: 3.0.4
16
53
  - [PR #72](https://github.com/caxlsx/caxlsx/pull/72) - Relax Ruby dependency to allow for Ruby 3. This required Travis to be upgraded from Ubuntu Trusty to Ubuntu Bionic. rbx-3 was dropped.
@@ -23,11 +60,16 @@ CHANGELOG
23
60
  - [PR #56](https://github.com/caxlsx/caxlsx/pull/56) - Add `zip_command` option to `#serialize` for faster serialization of large Excel files by using a zip binary
24
61
  - [PR #54](https://github.com/caxlsx/caxlsx/pull/54) - Fix type detection for floats with out-of-rage exponents
25
62
  - [I #67](https://github.com/caxlsx/caxlsx/issues/67) - Fix regression in worksheet name length enforcement: Some unicode characters were counted incorrectly, so that names that previously worked fine now stopped working. (This was introduced in 3.0.2)
63
+ - [I #58](https://github.com/caxlsx/caxlsx/issues/58) - Fix explosion for pie chart throwing error
64
+ - [PR #60](https://github.com/caxlsx/caxlsx/pull/60) - Add Ruby 2.7 to the CI
65
+ - [PR #47](https://github.com/caxlsx/caxlsx/pull/47) - Restructure examples folder
26
66
 
27
67
  - **July.16.20**: 3.0.2
28
68
  - [I #51](https://github.com/caxlsx/caxlsx/issues/51) - Images do not import on Windows. IO read set explicitly to binary mode.
29
69
  - [PR #53](https://github.com/caxlsx/caxlsx/pull/53) - Limit column width to 255. Maximum column width limit in MS Excel is 255 characters, see https://support.microsoft.com/en-us/office/excel-specifications-and-limits-1672b34d-7043-467e-8e27-269d656771c3
30
70
  - [PR #44](https://github.com/caxlsx/caxlsx/pull/44) - Improve cell autowidth calculations. Previously columns with undefined/auto width would tend to be just slightly too small for the content. This is because certain letters were being excluded from the width calculation because they were deemed not wide enough. We now treat all characters as equal width which helps ensure columns auto-widths are actually large enough for the content. This will gain us a very slight performance improvement because of we are no longer searching the string for specific characters.
71
+ - [PR #40](https://github.com/caxlsx/caxlsx/pull/40) - Escape special characters in charts
72
+ - [PR #34](https://github.com/caxlsx/caxlsx/pull/34) - Add option to protect against csv injection attacks
31
73
 
32
74
  - **October.4.19**: 3.0.1
33
75
  - Support for ruby versions limited to officially supported version (Ruby v2.3+)
data/README.md CHANGED
@@ -1,13 +1,12 @@
1
1
  # Caxlsx (Community Continued Version)
2
- [![Build Status](https://travis-ci.com/caxlsx/caxlsx.svg?branch=master)](https://travis-ci.com/caxlsx/caxlsx)
3
- [![Gem
4
- Version](https://badge.fury.io/rb/caxlsx.svg)](http://badge.fury.io/rb/caxlsx)
2
+ [![Build Status](https://github.com/caxlsx/caxlsx/workflows/Test/badge.svg)](https://github.com/caxlsx/caxlsx/actions)
3
+ [![Gem Version](https://badge.fury.io/rb/caxlsx.svg)](http://badge.fury.io/rb/caxlsx)
5
4
  ![Total downloads](http://ruby-gem-downloads-badge.herokuapp.com/caxlsx?type=total)
6
- ![Downloads for 3.1.1 (latest)](http://ruby-gem-downloads-badge.herokuapp.com/caxlsx/3.1.1?label=downloads%203.1.1)
5
+ ![Downloads for 3.3.0 (latest)](http://ruby-gem-downloads-badge.herokuapp.com/caxlsx/3.3.0?label=downloads%203.3.0)
7
6
 
8
7
  ## Notice: Community Axlsx Organization
9
8
 
10
- To better maintain the Axlsx ecosystem, all related gems have been forked or moved to the following community organization:
9
+ To better maintain the Axlsx ecosystem, all related gems have been forked or moved to the following community organization:
11
10
 
12
11
  http://github.com/caxlsx
13
12
 
@@ -120,8 +119,6 @@ Currently the following additional gems are available:
120
119
  * Provides a `.axlsx` renderer to Rails so you can move all your spreadsheet code from your controller into view files.
121
120
  - [activeadmin-caxlsx](https://github.com/caxlsx/activeadmin-caxlsx)
122
121
  * An Active Admin plugin that includes DSL to create downloadable reports.
123
- - [axlsx_styler](https://github.com/axlsx-styler-gem/axlsx_styler)
124
- * Allows you to build clean and maintainable styles for your axlsx spreadsheets. Build your spreadsheeet with data and then apply styles later.
125
122
 
126
123
  ## Known Software Interoperability Issues
127
124
 
@@ -155,10 +152,6 @@ p.use_shared_strings = true
155
152
  p.serialize('simple.xlsx')
156
153
  ```
157
154
 
158
- ## Known Bugs
159
-
160
- There’s a [list of known bugs](https://github.com/caxlsx/caxlsx/issues?q=label%3A%22known+bug%22). (If you want to contribute to caxlsx, this is a good place to start!)
161
-
162
155
  ## Contributing
163
156
 
164
157
  See [CONTRIBUTING.md](https://github.com/caxlsx/caxlsx/blob/master/CONTRIBUTING.md)
@@ -24,7 +24,7 @@ module Axlsx
24
24
  # Serialize the contenty type to xml
25
25
  def to_xml_string(node_name = '', str = '')
26
26
  str << "<#{node_name} "
27
- str << instance_values.map { |key, value| Axlsx::camel(key) << '="' << value.to_s << '"' }.join(' ')
27
+ str << Axlsx.instance_values_for(self).map { |key, value| Axlsx::camel(key) << '="' << value.to_s << '"' }.join(' ')
28
28
  str << '/>'
29
29
  end
30
30
 
@@ -223,7 +223,7 @@ module Axlsx
223
223
  def to_xml_string(str = '')
224
224
  str << '<?xml version="1.0" encoding="UTF-8"?>'
225
225
  str << ('<Properties xmlns="' << APP_NS << '" xmlns:vt="' << APP_NS_VT << '">')
226
- instance_values.each do |key, value|
226
+ Axlsx.instance_values_for(self).each do |key, value|
227
227
  node_name = Axlsx.camel(key)
228
228
  str << "<#{node_name}>#{value}</#{node_name}>"
229
229
  end
@@ -14,6 +14,8 @@ module Axlsx
14
14
  # @option options [Symbol] legend_position
15
15
  # @option options [Array|String|Cell] start_at The X, Y coordinates defining the top left corner of the chart.
16
16
  # @option options [Array|String|Cell] end_at The X, Y coordinates defining the bottom right corner of the chart.
17
+ # @option options [Boolean] plot_visible_only (true) Whether only data from visible cells should be plotted.
18
+ # @option options [Boolean] rounded_corners (true) Whether the chart area shall have rounded corners.
17
19
  def initialize(frame, options={})
18
20
  @style = 18
19
21
  @view_3D = nil
@@ -26,6 +28,8 @@ module Axlsx
26
28
  @series_type = Series
27
29
  @title = Title.new
28
30
  @bg_color = nil
31
+ @plot_visible_only = true
32
+ @rounded_corners = true
29
33
  parse_options options
30
34
  start_at(*options[:start_at]) if options[:start_at]
31
35
  end_at(*options[:end_at]) if options[:end_at]
@@ -98,6 +102,14 @@ module Axlsx
98
102
  # @return [String]
99
103
  attr_reader :bg_color
100
104
 
105
+ # Whether only data from visible cells should be plotted.
106
+ # @return [Boolean]
107
+ attr_reader :plot_visible_only
108
+
109
+ # Whether the chart area shall have rounded corners.
110
+ # @return [Boolean]
111
+ attr_reader :rounded_corners
112
+
101
113
  # The relationship object for this chart.
102
114
  # @return [Relationship]
103
115
  def relationship
@@ -180,6 +192,16 @@ module Axlsx
180
192
  @bg_color = v
181
193
  end
182
194
 
195
+ # Whether only data from visible cells should be plotted.
196
+ # @param [Boolean] v
197
+ # @return [Boolean]
198
+ def plot_visible_only=(v) Axlsx::validate_boolean(v); @plot_visible_only = v; end
199
+
200
+ # Whether the chart area shall have rounded corners.
201
+ # @param [Boolean] v
202
+ # @return [Boolean]
203
+ def rounded_corners=(v) Axlsx::validate_boolean(v); @rounded_corners = v; end
204
+
183
205
  # Serializes the object
184
206
  # @param [String] str
185
207
  # @return [String]
@@ -187,9 +209,10 @@ module Axlsx
187
209
  str << '<?xml version="1.0" encoding="UTF-8"?>'
188
210
  str << ('<c:chartSpace xmlns:c="' << XML_NS_C << '" xmlns:a="' << XML_NS_A << '" xmlns:r="' << XML_NS_R << '">')
189
211
  str << ('<c:date1904 val="' << Axlsx::Workbook.date1904.to_s << '"/>')
212
+ str << ('<c:roundedCorners val="' << rounded_corners.to_s << '"/>')
190
213
  str << ('<c:style val="' << style.to_s << '"/>')
191
214
  str << '<c:chart>'
192
- @title.to_xml_string str
215
+ @title.to_xml_string(str) unless @title.empty?
193
216
  str << ('<c:autoTitleDeleted val="' << (@title == nil).to_s << '"/>')
194
217
  @view_3D.to_xml_string(str) if @view_3D
195
218
  str << '<c:floor><c:thickness val="0"/></c:floor>'
@@ -206,7 +229,7 @@ module Axlsx
206
229
  str << '<c:overlay val="0"/>'
207
230
  str << '</c:legend>'
208
231
  end
209
- str << '<c:plotVisOnly val="1"/>'
232
+ str << ('<c:plotVisOnly val="' << @plot_visible_only.to_s << '"/>')
210
233
  str << ('<c:dispBlanksAs val="' << display_blanks_as.to_s << '"/>')
211
234
  str << '<c:showDLblsOverMax val="1"/>'
212
235
  str << '</c:chart>'
@@ -71,9 +71,10 @@ module Axlsx
71
71
  def to_xml_string(str = '')
72
72
  validate_attributes_for_chart_type
73
73
  str << '<c:dLbls>'
74
+ instance_vals = Axlsx.instance_values_for(self)
74
75
  %w(d_lbl_pos show_legend_key show_val show_cat_name show_ser_name show_percent show_bubble_size show_leader_lines).each do |key|
75
- next unless instance_values.keys.include?(key) && instance_values[key] != nil
76
- str << "<c:#{Axlsx::camel(key, false)} val='#{instance_values[key]}' />"
76
+ next unless instance_vals.keys.include?(key) && instance_vals[key] != nil
77
+ str << "<c:#{Axlsx::camel(key, false)} val='#{instance_vals[key]}' />"
77
78
  end
78
79
  str << '</c:dLbls>'
79
80
  end
@@ -28,6 +28,14 @@ module Axlsx
28
28
  # @return [Boolean]
29
29
  attr_reader :smooth
30
30
 
31
+ # Line markers presence
32
+ # @return [Boolean]
33
+ attr_reader :show_marker
34
+
35
+ # custom marker symbol
36
+ # @return [String]
37
+ attr_reader :marker_symbol
38
+
31
39
  # Creates a new ScatterSeries
32
40
  def initialize(chart, options={})
33
41
  @xData, @yData = nil
@@ -40,6 +48,9 @@ module Axlsx
40
48
  @smooth = options[:smooth]
41
49
  end
42
50
  @ln_width = options[:ln_width] unless options[:ln_width].nil?
51
+ @show_marker = [:lineMarker, :marker, :smoothMarker].include?(chart.scatter_style)
52
+ @marker_symbol = :default
53
+
43
54
  super(chart, options)
44
55
  @xData = AxDataSource.new(:tag_name => :xVal, :data => options[:xData]) unless options[:xData].nil?
45
56
  @yData = NumDataSource.new({:tag_name => :yVal, :data => options[:yData]}) unless options[:yData].nil?
@@ -61,6 +72,12 @@ module Axlsx
61
72
  @ln_width = v
62
73
  end
63
74
 
75
+ # @see marker_symbol
76
+ def marker_symbol=(v)
77
+ Axlsx::validate_marker_symbol(v)
78
+ @marker_symbol = v
79
+ end
80
+
64
81
  # Serializes the object
65
82
  # @param [String] str
66
83
  # @return [String]
@@ -81,8 +98,12 @@ module Axlsx
81
98
  str << '<a:ln><a:solidFill>'
82
99
  str << ('<a:srgbClr val="' << color << '"/></a:solidFill></a:ln>')
83
100
  str << '</c:spPr>'
101
+ str << marker_symbol_xml
84
102
  str << '</c:marker>'
103
+ else
104
+ str << "<c:marker>#{marker_symbol_xml}</c:marker>"
85
105
  end
106
+
86
107
  if ln_width
87
108
  str << '<c:spPr>'
88
109
  str << '<a:ln w="' << ln_width.to_s << '"/>'
@@ -94,5 +115,15 @@ module Axlsx
94
115
  end
95
116
  str
96
117
  end
118
+
119
+ private
120
+
121
+ def marker_symbol_xml
122
+ if !@show_marker
123
+ '<c:symbol val="none"/>'
124
+ elsif @marker_symbol != :default
125
+ '<c:symbol val="' + @marker_symbol.to_s + '"/>'
126
+ end.to_s
127
+ end
97
128
  end
98
129
  end
@@ -51,6 +51,16 @@ module Axlsx
51
51
  v
52
52
  end
53
53
 
54
+ # Check if the title is empty.
55
+ #
56
+ # A title is considered empty if it is an empty string. If the title references a cell it is *not* empty,
57
+ # even if the referenced cell is blank (because the cell’s value could still change later).
58
+ #
59
+ # @return [Boolean]
60
+ def empty?
61
+ @text.empty? && @cell.nil?
62
+ end
63
+
54
64
  # Not implemented at this time.
55
65
  #def layout=(v) DataTypeValidator.validate 'Title.layout', Layout, v; @layout = v; end
56
66
  #def overlay=(v) Axlsx::validate_boolean v; @overlay=v; end
@@ -61,7 +71,7 @@ module Axlsx
61
71
  # @return [String]
62
72
  def to_xml_string(str = '')
63
73
  str << '<c:title>'
64
- unless @text.empty?
74
+ unless empty?
65
75
  clean_value = Axlsx::trust_input ? @text.to_s : ::CGI.escapeHTML(Axlsx::sanitize(@text.to_s))
66
76
  str << '<c:tx>'
67
77
  if @cell.is_a?(Cell)
@@ -107,7 +107,7 @@ module Axlsx
107
107
  private
108
108
  # Note: move this to Axlsx module if we find the smae pattern elsewhere.
109
109
  def element_for_attribute(name, namespace='')
110
- val = instance_values[name]
110
+ val = Axlsx.instance_values_for(self)[name]
111
111
  return "" if val == nil
112
112
  "<%s:%s val='%s'/>" % [namespace, Axlsx::camel(name, false), val]
113
113
  end
data/lib/axlsx/package.rb CHANGED
@@ -99,8 +99,12 @@ module Axlsx
99
99
  #
100
100
  # # Serialize to a stream
101
101
  # s = p.to_stream()
102
- # File.open('example_streamed.xlsx', 'w') { |f| f.write(s.read) }
102
+ # File.open('example_streamed.xlsx', 'wb') { |f| f.write(s.read) }
103
103
  def serialize(output, options = {}, secondary_options = nil)
104
+ if !workbook.styles_applied
105
+ workbook.apply_styles
106
+ end
107
+
104
108
  confirm_valid, zip_command = parse_serialize_options(options, secondary_options)
105
109
  return false unless !confirm_valid || self.validate.empty?
106
110
  zip_provider = if zip_command
@@ -122,9 +126,13 @@ module Axlsx
122
126
  # @param [Boolean] confirm_valid Validate the package prior to serialization.
123
127
  # @return [StringIO|Boolean] False if confirm_valid and validation errors exist. rewound string IO if not.
124
128
  def to_stream(confirm_valid=false)
129
+ if !workbook.styles_applied
130
+ workbook.apply_styles
131
+ end
132
+
125
133
  return false unless !confirm_valid || self.validate.empty?
126
134
  Relationship.initialize_ids_cache
127
- zip = write_parts(Zip::OutputStream.new(StringIO.new, true))
135
+ zip = write_parts(Zip::OutputStream.new(StringIO.new.binmode, true))
128
136
  stream = zip.close_buffer
129
137
  stream.rewind
130
138
  stream
@@ -206,12 +214,10 @@ module Axlsx
206
214
  # @private
207
215
  def parts
208
216
  parts = [
209
- {:entry => RELS_PN, :doc => relationships, :schema => RELS_XSD},
210
217
  {:entry => "xl/#{STYLES_PN}", :doc => workbook.styles, :schema => SML_XSD},
211
218
  {:entry => CORE_PN, :doc => @core, :schema => CORE_XSD},
212
219
  {:entry => APP_PN, :doc => @app, :schema => APP_XSD},
213
220
  {:entry => WORKBOOK_RELS_PN, :doc => workbook.relationships, :schema => RELS_XSD},
214
- {:entry => CONTENT_TYPES_PN, :doc => content_types, :schema => CONTENT_TYPES_XSD},
215
221
  {:entry => WORKBOOK_PN, :doc => workbook, :schema => SML_XSD}
216
222
  ]
217
223
 
@@ -256,7 +262,11 @@ module Axlsx
256
262
  end
257
263
 
258
264
  # Sort parts for correct MIME detection
259
- parts.sort_by { |part| part[:entry] }
265
+ [
266
+ {:entry => CONTENT_TYPES_PN, :doc => content_types, :schema => CONTENT_TYPES_XSD},
267
+ {:entry => RELS_PN, :doc => relationships, :schema => RELS_XSD},
268
+ *(parts.sort_by { |part| part[:entry] }.reverse)
269
+ ]
260
270
  end
261
271
 
262
272
  # Performs xsd validation for a signle document
@@ -103,7 +103,7 @@ module Axlsx
103
103
  # @param [String] str
104
104
  # @return [String]
105
105
  def to_xml_string(str = '')
106
- h = self.instance_values.reject{|k, _| k == "source_obj"}
106
+ h = Axlsx.instance_values_for(self).reject{|k, _| k == "source_obj"}
107
107
  str << '<Relationship '
108
108
  str << (h.map { |key, value| '' << key.to_s << '="' << Axlsx::coder.encode(value.to_s) << '"'}.join(' '))
109
109
  str << '/>'
@@ -6,6 +6,8 @@ module Axlsx
6
6
  include Axlsx::SerializedAttributes
7
7
  include Axlsx::OptionsParser
8
8
 
9
+ EDGES = [:left, :right, :top, :bottom].freeze
10
+
9
11
  # Creates a new Border object
10
12
  # @option options [Boolean] diagonal_up
11
13
  # @option options [Boolean] diagonal_down
@@ -147,7 +147,7 @@ module Axlsx
147
147
  # @return [String]
148
148
  def to_xml_string(str = '')
149
149
  str << '<font>'
150
- instance_values.each do |k, v|
150
+ Axlsx.instance_values_for(self).each do |k, v|
151
151
  v.is_a?(Color) ? v.to_xml_string(str) : (str << ('<' << k.to_s << ' val="' << Axlsx.booleanize(v).to_s << '"/>'))
152
152
  end
153
153
  str << '</font>'
@@ -120,6 +120,10 @@ module Axlsx
120
120
  load_default_styles
121
121
  end
122
122
 
123
+ def style_index
124
+ @style_index ||= {}
125
+ end
126
+
123
127
  # Drastically simplifies style creation and management.
124
128
  # @return [Integer]
125
129
  # @option options [String] fg_color The text color
@@ -156,7 +160,7 @@ module Axlsx
156
160
  # ws.add_row ["Least Popular Pets"]
157
161
  # ws.add_row ["", "Dry Skinned Reptiles", "Bald Cats", "Violent Parrots"], :style=>title
158
162
  # ws.add_row ["Votes", 6, 4, 1], :style=>Axlsx::STYLE_THIN_BORDER
159
- # f = File.open('example_you_got_style.xlsx', 'w')
163
+ # f = File.open('example_you_got_style.xlsx', 'wb')
160
164
  # p.serialize(f)
161
165
  #
162
166
  # @example Styling specifically
@@ -190,7 +194,7 @@ module Axlsx
190
194
  # ws.add_row ["Q2", 3000, 30], :style=>[title, currency, percent]
191
195
  # ws.add_row ["Q3", 1000, 10], :style=>[title, currency, percent]
192
196
  # ws.add_row ["Q4", 2000, 20], :style=>[title, currency, percent]
193
- # f = File.open('example_you_got_style.xlsx', 'w')
197
+ # f = File.open('example_you_got_style.xlsx', 'wb')
194
198
  # p.serialize(f)
195
199
  #
196
200
  # @example Differential styling
@@ -216,14 +220,39 @@ module Axlsx
216
220
  # ws.add_row ["Q4", 2000, 20], :style=>[title, currency, percent]
217
221
  #
218
222
  # ws.add_conditional_formatting("A1:A7", { :type => :cellIs, :operator => :greaterThan, :formula => "2000", :dxfId => profitable, :priority => 1 })
219
- # f = File.open('example_differential_styling', 'w')
223
+ # f = File.open('example_differential_styling', 'wb')
220
224
  # p.serialize(f)
221
225
  #
226
+ # An index for cell styles where keys are styles codes as per Axlsx::Style and values are Cell#raw_style
227
+ # The reason for the backward key/value ordering is that style lookup must be most efficient, while `add_style` can be less efficient
222
228
  def add_style(options={})
223
229
  # Default to :xf
224
230
  options[:type] ||= :xf
231
+
225
232
  raise ArgumentError, "Type must be one of [:xf, :dxf]" unless [:xf, :dxf].include?(options[:type] )
226
233
 
234
+ if options[:border].is_a?(Hash) && options[:border][:edges] == :all
235
+ options[:border][:edges] = Axlsx::Border::EDGES
236
+ end
237
+
238
+ if options[:type] == :xf
239
+ # Check to see if style in cache already
240
+
241
+ font_defaults = {name: @fonts.first.name, sz: @fonts.first.sz, family: @fonts.first.family}
242
+
243
+ raw_style = {type: :xf}.merge(font_defaults).merge(options)
244
+
245
+ if raw_style[:format_code]
246
+ raw_style.delete(:num_fmt)
247
+ end
248
+
249
+ xf_index = style_index.key(raw_style)
250
+
251
+ if xf_index
252
+ return xf_index
253
+ end
254
+ end
255
+
227
256
  fill = parse_fill_options options
228
257
  font = parse_font_options options
229
258
  numFmt = parse_num_fmt_options options
@@ -238,7 +267,18 @@ module Axlsx
238
267
  style = Xf.new :fillId=>fill || 0, :fontId=>font || 0, :numFmtId=>numFmt || 0, :borderId=>border || 0, :alignment => alignment, :protection => protection, :applyFill=>!fill.nil?, :applyFont=>!font.nil?, :applyNumberFormat =>!numFmt.nil?, :applyBorder=>!border.nil?, :applyAlignment => !alignment.nil?, :applyProtection => !protection.nil?
239
268
  end
240
269
 
241
- options[:type] == :xf ? cellXfs << style : dxfs << style
270
+ if options[:type] == :xf
271
+ xf_index = (cellXfs << style)
272
+
273
+ # Add styles to style_index cache for re-use
274
+ style_index[xf_index] = raw_style
275
+
276
+ return xf_index
277
+ else
278
+ dxf_index = (dxfs << style)
279
+
280
+ return dxf_index
281
+ end
242
282
  end
243
283
 
244
284
  # parses add_style options for protection styles
@@ -279,7 +319,7 @@ module Axlsx
279
319
  # @return [Font|Integer]
280
320
  def parse_font_options(options={})
281
321
  return if (options.keys & [:fg_color, :sz, :b, :i, :u, :strike, :outline, :shadow, :charset, :family, :font_name]).empty?
282
- fonts.first.instance_values.each do |key, value|
322
+ Axlsx.instance_values_for(fonts.first).each do |key, value|
283
323
  # Thanks for that 1.8.7 - cant do a simple merge...
284
324
  options[key.to_sym] = value unless options.keys.include?(key.to_sym)
285
325
  end
@@ -310,33 +350,108 @@ module Axlsx
310
350
  # may include an :edges entry that references an array of symbols identifying which border edges
311
351
  # you wish to apply the style or any other valid Border initializer options.
312
352
  # If the :edges entity is not provided the style is applied to all edges of cells that reference this style.
313
- # Also available :border_top, :border_right, :border_bottom and :border_left options with :style and/or :color
314
- # key-value entries, which override :border values.
353
+ # Also available :border_top, :border_right, :border_bottom and :border_left options with :style and/or :color
354
+ # key-value entries, which override :border values.
315
355
  # @example
316
356
  # #apply a thick red border to the top and bottom
317
357
  # { :border => { :style => :thick, :color => "FFFF0000", :edges => [:top, :bottom] }
318
358
  # @return [Border|Integer]
319
359
  def parse_border_options(options={})
320
- return unless options[:border]
321
- b_opts = options[:border]
322
- if b_opts.is_a?(Hash)
323
- raise ArgumentError, (ERR_INVALID_BORDER_OPTIONS % b_opts) unless b_opts.keys.include?(:style) && b_opts.keys.include?(:color)
324
- border = Border.new b_opts
325
- (b_opts[:edges] || [:left, :right, :top, :bottom]).each do |edge|
326
- edge_options = options["border_#{edge}".to_sym] || {}
327
- border_edge = b_opts.merge(edge_options)
328
- b_options = { :name => edge, :style => border_edge[:style], :color => Color.new(:rgb => border_edge[:color]) }
329
- border.prs << BorderPr.new(b_options)
360
+ if options[:border].nil? && Border::EDGES.all?{|x| options["border_#{x}".to_sym].nil? }
361
+ return nil
362
+ end
363
+
364
+ if options[:border].is_a?(Integer)
365
+ if options[:border] >= borders.size
366
+ raise ArgumentError, (ERR_INVALID_BORDER_ID % options[:border])
330
367
  end
331
- options[:type] == :dxf ? border : borders << border
332
- elsif b_opts.is_a? Integer
333
- raise ArgumentError, (ERR_INVALID_BORDER_ID % b_opts) unless b_opts < borders.size
368
+
334
369
  if options[:type] == :dxf
335
- borders[b_opts].clone
370
+ return borders[options[:border]].clone
371
+ else
372
+ return options[:border]
373
+ end
374
+ end
375
+
376
+ validate_border_hash = ->(val){
377
+ if !(val.keys.include?(:style) && val.keys.include?(:color))
378
+ raise ArgumentError, (ERR_INVALID_BORDER_OPTIONS % options[:border])
379
+ end
380
+ }
381
+
382
+ borders_array = []
383
+
384
+ if options[:border].nil?
385
+ base_border_opts = {}
386
+ else
387
+ if options[:border].is_a?(Array)
388
+ borders_array += options[:border]
389
+
390
+ base_border_opts = {}
391
+
392
+ options[:border].each do |b_opts|
393
+ if b_opts[:edges].nil?
394
+ base_border_opts = base_border_opts.merge(b_opts)
395
+ end
396
+ end
336
397
  else
337
- border = b_opts
398
+ borders_array << options[:border]
399
+
400
+ base_border_opts = options[:border]
401
+
402
+ validate_border_hash.call(base_border_opts)
403
+ end
404
+ end
405
+
406
+ Border::EDGES.each do |edge|
407
+ val = options["border_#{edge}".to_sym]
408
+
409
+ if val
410
+ borders_array << val.merge(edges: [edge])
338
411
  end
339
412
  end
413
+
414
+ border = Border.new(base_border_opts)
415
+
416
+ Border::EDGES.each do |edge|
417
+ edge_b_opts = base_border_opts
418
+
419
+ skip_edge = true
420
+
421
+ borders_array.each do |b_opts|
422
+ if b_opts[:edges] && b_opts[:edges].include?(edge)
423
+ edge_b_opts = edge_b_opts.merge(b_opts)
424
+ skip_edge = false
425
+ end
426
+ end
427
+
428
+ if options["border_#{edge}".to_sym]
429
+ edge_b_opts = edge_b_opts.merge(options["border_#{edge}".to_sym])
430
+ skip_edge = false
431
+ end
432
+
433
+ if skip_edge && base_border_opts[:edges]
434
+ next
435
+ end
436
+
437
+ if !edge_b_opts.empty?
438
+ if base_border_opts.empty?
439
+ validate_border_hash.call(edge_b_opts)
440
+ end
441
+
442
+ border.prs << BorderPr.new({
443
+ :name => edge,
444
+ :style => edge_b_opts[:style],
445
+ :color => Color.new(:rgb => edge_b_opts[:color]) },
446
+ )
447
+ end
448
+ end
449
+
450
+ if options[:type] == :dxf
451
+ return border
452
+ else
453
+ return borders << border
454
+ end
340
455
  end
341
456
 
342
457
  # Parses Style#add_style options for number formatting.
@@ -363,8 +478,9 @@ module Axlsx
363
478
  # @return [String]
364
479
  def to_xml_string(str = '')
365
480
  str << ('<styleSheet xmlns="' << XML_NS << '">')
481
+ instance_vals = Axlsx.instance_values_for(self)
366
482
  [:numFmts, :fonts, :fills, :borders, :cellStyleXfs, :cellXfs, :cellStyles, :dxfs, :tableStyles].each do |key|
367
- self.instance_values[key.to_s].to_xml_string(str) unless self.instance_values[key.to_s].nil?
483
+ instance_vals[key.to_s].to_xml_string(str) unless instance_vals[key.to_s].nil?
368
484
  end
369
485
  str << '</styleSheet>'
370
486
  end
@@ -417,4 +533,3 @@ module Axlsx
417
533
  end
418
534
  end
419
535
  end
420
-