xlsxrb 0.1.13 → 0.1.15
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 +104 -0
- data/README.md +17 -14
- data/lib/xlsxrb/colors.rb +118 -0
- data/lib/xlsxrb/elements/cell.rb +205 -16
- data/lib/xlsxrb/elements/column.rb +6 -4
- data/lib/xlsxrb/elements/coordinate_access.rb +32 -0
- data/lib/xlsxrb/elements/image.rb +128 -0
- data/lib/xlsxrb/elements/row.rb +206 -9
- data/lib/xlsxrb/elements/styles.rb +157 -0
- data/lib/xlsxrb/elements/types.rb +95 -1
- data/lib/xlsxrb/elements/workbook.rb +121 -4
- data/lib/xlsxrb/elements/worksheet.rb +519 -29
- data/lib/xlsxrb/elements.rb +2 -0
- data/lib/xlsxrb/number_formatter.rb +429 -0
- data/lib/xlsxrb/ooxml/cfb.rb +1 -1
- data/lib/xlsxrb/ooxml/reader/listeners/core_listeners.rb +7 -5
- data/lib/xlsxrb/ooxml/reader/listeners/drawing_listeners.rb +11 -4
- data/lib/xlsxrb/ooxml/reader/listeners/feature_listeners.rb +7 -1
- data/lib/xlsxrb/ooxml/reader.rb +14 -17
- data/lib/xlsxrb/ooxml/shared_strings_parser.rb +7 -1
- data/lib/xlsxrb/ooxml/styles_parser.rb +39 -9
- data/lib/xlsxrb/ooxml/utils.rb +34 -18
- data/lib/xlsxrb/ooxml/workbook_parser.rb +74 -16
- data/lib/xlsxrb/ooxml/workbook_writer.rb +82 -23
- data/lib/xlsxrb/ooxml/worksheet_parser.rb +319 -79
- data/lib/xlsxrb/ooxml/worksheet_writer.rb +263 -66
- data/lib/xlsxrb/ooxml/writer/features_xml.rb +5 -3
- data/lib/xlsxrb/ooxml/writer.rb +14 -0
- data/lib/xlsxrb/ooxml/xml_builder.rb +14 -2
- data/lib/xlsxrb/ooxml/zip_reader.rb +144 -28
- data/lib/xlsxrb/stream_row.rb +243 -16
- data/lib/xlsxrb/stream_sheet.rb +647 -16
- data/lib/xlsxrb/stream_writer.rb +375 -34
- data/lib/xlsxrb/style_builder.rb +308 -22
- data/lib/xlsxrb/utils.rb +211 -0
- data/lib/xlsxrb/version.rb +1 -1
- data/lib/xlsxrb/workbook_builder.rb +72 -11
- data/lib/xlsxrb/worksheet_builder.rb +738 -24
- data/lib/xlsxrb.rb +1073 -83
- data/sig/generated/xlsxrb/colors.rbs +40 -0
- data/sig/generated/xlsxrb/elements/cell.rbs +113 -8
- data/sig/generated/xlsxrb/elements/column.rbs +3 -2
- data/sig/generated/xlsxrb/elements/coordinate_access.rbs +18 -0
- data/sig/generated/xlsxrb/elements/image.rbs +82 -0
- data/sig/generated/xlsxrb/elements/row.rbs +83 -4
- data/sig/generated/xlsxrb/elements/styles.rbs +79 -0
- data/sig/generated/xlsxrb/elements/types.rbs +43 -0
- data/sig/generated/xlsxrb/elements/workbook.rbs +79 -2
- data/sig/generated/xlsxrb/elements/worksheet.rbs +282 -18
- data/sig/generated/xlsxrb/number_formatter.rbs +132 -0
- data/sig/generated/xlsxrb/ooxml/reader.rbs +6 -0
- data/sig/generated/xlsxrb/ooxml/shared_strings_parser.rbs +2 -0
- data/sig/generated/xlsxrb/ooxml/styles_parser.rbs +5 -2
- data/sig/generated/xlsxrb/ooxml/utils.rbs +17 -8
- data/sig/generated/xlsxrb/ooxml/workbook_parser.rbs +9 -3
- data/sig/generated/xlsxrb/ooxml/workbook_writer.rbs +1 -1
- data/sig/generated/xlsxrb/ooxml/worksheet_parser.rbs +28 -6
- data/sig/generated/xlsxrb/ooxml/worksheet_writer.rbs +13 -3
- data/sig/generated/xlsxrb/ooxml/writer.rbs +2 -0
- data/sig/generated/xlsxrb/ooxml/xml_builder.rbs +3 -1
- data/sig/generated/xlsxrb/ooxml/zip_reader.rbs +13 -0
- data/sig/generated/xlsxrb/stream_row.rbs +100 -6
- data/sig/generated/xlsxrb/stream_sheet.rbs +358 -14
- data/sig/generated/xlsxrb/stream_writer.rbs +220 -30
- data/sig/generated/xlsxrb/style_builder.rbs +55 -18
- data/sig/generated/xlsxrb/utils.rbs +151 -0
- data/sig/generated/xlsxrb/workbook_builder.rbs +26 -0
- data/sig/generated/xlsxrb/worksheet_builder.rbs +356 -18
- data/sig/generated/xlsxrb.rbs +223 -27
- metadata +11 -1
|
@@ -17,23 +17,139 @@ module Xlsxrb
|
|
|
17
17
|
class Worksheet
|
|
18
18
|
[Enumerable, CoordinateAccess].each { |m| include m }
|
|
19
19
|
|
|
20
|
-
attr_reader :name, :rows, :columns, :charts, :unmapped_data, :errors
|
|
20
|
+
attr_reader :name, :rows, :columns, :charts, :conditional_formatting, :data_validations, :unmapped_data, :errors, :state, :hyperlinks, :comments, :images, :styles, :date1904, :print_area, :print_titles, :sparkline_groups, :merged_cells, :auto_filter, :tables, :shapes, :freeze_pane, :page_setup, :page_margins, :header_footer, :print_options, :sheet_protection, :sheet_view, :sheet_properties, :sheet_format, :row_breaks, :col_breaks, :protected_ranges, :cell_watches
|
|
21
|
+
attr_writer :dimension
|
|
22
|
+
alias conditional_formats conditional_formatting
|
|
21
23
|
|
|
22
24
|
# @param name [String] The worksheet name (max 31 characters).
|
|
23
25
|
# @param rows [Array<Elements::Row>] Rows in the sheet.
|
|
24
26
|
# @param columns [Array<Elements::Column>] Column definitions.
|
|
25
27
|
# @param charts [Array<Hash>] Charts in the sheet.
|
|
28
|
+
# @param conditional_formatting [Array<Hash>, nil] Conditional formatting rules.
|
|
29
|
+
# @param data_validations [Array<Hash>] Data validation rules.
|
|
26
30
|
# @param unmapped_data [Hash] Additional metadata for round-tripping.
|
|
27
31
|
# @param errors [Array<String>, nil] Validation errors.
|
|
28
|
-
|
|
29
|
-
|
|
32
|
+
# @param conditional_formats [Array<Hash>, nil] Alias for conditional_formatting.
|
|
33
|
+
# @param state [Symbol] Sheet visibility state (:visible, :hidden, or :very_hidden).
|
|
34
|
+
# @param hyperlinks [Hash{String => Hash}] Hyperlink mappings by cell reference.
|
|
35
|
+
# @param comments [Array<Hash>] Comments and notes in the sheet.
|
|
36
|
+
# @param images [Array<Elements::Image>] Embedded images in the sheet.
|
|
37
|
+
# @param styles [Hash, nil] Optional parsed styles hash.
|
|
38
|
+
# @param dimension [String, nil] Sheet dimension reference string (e.g. "A1:Z50000").
|
|
39
|
+
# @param trim_empty_rows [Boolean] Whether to omit trailing empty rows during iteration.
|
|
40
|
+
# @param pad_empty_rows [Boolean] Whether to yield empty rows for skipped row numbers.
|
|
41
|
+
# @param pad_empty_cells [Boolean] Whether to pad missing cells within rows.
|
|
42
|
+
# @param print_area [String, nil] Sheet print area range (e.g. "A1:H50").
|
|
43
|
+
# @param print_titles [Hash, nil] Repeating print title rows/cols (e.g. { rows: "1:2", cols: "A:B" }).
|
|
44
|
+
# @param sparkline_groups [Array<Hash>] Sparkline groups in the sheet.
|
|
45
|
+
# @param merged_cells [Array<String>] Merged cell ranges (e.g. ["A1:B2"]).
|
|
46
|
+
# @param auto_filter [String, nil] AutoFilter range (e.g. "A1:E10").
|
|
47
|
+
# @param tables [Array<Hash>] Table definitions in the sheet.
|
|
48
|
+
# @param shapes [Array<Hash>] Shape definitions in the sheet.
|
|
49
|
+
# @param freeze_pane [Hash, nil] Freeze pane settings (e.g. { row: 1, col: 0 }).
|
|
50
|
+
# @param page_setup [Hash] Page setup properties (e.g. orientation, paper size).
|
|
51
|
+
# @param page_margins [Hash, nil] Page margins settings.
|
|
52
|
+
# @param header_footer [Hash] Header and footer configurations.
|
|
53
|
+
# @param print_options [Hash] Print options (e.g. gridlines, headings).
|
|
54
|
+
# @param sheet_protection [Hash, nil] Sheet protection settings.
|
|
55
|
+
# @param sheet_view [Hash] Sheet view configurations (e.g. zoom, gridlines).
|
|
56
|
+
# @param sheet_properties [Hash] Sheet properties (e.g. tabColor, outlinePr).
|
|
57
|
+
# @param sheet_format [Hash] Sheet format properties (e.g. defaultRowHeight, defaultColWidth).
|
|
58
|
+
# @param row_breaks [Array<Integer | Hash>] Explicit page row breaks.
|
|
59
|
+
# @param col_breaks [Array<Integer | Hash>] Explicit page column breaks.
|
|
60
|
+
# @param protected_ranges [Array<Hash>] Protected range definitions.
|
|
61
|
+
# @param cell_watches [Array<String>] Watched cell references.
|
|
62
|
+
#: (name: String?, ?rows: Array[Elements::Row], ?columns: Array[Elements::Column], ?charts: Array[Hash[Symbol, untyped]], ?conditional_formatting: Array[Hash[Symbol, untyped]]?, ?data_validations: Array[Hash[Symbol, untyped]], ?unmapped_data: Hash[untyped, untyped], ?errors: Array[String]?, ?conditional_formats: Array[Hash[Symbol, untyped]]?, ?state: Symbol, ?hyperlinks: Hash[String, untyped], ?comments: Array[Hash[Symbol, untyped]], ?images: Array[Elements::Image], ?styles: Hash[untyped, untyped]?, ?date1904: bool, ?dimension: String?, ?trim_empty_rows: bool, ?pad_empty_rows: bool, ?pad_empty_cells: bool, ?print_area: String?, ?print_titles: Hash[Symbol, untyped]?, ?sparkline_groups: Array[Hash[Symbol, untyped]], ?merged_cells: Array[String], ?auto_filter: String?, ?tables: Array[Hash[Symbol, untyped]], ?shapes: Array[Hash[Symbol, untyped]], ?freeze_pane: Hash[Symbol, untyped]?, ?page_setup: Hash[Symbol, untyped], ?page_margins: Hash[Symbol, untyped]?, ?header_footer: Hash[Symbol, untyped], ?print_options: Hash[Symbol, untyped], ?sheet_protection: Hash[Symbol, untyped]?, ?sheet_view: Hash[Symbol, untyped], ?sheet_properties: Hash[Symbol, untyped], ?sheet_format: Hash[Symbol, untyped], ?row_breaks: Array[untyped], ?col_breaks: Array[untyped], ?protected_ranges: Array[Hash[Symbol, untyped]], ?cell_watches: Array[String]) -> void
|
|
63
|
+
def initialize(name:, rows: [], columns: [], charts: [], conditional_formatting: nil, data_validations: [], unmapped_data: {}, errors: nil, conditional_formats: nil, state: :visible, hyperlinks: {}, comments: [], images: [], styles: nil, date1904: false, dimension: nil, trim_empty_rows: false, pad_empty_rows: false, pad_empty_cells: false, print_area: nil, print_titles: nil, sparkline_groups: [], merged_cells: [], auto_filter: nil, tables: [], shapes: [], freeze_pane: nil, page_setup: {}, page_margins: nil, header_footer: {}, print_options: {}, sheet_protection: nil, sheet_view: {}, sheet_properties: {}, sheet_format: {}, row_breaks: [], col_breaks: [], protected_ranges: [], cell_watches: [])
|
|
30
64
|
@name = name
|
|
31
65
|
@rows = (rows || []).freeze
|
|
32
66
|
@columns = (columns || []).freeze
|
|
33
67
|
@charts = (charts || []).freeze
|
|
68
|
+
cf = conditional_formatting || conditional_formats || []
|
|
69
|
+
@conditional_formatting = cf.freeze
|
|
70
|
+
@data_validations = (data_validations || []).freeze
|
|
34
71
|
@unmapped_data = (unmapped_data || {}).freeze
|
|
35
72
|
computed_errors = errors || self.class.validate(@name, @rows)
|
|
36
73
|
@errors = computed_errors.freeze
|
|
74
|
+
@state = state ? state.to_sym : :visible
|
|
75
|
+
@hyperlinks = (hyperlinks || {}).freeze
|
|
76
|
+
@comments = (comments || []).freeze
|
|
77
|
+
@images = (images || []).freeze
|
|
78
|
+
@styles = styles
|
|
79
|
+
@date1904 = date1904 ? true : false
|
|
80
|
+
@dimension = dimension
|
|
81
|
+
@print_area = print_area
|
|
82
|
+
@print_titles = print_titles&.freeze
|
|
83
|
+
@sparkline_groups = (sparkline_groups || []).freeze
|
|
84
|
+
@trim_empty_rows = trim_empty_rows ? true : false
|
|
85
|
+
@pad_empty_rows = pad_empty_rows ? true : false
|
|
86
|
+
@pad_empty_cells = pad_empty_cells ? true : false
|
|
87
|
+
@merged_cells = (merged_cells || []).freeze
|
|
88
|
+
@auto_filter = auto_filter
|
|
89
|
+
@tables = (tables || []).freeze
|
|
90
|
+
@shapes = (shapes || []).freeze
|
|
91
|
+
@freeze_pane = freeze_pane&.freeze
|
|
92
|
+
@page_setup = (page_setup || {}).freeze
|
|
93
|
+
@page_margins = page_margins&.freeze
|
|
94
|
+
@header_footer = (header_footer || {}).freeze
|
|
95
|
+
@print_options = (print_options || {}).freeze
|
|
96
|
+
@sheet_protection = sheet_protection&.freeze
|
|
97
|
+
@sheet_view = (sheet_view || {}).freeze
|
|
98
|
+
@sheet_properties = (sheet_properties || {}).freeze
|
|
99
|
+
@sheet_format = (sheet_format || unmapped_data[:sheet_format] || unmapped_data.dig(:facade, :sheet_format) || {}).freeze
|
|
100
|
+
@row_breaks = (row_breaks || []).freeze
|
|
101
|
+
@col_breaks = (col_breaks || []).freeze
|
|
102
|
+
@protected_ranges = (protected_ranges || unmapped_data[:protected_ranges] || unmapped_data.dig(:facade, :protected_ranges) || []).freeze
|
|
103
|
+
@cell_watches = (cell_watches || unmapped_data[:cell_watches] || unmapped_data.dig(:facade, :cell_watches) || []).freeze
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Returns whether trailing empty rows are omitted during iteration.
|
|
107
|
+
#
|
|
108
|
+
# @return [Boolean]
|
|
109
|
+
# @api public
|
|
110
|
+
#: () -> bool
|
|
111
|
+
def trim_empty_rows?
|
|
112
|
+
@trim_empty_rows ? true : false
|
|
113
|
+
end
|
|
114
|
+
alias trim_empty_rows trim_empty_rows?
|
|
115
|
+
|
|
116
|
+
# Returns whether skipped rows are padded during iteration.
|
|
117
|
+
#
|
|
118
|
+
# @return [Boolean]
|
|
119
|
+
# @api public
|
|
120
|
+
#: () -> bool
|
|
121
|
+
def pad_empty_rows?
|
|
122
|
+
@pad_empty_rows ? true : false
|
|
123
|
+
end
|
|
124
|
+
alias pad_empty_rows pad_empty_rows?
|
|
125
|
+
|
|
126
|
+
# Returns whether missing cells within rows are padded during iteration.
|
|
127
|
+
#
|
|
128
|
+
# @return [Boolean]
|
|
129
|
+
# @api public
|
|
130
|
+
#: () -> bool
|
|
131
|
+
def pad_empty_cells?
|
|
132
|
+
@pad_empty_cells ? true : false
|
|
133
|
+
end
|
|
134
|
+
alias pad_empty_cells pad_empty_cells?
|
|
135
|
+
|
|
136
|
+
# Returns whether the worksheet uses the 1904 date system.
|
|
137
|
+
#
|
|
138
|
+
# @return [Boolean]
|
|
139
|
+
# @api public
|
|
140
|
+
#: () -> bool
|
|
141
|
+
def date1904?
|
|
142
|
+
@date1904
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Returns the worksheet dimension reference string (e.g. "A1:Z50000"),
|
|
146
|
+
# or computes it dynamically from rows if not explicitly set.
|
|
147
|
+
#
|
|
148
|
+
# @return [String, nil]
|
|
149
|
+
# @api public
|
|
150
|
+
#: () -> String?
|
|
151
|
+
def dimension
|
|
152
|
+
@dimension ||= compute_dimension
|
|
37
153
|
end
|
|
38
154
|
|
|
39
155
|
# Iterate over rows in the worksheet.
|
|
@@ -43,16 +159,27 @@ module Xlsxrb
|
|
|
43
159
|
# puts row.to_a.inspect
|
|
44
160
|
# end
|
|
45
161
|
#
|
|
46
|
-
# @
|
|
47
|
-
#
|
|
48
|
-
#
|
|
162
|
+
# @overload each(trim_empty_rows: nil, pad_empty_rows: nil, pad_empty_cells: nil, &block)
|
|
163
|
+
# @param trim_empty_rows [Boolean, nil] Whether to omit trailing empty rows.
|
|
164
|
+
# @param pad_empty_rows [Boolean, nil] Whether to yield empty rows for skipped row numbers.
|
|
165
|
+
# @param pad_empty_cells [Boolean, nil] Whether to pad missing cells within rows.
|
|
166
|
+
# @yield [row]
|
|
167
|
+
# @yieldparam row [Elements::Row]
|
|
168
|
+
# @return [void]
|
|
169
|
+
#
|
|
170
|
+
# @overload each(trim_empty_rows: nil, pad_empty_rows: nil, pad_empty_cells: nil)
|
|
171
|
+
# @param trim_empty_rows [Boolean, nil] Whether to omit trailing empty rows.
|
|
172
|
+
# @param pad_empty_rows [Boolean, nil] Whether to yield empty rows for skipped row numbers.
|
|
173
|
+
# @param pad_empty_cells [Boolean, nil] Whether to pad missing cells within rows.
|
|
174
|
+
# @return [Enumerator<Elements::Row, void>]
|
|
175
|
+
#
|
|
49
176
|
# @api public
|
|
50
|
-
#: () { (Elements::Row) -> void } -> void
|
|
51
|
-
#: () -> Enumerator[Elements::Row, void]
|
|
52
|
-
def each(&)
|
|
53
|
-
return to_enum(:each) unless block_given?
|
|
177
|
+
#: (?trim_empty_rows: bool?, ?pad_empty_rows: bool?, ?pad_empty_cells: bool?) { (Elements::Row) -> void } -> void
|
|
178
|
+
#: (?trim_empty_rows: bool?, ?pad_empty_rows: bool?, ?pad_empty_cells: bool?) -> Enumerator[Elements::Row, void]
|
|
179
|
+
def each(trim_empty_rows: nil, pad_empty_rows: nil, pad_empty_cells: nil, &)
|
|
180
|
+
return to_enum(:each, trim_empty_rows: trim_empty_rows, pad_empty_rows: pad_empty_rows, pad_empty_cells: pad_empty_cells) unless block_given?
|
|
54
181
|
|
|
55
|
-
|
|
182
|
+
each_row(trim_empty_rows: trim_empty_rows, pad_empty_rows: pad_empty_rows, pad_empty_cells: pad_empty_cells, &)
|
|
56
183
|
end
|
|
57
184
|
|
|
58
185
|
# Iterate over rows in the worksheet.
|
|
@@ -62,16 +189,104 @@ module Xlsxrb
|
|
|
62
189
|
# puts "Row #{row.index}: #{row.to_a.inspect}"
|
|
63
190
|
# end
|
|
64
191
|
#
|
|
65
|
-
# @
|
|
66
|
-
#
|
|
67
|
-
#
|
|
192
|
+
# @overload each_row(trim_empty_rows: nil, pad_empty_rows: nil, pad_empty_cells: nil, &block)
|
|
193
|
+
# @param trim_empty_rows [Boolean, nil] Whether to omit trailing empty rows.
|
|
194
|
+
# @param pad_empty_rows [Boolean, nil] Whether to yield empty rows for skipped row numbers.
|
|
195
|
+
# @param pad_empty_cells [Boolean, nil] Whether to pad missing cells within rows.
|
|
196
|
+
# @yield [row]
|
|
197
|
+
# @yieldparam row [Elements::Row]
|
|
198
|
+
# @return [void]
|
|
199
|
+
#
|
|
200
|
+
# @overload each_row(trim_empty_rows: nil, pad_empty_rows: nil, pad_empty_cells: nil)
|
|
201
|
+
# @param trim_empty_rows [Boolean, nil] Whether to omit trailing empty rows.
|
|
202
|
+
# @param pad_empty_rows [Boolean, nil] Whether to yield empty rows for skipped row numbers.
|
|
203
|
+
# @param pad_empty_cells [Boolean, nil] Whether to pad missing cells within rows.
|
|
204
|
+
# @return [Enumerator<Elements::Row, void>]
|
|
205
|
+
#
|
|
206
|
+
# @api public
|
|
207
|
+
#: (?trim_empty_rows: bool?, ?pad_empty_rows: bool?, ?pad_empty_cells: bool?) { (Elements::Row) -> void } -> void
|
|
208
|
+
#: (?trim_empty_rows: bool?, ?pad_empty_rows: bool?, ?pad_empty_cells: bool?) -> Enumerator[Elements::Row, void]
|
|
209
|
+
def each_row(trim_empty_rows: nil, pad_empty_rows: nil, pad_empty_cells: nil, &block)
|
|
210
|
+
return to_enum(:each_row, trim_empty_rows: trim_empty_rows, pad_empty_rows: pad_empty_rows, pad_empty_cells: pad_empty_cells) unless block
|
|
211
|
+
|
|
212
|
+
trim = if trim_empty_rows.nil?
|
|
213
|
+
@trim_empty_rows
|
|
214
|
+
else
|
|
215
|
+
(trim_empty_rows ? true : false)
|
|
216
|
+
end
|
|
217
|
+
pad_rows = if pad_empty_rows.nil?
|
|
218
|
+
@pad_empty_rows
|
|
219
|
+
else
|
|
220
|
+
(pad_empty_rows ? true : false)
|
|
221
|
+
end
|
|
222
|
+
pad_cells = if pad_empty_cells.nil?
|
|
223
|
+
@pad_empty_cells
|
|
224
|
+
else
|
|
225
|
+
(pad_empty_cells ? true : false)
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
row_consumer = if trim
|
|
229
|
+
pending_empty = []
|
|
230
|
+
lambda do |row|
|
|
231
|
+
if row.empty?
|
|
232
|
+
pending_empty << row
|
|
233
|
+
else
|
|
234
|
+
pending_empty.each(&block)
|
|
235
|
+
pending_empty.clear
|
|
236
|
+
block.call(row)
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
else
|
|
240
|
+
block
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
if pad_rows
|
|
244
|
+
current_expected_idx = 0
|
|
245
|
+
inner_consumer = row_consumer
|
|
246
|
+
row_consumer = lambda do |row|
|
|
247
|
+
while current_expected_idx < row.index
|
|
248
|
+
empty_row = Row.new(index: current_expected_idx)
|
|
249
|
+
inner_consumer.call(pad_cells ? empty_row.pad_empty_cells : empty_row)
|
|
250
|
+
current_expected_idx += 1
|
|
251
|
+
end
|
|
252
|
+
inner_consumer.call(row)
|
|
253
|
+
current_expected_idx = row.index + 1
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
rows.each do |row|
|
|
258
|
+
row_to_yield = pad_cells ? row.pad_empty_cells : row
|
|
259
|
+
row_consumer.call(row_to_yield)
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
# Iterates over row values as Arrays.
|
|
264
|
+
#
|
|
265
|
+
# @overload each_row_values(type_cast: false, trim_empty_rows: nil, pad_empty_rows: nil, pad_empty_cells: nil, &block)
|
|
266
|
+
# @param type_cast [Boolean] Whether to coerce date/time serial numbers into Date/Time instances.
|
|
267
|
+
# @param trim_empty_rows [Boolean, nil] Whether to omit trailing empty rows.
|
|
268
|
+
# @param pad_empty_rows [Boolean, nil] Whether to yield empty rows for skipped row numbers.
|
|
269
|
+
# @param pad_empty_cells [Boolean, nil] Whether to pad missing cells within rows.
|
|
270
|
+
# @yield [values]
|
|
271
|
+
# @yieldparam values [Array<Object>] Row values array.
|
|
272
|
+
# @return [void]
|
|
273
|
+
#
|
|
274
|
+
# @overload each_row_values(type_cast: false, trim_empty_rows: nil, pad_empty_rows: nil, pad_empty_cells: nil)
|
|
275
|
+
# @param type_cast [Boolean] Whether to coerce date/time serial numbers into Date/Time instances.
|
|
276
|
+
# @param trim_empty_rows [Boolean, nil] Whether to omit trailing empty rows.
|
|
277
|
+
# @param pad_empty_rows [Boolean, nil] Whether to yield empty rows for skipped row numbers.
|
|
278
|
+
# @param pad_empty_cells [Boolean, nil] Whether to pad missing cells within rows.
|
|
279
|
+
# @return [Enumerator<Array<Object>, void>]
|
|
280
|
+
#
|
|
68
281
|
# @api public
|
|
69
|
-
#: () { (
|
|
70
|
-
#: () -> Enumerator[
|
|
71
|
-
def
|
|
72
|
-
return to_enum(:
|
|
282
|
+
#: (?type_cast: bool, ?trim_empty_rows: bool?, ?pad_empty_rows: bool?, ?pad_empty_cells: bool?) { (Array[untyped]) -> void } -> void
|
|
283
|
+
#: (?type_cast: bool, ?trim_empty_rows: bool?, ?pad_empty_rows: bool?, ?pad_empty_cells: bool?) -> Enumerator[Array[untyped], void]
|
|
284
|
+
def each_row_values(type_cast: false, trim_empty_rows: nil, pad_empty_rows: nil, pad_empty_cells: nil, &block)
|
|
285
|
+
return to_enum(:each_row_values, type_cast: type_cast, trim_empty_rows: trim_empty_rows, pad_empty_rows: pad_empty_rows, pad_empty_cells: pad_empty_cells) unless block
|
|
73
286
|
|
|
74
|
-
|
|
287
|
+
each_row(trim_empty_rows: trim_empty_rows, pad_empty_rows: pad_empty_rows, pad_empty_cells: pad_empty_cells) do |row|
|
|
288
|
+
block.call(row.values(type_cast: type_cast))
|
|
289
|
+
end
|
|
75
290
|
end
|
|
76
291
|
|
|
77
292
|
# Iterate over all cells across rows.
|
|
@@ -88,6 +303,39 @@ module Xlsxrb
|
|
|
88
303
|
cells.each(&)
|
|
89
304
|
end
|
|
90
305
|
|
|
306
|
+
# Returns all images anchored at a specific cell reference or 0-based coordinate.
|
|
307
|
+
#
|
|
308
|
+
# @param ref_or_row [String, Symbol, Integer] Cell reference (e.g. "A1") or 0-based row index.
|
|
309
|
+
# @param col [Integer, nil] Optional 0-based column index.
|
|
310
|
+
# @return [Array<Elements::Image>]
|
|
311
|
+
# @api public
|
|
312
|
+
#: (String | Symbol | Integer ref_or_row, ?Integer? col) -> Array[Elements::Image]
|
|
313
|
+
def images_at(ref_or_row, col = nil)
|
|
314
|
+
ref = if col
|
|
315
|
+
"#{Cell.column_letter(col)}#{ref_or_row.to_i + 1}"
|
|
316
|
+
else
|
|
317
|
+
ref_or_row.to_s.upcase
|
|
318
|
+
end
|
|
319
|
+
images.select { |img| img.cell_ref == ref }
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
# Yields self with images loaded or returns self.
|
|
323
|
+
#
|
|
324
|
+
# @yield [sheet]
|
|
325
|
+
# @yieldparam sheet [Elements::Worksheet]
|
|
326
|
+
# @return [Elements::Worksheet, void]
|
|
327
|
+
# @api public
|
|
328
|
+
#: () { (Elements::Worksheet) -> void } -> void
|
|
329
|
+
#: () -> Elements::Worksheet
|
|
330
|
+
def with_images
|
|
331
|
+
if block_given?
|
|
332
|
+
yield self
|
|
333
|
+
nil
|
|
334
|
+
else
|
|
335
|
+
self
|
|
336
|
+
end
|
|
337
|
+
end
|
|
338
|
+
|
|
91
339
|
# Returns whether the worksheet is valid according to OOXML specifications.
|
|
92
340
|
#
|
|
93
341
|
# @return [Boolean]
|
|
@@ -96,6 +344,95 @@ module Xlsxrb
|
|
|
96
344
|
errors.empty?
|
|
97
345
|
end
|
|
98
346
|
|
|
347
|
+
# Returns whether the worksheet is hidden (:hidden or :very_hidden).
|
|
348
|
+
#
|
|
349
|
+
# @return [Boolean]
|
|
350
|
+
# @api public
|
|
351
|
+
#: () -> bool
|
|
352
|
+
def hidden?
|
|
353
|
+
@state == :hidden || @state == :very_hidden
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
# Returns whether the worksheet is visible.
|
|
357
|
+
#
|
|
358
|
+
# @return [Boolean]
|
|
359
|
+
# @api public
|
|
360
|
+
#: () -> bool
|
|
361
|
+
def visible?
|
|
362
|
+
@state == :visible
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
# Returns hyperlink metadata for the given cell reference, or nil.
|
|
366
|
+
#
|
|
367
|
+
# @param ref_or_row [String, Symbol, Integer] Cell reference (e.g. "A1") or 0-based row index.
|
|
368
|
+
# @param col [Integer, nil] Optional 0-based column index if ref_or_row is a row index.
|
|
369
|
+
# @return [Hash, nil]
|
|
370
|
+
# @api public
|
|
371
|
+
#: (String | Symbol | Integer ref_or_row, ?Integer? col) -> Hash[Symbol, untyped]?
|
|
372
|
+
def hyperlink(ref_or_row, col = nil)
|
|
373
|
+
ref = if col
|
|
374
|
+
"#{Cell.column_letter(col)}#{ref_or_row.to_i + 1}"
|
|
375
|
+
else
|
|
376
|
+
ref_or_row.to_s.upcase
|
|
377
|
+
end
|
|
378
|
+
@hyperlinks[ref]
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
# Returns comment metadata for the given cell reference, or nil.
|
|
382
|
+
#
|
|
383
|
+
# @param ref_or_row [String, Symbol, Integer] Cell reference (e.g. "A1") or 0-based row index.
|
|
384
|
+
# @param col [Integer, nil] Optional 0-based column index if ref_or_row is a row index.
|
|
385
|
+
# @return [Hash, nil]
|
|
386
|
+
# @api public
|
|
387
|
+
#: (String | Symbol | Integer ref_or_row, ?Integer? col) -> Hash[Symbol, untyped]?
|
|
388
|
+
def comment(ref_or_row, col = nil)
|
|
389
|
+
ref = if col
|
|
390
|
+
"#{Cell.column_letter(col)}#{ref_or_row.to_i + 1}"
|
|
391
|
+
else
|
|
392
|
+
ref_or_row.to_s.upcase
|
|
393
|
+
end
|
|
394
|
+
comments_by_ref[ref]
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
# Returns comments indexed by cell reference.
|
|
398
|
+
#
|
|
399
|
+
# @return [Hash<String, Hash[Symbol, untyped]>]
|
|
400
|
+
# @api public
|
|
401
|
+
#: () -> Hash[String, Hash[Symbol, untyped]]
|
|
402
|
+
def comments_by_ref
|
|
403
|
+
@comments_by_ref ||= @comments.each_with_object({}) do |c, acc|
|
|
404
|
+
r = c[:ref] || c[:cell]
|
|
405
|
+
acc[r.to_s.upcase] = c if r
|
|
406
|
+
end
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
# Access a cell by reference or 0-based coordinates.
|
|
410
|
+
#
|
|
411
|
+
# @param ref_or_row [String, Symbol, Integer] Cell reference (e.g. "A1") or 0-based row index.
|
|
412
|
+
# @param col [Integer, nil] Optional 0-based column index.
|
|
413
|
+
# @return [Elements::Cell, nil]
|
|
414
|
+
# @api public
|
|
415
|
+
#: (String | Symbol | Integer ref_or_row, ?Integer? col) -> Elements::Cell?
|
|
416
|
+
def cell(ref_or_row, col = nil)
|
|
417
|
+
if col
|
|
418
|
+
row = row_at(ref_or_row.to_i)
|
|
419
|
+
row&.cell_at(col.to_i)
|
|
420
|
+
else
|
|
421
|
+
self[ref_or_row]
|
|
422
|
+
end
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
# Returns the formatted string representation of a cell's value.
|
|
426
|
+
#
|
|
427
|
+
# @param ref_or_row [String, Symbol, Integer] Cell reference (e.g. "A1") or 0-based row index.
|
|
428
|
+
# @param col [Integer, nil] Optional 0-based column index.
|
|
429
|
+
# @return [String, nil]
|
|
430
|
+
# @api public
|
|
431
|
+
#: (String | Symbol | Integer ref_or_row, ?Integer? col) -> String?
|
|
432
|
+
def formatted_value(ref_or_row, col = nil)
|
|
433
|
+
cell(ref_or_row, col)&.formatted_value
|
|
434
|
+
end
|
|
435
|
+
|
|
99
436
|
# Returns a new Worksheet with the specified cell updated.
|
|
100
437
|
#
|
|
101
438
|
# @example
|
|
@@ -105,10 +442,12 @@ module Xlsxrb
|
|
|
105
442
|
# @param value [Object] The new cell value.
|
|
106
443
|
# @param style_index [Integer, String, nil] Optional new style index.
|
|
107
444
|
# @param formula [Elements::Formula, nil] Optional new formula.
|
|
445
|
+
# @param hyperlink [Hash, String, nil] Optional new hyperlink.
|
|
446
|
+
# @param comment [Hash, String, nil] Optional new comment.
|
|
108
447
|
# @return [Worksheet] A new Worksheet instance.
|
|
109
448
|
# @api public
|
|
110
|
-
#: (String ref, ?value: untyped, ?style_index: Integer | String | nil, ?formula: Elements::Formula?) -> Elements::Worksheet
|
|
111
|
-
def update_cell(ref, value: nil, style_index: nil, formula: nil)
|
|
449
|
+
#: (String ref, ?value: untyped, ?style_index: Integer | String | nil, ?formula: Elements::Formula?, ?hyperlink: (Hash[Symbol, untyped] | String)?, ?comment: (Hash[Symbol, untyped] | String)?) -> Elements::Worksheet
|
|
450
|
+
def update_cell(ref, value: nil, style_index: nil, formula: nil, hyperlink: nil, comment: nil)
|
|
112
451
|
parsed = Cell.parse_ref(ref)
|
|
113
452
|
raise ArgumentError, "invalid cell reference: #{ref}" unless parsed
|
|
114
453
|
|
|
@@ -121,10 +460,12 @@ module Xlsxrb
|
|
|
121
460
|
existing_cell.with(
|
|
122
461
|
value: value || existing_cell.value,
|
|
123
462
|
style_index: style_index || existing_cell.style_index,
|
|
124
|
-
formula: formula || existing_cell.formula
|
|
463
|
+
formula: formula || existing_cell.formula,
|
|
464
|
+
hyperlink: hyperlink || existing_cell.hyperlink,
|
|
465
|
+
comment: comment || existing_cell.comment
|
|
125
466
|
)
|
|
126
467
|
else
|
|
127
|
-
Cell.new(row_index: row_idx, column_index: col_idx, value: value, style_index: style_index, formula: formula)
|
|
468
|
+
Cell.new(row_index: row_idx, column_index: col_idx, value: value, style_index: style_index, formula: formula, hyperlink: hyperlink, comment: comment)
|
|
128
469
|
end
|
|
129
470
|
|
|
130
471
|
# Replace cell in the existing row
|
|
@@ -136,11 +477,18 @@ module Xlsxrb
|
|
|
136
477
|
new_rows = rows.map { |r| r.index == row_idx ? new_row : r }
|
|
137
478
|
else
|
|
138
479
|
# Row doesn't exist, create it
|
|
139
|
-
new_cell = Cell.new(row_index: row_idx, column_index: col_idx, value: value, style_index: style_index, formula: formula)
|
|
480
|
+
new_cell = Cell.new(row_index: row_idx, column_index: col_idx, value: value, style_index: style_index, formula: formula, hyperlink: hyperlink, comment: comment)
|
|
140
481
|
new_row = Row.new(index: row_idx, cells: [new_cell])
|
|
141
482
|
new_rows = (rows + [new_row]).sort_by!(&:index)
|
|
142
483
|
end
|
|
143
|
-
|
|
484
|
+
new_hyperlinks = hyperlink ? hyperlinks.merge(ref.upcase => hyperlink) : hyperlinks
|
|
485
|
+
new_comments = if comment
|
|
486
|
+
entry = comment.is_a?(Hash) ? comment.merge(ref: ref.upcase) : { ref: ref.upcase, text: comment }
|
|
487
|
+
@comments.reject { |c| (c[:ref] || c[:cell])&.to_s&.upcase == ref.upcase } + [entry]
|
|
488
|
+
else
|
|
489
|
+
@comments
|
|
490
|
+
end
|
|
491
|
+
with(rows: new_rows, hyperlinks: new_hyperlinks, comments: new_comments)
|
|
144
492
|
end
|
|
145
493
|
|
|
146
494
|
# Returns a new Worksheet with attributes replaced (Data-like behavior).
|
|
@@ -154,23 +502,122 @@ module Xlsxrb
|
|
|
154
502
|
new_rows = changes.key?(:rows) ? changes[:rows] : rows
|
|
155
503
|
new_cols = changes.key?(:columns) ? changes[:columns] : columns
|
|
156
504
|
new_charts = changes.key?(:charts) ? changes[:charts] : charts
|
|
505
|
+
new_cf = if changes.key?(:conditional_formatting)
|
|
506
|
+
changes[:conditional_formatting]
|
|
507
|
+
elsif changes.key?(:conditional_formats)
|
|
508
|
+
changes[:conditional_formats]
|
|
509
|
+
else
|
|
510
|
+
conditional_formatting
|
|
511
|
+
end
|
|
512
|
+
new_dv = changes.key?(:data_validations) ? changes[:data_validations] : data_validations
|
|
157
513
|
new_unmapped = changes.key?(:unmapped_data) ? changes[:unmapped_data] : unmapped_data
|
|
158
514
|
new_errors = changes.key?(:errors) ? changes[:errors] : errors
|
|
515
|
+
new_state = changes.key?(:state) ? changes[:state] : state
|
|
516
|
+
new_hyperlinks = changes.key?(:hyperlinks) ? changes[:hyperlinks] : hyperlinks
|
|
517
|
+
new_comments = changes.key?(:comments) ? changes[:comments] : comments
|
|
518
|
+
new_styles = changes.key?(:styles) ? changes[:styles] : styles
|
|
519
|
+
new_date1904 = changes.key?(:date1904) ? changes[:date1904] : date1904
|
|
520
|
+
new_dim = changes.key?(:dimension) ? changes[:dimension] : @dimension
|
|
521
|
+
new_print_area = changes.key?(:print_area) ? changes[:print_area] : print_area
|
|
522
|
+
new_print_titles = changes.key?(:print_titles) ? changes[:print_titles] : print_titles
|
|
523
|
+
new_sparklines = changes.key?(:sparkline_groups) ? changes[:sparkline_groups] : sparkline_groups
|
|
524
|
+
new_trim = changes.key?(:trim_empty_rows) ? changes[:trim_empty_rows] : @trim_empty_rows
|
|
525
|
+
new_merged = changes.key?(:merged_cells) ? changes[:merged_cells] : merged_cells
|
|
526
|
+
new_auto_filter = changes.key?(:auto_filter) ? changes[:auto_filter] : auto_filter
|
|
527
|
+
new_tables = changes.key?(:tables) ? changes[:tables] : tables
|
|
528
|
+
new_shapes = changes.key?(:shapes) ? changes[:shapes] : shapes
|
|
529
|
+
new_freeze_pane = changes.key?(:freeze_pane) ? changes[:freeze_pane] : freeze_pane
|
|
530
|
+
new_page_setup = changes.key?(:page_setup) ? changes[:page_setup] : page_setup
|
|
531
|
+
new_page_margins = changes.key?(:page_margins) ? changes[:page_margins] : page_margins
|
|
532
|
+
new_header_footer = changes.key?(:header_footer) ? changes[:header_footer] : header_footer
|
|
533
|
+
new_print_options = changes.key?(:print_options) ? changes[:print_options] : print_options
|
|
534
|
+
new_sheet_protection = changes.key?(:sheet_protection) ? changes[:sheet_protection] : sheet_protection
|
|
535
|
+
new_sheet_view = changes.key?(:sheet_view) ? changes[:sheet_view] : sheet_view
|
|
536
|
+
new_sheet_properties = changes.key?(:sheet_properties) ? changes[:sheet_properties] : sheet_properties
|
|
537
|
+
new_sheet_format = changes.key?(:sheet_format) ? changes[:sheet_format] : sheet_format
|
|
538
|
+
new_row_breaks = changes.key?(:row_breaks) ? changes[:row_breaks] : row_breaks
|
|
539
|
+
new_col_breaks = changes.key?(:col_breaks) ? changes[:col_breaks] : col_breaks
|
|
540
|
+
new_protected_ranges = changes.key?(:protected_ranges) ? changes[:protected_ranges] : protected_ranges
|
|
541
|
+
new_cell_watches = changes.key?(:cell_watches) ? changes[:cell_watches] : cell_watches
|
|
159
542
|
|
|
160
543
|
self.class.new(
|
|
161
544
|
name: new_name,
|
|
162
545
|
rows: new_rows,
|
|
163
546
|
columns: new_cols,
|
|
164
547
|
charts: new_charts,
|
|
548
|
+
conditional_formatting: new_cf,
|
|
549
|
+
data_validations: new_dv,
|
|
165
550
|
unmapped_data: new_unmapped,
|
|
166
|
-
errors: new_errors
|
|
551
|
+
errors: new_errors,
|
|
552
|
+
state: new_state,
|
|
553
|
+
hyperlinks: new_hyperlinks,
|
|
554
|
+
comments: new_comments,
|
|
555
|
+
styles: new_styles,
|
|
556
|
+
date1904: new_date1904,
|
|
557
|
+
dimension: new_dim,
|
|
558
|
+
print_area: new_print_area,
|
|
559
|
+
print_titles: new_print_titles,
|
|
560
|
+
sparkline_groups: new_sparklines,
|
|
561
|
+
trim_empty_rows: new_trim,
|
|
562
|
+
merged_cells: new_merged,
|
|
563
|
+
auto_filter: new_auto_filter,
|
|
564
|
+
tables: new_tables,
|
|
565
|
+
shapes: new_shapes,
|
|
566
|
+
freeze_pane: new_freeze_pane,
|
|
567
|
+
page_setup: new_page_setup,
|
|
568
|
+
page_margins: new_page_margins,
|
|
569
|
+
header_footer: new_header_footer,
|
|
570
|
+
print_options: new_print_options,
|
|
571
|
+
sheet_protection: new_sheet_protection,
|
|
572
|
+
sheet_view: new_sheet_view,
|
|
573
|
+
sheet_properties: new_sheet_properties,
|
|
574
|
+
sheet_format: new_sheet_format,
|
|
575
|
+
row_breaks: new_row_breaks,
|
|
576
|
+
col_breaks: new_col_breaks,
|
|
577
|
+
protected_ranges: new_protected_ranges,
|
|
578
|
+
cell_watches: new_cell_watches
|
|
167
579
|
)
|
|
168
580
|
end
|
|
169
581
|
|
|
170
582
|
# Support pattern matching.
|
|
171
583
|
#: (Array[Symbol]?) -> Hash[Symbol, untyped]
|
|
172
584
|
def deconstruct_keys(_keys)
|
|
173
|
-
{
|
|
585
|
+
{
|
|
586
|
+
name: name,
|
|
587
|
+
rows: rows,
|
|
588
|
+
columns: columns,
|
|
589
|
+
charts: charts,
|
|
590
|
+
conditional_formatting: conditional_formatting,
|
|
591
|
+
conditional_formats: conditional_formatting,
|
|
592
|
+
data_validations: data_validations,
|
|
593
|
+
unmapped_data: unmapped_data,
|
|
594
|
+
errors: errors,
|
|
595
|
+
state: state,
|
|
596
|
+
hyperlinks: hyperlinks,
|
|
597
|
+
comments: comments,
|
|
598
|
+
styles: styles,
|
|
599
|
+
date1904: date1904,
|
|
600
|
+
dimension: dimension,
|
|
601
|
+
print_area: print_area,
|
|
602
|
+
print_titles: print_titles,
|
|
603
|
+
sparkline_groups: sparkline_groups,
|
|
604
|
+
trim_empty_rows: @trim_empty_rows,
|
|
605
|
+
merged_cells: merged_cells,
|
|
606
|
+
auto_filter: auto_filter,
|
|
607
|
+
tables: tables,
|
|
608
|
+
shapes: shapes,
|
|
609
|
+
freeze_pane: freeze_pane,
|
|
610
|
+
page_setup: page_setup,
|
|
611
|
+
page_margins: page_margins,
|
|
612
|
+
header_footer: header_footer,
|
|
613
|
+
print_options: print_options,
|
|
614
|
+
sheet_protection: sheet_protection,
|
|
615
|
+
sheet_view: sheet_view,
|
|
616
|
+
sheet_properties: sheet_properties,
|
|
617
|
+
sheet_format: sheet_format,
|
|
618
|
+
row_breaks: row_breaks,
|
|
619
|
+
col_breaks: col_breaks
|
|
620
|
+
}
|
|
174
621
|
end
|
|
175
622
|
|
|
176
623
|
# Compare worksheets for equality.
|
|
@@ -178,13 +625,27 @@ module Xlsxrb
|
|
|
178
625
|
def ==(other)
|
|
179
626
|
return false unless other.is_a?(Worksheet)
|
|
180
627
|
|
|
181
|
-
name == other.name && rows == other.rows && columns == other.columns && charts == other.charts
|
|
628
|
+
name == other.name && rows == other.rows && columns == other.columns && charts == other.charts &&
|
|
629
|
+
conditional_formatting == other.conditional_formatting && data_validations == other.data_validations &&
|
|
630
|
+
state == other.state && hyperlinks == other.hyperlinks && comments == other.comments &&
|
|
631
|
+
merged_cells == other.merged_cells && auto_filter == other.auto_filter &&
|
|
632
|
+
tables == other.tables && shapes == other.shapes && freeze_pane == other.freeze_pane &&
|
|
633
|
+
page_setup == other.page_setup && page_margins == other.page_margins &&
|
|
634
|
+
header_footer == other.header_footer && print_options == other.print_options &&
|
|
635
|
+
sheet_protection == other.sheet_protection && sheet_view == other.sheet_view &&
|
|
636
|
+
sheet_properties == other.sheet_properties && sheet_format == other.sheet_format &&
|
|
637
|
+
row_breaks == other.row_breaks && col_breaks == other.col_breaks
|
|
182
638
|
end
|
|
183
639
|
alias eql? ==
|
|
184
640
|
|
|
185
641
|
#: () -> Integer
|
|
186
642
|
def hash
|
|
187
|
-
[
|
|
643
|
+
[
|
|
644
|
+
self.class, name, rows, columns, charts, conditional_formatting, data_validations,
|
|
645
|
+
state, hyperlinks, comments, merged_cells, auto_filter, tables, shapes, freeze_pane,
|
|
646
|
+
page_setup, page_margins, header_footer, print_options, sheet_protection, sheet_view,
|
|
647
|
+
sheet_properties, sheet_format, row_breaks, col_breaks
|
|
648
|
+
].hash
|
|
188
649
|
end
|
|
189
650
|
|
|
190
651
|
# Returns self when load is called on an already in-memory Worksheet.
|
|
@@ -237,6 +698,35 @@ module Xlsxrb
|
|
|
237
698
|
end
|
|
238
699
|
errs
|
|
239
700
|
end
|
|
701
|
+
|
|
702
|
+
private
|
|
703
|
+
|
|
704
|
+
#: () -> String?
|
|
705
|
+
def compute_dimension
|
|
706
|
+
return nil if rows.empty?
|
|
707
|
+
|
|
708
|
+
min_r = nil
|
|
709
|
+
max_r = nil
|
|
710
|
+
min_c = nil
|
|
711
|
+
max_c = nil
|
|
712
|
+
|
|
713
|
+
rows.each do |r|
|
|
714
|
+
next if r.cells.empty?
|
|
715
|
+
|
|
716
|
+
min_r = r.index if min_r.nil? || r.index < min_r
|
|
717
|
+
max_r = r.index if max_r.nil? || r.index > max_r
|
|
718
|
+
r.cells.each do |c|
|
|
719
|
+
min_c = c.column_index if min_c.nil? || c.column_index < min_c
|
|
720
|
+
max_c = c.column_index if max_c.nil? || c.column_index > max_c
|
|
721
|
+
end
|
|
722
|
+
end
|
|
723
|
+
|
|
724
|
+
return nil if min_r.nil? || min_c.nil?
|
|
725
|
+
|
|
726
|
+
start_cell = "#{Elements::Cell.column_letter(min_c)}#{min_r + 1}"
|
|
727
|
+
end_cell = "#{Elements::Cell.column_letter(max_c)}#{max_r + 1}"
|
|
728
|
+
start_cell == end_cell ? start_cell : "#{start_cell}:#{end_cell}"
|
|
729
|
+
end
|
|
240
730
|
end
|
|
241
731
|
end
|
|
242
732
|
end
|
data/lib/xlsxrb/elements.rb
CHANGED
|
@@ -9,6 +9,8 @@ require_relative "elements/column"
|
|
|
9
9
|
require_relative "elements/coordinate_access"
|
|
10
10
|
require_relative "elements/worksheet"
|
|
11
11
|
require_relative "elements/workbook"
|
|
12
|
+
require_relative "elements/styles"
|
|
13
|
+
require_relative "elements/image"
|
|
12
14
|
|
|
13
15
|
module Xlsxrb
|
|
14
16
|
# High-level domain model layer.
|