xlsxrb 0.1.12 → 0.1.14
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 +116 -42
- data/README.md +28 -22
- data/lib/xlsxrb/colors.rb +118 -0
- data/lib/xlsxrb/dsl_helpers.rb +59 -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 +96 -4
- data/lib/xlsxrb/elements/worksheet.rb +424 -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.rb +12 -14
- data/lib/xlsxrb/ooxml/shared_strings_parser.rb +10 -6
- data/lib/xlsxrb/ooxml/styles_parser.rb +39 -9
- data/lib/xlsxrb/ooxml/utils.rb +34 -18
- data/lib/xlsxrb/ooxml/workbook_parser.rb +53 -15
- data/lib/xlsxrb/ooxml/workbook_writer.rb +70 -21
- data/lib/xlsxrb/ooxml/worksheet_parser.rb +466 -63
- data/lib/xlsxrb/ooxml/worksheet_writer.rb +206 -61
- data/lib/xlsxrb/ooxml/writer/features_xml.rb +4 -2
- data/lib/xlsxrb/ooxml/writer.rb +16 -1
- data/lib/xlsxrb/ooxml/xml_builder.rb +20 -0
- data/lib/xlsxrb/ooxml/zip_reader.rb +452 -82
- data/lib/xlsxrb/ooxml/zip_writer.rb +32 -5
- data/lib/xlsxrb/stream_row.rb +243 -16
- data/lib/xlsxrb/stream_sheet.rb +504 -17
- data/lib/xlsxrb/stream_writer.rb +246 -83
- data/lib/xlsxrb/style_builder.rb +308 -22
- data/lib/xlsxrb/utils.rb +158 -0
- data/lib/xlsxrb/version.rb +1 -1
- data/lib/xlsxrb/workbook_builder.rb +74 -4
- data/lib/xlsxrb/worksheet_builder.rb +230 -47
- data/lib/xlsxrb.rb +1005 -229
- data/sig/generated/xlsxrb/colors.rbs +40 -0
- data/sig/generated/xlsxrb/dsl_helpers.rbs +32 -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 +58 -2
- data/sig/generated/xlsxrb/elements/worksheet.rbs +231 -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 -2
- 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/worksheet_parser.rbs +31 -8
- data/sig/generated/xlsxrb/ooxml/worksheet_writer.rbs +3 -1
- data/sig/generated/xlsxrb/ooxml/writer.rbs +2 -0
- data/sig/generated/xlsxrb/ooxml/xml_builder.rbs +11 -0
- data/sig/generated/xlsxrb/ooxml/zip_reader.rbs +106 -8
- data/sig/generated/xlsxrb/ooxml/zip_writer.rbs +5 -1
- data/sig/generated/xlsxrb/stream_row.rbs +100 -6
- data/sig/generated/xlsxrb/stream_sheet.rbs +288 -14
- data/sig/generated/xlsxrb/stream_writer.rbs +120 -14
- data/sig/generated/xlsxrb/style_builder.rbs +55 -18
- data/sig/generated/xlsxrb/utils.rbs +119 -0
- data/sig/generated/xlsxrb/workbook_builder.rbs +26 -0
- data/sig/generated/xlsxrb/worksheet_builder.rbs +107 -11
- data/sig/generated/xlsxrb.rbs +202 -36
- metadata +16 -146
- data/.devcontainer/Dockerfile +0 -65
- data/.devcontainer/devcontainer.json +0 -17
- data/.gem_rbs_collection/ast/2.4/.rbs_meta.yaml +0 -9
- data/.gem_rbs_collection/ast/2.4/ast.rbs +0 -73
- data/.gem_rbs_collection/concurrent-ruby/1.1/.rbs_meta.yaml +0 -9
- data/.gem_rbs_collection/concurrent-ruby/1.1/array.rbs +0 -4
- data/.gem_rbs_collection/concurrent-ruby/1.1/atomic_reference.rbs +0 -16
- data/.gem_rbs_collection/concurrent-ruby/1.1/executor.rbs +0 -96
- data/.gem_rbs_collection/concurrent-ruby/1.1/hash.rbs +0 -4
- data/.gem_rbs_collection/concurrent-ruby/1.1/map.rbs +0 -68
- data/.gem_rbs_collection/concurrent-ruby/1.1/promises.rbs +0 -249
- data/.gem_rbs_collection/concurrent-ruby/1.1/set.rbs +0 -4
- data/.gem_rbs_collection/concurrent-ruby/1.1/timer_task.rbs +0 -47
- data/.gem_rbs_collection/concurrent-ruby/1.1/utility/processor_counter.rbs +0 -5
- data/.gem_rbs_collection/csv/3.3/.rbs_meta.yaml +0 -9
- data/.gem_rbs_collection/csv/3.3/csv.rbs +0 -3871
- data/.gem_rbs_collection/csv/3.3/manifest.yaml +0 -3
- data/.gem_rbs_collection/lint_roller/1.1/.rbs_meta.yaml +0 -9
- data/.gem_rbs_collection/lint_roller/1.1/lint_roller.rbs +0 -48
- data/.gem_rbs_collection/listen/3.9/.rbs_meta.yaml +0 -9
- data/.gem_rbs_collection/listen/3.9/listen.rbs +0 -25
- data/.gem_rbs_collection/listen/3.9/listener.rbs +0 -24
- data/.gem_rbs_collection/logger/1.7/.rbs_meta.yaml +0 -9
- data/.gem_rbs_collection/logger/1.7/formatter.rbs +0 -45
- data/.gem_rbs_collection/logger/1.7/log_device.rbs +0 -100
- data/.gem_rbs_collection/logger/1.7/logger.rbs +0 -796
- data/.gem_rbs_collection/logger/1.7/manifest.yaml +0 -2
- data/.gem_rbs_collection/logger/1.7/period.rbs +0 -17
- data/.gem_rbs_collection/logger/1.7/severity.rbs +0 -34
- data/.gem_rbs_collection/nokogiri/1.11/.rbs_meta.yaml +0 -9
- data/.gem_rbs_collection/nokogiri/1.11/nokogiri.rbs +0 -2332
- data/.gem_rbs_collection/nokogiri/1.11/patch.rbs +0 -4
- data/.gem_rbs_collection/parallel/1.20/.rbs_meta.yaml +0 -9
- data/.gem_rbs_collection/parallel/1.20/parallel.rbs +0 -86
- data/.gem_rbs_collection/parser/3.2/.rbs_meta.yaml +0 -9
- data/.gem_rbs_collection/parser/3.2/manifest.yaml +0 -7
- data/.gem_rbs_collection/parser/3.2/parser.rbs +0 -194
- data/.gem_rbs_collection/parser/3.2/polyfill.rbs +0 -4
- data/.gem_rbs_collection/rainbow/3.0/.rbs_meta.yaml +0 -9
- data/.gem_rbs_collection/rainbow/3.0/global.rbs +0 -7
- data/.gem_rbs_collection/rainbow/3.0/presenter.rbs +0 -209
- data/.gem_rbs_collection/rainbow/3.0/rainbow.rbs +0 -5
- data/.gem_rbs_collection/rake/13.0/.rbs_meta.yaml +0 -9
- data/.gem_rbs_collection/rake/13.0/manifest.yaml +0 -2
- data/.gem_rbs_collection/rake/13.0/rake.rbs +0 -39
- data/.gem_rbs_collection/regexp_parser/2.8/.rbs_meta.yaml +0 -9
- data/.gem_rbs_collection/regexp_parser/2.8/regexp_parser.rbs +0 -17
- data/.gem_rbs_collection/rubocop/1.57/.rbs_meta.yaml +0 -9
- data/.gem_rbs_collection/rubocop/1.57/rubocop.rbs +0 -208
- data/.gem_rbs_collection/rubocop-ast/1.46/.rbs_meta.yaml +0 -9
- data/.gem_rbs_collection/rubocop-ast/1.46/rubocop-ast.rbs +0 -903
- data/.gem_rbs_collection/rubyzip/3.2/.rbs_meta.yaml +0 -9
- data/.gem_rbs_collection/rubyzip/3.2/manifest.yaml +0 -8
- data/.gem_rbs_collection/rubyzip/3.2/zip/central_directory.rbs +0 -42
- data/.gem_rbs_collection/rubyzip/3.2/zip/compressor.rbs +0 -5
- data/.gem_rbs_collection/rubyzip/3.2/zip/constants.rbs +0 -47
- data/.gem_rbs_collection/rubyzip/3.2/zip/crypto/aes_encryption.rbs +0 -30
- data/.gem_rbs_collection/rubyzip/3.2/zip/crypto/decrypted_io.rbs +0 -9
- data/.gem_rbs_collection/rubyzip/3.2/zip/crypto/encryption.rbs +0 -7
- data/.gem_rbs_collection/rubyzip/3.2/zip/crypto/null_encryption.rbs +0 -19
- data/.gem_rbs_collection/rubyzip/3.2/zip/crypto/traditional_encryption.rbs +0 -31
- data/.gem_rbs_collection/rubyzip/3.2/zip/decompressor.rbs +0 -18
- data/.gem_rbs_collection/rubyzip/3.2/zip/deflater.rbs +0 -12
- data/.gem_rbs_collection/rubyzip/3.2/zip/dirtyable.rbs +0 -11
- data/.gem_rbs_collection/rubyzip/3.2/zip/dos_time.rbs +0 -13
- data/.gem_rbs_collection/rubyzip/3.2/zip/entry.rbs +0 -95
- data/.gem_rbs_collection/rubyzip/3.2/zip/entry_set.rbs +0 -31
- data/.gem_rbs_collection/rubyzip/3.2/zip/errors.rbs +0 -58
- data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/aes.rbs +0 -24
- data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/generic.rbs +0 -17
- data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/ntfs.rbs +0 -23
- data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/old_unix.rbs +0 -22
- data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/universal_time.rbs +0 -30
- data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/unix.rbs +0 -20
- data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/unknown.rbs +0 -15
- data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/zip64.rbs +0 -26
- data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field.rbs +0 -21
- data/.gem_rbs_collection/rubyzip/3.2/zip/file.rbs +0 -131
- data/.gem_rbs_collection/rubyzip/3.2/zip/file_split.rbs +0 -14
- data/.gem_rbs_collection/rubyzip/3.2/zip/filesystem/dir.rbs +0 -33
- data/.gem_rbs_collection/rubyzip/3.2/zip/filesystem/directory_iterator.rbs +0 -21
- data/.gem_rbs_collection/rubyzip/3.2/zip/filesystem/file.rbs +0 -63
- data/.gem_rbs_collection/rubyzip/3.2/zip/filesystem/file_stat.rbs +0 -55
- data/.gem_rbs_collection/rubyzip/3.2/zip/filesystem/zip_file_name_mapper.rbs +0 -35
- data/.gem_rbs_collection/rubyzip/3.2/zip/filesystem.rbs +0 -7
- data/.gem_rbs_collection/rubyzip/3.2/zip/inflater.rbs +0 -10
- data/.gem_rbs_collection/rubyzip/3.2/zip/input_stream.rbs +0 -22
- data/.gem_rbs_collection/rubyzip/3.2/zip/ioextras/abstract_input_stream.rbs +0 -29
- data/.gem_rbs_collection/rubyzip/3.2/zip/ioextras/abstract_output_stream.rbs +0 -17
- data/.gem_rbs_collection/rubyzip/3.2/zip/ioextras.rbs +0 -13
- data/.gem_rbs_collection/rubyzip/3.2/zip/null_compressor.rbs +0 -10
- data/.gem_rbs_collection/rubyzip/3.2/zip/null_decompressor.rbs +0 -8
- data/.gem_rbs_collection/rubyzip/3.2/zip/null_input_stream.rbs +0 -6
- data/.gem_rbs_collection/rubyzip/3.2/zip/output_stream.rbs +0 -30
- data/.gem_rbs_collection/rubyzip/3.2/zip/pass_thru_compressor.rbs +0 -10
- data/.gem_rbs_collection/rubyzip/3.2/zip/pass_thru_decompressor.rbs +0 -10
- data/.gem_rbs_collection/rubyzip/3.2/zip/streamable_directory.rbs +0 -5
- data/.gem_rbs_collection/rubyzip/3.2/zip/streamable_stream.rbs +0 -15
- data/.gem_rbs_collection/rubyzip/3.2/zip/version.rbs +0 -3
- data/.gem_rbs_collection/rubyzip/3.2/zip.rbs +0 -40
- data/.mutant.yml +0 -8
- data/Rakefile +0 -633
- data/Steepfile +0 -18
- data/benchmark.rb +0 -406
- data/docs/ARCHITECTURE.md +0 -514
- data/docs/DEVELOPMENT.md +0 -137
- data/docs/MUTATION_TESTING.md +0 -52
- data/docs/PEER_LIBRARIES.md +0 -121
- data/docs/QUALITY_ASSURANCE.md +0 -26
- data/docs/SPEC_SOURCES.md +0 -48
- data/docs/assets/benchmark_results.svg +0 -144
- data/docs/assets/lsp_autocompletion.png +0 -0
- data/docs/assets/playground_preview.png +0 -0
- data/docs/coi-serviceworker.js +0 -82
- data/docs/office_thread.js +0 -77
- data/docs/preview.html +0 -719
- data/docs/visual/VisualGallery.md +0 -4683
- data/docs/wasm/ruby.wasm +0 -0
- data/docs/wasm/wasm_doc_helper.css +0 -351
- data/docs/wasm/wasm_doc_helper.js +0 -439
- data/docs/zeta.js +0 -1107
- data/rbs_collection.lock.yaml +0 -252
- data/rbs_collection.yaml +0 -19
- data/vendor/sdk_runner/Program.cs +0 -93
- data/vendor/sdk_runner/sdk_runner.csproj +0 -13
data/lib/xlsxrb/elements/cell.rb
CHANGED
|
@@ -16,7 +16,7 @@ module Xlsxrb
|
|
|
16
16
|
#
|
|
17
17
|
# @api public
|
|
18
18
|
class Cell
|
|
19
|
-
attr_reader :row_index, :column_index, :value, :formula, :style_index, :unmapped_data, :errors
|
|
19
|
+
attr_reader :row_index, :column_index, :value, :formula, :style_index, :unmapped_data, :errors, :hyperlink, :comment, :raw_value, :format_code, :date1904
|
|
20
20
|
|
|
21
21
|
# @param row_index [Integer] 0-based row index.
|
|
22
22
|
# @param column_index [Integer] 0-based column index.
|
|
@@ -25,8 +25,13 @@ module Xlsxrb
|
|
|
25
25
|
# @param style_index [Integer, String, nil] Style identifier.
|
|
26
26
|
# @param unmapped_data [Hash] Additional metadata.
|
|
27
27
|
# @param errors [Array<String>, nil] Validation errors.
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
# @param hyperlink [Hash, String, Elements::Hyperlink, nil] Optional hyperlink metadata or URL.
|
|
29
|
+
# @param comment [Hash, String, nil] Optional cell comment or note.
|
|
30
|
+
# @param raw_value [String, nil] Optional unparsed raw string value.
|
|
31
|
+
# @param format_code [String, nil] Optional OpenXML number/date format code.
|
|
32
|
+
# @param date1904 [Boolean] Whether the cell belongs to a 1904 date system workbook.
|
|
33
|
+
#: (row_index: untyped, column_index: untyped, ?value: untyped, ?formula: (Elements::Formula | String)?, ?style_index: (Integer | String)?, ?unmapped_data: Hash[untyped, untyped], ?errors: Array[String]?, ?hyperlink: (Hash[Symbol, untyped] | String | Elements::Hyperlink)?, ?comment: (Hash[Symbol, untyped] | String)?, ?raw_value: String?, ?format_code: String?, ?date1904: bool) -> void
|
|
34
|
+
def initialize(row_index:, column_index:, value: nil, formula: nil, style_index: nil, unmapped_data: EMPTY_HASH, errors: nil, hyperlink: nil, comment: nil, raw_value: nil, format_code: nil, date1904: false)
|
|
30
35
|
@row_index = row_index
|
|
31
36
|
@column_index = column_index
|
|
32
37
|
@value = value
|
|
@@ -35,9 +40,15 @@ module Xlsxrb
|
|
|
35
40
|
@unmapped_data = unmapped_data || EMPTY_HASH
|
|
36
41
|
computed_errors = errors || self.class.validate(row_index, column_index, value)
|
|
37
42
|
@errors = computed_errors.frozen? ? computed_errors : computed_errors.freeze
|
|
43
|
+
@hyperlink = hyperlink
|
|
44
|
+
@comment = comment
|
|
45
|
+
@raw_value = raw_value
|
|
46
|
+
@format_code = format_code
|
|
47
|
+
@date1904 = date1904 ? true : false
|
|
38
48
|
end
|
|
39
49
|
|
|
40
|
-
|
|
50
|
+
# rubocop:disable Style/OptionalBooleanParameter
|
|
51
|
+
def self.fast_create(row_index, column_index, value, style_index = nil, formula = nil, raw_value = nil, format_code = nil, date1904 = false)
|
|
41
52
|
inst = allocate
|
|
42
53
|
inst.instance_variable_set(:@row_index, row_index)
|
|
43
54
|
inst.instance_variable_set(:@column_index, column_index)
|
|
@@ -46,8 +57,14 @@ module Xlsxrb
|
|
|
46
57
|
inst.instance_variable_set(:@style_index, style_index)
|
|
47
58
|
inst.instance_variable_set(:@unmapped_data, EMPTY_HASH)
|
|
48
59
|
inst.instance_variable_set(:@errors, EMPTY_ERRORS)
|
|
60
|
+
inst.instance_variable_set(:@hyperlink, nil)
|
|
61
|
+
inst.instance_variable_set(:@comment, nil)
|
|
62
|
+
inst.instance_variable_set(:@raw_value, raw_value)
|
|
63
|
+
inst.instance_variable_set(:@format_code, format_code)
|
|
64
|
+
inst.instance_variable_set(:@date1904, date1904 ? true : false)
|
|
49
65
|
inst
|
|
50
66
|
end
|
|
67
|
+
# rubocop:enable Style/OptionalBooleanParameter
|
|
51
68
|
|
|
52
69
|
def ==(other)
|
|
53
70
|
other.is_a?(Cell) &&
|
|
@@ -57,21 +74,26 @@ module Xlsxrb
|
|
|
57
74
|
formula == other.formula &&
|
|
58
75
|
style_index == other.style_index &&
|
|
59
76
|
unmapped_data == other.unmapped_data &&
|
|
60
|
-
errors == other.errors
|
|
77
|
+
errors == other.errors &&
|
|
78
|
+
hyperlink == other.hyperlink &&
|
|
79
|
+
comment == other.comment &&
|
|
80
|
+
raw_value == other.raw_value &&
|
|
81
|
+
format_code == other.format_code
|
|
61
82
|
end
|
|
62
83
|
alias eql? ==
|
|
63
84
|
|
|
64
85
|
def hash
|
|
65
|
-
[row_index, column_index, value, formula, style_index, unmapped_data, errors].hash
|
|
86
|
+
[row_index, column_index, value, formula, style_index, unmapped_data, errors, hyperlink, comment, raw_value, format_code].hash
|
|
66
87
|
end
|
|
67
88
|
|
|
68
89
|
def deconstruct
|
|
69
|
-
[row_index, column_index, value, formula, style_index, unmapped_data, errors]
|
|
90
|
+
[row_index, column_index, value, formula, style_index, unmapped_data, errors, hyperlink, comment, raw_value, format_code]
|
|
70
91
|
end
|
|
71
92
|
|
|
72
93
|
def deconstruct_keys(keys)
|
|
73
94
|
h = { row_index: row_index, column_index: column_index, value: value, formula: formula,
|
|
74
|
-
style_index: style_index, unmapped_data: unmapped_data, errors: errors
|
|
95
|
+
style_index: style_index, unmapped_data: unmapped_data, errors: errors, hyperlink: hyperlink,
|
|
96
|
+
comment: comment, raw_value: raw_value, format_code: format_code }
|
|
75
97
|
keys ? h.slice(*keys) : h
|
|
76
98
|
end
|
|
77
99
|
|
|
@@ -83,7 +105,12 @@ module Xlsxrb
|
|
|
83
105
|
formula: changes.fetch(:formula, formula),
|
|
84
106
|
style_index: changes.fetch(:style_index, style_index),
|
|
85
107
|
unmapped_data: changes.fetch(:unmapped_data, unmapped_data),
|
|
86
|
-
errors: changes.fetch(:errors, errors)
|
|
108
|
+
errors: changes.fetch(:errors, errors),
|
|
109
|
+
hyperlink: changes.fetch(:hyperlink, hyperlink),
|
|
110
|
+
comment: changes.fetch(:comment, comment),
|
|
111
|
+
raw_value: changes.fetch(:raw_value, raw_value),
|
|
112
|
+
format_code: changes.fetch(:format_code, format_code),
|
|
113
|
+
date1904: changes.fetch(:date1904, @date1904 || false)
|
|
87
114
|
)
|
|
88
115
|
end
|
|
89
116
|
|
|
@@ -104,9 +131,120 @@ module Xlsxrb
|
|
|
104
131
|
"#{self.class.column_letter(column_index)}#{row_index + 1}"
|
|
105
132
|
end
|
|
106
133
|
|
|
134
|
+
# Returns whether the cell contains a formula.
|
|
135
|
+
#
|
|
136
|
+
# @return [Boolean]
|
|
137
|
+
# @api public
|
|
138
|
+
#: () -> bool
|
|
139
|
+
def formula?
|
|
140
|
+
if formula.is_a?(Formula)
|
|
141
|
+
!formula.expression.nil? && !formula.expression.empty?
|
|
142
|
+
else
|
|
143
|
+
!formula.nil? && !formula.to_s.empty?
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Returns the formula expression string without leading '=', or nil.
|
|
148
|
+
#
|
|
149
|
+
# @return [String, nil]
|
|
150
|
+
# @api public
|
|
151
|
+
#: () -> String?
|
|
152
|
+
def formula_expression
|
|
153
|
+
expr = formula.is_a?(Formula) ? formula.expression : formula
|
|
154
|
+
return nil if expr.nil?
|
|
155
|
+
|
|
156
|
+
str = expr.to_s
|
|
157
|
+
str.empty? ? nil : str
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Returns whether the cell contains a hyperlink.
|
|
161
|
+
#
|
|
162
|
+
# @return [Boolean]
|
|
163
|
+
# @api public
|
|
164
|
+
#: () -> bool
|
|
165
|
+
def link?
|
|
166
|
+
case hyperlink
|
|
167
|
+
when nil then false
|
|
168
|
+
when Hash, String then !hyperlink.empty?
|
|
169
|
+
else true
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
alias hyperlink? link?
|
|
173
|
+
|
|
174
|
+
# Returns the hyperlink target URL or location string, or nil.
|
|
175
|
+
#
|
|
176
|
+
# @return [String, nil]
|
|
177
|
+
# @api public
|
|
178
|
+
#: () -> String?
|
|
179
|
+
def url
|
|
180
|
+
case hyperlink
|
|
181
|
+
when Hash
|
|
182
|
+
u = hyperlink[:url] || hyperlink[:location]
|
|
183
|
+
u&.to_s
|
|
184
|
+
when String
|
|
185
|
+
hyperlink.empty? ? nil : hyperlink
|
|
186
|
+
when Elements::Hyperlink
|
|
187
|
+
(hyperlink.url || hyperlink.location)&.to_s
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# Returns the hyperlink tooltip (ScreenTip) text, or nil.
|
|
192
|
+
#
|
|
193
|
+
# @return [String, nil]
|
|
194
|
+
# @api public
|
|
195
|
+
#: () -> String?
|
|
196
|
+
def tooltip
|
|
197
|
+
case hyperlink
|
|
198
|
+
when Hash
|
|
199
|
+
hyperlink[:tooltip]&.to_s
|
|
200
|
+
when Elements::Hyperlink
|
|
201
|
+
hyperlink.tooltip&.to_s
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# Returns whether the cell contains a comment or note.
|
|
206
|
+
#
|
|
207
|
+
# @return [Boolean]
|
|
208
|
+
# @api public
|
|
209
|
+
#: () -> bool
|
|
210
|
+
def comment?
|
|
211
|
+
case comment
|
|
212
|
+
when nil then false
|
|
213
|
+
when Hash, String then !comment.empty?
|
|
214
|
+
else true
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# Returns the plain text of the cell comment or note, or nil.
|
|
219
|
+
#
|
|
220
|
+
# @return [String, nil]
|
|
221
|
+
# @api public
|
|
222
|
+
#: () -> String?
|
|
223
|
+
def comment_text
|
|
224
|
+
case comment
|
|
225
|
+
when Hash
|
|
226
|
+
txt = comment[:text]
|
|
227
|
+
txt&.to_s
|
|
228
|
+
when String
|
|
229
|
+
comment.empty? ? nil : comment
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
# Returns the formatted string representation of the cell value according to its format code.
|
|
234
|
+
#
|
|
235
|
+
# @param custom_format_code [String, nil] Optional format code override.
|
|
236
|
+
# @return [String, nil]
|
|
237
|
+
# @api public
|
|
238
|
+
#: (?String? custom_format_code) -> String?
|
|
239
|
+
def formatted_value(custom_format_code = nil)
|
|
240
|
+
return nil if value.nil?
|
|
241
|
+
|
|
242
|
+
NumberFormatter.format(value, custom_format_code || format_code)
|
|
243
|
+
end
|
|
244
|
+
|
|
107
245
|
# Access cell attributes by Symbol key.
|
|
108
246
|
#
|
|
109
|
-
# @param key [Symbol] Attribute key (:value, :formula, :style_index, :ref, :column_index, :row_index, :type).
|
|
247
|
+
# @param key [Symbol] Attribute key (:value, :formula, :style_index, :ref, :column_index, :row_index, :type, :raw_value, :format_code, :formatted_value).
|
|
110
248
|
# @return [Object, nil]
|
|
111
249
|
# @api public
|
|
112
250
|
#: (Symbol key) -> untyped
|
|
@@ -119,6 +257,17 @@ module Xlsxrb
|
|
|
119
257
|
when :ref then ref
|
|
120
258
|
when :column_index then column_index
|
|
121
259
|
when :row_index then row_index
|
|
260
|
+
when :hyperlink then hyperlink
|
|
261
|
+
when :url then url
|
|
262
|
+
when :tooltip then tooltip
|
|
263
|
+
when :comment then comment
|
|
264
|
+
when :raw_value then raw_value
|
|
265
|
+
when :format_code then format_code
|
|
266
|
+
when :formatted_value then formatted_value
|
|
267
|
+
when :format_type then format_type
|
|
268
|
+
when :date_format then date_format?
|
|
269
|
+
when :time_format then time_format?
|
|
270
|
+
when :date1904 then date1904?
|
|
122
271
|
when :type
|
|
123
272
|
case value
|
|
124
273
|
when String then "s"
|
|
@@ -127,6 +276,42 @@ module Xlsxrb
|
|
|
127
276
|
end
|
|
128
277
|
end
|
|
129
278
|
|
|
279
|
+
# Returns the classified format category for this cell (:date, :datetime, :time, :number, :text, :general, or nil).
|
|
280
|
+
#
|
|
281
|
+
# @return [Symbol, nil]
|
|
282
|
+
# @api public
|
|
283
|
+
#: () -> Symbol?
|
|
284
|
+
def format_type
|
|
285
|
+
format_code ? NumberFormatter.format_type(format_code) : nil
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
# Returns whether the cell has a date, datetime, or time format.
|
|
289
|
+
#
|
|
290
|
+
# @return [Boolean]
|
|
291
|
+
# @api public
|
|
292
|
+
#: () -> bool
|
|
293
|
+
def date_format?
|
|
294
|
+
format_code ? NumberFormatter.date_format?(format_code) : false
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
# Returns whether the cell has a time-only format.
|
|
298
|
+
#
|
|
299
|
+
# @return [Boolean]
|
|
300
|
+
# @api public
|
|
301
|
+
#: () -> bool
|
|
302
|
+
def time_format?
|
|
303
|
+
format_code ? NumberFormatter.time_format?(format_code) : false
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
# Returns whether the cell's workbook uses the 1904 date system.
|
|
307
|
+
#
|
|
308
|
+
# @return [Boolean]
|
|
309
|
+
# @api public
|
|
310
|
+
#: () -> bool
|
|
311
|
+
def date1904?
|
|
312
|
+
@date1904 ? true : false
|
|
313
|
+
end
|
|
314
|
+
|
|
130
315
|
# Returns the cell value.
|
|
131
316
|
#
|
|
132
317
|
# @return [Object, nil]
|
|
@@ -165,14 +350,16 @@ module Xlsxrb
|
|
|
165
350
|
|
|
166
351
|
# Converts the cell value (numeric serial date or date string) to Date.
|
|
167
352
|
#
|
|
353
|
+
# @param date1904 [Boolean, nil] Whether to use the 1904 date system (defaults to cell's date1904 setting).
|
|
168
354
|
# @return [Date, nil]
|
|
169
355
|
# @api public
|
|
170
|
-
#: () -> Date?
|
|
171
|
-
def to_date
|
|
356
|
+
#: (?date1904: bool?) -> Date?
|
|
357
|
+
def to_date(date1904: nil)
|
|
172
358
|
return value if value.is_a?(Date)
|
|
173
359
|
|
|
360
|
+
d1904 = date1904.nil? ? date1904? : date1904
|
|
174
361
|
if value.is_a?(Numeric)
|
|
175
|
-
Ooxml::Utils.serial_to_date(value)
|
|
362
|
+
Ooxml::Utils.serial_to_date(value, date1904: d1904)
|
|
176
363
|
else
|
|
177
364
|
begin
|
|
178
365
|
Date.parse(value.to_s)
|
|
@@ -184,14 +371,16 @@ module Xlsxrb
|
|
|
184
371
|
|
|
185
372
|
# Converts the cell value (numeric serial datetime or datetime string) to Time.
|
|
186
373
|
#
|
|
374
|
+
# @param date1904 [Boolean, nil] Whether to use the 1904 date system (defaults to cell's date1904 setting).
|
|
187
375
|
# @return [Time, nil]
|
|
188
376
|
# @api public
|
|
189
|
-
#: () -> Time?
|
|
190
|
-
def to_time
|
|
377
|
+
#: (?date1904: bool?) -> Time?
|
|
378
|
+
def to_time(date1904: nil)
|
|
191
379
|
return value if value.is_a?(Time)
|
|
192
380
|
|
|
381
|
+
d1904 = date1904.nil? ? date1904? : date1904
|
|
193
382
|
if value.is_a?(Numeric)
|
|
194
|
-
Ooxml::Utils.serial_to_datetime(value)
|
|
383
|
+
Ooxml::Utils.serial_to_datetime(value, date1904: d1904)
|
|
195
384
|
else
|
|
196
385
|
begin
|
|
197
386
|
Time.parse(value.to_s)
|
|
@@ -12,21 +12,23 @@ module Xlsxrb
|
|
|
12
12
|
#
|
|
13
13
|
# @api public
|
|
14
14
|
# rubocop:disable Style/DataInheritance -- Required as class syntax for mutant subject matcher
|
|
15
|
-
class Column < Data.define(:index, :width, :hidden, :custom_width, :outline_level, :unmapped_data, :errors)
|
|
15
|
+
class Column < Data.define(:index, :width, :hidden, :custom_width, :outline_level, :style_index, :unmapped_data, :errors)
|
|
16
16
|
# rubocop:enable Style/DataInheritance
|
|
17
17
|
# @param index [Integer] 0-based column index.
|
|
18
18
|
# @param width [Float, Integer, nil] Column width in characters.
|
|
19
19
|
# @param hidden [Boolean] Whether the column is hidden.
|
|
20
20
|
# @param custom_width [Boolean] Whether custom width flag is set.
|
|
21
21
|
# @param outline_level [Integer, nil] Grouping/outline level.
|
|
22
|
+
# @param style_index [Integer, String, nil] Optional style identifier.
|
|
22
23
|
# @param unmapped_data [Hash] Additional metadata.
|
|
23
24
|
# @param errors [Array<String>, nil] Validation errors.
|
|
24
|
-
#: (index: Integer, ?width: Float | Integer | nil, ?hidden: bool, ?custom_width: bool, ?outline_level: Integer | nil, ?unmapped_data: Hash[untyped, untyped], ?errors: Array[String]?) -> void
|
|
25
|
+
#: (index: Integer, ?width: Float | Integer | nil, ?hidden: bool, ?custom_width: bool, ?outline_level: Integer | nil, ?style_index: (Integer | String)?, ?unmapped_data: Hash[untyped, untyped], ?errors: Array[String]?) -> void
|
|
25
26
|
def initialize(index:, width: nil, hidden: false, custom_width: false, outline_level: nil,
|
|
26
|
-
unmapped_data: {}, errors: nil)
|
|
27
|
+
style_index: nil, unmapped_data: {}, errors: nil)
|
|
28
|
+
style_idx = style_index || unmapped_data[:style_index] || unmapped_data[:style]
|
|
27
29
|
computed_errors = errors || self.class.validate(index)
|
|
28
30
|
super(index: index, width: width, hidden: hidden, custom_width: custom_width,
|
|
29
|
-
outline_level: outline_level, unmapped_data: unmapped_data,
|
|
31
|
+
outline_level: outline_level, style_index: style_idx, unmapped_data: unmapped_data,
|
|
30
32
|
errors: computed_errors.freeze)
|
|
31
33
|
end
|
|
32
34
|
|
|
@@ -76,6 +76,38 @@ module Xlsxrb
|
|
|
76
76
|
rows.max_by(&:index)
|
|
77
77
|
end
|
|
78
78
|
|
|
79
|
+
# Returns the 1-based index of the first column containing data, or nil.
|
|
80
|
+
#
|
|
81
|
+
# @return [Integer, nil]
|
|
82
|
+
# @api public
|
|
83
|
+
#: () -> Integer?
|
|
84
|
+
def first_column
|
|
85
|
+
min_c = nil
|
|
86
|
+
rows.each do |r|
|
|
87
|
+
r.cells.each do |c|
|
|
88
|
+
min_c = c.column_index if min_c.nil? || c.column_index < min_c
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
min_c ? min_c + 1 : nil
|
|
92
|
+
end
|
|
93
|
+
alias first_col first_column
|
|
94
|
+
|
|
95
|
+
# Returns the 1-based index of the last column containing data, or nil.
|
|
96
|
+
#
|
|
97
|
+
# @return [Integer, nil]
|
|
98
|
+
# @api public
|
|
99
|
+
#: () -> Integer?
|
|
100
|
+
def last_column
|
|
101
|
+
max_c = nil
|
|
102
|
+
rows.each do |r|
|
|
103
|
+
r.cells.each do |c|
|
|
104
|
+
max_c = c.column_index if max_c.nil? || c.column_index > max_c
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
max_c ? max_c + 1 : nil
|
|
108
|
+
end
|
|
109
|
+
alias last_col last_column
|
|
110
|
+
|
|
79
111
|
# Returns the raw cell value at the given Excel-style reference (e.g. "A1").
|
|
80
112
|
#
|
|
81
113
|
# @example
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# rbs_inline: enabled
|
|
4
|
+
|
|
5
|
+
module Xlsxrb
|
|
6
|
+
module Elements
|
|
7
|
+
# Represents an embedded image anchored to worksheet cells.
|
|
8
|
+
# Coordinates (from_row, from_col, to_row, to_col) are 0-based.
|
|
9
|
+
#
|
|
10
|
+
# @example Access image properties
|
|
11
|
+
# image = sheet.images.first
|
|
12
|
+
# image.filename #=> "image1.png"
|
|
13
|
+
# image.cell_ref #=> "B3"
|
|
14
|
+
# image.content_type #=> "image/png"
|
|
15
|
+
# image.data #=> "\x89PNG..."
|
|
16
|
+
#
|
|
17
|
+
# @api public
|
|
18
|
+
class Image < Data.define(:name, :filename, :content_type, :data, :from_col, :from_row, :to_col, :to_row, :cx, :cy, :unmapped_data)
|
|
19
|
+
MIME_TYPES = {
|
|
20
|
+
"png" => "image/png",
|
|
21
|
+
"jpg" => "image/jpeg",
|
|
22
|
+
"jpeg" => "image/jpeg",
|
|
23
|
+
"gif" => "image/gif",
|
|
24
|
+
"svg" => "image/svg+xml",
|
|
25
|
+
"tif" => "image/tiff",
|
|
26
|
+
"tiff" => "image/tiff",
|
|
27
|
+
"bmp" => "image/bmp",
|
|
28
|
+
"webp" => "image/webp",
|
|
29
|
+
"emf" => "image/x-emf",
|
|
30
|
+
"wmf" => "image/x-wmf"
|
|
31
|
+
}.freeze
|
|
32
|
+
|
|
33
|
+
# @param filename [String] Target filename (e.g. "image1.png").
|
|
34
|
+
# @param name [String, nil] Image or shape name.
|
|
35
|
+
# @param content_type [String, nil] MIME content type (e.g. "image/png").
|
|
36
|
+
# @param data [String, nil] Raw binary image data.
|
|
37
|
+
# @param from_col [Integer] 0-based starting column index.
|
|
38
|
+
# @param from_row [Integer] 0-based starting row index.
|
|
39
|
+
# @param to_col [Integer, nil] 0-based ending column index (nil for 1-cell anchor).
|
|
40
|
+
# @param to_row [Integer, nil] 0-based ending row index (nil for 1-cell anchor).
|
|
41
|
+
# @param cx [Integer, nil] Extent width in EMUs (English Metric Units).
|
|
42
|
+
# @param cy [Integer, nil] Extent height in EMUs (English Metric Units).
|
|
43
|
+
# @param unmapped_data [Hash] Additional metadata from drawing XML.
|
|
44
|
+
#: (filename: String, ?name: String?, ?content_type: String?, ?data: String?, ?from_col: Integer, ?from_row: Integer, ?to_col: Integer?, ?to_row: Integer?, ?cx: Integer?, ?cy: Integer?, ?unmapped_data: Hash[untyped, untyped]) -> void
|
|
45
|
+
# rubocop:disable Naming/MethodParameterName
|
|
46
|
+
def initialize(filename:, name: nil, content_type: nil, data: nil, from_col: 0, from_row: 0,
|
|
47
|
+
to_col: nil, to_row: nil, cx: nil, cy: nil, unmapped_data: EMPTY_HASH)
|
|
48
|
+
# rubocop:enable Naming/MethodParameterName
|
|
49
|
+
ext = File.extname(filename).delete_prefix(".").downcase
|
|
50
|
+
mime = content_type || MIME_TYPES[ext] || "application/octet-stream"
|
|
51
|
+
super(
|
|
52
|
+
name: name,
|
|
53
|
+
filename: filename,
|
|
54
|
+
content_type: mime,
|
|
55
|
+
data: data&.b,
|
|
56
|
+
from_col: from_col,
|
|
57
|
+
from_row: from_row,
|
|
58
|
+
to_col: to_col,
|
|
59
|
+
to_row: to_row,
|
|
60
|
+
cx: cx,
|
|
61
|
+
cy: cy,
|
|
62
|
+
unmapped_data: unmapped_data
|
|
63
|
+
)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Returns the top-left cell coordinate reference string (e.g. "A1").
|
|
67
|
+
#
|
|
68
|
+
# @return [String]
|
|
69
|
+
# @api public
|
|
70
|
+
#: () -> String
|
|
71
|
+
def cell_ref
|
|
72
|
+
"#{Cell.column_letter(from_col)}#{from_row + 1}"
|
|
73
|
+
end
|
|
74
|
+
alias cell cell_ref
|
|
75
|
+
alias ref cell_ref
|
|
76
|
+
|
|
77
|
+
# Returns the bottom-right cell coordinate reference string (e.g. "B5"), or nil for 1-cell anchors.
|
|
78
|
+
#
|
|
79
|
+
# @return [String, nil]
|
|
80
|
+
# @api public
|
|
81
|
+
#: () -> String?
|
|
82
|
+
def to_cell_ref
|
|
83
|
+
return nil if to_col.nil? || to_row.nil?
|
|
84
|
+
|
|
85
|
+
"#{Cell.column_letter(to_col)}#{to_row + 1}"
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Returns whether this image uses a one-cell anchor.
|
|
89
|
+
#
|
|
90
|
+
# @return [Boolean]
|
|
91
|
+
# @api public
|
|
92
|
+
#: () -> bool
|
|
93
|
+
def one_cell_anchor?
|
|
94
|
+
to_col.nil? || to_row.nil?
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Returns whether this image uses a two-cell anchor.
|
|
98
|
+
#
|
|
99
|
+
# @return [Boolean]
|
|
100
|
+
# @api public
|
|
101
|
+
#: () -> bool
|
|
102
|
+
def two_cell_anchor?
|
|
103
|
+
!one_cell_anchor?
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Returns the size of the binary image data in bytes.
|
|
107
|
+
#
|
|
108
|
+
# @return [Integer]
|
|
109
|
+
# @api public
|
|
110
|
+
#: () -> Integer
|
|
111
|
+
def bytesize
|
|
112
|
+
data ? data.bytesize : 0
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Writes the image data directly to a file on disk.
|
|
116
|
+
#
|
|
117
|
+
# @param path [String] Target file path.
|
|
118
|
+
# @return [Integer] Number of bytes written.
|
|
119
|
+
# @api public
|
|
120
|
+
#: (String path) -> Integer
|
|
121
|
+
def write_to(path)
|
|
122
|
+
raise Error, "No image binary data available to write" unless data
|
|
123
|
+
|
|
124
|
+
File.binwrite(path, data)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|