write_xlsx 1.11.1 → 1.12.0
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/Changes +9 -0
- data/README.md +1 -1
- data/examples/shape_all.rb +1 -1
- data/lib/write_xlsx/chart/pie.rb +14 -2
- data/lib/write_xlsx/chart/series.rb +48 -0
- data/lib/write_xlsx/chart.rb +65 -12
- data/lib/write_xlsx/chartsheet.rb +10 -1
- data/lib/write_xlsx/col_name.rb +7 -3
- data/lib/write_xlsx/format.rb +6 -6
- data/lib/write_xlsx/package/app.rb +9 -5
- data/lib/write_xlsx/package/conditional_format.rb +2 -2
- data/lib/write_xlsx/package/content_types.rb +22 -0
- data/lib/write_xlsx/package/metadata.rb +139 -22
- data/lib/write_xlsx/package/packager.rb +122 -6
- data/lib/write_xlsx/package/relationships.rb +25 -0
- data/lib/write_xlsx/package/rich_value.rb +70 -0
- data/lib/write_xlsx/package/rich_value_rel.rb +70 -0
- data/lib/write_xlsx/package/rich_value_structure.rb +83 -0
- data/lib/write_xlsx/package/rich_value_types.rb +103 -0
- data/lib/write_xlsx/package/table.rb +74 -20
- data/lib/write_xlsx/package/xml_writer_simple.rb +32 -44
- data/lib/write_xlsx/sheets.rb +6 -2
- data/lib/write_xlsx/sparkline.rb +2 -2
- data/lib/write_xlsx/utility.rb +183 -9
- data/lib/write_xlsx/version.rb +1 -1
- data/lib/write_xlsx/workbook.rb +48 -168
- data/lib/write_xlsx/worksheet/cell_data.rb +35 -16
- data/lib/write_xlsx/worksheet/hyperlink.rb +4 -3
- data/lib/write_xlsx/worksheet.rb +180 -57
- data/write_xlsx.gemspec +2 -0
- metadata +35 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b8f704b9674f7d6de467d512cea780114dccc51ed88d99ad4d57727fdafd32b4
|
4
|
+
data.tar.gz: 54df4aec8346b1935bb3b0ba283c11b04f415b3b644308ab8f4cce2f0595d14d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ecbd4957e8b5ee4d9c77e46da68ddfa0f877dd94166551a20c1b76a782209db761a43a86bae340657181ec8993bdc277ee67b66c4c889bc5ad418e6fe2b953c5
|
7
|
+
data.tar.gz: c2a9f0b209de183bbb87ddceb0897dca8708b372d7bb8a5fb7953595440fdaceac60fe4500dafe2ed74585208c6f17b03c554e20c4b5d05af2ec019854b0a259
|
data/.rubocop.yml
CHANGED
data/Changes
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
Change history of write_xlsx rubygem.
|
2
2
|
|
3
|
+
2023-12-26 v1.11.2
|
4
|
+
Fix issue where header images in chartsheets weren't displayed.
|
5
|
+
Add support for custom table total functions.
|
6
|
+
Add chart option to display N/A as empty cells.
|
7
|
+
Add support for leader lines to all chart types.
|
8
|
+
Fix issue where column formulas were overwritten by table data
|
9
|
+
add Worksheet#very_hidden method.
|
10
|
+
Add add trendline equation formatting for chart.
|
11
|
+
|
3
12
|
2023-08-09 v1.11.1
|
4
13
|
Fixed issue #110. Redefining costant Struct::ColInfo
|
5
14
|
|
data/README.md
CHANGED
@@ -85,7 +85,7 @@ the first worksheet in an Excel XML spreadsheet called ruby.xlsx:
|
|
85
85
|
Original Perl module was written by John McNamara(jmcnamara@cpan.org).
|
86
86
|
|
87
87
|
Converted to ruby by Hideo NAKAMURA(nakamrua.hideo@gmail.com)
|
88
|
-
Copyright (c) 2012-
|
88
|
+
Copyright (c) 2012-2024 Hideo NAKAMURA.
|
89
89
|
|
90
90
|
See LICENSE.txt for further details.
|
91
91
|
|
data/examples/shape_all.rb
CHANGED
@@ -218,7 +218,7 @@ shapes_list.each_line do |line|
|
|
218
218
|
line = line.chomp
|
219
219
|
next unless line =~ /^\w/ # Skip blank lines and comments.
|
220
220
|
|
221
|
-
sheet, name = line.split(
|
221
|
+
sheet, name = line.split("\t")
|
222
222
|
if last_sheet != sheet
|
223
223
|
worksheet = workbook.add_worksheet(sheet)
|
224
224
|
row = 2
|
data/lib/write_xlsx/chart/pie.rb
CHANGED
@@ -123,8 +123,7 @@ module Writexlsx
|
|
123
123
|
# Write the <c:legend> element.
|
124
124
|
#
|
125
125
|
def write_legend
|
126
|
-
|
127
|
-
allowed = %w[right left top bottom]
|
126
|
+
allowed = %w[right left top bottom]
|
128
127
|
delete_series = @legend.delete_series || []
|
129
128
|
|
130
129
|
if @legend.position =~ /^overlay_/
|
@@ -207,6 +206,19 @@ module Writexlsx
|
|
207
206
|
def write_first_slice_ang
|
208
207
|
@writer.empty_tag('c:firstSliceAng', [['val', @rotation]])
|
209
208
|
end
|
209
|
+
|
210
|
+
#
|
211
|
+
# Write the <c:showLeaderLines> element. This is for Pie/Doughnut charts.
|
212
|
+
# Other chart types only supported leader lines after Excel 2015 via an
|
213
|
+
# extension element.
|
214
|
+
#
|
215
|
+
def write_show_leader_lines
|
216
|
+
val = 1
|
217
|
+
|
218
|
+
attributes = [['val', val]]
|
219
|
+
|
220
|
+
@writer.empty_tag('c:showLeaderLines', attributes)
|
221
|
+
end
|
210
222
|
end
|
211
223
|
end
|
212
224
|
end
|
@@ -59,10 +59,13 @@ module Writexlsx
|
|
59
59
|
class Trendline < Chartline
|
60
60
|
attr_reader :name, :forward, :backward, :order, :period
|
61
61
|
attr_reader :intercept, :display_equation, :display_r_squared
|
62
|
+
attr_reader :label
|
62
63
|
|
63
64
|
def initialize(params)
|
64
65
|
super(params)
|
65
66
|
|
67
|
+
@label = trendline_label_properties(params[:label])
|
68
|
+
|
66
69
|
@name = params[:name]
|
67
70
|
@forward = params[:forward]
|
68
71
|
@backward = params[:backward]
|
@@ -76,6 +79,51 @@ module Writexlsx
|
|
76
79
|
|
77
80
|
private
|
78
81
|
|
82
|
+
#
|
83
|
+
# Convert user defined trendline label properties to the structure required
|
84
|
+
# internally.
|
85
|
+
#
|
86
|
+
def trendline_label_properties(_label)
|
87
|
+
return unless _label || _label.is_a?(Hash)
|
88
|
+
|
89
|
+
# Copy the user supplied properties.
|
90
|
+
label = {}
|
91
|
+
|
92
|
+
# Set the font properties for the label.
|
93
|
+
label[:font] = convert_font_args(_label[:font]) if ptrue?(_label[:font])
|
94
|
+
|
95
|
+
# Set the line properties for the label.
|
96
|
+
line = line_properties(_label[:line])
|
97
|
+
|
98
|
+
# Allow 'border' as a synonym for 'line'.
|
99
|
+
line = line_properties(_label[:border]) if ptrue?(_label[:border])
|
100
|
+
|
101
|
+
# Set the fill properties for the label.
|
102
|
+
fill = fill_properties(_label[:fill])
|
103
|
+
|
104
|
+
# Set the pattern properties for the label.
|
105
|
+
pattern = pattern_properties(_label[:pattern])
|
106
|
+
|
107
|
+
# Set the gradient fill properties for the label.
|
108
|
+
gradient = gradient_properties(_label[:gradient])
|
109
|
+
|
110
|
+
# Pattern fill overrides solid fill.
|
111
|
+
fill = nil if ptrue?(pattern)
|
112
|
+
|
113
|
+
# Gradient fill overrides solid and pattern fills.
|
114
|
+
if ptrue?(gradient)
|
115
|
+
pattern = nil
|
116
|
+
fill = nil
|
117
|
+
end
|
118
|
+
|
119
|
+
label[:line] = line
|
120
|
+
label[:fill] = fill
|
121
|
+
label[:pattern] = pattern
|
122
|
+
label[:gradient] = gradient
|
123
|
+
|
124
|
+
label
|
125
|
+
end
|
126
|
+
|
79
127
|
def types
|
80
128
|
{
|
81
129
|
exponential: 'exp',
|
data/lib/write_xlsx/chart.rb
CHANGED
@@ -568,6 +568,13 @@ module Writexlsx
|
|
568
568
|
@is_secondary
|
569
569
|
end
|
570
570
|
|
571
|
+
#
|
572
|
+
# Set the option for displaying #N/A as an empty cell in a chart.
|
573
|
+
#
|
574
|
+
def show_na_as_empty_cell
|
575
|
+
@show_na_as_empty = true
|
576
|
+
end
|
577
|
+
|
571
578
|
private
|
572
579
|
|
573
580
|
def axis_setup
|
@@ -598,6 +605,7 @@ module Writexlsx
|
|
598
605
|
@cross_between = 'between'
|
599
606
|
@date_category = false
|
600
607
|
@show_blanks = 'gap'
|
608
|
+
@show_na_as_empty = false
|
601
609
|
@show_hidden_data = false
|
602
610
|
@show_crosses = true
|
603
611
|
end
|
@@ -782,6 +790,9 @@ module Writexlsx
|
|
782
790
|
|
783
791
|
# Write the c:dispBlanksAs element.
|
784
792
|
write_disp_blanks_as
|
793
|
+
|
794
|
+
# Write the c:extLst element.
|
795
|
+
write_ext_lst_display_na if @show_na_as_empty
|
785
796
|
end
|
786
797
|
end
|
787
798
|
|
@@ -950,12 +961,13 @@ module Writexlsx
|
|
950
961
|
write_val(series)
|
951
962
|
# Write the c:smooth element.
|
952
963
|
write_c_smooth(series.smooth) if ptrue?(@smooth_allowed)
|
953
|
-
|
964
|
+
# Write the c:extLst element.
|
965
|
+
write_ext_lst_inverted_fill(series.inverted_color) if series.inverted_color
|
954
966
|
end
|
955
967
|
@series_index += 1
|
956
968
|
end
|
957
969
|
|
958
|
-
def
|
970
|
+
def write_ext_lst_inverted_fill(color)
|
959
971
|
uri = '{6F2FDCE9-48DA-4B69-8628-5D25D57E5C99}'
|
960
972
|
xmlns_c_14 =
|
961
973
|
'http://schemas.microsoft.com/office/drawing/2007/8/2/chart'
|
@@ -980,6 +992,31 @@ module Writexlsx
|
|
980
992
|
end
|
981
993
|
end
|
982
994
|
|
995
|
+
#
|
996
|
+
# Write the <c:extLst> element for the display N/A as empty cell option.
|
997
|
+
#
|
998
|
+
def write_ext_lst_display_na
|
999
|
+
uri = '{56B9EC1D-385E-4148-901F-78D8002777C0}'
|
1000
|
+
xmlns_c_16 = 'http://schemas.microsoft.com/office/drawing/2017/03/chart'
|
1001
|
+
|
1002
|
+
attributes1 = [
|
1003
|
+
['uri', uri],
|
1004
|
+
['xmlns:c16r3', xmlns_c_16]
|
1005
|
+
]
|
1006
|
+
|
1007
|
+
attributes2 = [
|
1008
|
+
['val', 1]
|
1009
|
+
]
|
1010
|
+
|
1011
|
+
@writer.tag_elements('c:extLst') do
|
1012
|
+
@writer.tag_elements('c:ext', attributes1) do
|
1013
|
+
@writer.tag_elements('c16r3:dataDisplayOptions16') do
|
1014
|
+
@writer.empty_tag('c16r3:dispNaAsBlank', attributes2)
|
1015
|
+
end
|
1016
|
+
end
|
1017
|
+
end
|
1018
|
+
end
|
1019
|
+
|
983
1020
|
def write_ser_base(series)
|
984
1021
|
# Write the c:idx element.
|
985
1022
|
write_idx(@series_index)
|
@@ -2122,7 +2159,7 @@ module Writexlsx
|
|
2122
2159
|
# Write the c:dispEq element.
|
2123
2160
|
write_disp_eq
|
2124
2161
|
# Write the c:trendlineLbl element.
|
2125
|
-
write_trendline_lbl
|
2162
|
+
write_trendline_lbl(trendline)
|
2126
2163
|
end
|
2127
2164
|
end
|
2128
2165
|
end
|
@@ -2199,12 +2236,18 @@ module Writexlsx
|
|
2199
2236
|
#
|
2200
2237
|
# Write the <c:trendlineLbl> element.
|
2201
2238
|
#
|
2202
|
-
def write_trendline_lbl
|
2239
|
+
def write_trendline_lbl(trendline)
|
2203
2240
|
@writer.tag_elements('c:trendlineLbl') do
|
2204
2241
|
# Write the c:layout element.
|
2205
2242
|
write_layout
|
2206
2243
|
# Write the c:numFmt element.
|
2207
2244
|
write_trendline_num_fmt
|
2245
|
+
# Write the c:spPr element for the label formatting.
|
2246
|
+
write_sp_pr(trendline.label)
|
2247
|
+
# Write the data label font elements.
|
2248
|
+
if trendline.label && ptrue?(trendline.label[:font])
|
2249
|
+
write_axis_font(trendline.label[:font])
|
2250
|
+
end
|
2208
2251
|
end
|
2209
2252
|
end
|
2210
2253
|
|
@@ -2544,11 +2587,25 @@ module Writexlsx
|
|
2544
2587
|
@writer.data_element('c:separator', data)
|
2545
2588
|
end
|
2546
2589
|
|
2547
|
-
#
|
2548
|
-
#
|
2549
|
-
#
|
2590
|
+
# Write the <c:showLeaderLines> element. This is different for Pie/Doughnut
|
2591
|
+
# charts. Other chart types only supported leader lines after Excel 2015 via
|
2592
|
+
# an extension element.
|
2550
2593
|
def write_show_leader_lines
|
2551
|
-
|
2594
|
+
uri = '{CE6537A1-D6FC-4f65-9D91-7224C49458BB}'
|
2595
|
+
xmlns_c_15 = 'http://schemas.microsoft.com/office/drawing/2012/chart'
|
2596
|
+
|
2597
|
+
attributes1 = [
|
2598
|
+
['uri', uri],
|
2599
|
+
['xmlns:c15', xmlns_c_15]
|
2600
|
+
]
|
2601
|
+
|
2602
|
+
attributes2 = [['val', 1]]
|
2603
|
+
|
2604
|
+
@writer.tag_elements('c:extLst') do
|
2605
|
+
@writer.tag_elements('c:ext', attributes1) do
|
2606
|
+
@writer.empty_tag('c15:showLeaderLines', attributes2)
|
2607
|
+
end
|
2608
|
+
end
|
2552
2609
|
end
|
2553
2610
|
|
2554
2611
|
#
|
@@ -2862,8 +2919,6 @@ module Writexlsx
|
|
2862
2919
|
# Write the <a:fillToRect> element.
|
2863
2920
|
#
|
2864
2921
|
def write_a_fill_to_rect(type)
|
2865
|
-
attributes = []
|
2866
|
-
|
2867
2922
|
attributes = if type == 'shape'
|
2868
2923
|
[
|
2869
2924
|
['l', 50000],
|
@@ -2885,8 +2940,6 @@ module Writexlsx
|
|
2885
2940
|
# Write the <a:tileRect> element.
|
2886
2941
|
#
|
2887
2942
|
def write_a_tile_rect(type)
|
2888
|
-
attributes = []
|
2889
|
-
|
2890
2943
|
attributes = if type == 'shape'
|
2891
2944
|
[]
|
2892
2945
|
else
|
@@ -54,6 +54,8 @@ module Writexlsx
|
|
54
54
|
write_header_footer
|
55
55
|
# Write the drawing element.
|
56
56
|
write_drawings
|
57
|
+
# Write the legaacyDrawingHF element.
|
58
|
+
write_legacy_drawing_hf
|
57
59
|
# Close the worksheet tag.
|
58
60
|
end
|
59
61
|
end
|
@@ -145,6 +147,10 @@ module Writexlsx
|
|
145
147
|
@chart.show_blanks_as(*args)
|
146
148
|
end
|
147
149
|
|
150
|
+
def show_na_as_empty_cell
|
151
|
+
@chart.show_na_as_empty_cell(*args)
|
152
|
+
end
|
153
|
+
|
148
154
|
def show_hidden_data(*args)
|
149
155
|
@chart.show_hidden_data(*args)
|
150
156
|
end
|
@@ -185,7 +191,10 @@ module Writexlsx
|
|
185
191
|
end
|
186
192
|
|
187
193
|
def external_links
|
188
|
-
[
|
194
|
+
[
|
195
|
+
@external_drawing_links,
|
196
|
+
@external_vml_links
|
197
|
+
]
|
189
198
|
end
|
190
199
|
|
191
200
|
private
|
data/lib/write_xlsx/col_name.rb
CHANGED
@@ -7,12 +7,16 @@ class ColName
|
|
7
7
|
include Singleton
|
8
8
|
|
9
9
|
def initialize
|
10
|
-
@col_str_table =
|
10
|
+
@col_str_table = []
|
11
|
+
@row_str_table = []
|
11
12
|
end
|
12
13
|
|
13
14
|
def col_str(col)
|
14
|
-
@col_str_table[col]
|
15
|
-
|
15
|
+
@col_str_table[col] ||= col_str_build(col)
|
16
|
+
end
|
17
|
+
|
18
|
+
def row_str(row)
|
19
|
+
@row_str_table[row] ||= row.to_s
|
16
20
|
end
|
17
21
|
|
18
22
|
private
|
data/lib/write_xlsx/format.rb
CHANGED
@@ -146,10 +146,10 @@ module Writexlsx
|
|
146
146
|
return
|
147
147
|
end
|
148
148
|
|
149
|
-
# Indent is only allowed for
|
150
|
-
#
|
151
|
-
#
|
152
|
-
@text_h_align = 1 if @indent != 0 && ![1, 3, 7].include?(@text_h_align)
|
149
|
+
# Indent is only allowed for some alignment properties. If it is defined
|
150
|
+
# for any other alignment or no alignment has been set then default to
|
151
|
+
# left alignment.
|
152
|
+
@text_h_align = 1 if @indent != 0 && ![1, 3, 7].include?(@text_h_align) && ![1, 3, 5].include?(@text_v_align)
|
153
153
|
|
154
154
|
# Check for properties that are mutually exclusive.
|
155
155
|
@shrink = 0 if @text_wrap != 0
|
@@ -178,8 +178,8 @@ module Writexlsx
|
|
178
178
|
align << %w[vertical justify] if @text_v_align == 4
|
179
179
|
align << %w[vertical distributed] if @text_v_align == 5
|
180
180
|
|
181
|
-
align << ['indent', @indent] if @indent != 0
|
182
181
|
align << ['textRotation', @rotation] if @rotation != 0
|
182
|
+
align << ['indent', @indent] if @indent != 0
|
183
183
|
|
184
184
|
align << ['wrapText', 1] if @text_wrap != 0
|
185
185
|
align << ['shrinkToFit', 1] if @shrink != 0
|
@@ -324,7 +324,7 @@ module Writexlsx
|
|
324
324
|
return colors[color_code.downcase.to_sym] if colors[color_code.downcase.to_sym]
|
325
325
|
|
326
326
|
# or the default color if string is unrecognised,
|
327
|
-
|
327
|
+
0x00 if color_code =~ /\D/
|
328
328
|
else
|
329
329
|
# or an index < 8 mapped into the correct range,
|
330
330
|
return color_code + 8 if color_code < 8
|
@@ -46,7 +46,9 @@ module Writexlsx
|
|
46
46
|
add_heading_pair(
|
47
47
|
[
|
48
48
|
'Worksheets',
|
49
|
-
@workbook.worksheets.reject
|
49
|
+
@workbook.worksheets.reject do |s|
|
50
|
+
s.is_chartsheet? || s.very_hidden?
|
51
|
+
end.count
|
50
52
|
]
|
51
53
|
)
|
52
54
|
end
|
@@ -57,14 +59,16 @@ module Writexlsx
|
|
57
59
|
|
58
60
|
def add_worksheet_part_names
|
59
61
|
@workbook.worksheets
|
60
|
-
|
61
|
-
|
62
|
+
.reject { |sheet| sheet.is_chartsheet? || sheet.very_hidden? }
|
63
|
+
.each do |sheet|
|
64
|
+
add_part_name(sheet.name)
|
65
|
+
end
|
62
66
|
end
|
63
67
|
|
64
68
|
def add_chartsheet_part_names
|
65
69
|
@workbook.worksheets
|
66
|
-
|
67
|
-
|
70
|
+
.select { |sheet| sheet.is_chartsheet? }
|
71
|
+
.each { |sheet| add_part_name(sheet.name) }
|
68
72
|
end
|
69
73
|
|
70
74
|
def add_part_name(part_name)
|
@@ -411,7 +411,7 @@ module Writexlsx
|
|
411
411
|
# Check for a cell reference in A1 notation and substitute row and column
|
412
412
|
user_range = if args[0].to_s =~ (/^\D/) && (args[0] =~ /,/)
|
413
413
|
# Check for a user defined multiple range like B3:K6,B8:K11.
|
414
|
-
args[0].sub(/^=/, '').gsub(/\s*,\s*/, ' ').gsub(
|
414
|
+
args[0].sub(/^=/, '').gsub(/\s*,\s*/, ' ').gsub("$", '')
|
415
415
|
end
|
416
416
|
|
417
417
|
if (row_col_array = row_col_notation(args.first))
|
@@ -769,7 +769,7 @@ module Writexlsx
|
|
769
769
|
attr = super
|
770
770
|
attr << ['percent', 1] if criteria == '%'
|
771
771
|
attr << ['bottom', 1] if direction
|
772
|
-
attr << ['rank',
|
772
|
+
attr << ['rank', value || 10]
|
773
773
|
attr
|
774
774
|
end
|
775
775
|
end
|
@@ -199,6 +199,28 @@ module Writexlsx
|
|
199
199
|
)
|
200
200
|
end
|
201
201
|
|
202
|
+
def add_richvalue
|
203
|
+
add_override(
|
204
|
+
'/xl/richData/rdRichValueTypes.xml',
|
205
|
+
'application/vnd.ms-excel.rdrichvaluetypes+xml'
|
206
|
+
)
|
207
|
+
|
208
|
+
add_override(
|
209
|
+
'/xl/richData/rdrichvalue.xml',
|
210
|
+
'application/vnd.ms-excel.rdrichvalue+xml'
|
211
|
+
)
|
212
|
+
|
213
|
+
add_override(
|
214
|
+
'/xl/richData/rdrichvaluestructure.xml',
|
215
|
+
'application/vnd.ms-excel.rdrichvaluestructure+xml'
|
216
|
+
)
|
217
|
+
|
218
|
+
add_override(
|
219
|
+
'/xl/richData/richValueRel.xml',
|
220
|
+
'application/vnd.ms-excel.richvaluerel+xml'
|
221
|
+
)
|
222
|
+
end
|
223
|
+
|
202
224
|
private
|
203
225
|
|
204
226
|
def change_the_workbook_xml_content_type_from_xlsx_to_xlsm
|