xlsxrb 0.1.16 → 0.1.17
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/CHANGELOG.md +64 -0
- data/README.md +2 -2
- data/lib/xlsxrb/chart_builder.rb +41 -2
- data/lib/xlsxrb/dsl_helpers.rb +522 -6
- data/lib/xlsxrb/elements/cell.rb +34 -9
- data/lib/xlsxrb/elements/column.rb +2 -2
- data/lib/xlsxrb/elements/types.rb +1 -0
- data/lib/xlsxrb/elements/workbook.rb +48 -0
- data/lib/xlsxrb/elements/worksheet.rb +158 -11
- data/lib/xlsxrb/ooxml/reader/listeners/core_listeners.rb +22 -1
- data/lib/xlsxrb/ooxml/reader/listeners/drawing_listeners.rb +187 -24
- data/lib/xlsxrb/ooxml/reader/listeners/feature_listeners.rb +108 -1
- data/lib/xlsxrb/ooxml/reader/listeners/style_listeners.rb +16 -11
- data/lib/xlsxrb/ooxml/reader.rb +88 -0
- data/lib/xlsxrb/ooxml/styles_parser.rb +19 -11
- data/lib/xlsxrb/ooxml/workbook_parser.rb +18 -3
- data/lib/xlsxrb/ooxml/workbook_writer.rb +266 -46
- data/lib/xlsxrb/ooxml/worksheet_parser.rb +18 -4
- data/lib/xlsxrb/ooxml/worksheet_writer.rb +289 -88
- data/lib/xlsxrb/ooxml/writer/drawing_xml.rb +579 -441
- data/lib/xlsxrb/ooxml/writer/features_xml.rb +26 -9
- data/lib/xlsxrb/ooxml/writer/styles_xml.rb +23 -9
- data/lib/xlsxrb/ooxml/writer.rb +268 -31
- data/lib/xlsxrb/ooxml/zip_writer.rb +15 -5
- data/lib/xlsxrb/stream_sheet.rb +157 -3
- data/lib/xlsxrb/stream_writer.rb +946 -74
- data/lib/xlsxrb/style_builder.rb +59 -6
- data/lib/xlsxrb/utils.rb +65 -0
- data/lib/xlsxrb/version.rb +1 -1
- data/lib/xlsxrb/workbook_builder.rb +197 -14
- data/lib/xlsxrb/worksheet_builder.rb +1137 -44
- data/lib/xlsxrb.rb +302 -47
- data/sig/generated/xlsxrb/chart_builder.rbs +31 -3
- data/sig/generated/xlsxrb/dsl_helpers.rbs +119 -4
- data/sig/generated/xlsxrb/elements/cell.rbs +20 -3
- data/sig/generated/xlsxrb/elements/column.rbs +3 -3
- data/sig/generated/xlsxrb/elements/types.rbs +2 -0
- data/sig/generated/xlsxrb/elements/workbook.rbs +37 -0
- data/sig/generated/xlsxrb/elements/worksheet.rbs +82 -2
- data/sig/generated/xlsxrb/ooxml/reader/listeners/core_listeners.rbs +2 -0
- data/sig/generated/xlsxrb/ooxml/reader/listeners/drawing_listeners.rbs +74 -2
- data/sig/generated/xlsxrb/ooxml/reader/listeners/feature_listeners.rbs +36 -0
- data/sig/generated/xlsxrb/ooxml/reader/listeners/style_listeners.rbs +3 -0
- data/sig/generated/xlsxrb/ooxml/reader.rbs +17 -0
- data/sig/generated/xlsxrb/ooxml/styles_parser.rbs +3 -0
- data/sig/generated/xlsxrb/ooxml/workbook_parser.rbs +8 -0
- data/sig/generated/xlsxrb/ooxml/workbook_writer.rbs +8 -4
- data/sig/generated/xlsxrb/ooxml/worksheet_parser.rbs +1 -1
- data/sig/generated/xlsxrb/ooxml/worksheet_writer.rbs +12 -1
- data/sig/generated/xlsxrb/ooxml/writer/drawing_xml.rbs +16 -0
- data/sig/generated/xlsxrb/ooxml/writer.rbs +42 -8
- data/sig/generated/xlsxrb/ooxml/zip_writer.rbs +8 -2
- data/sig/generated/xlsxrb/stream_sheet.rbs +101 -1
- data/sig/generated/xlsxrb/stream_writer.rbs +592 -23
- data/sig/generated/xlsxrb/style_builder.rbs +24 -6
- data/sig/generated/xlsxrb/utils.rbs +20 -0
- data/sig/generated/xlsxrb/workbook_builder.rbs +87 -5
- data/sig/generated/xlsxrb/worksheet_builder.rbs +554 -10
- data/sig/generated/xlsxrb.rbs +77 -16
- metadata +1 -1
data/lib/xlsxrb/ooxml/reader.rb
CHANGED
|
@@ -323,6 +323,18 @@ module Xlsxrb
|
|
|
323
323
|
parse_worksheet_properties(worksheet_xml)
|
|
324
324
|
end
|
|
325
325
|
|
|
326
|
+
# Returns outline and grouping properties (<outlinePr>) for the given sheet.
|
|
327
|
+
def outline_properties(sheet: nil)
|
|
328
|
+
props = sheet_properties(sheet: sheet)
|
|
329
|
+
props[:outline_properties] || {
|
|
330
|
+
apply_styles: props[:apply_styles],
|
|
331
|
+
summary_below: props[:summary_below],
|
|
332
|
+
summary_right: props[:summary_right],
|
|
333
|
+
show_outline_symbols: props[:show_outline_symbols]
|
|
334
|
+
}.compact
|
|
335
|
+
end
|
|
336
|
+
alias outline_pr outline_properties
|
|
337
|
+
|
|
326
338
|
# Returns phonetic properties for the given sheet, or nil if not present.
|
|
327
339
|
def phonetic_properties(sheet: nil)
|
|
328
340
|
worksheet_xml = load_worksheet_xml(sheet)
|
|
@@ -709,6 +721,7 @@ module Xlsxrb
|
|
|
709
721
|
cp.listen(cl)
|
|
710
722
|
cp.parse
|
|
711
723
|
chart[:chart_type] = cl.chart_type
|
|
724
|
+
chart[:type] = cl.chart_type
|
|
712
725
|
chart[:title] = cl.title
|
|
713
726
|
chart[:title_overlay] = cl.title_overlay unless cl.title_overlay.nil?
|
|
714
727
|
chart[:title_font] = cl.title_font if cl.title_font
|
|
@@ -855,6 +868,30 @@ module Xlsxrb
|
|
|
855
868
|
chart[:protection] = cl.protection if cl.protection
|
|
856
869
|
chart[:print_settings] = cl.print_settings if cl.print_settings
|
|
857
870
|
chart[:chart_font] = cl.chart_font if cl.chart_font
|
|
871
|
+
chart[:sec_val_axis_title] = cl.sec_val_axis_title if cl.sec_val_axis_title
|
|
872
|
+
chart[:sec_val_axis_major_gridlines] = cl.sec_val_axis_major_gridlines if cl.sec_val_axis_major_gridlines
|
|
873
|
+
chart[:sec_val_axis_minor_gridlines] = cl.sec_val_axis_minor_gridlines if cl.sec_val_axis_minor_gridlines
|
|
874
|
+
chart[:sec_val_axis_num_fmt] = cl.sec_val_axis_num_fmt if cl.sec_val_axis_num_fmt
|
|
875
|
+
chart[:sec_val_axis_pos] = cl.sec_val_axis_pos if cl.sec_val_axis_pos
|
|
876
|
+
chart[:sec_val_axis_scaling_max] = cl.sec_val_axis_scaling_max if cl.sec_val_axis_scaling_max
|
|
877
|
+
chart[:sec_val_axis_scaling_min] = cl.sec_val_axis_scaling_min if cl.sec_val_axis_scaling_min
|
|
878
|
+
chart[:sec_val_axis_major_unit] = cl.sec_val_axis_major_unit if cl.sec_val_axis_major_unit
|
|
879
|
+
chart[:sec_val_axis_minor_unit] = cl.sec_val_axis_minor_unit if cl.sec_val_axis_minor_unit
|
|
880
|
+
next unless cl.sec_val_axis_title || cl.sec_val_axis_major_gridlines || cl.sec_val_axis_scaling_max ||
|
|
881
|
+
cl.sec_val_axis_scaling_min || cl.sec_val_axis_num_fmt || cl.sec_val_axis_pos
|
|
882
|
+
|
|
883
|
+
sva = {
|
|
884
|
+
title: cl.sec_val_axis_title,
|
|
885
|
+
major_gridlines: cl.sec_val_axis_major_gridlines,
|
|
886
|
+
minor_gridlines: cl.sec_val_axis_minor_gridlines,
|
|
887
|
+
num_fmt: cl.sec_val_axis_num_fmt,
|
|
888
|
+
pos: cl.sec_val_axis_pos,
|
|
889
|
+
max: cl.sec_val_axis_scaling_max,
|
|
890
|
+
min: cl.sec_val_axis_scaling_min,
|
|
891
|
+
major_unit: cl.sec_val_axis_major_unit,
|
|
892
|
+
minor_unit: cl.sec_val_axis_minor_unit
|
|
893
|
+
}.compact
|
|
894
|
+
chart[:secondary_value_axis] = sva unless sva.empty?
|
|
858
895
|
end
|
|
859
896
|
listener.charts
|
|
860
897
|
end
|
|
@@ -889,6 +926,57 @@ module Xlsxrb
|
|
|
889
926
|
listener.comments
|
|
890
927
|
end
|
|
891
928
|
|
|
929
|
+
# Returns all persons registered in xl/persons/person.xml.
|
|
930
|
+
# Each hash: { id:, display_name:, user_id:, provider_id: }
|
|
931
|
+
# : () -> Array[Hash[Symbol, untyped]]
|
|
932
|
+
def persons
|
|
933
|
+
@persons ||= begin
|
|
934
|
+
xml = extract_zip_entry("xl/persons/person.xml")
|
|
935
|
+
if xml.nil? || xml.empty?
|
|
936
|
+
wb_rels_xml = extract_zip_entry("xl/_rels/workbook.xml.rels")
|
|
937
|
+
if wb_rels_xml && !wb_rels_xml.empty?
|
|
938
|
+
rels = parse_rels_with_types(wb_rels_xml)
|
|
939
|
+
p_rel = rels.find { |r| r[:type]&.end_with?("person") }
|
|
940
|
+
xml = extract_zip_entry(normalize_xl_path(p_rel[:target], "xl")) if p_rel
|
|
941
|
+
end
|
|
942
|
+
end
|
|
943
|
+
if xml && !xml.empty?
|
|
944
|
+
parser = REXML::Parsers::SAX2Parser.new(xml)
|
|
945
|
+
listener = PersonListListener.new
|
|
946
|
+
parser.listen(listener)
|
|
947
|
+
parser.parse
|
|
948
|
+
listener.persons
|
|
949
|
+
else
|
|
950
|
+
[]
|
|
951
|
+
end
|
|
952
|
+
end
|
|
953
|
+
end
|
|
954
|
+
alias person_list persons
|
|
955
|
+
|
|
956
|
+
# Returns threaded comments for the given sheet as an array of hashes.
|
|
957
|
+
# Each hash: { ref:, text:, author:, person_id:, id:, parent_id:, dt:, done: }
|
|
958
|
+
# : (?sheet: untyped?) -> Array[Hash[Symbol, untyped]]
|
|
959
|
+
def threaded_comments(sheet: nil)
|
|
960
|
+
sheet_index = resolve_sheet_index(sheet)
|
|
961
|
+
tc_path = find_sheet_rel_target(sheet_index, "threadedComment")
|
|
962
|
+
return [] unless tc_path
|
|
963
|
+
|
|
964
|
+
xml = extract_zip_entry(tc_path)
|
|
965
|
+
return [] if xml.nil? || xml.empty?
|
|
966
|
+
|
|
967
|
+
parser = REXML::Parsers::SAX2Parser.new(xml)
|
|
968
|
+
listener = ThreadedCommentsListener.new
|
|
969
|
+
parser.listen(listener)
|
|
970
|
+
parser.parse
|
|
971
|
+
|
|
972
|
+
persons_map = persons.to_h { |p| [p[:id], p[:display_name]] }
|
|
973
|
+
listener.threaded_comments.map do |tc|
|
|
974
|
+
tc_author = persons_map[tc[:person_id]]
|
|
975
|
+
tc[:author] = tc_author if tc_author
|
|
976
|
+
tc
|
|
977
|
+
end
|
|
978
|
+
end
|
|
979
|
+
|
|
892
980
|
# Returns pivot tables for the given sheet as an array of hashes.
|
|
893
981
|
# Each hash: { name:, ref:, cache_id:, fields:, row_fields:, col_fields:, data_fields:, cache: }
|
|
894
982
|
def pivot_tables(sheet: nil)
|
|
@@ -80,6 +80,8 @@ module Xlsxrb
|
|
|
80
80
|
@current_font[:extend] = truthy_val?(attrs) if @current_font
|
|
81
81
|
when "u"
|
|
82
82
|
@current_font[:underline] = attrs["val"] || "single" if @current_font
|
|
83
|
+
when "vertAlign"
|
|
84
|
+
@current_font[:vert_align] = attrs["val"] if @current_font && attrs["val"]
|
|
83
85
|
when "sz"
|
|
84
86
|
@current_font[:sz] = attrs["val"]&.to_f if @current_font
|
|
85
87
|
when "color"
|
|
@@ -95,8 +97,8 @@ module Xlsxrb
|
|
|
95
97
|
when "border"
|
|
96
98
|
if parent_context?("borders") || (@current_dxf && parent_context?("dxf"))
|
|
97
99
|
@current_border = {}
|
|
98
|
-
@current_border[:diagonal_up] = true if attrs["diagonalUp"]
|
|
99
|
-
@current_border[:diagonal_down] = true if attrs["diagonalDown"]
|
|
100
|
+
@current_border[:diagonal_up] = true if boolean_val(attrs["diagonalUp"])
|
|
101
|
+
@current_border[:diagonal_down] = true if boolean_val(attrs["diagonalDown"])
|
|
100
102
|
end
|
|
101
103
|
when "left", "right", "top", "bottom", "diagonal"
|
|
102
104
|
handle_border_side(localname, attrs)
|
|
@@ -206,14 +208,20 @@ module Xlsxrb
|
|
|
206
208
|
fill_id: attrs["fillId"]&.to_i,
|
|
207
209
|
border_id: attrs["borderId"]&.to_i,
|
|
208
210
|
xf_id: attrs["xfId"]&.to_i,
|
|
209
|
-
apply_number_format: attrs["applyNumberFormat"]
|
|
210
|
-
apply_font: attrs["applyFont"]
|
|
211
|
-
apply_fill: attrs["applyFill"]
|
|
212
|
-
apply_border: attrs["applyBorder"]
|
|
213
|
-
apply_alignment: attrs["applyAlignment"]
|
|
211
|
+
apply_number_format: boolean_val(attrs["applyNumberFormat"]),
|
|
212
|
+
apply_font: boolean_val(attrs["applyFont"]),
|
|
213
|
+
apply_fill: boolean_val(attrs["applyFill"]),
|
|
214
|
+
apply_border: boolean_val(attrs["applyBorder"]),
|
|
215
|
+
apply_alignment: boolean_val(attrs["applyAlignment"]),
|
|
216
|
+
apply_protection: boolean_val(attrs["applyProtection"])
|
|
214
217
|
}
|
|
215
218
|
end
|
|
216
219
|
|
|
220
|
+
#: (untyped val) -> bool
|
|
221
|
+
def boolean_val(val)
|
|
222
|
+
val == "1" || (val&.casecmp?("true") || false)
|
|
223
|
+
end
|
|
224
|
+
|
|
217
225
|
def truthy_val?(attrs)
|
|
218
226
|
val = attrs["val"]
|
|
219
227
|
val.nil? || (val != "0" && val.downcase != "false")
|
|
@@ -226,10 +234,10 @@ module Xlsxrb
|
|
|
226
234
|
alignment = {}
|
|
227
235
|
alignment[:horizontal] = attrs["horizontal"] if attrs["horizontal"]
|
|
228
236
|
alignment[:vertical] = attrs["vertical"] if attrs["vertical"]
|
|
229
|
-
alignment[:wrap_text] = true if attrs["wrapText"]
|
|
237
|
+
alignment[:wrap_text] = true if boolean_val(attrs["wrapText"])
|
|
230
238
|
alignment[:text_rotation] = attrs["textRotation"]&.to_i if attrs["textRotation"]
|
|
231
239
|
alignment[:indent] = attrs["indent"]&.to_i if attrs["indent"]
|
|
232
|
-
alignment[:shrink_to_fit] = true if attrs["shrinkToFit"]
|
|
240
|
+
alignment[:shrink_to_fit] = true if boolean_val(attrs["shrinkToFit"])
|
|
233
241
|
target[:alignment] = alignment unless alignment.empty?
|
|
234
242
|
end
|
|
235
243
|
|
|
@@ -238,8 +246,8 @@ module Xlsxrb
|
|
|
238
246
|
return unless target
|
|
239
247
|
|
|
240
248
|
protection = {}
|
|
241
|
-
protection[:locked] = attrs["locked"]
|
|
242
|
-
protection[:hidden] = attrs["hidden"]
|
|
249
|
+
protection[:locked] = !%w[0 false].include?(attrs["locked"]&.downcase) unless attrs["locked"].nil?
|
|
250
|
+
protection[:hidden] = boolean_val(attrs["hidden"]) unless attrs["hidden"].nil?
|
|
243
251
|
target[:protection] = protection unless protection.empty?
|
|
244
252
|
end
|
|
245
253
|
|
|
@@ -14,7 +14,7 @@ module Xlsxrb
|
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
def self.parse_with_properties(xml_string)
|
|
17
|
-
return { sheets: [], date1904: false, defined_names: [], active_tab: nil, full_calc_on_load: nil } if xml_string.nil? || xml_string.empty?
|
|
17
|
+
return { sheets: [], date1904: false, defined_names: [], active_tab: nil, full_calc_on_load: nil, first_sheet: nil, show_sheet_tabs: nil, tab_ratio: nil, code_name: nil } if xml_string.nil? || xml_string.empty?
|
|
18
18
|
|
|
19
19
|
listener = Listener.new
|
|
20
20
|
XmlParser.parse(xml_string, listener)
|
|
@@ -23,7 +23,11 @@ module Xlsxrb
|
|
|
23
23
|
date1904: listener.date1904,
|
|
24
24
|
defined_names: listener.defined_names,
|
|
25
25
|
active_tab: listener.active_tab,
|
|
26
|
-
full_calc_on_load: listener.full_calc_on_load
|
|
26
|
+
full_calc_on_load: listener.full_calc_on_load,
|
|
27
|
+
first_sheet: listener.first_sheet,
|
|
28
|
+
show_sheet_tabs: listener.show_sheet_tabs,
|
|
29
|
+
tab_ratio: listener.tab_ratio,
|
|
30
|
+
code_name: listener.code_name
|
|
27
31
|
}
|
|
28
32
|
end
|
|
29
33
|
|
|
@@ -31,7 +35,7 @@ module Xlsxrb
|
|
|
31
35
|
class Listener
|
|
32
36
|
include REXML::SAX2Listener
|
|
33
37
|
|
|
34
|
-
attr_reader :sheets, :date1904, :defined_names, :active_tab, :full_calc_on_load
|
|
38
|
+
attr_reader :sheets, :date1904, :defined_names, :active_tab, :full_calc_on_load, :first_sheet, :show_sheet_tabs, :tab_ratio, :code_name
|
|
35
39
|
|
|
36
40
|
def initialize
|
|
37
41
|
@sheets = []
|
|
@@ -39,6 +43,10 @@ module Xlsxrb
|
|
|
39
43
|
@defined_names = []
|
|
40
44
|
@active_tab = nil
|
|
41
45
|
@full_calc_on_load = nil
|
|
46
|
+
@first_sheet = nil
|
|
47
|
+
@show_sheet_tabs = nil
|
|
48
|
+
@tab_ratio = nil
|
|
49
|
+
@code_name = nil
|
|
42
50
|
@in_defined_name = false
|
|
43
51
|
@current_dn = nil
|
|
44
52
|
@dn_text = +""
|
|
@@ -65,9 +73,16 @@ module Xlsxrb
|
|
|
65
73
|
when "workbookPr"
|
|
66
74
|
d1904 = attrs["date1904"]
|
|
67
75
|
@date1904 = %w[1 true].include?(d1904) unless d1904.nil?
|
|
76
|
+
@code_name = attrs["codeName"] if attrs["codeName"]
|
|
68
77
|
when "workbookView"
|
|
69
78
|
at = attrs["activeTab"]
|
|
70
79
|
@active_tab = at.to_i if at
|
|
80
|
+
fs = attrs["firstSheet"]
|
|
81
|
+
@first_sheet = fs.to_i if fs
|
|
82
|
+
sst = attrs["showSheetTabs"]
|
|
83
|
+
@show_sheet_tabs = %w[1 true].include?(sst) unless sst.nil?
|
|
84
|
+
tr = attrs["tabRatio"]
|
|
85
|
+
@tab_ratio = tr.to_i if tr
|
|
71
86
|
when "calcPr"
|
|
72
87
|
fcol = attrs["fullCalcOnLoad"]
|
|
73
88
|
@full_calc_on_load = %w[1 true].include?(fcol) unless fcol.nil?
|