xlsxrb 0.1.7 → 0.1.8
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 +11 -0
- data/README.md +87 -35
- data/Rakefile +16 -5
- data/benchmark.rb +32 -4
- data/docs/ARCHITECTURE.md +32 -30
- data/docs/visual/VisualGallery.md +157 -157
- data/docs/wasm/ruby.wasm +0 -0
- data/lib/ruby_lsp/xlsxrb/addon.rb +1 -1
- data/lib/ruby_lsp/xlsxrb/completion_listener.rb +11 -13
- data/lib/xlsxrb/elements/coordinate_access.rb +101 -0
- data/lib/xlsxrb/elements/workbook.rb +19 -1
- data/lib/xlsxrb/elements/worksheet.rb +92 -122
- data/lib/xlsxrb/elements.rb +1 -0
- data/lib/xlsxrb/ooxml/worksheet_parser.rb +21 -15
- data/lib/xlsxrb/stream_row.rb +181 -0
- data/lib/xlsxrb/version.rb +1 -1
- data/lib/xlsxrb.rb +164 -106
- data/sig/generated/xlsxrb/elements/coordinate_access.rbs +70 -0
- data/sig/generated/xlsxrb/elements/worksheet.rbs +116 -14
- data/sig/generated/xlsxrb/ooxml/worksheet_parser.rbs +2 -0
- data/sig/generated/xlsxrb/stream_row.rbs +125 -0
- data/sig/generated/xlsxrb.rbs +110 -68
- metadata +5 -1
data/docs/wasm/ruby.wasm
CHANGED
|
Binary file
|
|
@@ -12,7 +12,7 @@ module RubyLsp
|
|
|
12
12
|
# This add-on serves as a bridge/polyfill for current Ruby LSP environments.
|
|
13
13
|
# While xlsxrb ships with complete RBS signatures (`sig/generated/`), Ruby LSP's
|
|
14
14
|
# type inferrer does not yet perform automatic static type inference from method
|
|
15
|
-
# block signatures to block parameters (e.g., `Xlsxrb.
|
|
15
|
+
# block signatures to block parameters (e.g., `Xlsxrb.write do |wb|`).
|
|
16
16
|
#
|
|
17
17
|
# This add-on enables immediate out-of-the-box autocompletion and rich Markdown
|
|
18
18
|
# documentation across all public block arguments.
|
|
@@ -693,9 +693,9 @@ module RubyLsp
|
|
|
693
693
|
|
|
694
694
|
if caller_receiver_is_xlsxrb?(caller_receiver)
|
|
695
695
|
case method_name
|
|
696
|
-
when :
|
|
696
|
+
when :write then return :stream_writer
|
|
697
|
+
when :read then return :stream_sheet
|
|
697
698
|
when :build then return :workbook_builder
|
|
698
|
-
when :foreach then return :stream_sheet
|
|
699
699
|
when :modify then return :workbook
|
|
700
700
|
end
|
|
701
701
|
end
|
|
@@ -718,25 +718,23 @@ module RubyLsp
|
|
|
718
718
|
def infer_each_block_target(caller_receiver)
|
|
719
719
|
if receiver_matches?(caller_receiver, %i[workbook wb])
|
|
720
720
|
:worksheet
|
|
721
|
-
elsif receiver_matches?(caller_receiver, %i[row r])
|
|
721
|
+
elsif receiver_matches?(caller_receiver, %i[row r stream_row])
|
|
722
722
|
:cell
|
|
723
723
|
else
|
|
724
724
|
:row
|
|
725
725
|
end
|
|
726
726
|
end
|
|
727
727
|
|
|
728
|
-
def infer_from_variable_name(
|
|
729
|
-
case
|
|
730
|
-
when :wb, :
|
|
731
|
-
:
|
|
732
|
-
when :
|
|
733
|
-
:workbook
|
|
734
|
-
when :s, :ws, :sheet
|
|
728
|
+
def infer_from_variable_name(name)
|
|
729
|
+
case name
|
|
730
|
+
when :wb, :workbook
|
|
731
|
+
:workbook_builder
|
|
732
|
+
when :s, :sheet, :ws, :worksheet
|
|
735
733
|
:worksheet_proxy
|
|
736
|
-
when :
|
|
737
|
-
:worksheet
|
|
738
|
-
when :stream_sheet
|
|
734
|
+
when :stream_sheet, :ss
|
|
739
735
|
:stream_sheet
|
|
736
|
+
when :stream_writer, :sw
|
|
737
|
+
:stream_writer
|
|
740
738
|
when :r, :row
|
|
741
739
|
:row
|
|
742
740
|
when :c, :cell
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# rbs_inline: enabled
|
|
4
|
+
|
|
5
|
+
module Xlsxrb
|
|
6
|
+
module Elements
|
|
7
|
+
# Mixin providing coordinate-based and random-access cell/row lookups
|
|
8
|
+
# for in-memory worksheet structures.
|
|
9
|
+
#
|
|
10
|
+
# Expects the including class to provide a `#rows` method returning an `Array<Elements::Row>`.
|
|
11
|
+
#
|
|
12
|
+
# @api public
|
|
13
|
+
module CoordinateAccess
|
|
14
|
+
# Returns a Hash mapping Excel cell references (e.g. "A1") to Cell objects.
|
|
15
|
+
#
|
|
16
|
+
# @return [Hash<String, Elements::Cell>]
|
|
17
|
+
#: () -> Hash[String, Elements::Cell]
|
|
18
|
+
def cells_hash
|
|
19
|
+
h = {}
|
|
20
|
+
rows.each do |r|
|
|
21
|
+
r.cells.each do |c|
|
|
22
|
+
ref = "#{Cell.column_letter(c.column_index)}#{c.row_index + 1}"
|
|
23
|
+
h[ref] = c
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
h
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Returns all cells ordered by row and column index.
|
|
30
|
+
#
|
|
31
|
+
# @return [Array<Elements::Cell>]
|
|
32
|
+
# @api public
|
|
33
|
+
#: () -> Array[Elements::Cell]
|
|
34
|
+
def cells
|
|
35
|
+
cells_hash.values.sort_by { |c| [c.row_index, c.column_index] }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Access a cell by its Excel-style reference (e.g. "A1").
|
|
39
|
+
#
|
|
40
|
+
# @example
|
|
41
|
+
# sheet["A1"] #=> #<Elements::Cell value="Hello">
|
|
42
|
+
#
|
|
43
|
+
# @param ref [String, Symbol] Cell reference (e.g. "A1" or :A1).
|
|
44
|
+
# @return [Elements::Cell, nil]
|
|
45
|
+
# @api public
|
|
46
|
+
#: (String | Symbol ref) -> Elements::Cell?
|
|
47
|
+
def [](ref)
|
|
48
|
+
cells_hash[ref.to_s.upcase]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Returns the row at the given 0-based index, or nil.
|
|
52
|
+
#
|
|
53
|
+
# @param index [Integer] 0-based row index.
|
|
54
|
+
# @return [Elements::Row, nil]
|
|
55
|
+
# @api public
|
|
56
|
+
#: (Integer index) -> Elements::Row?
|
|
57
|
+
def row_at(index)
|
|
58
|
+
rows.find { |r| r.index == index }
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Returns the first row in the sheet, or nil.
|
|
62
|
+
#
|
|
63
|
+
# @return [Elements::Row, nil]
|
|
64
|
+
# @api public
|
|
65
|
+
#: () -> Elements::Row?
|
|
66
|
+
def first_row
|
|
67
|
+
rows.min_by(&:index)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Returns the last row in the sheet, or nil.
|
|
71
|
+
#
|
|
72
|
+
# @return [Elements::Row, nil]
|
|
73
|
+
# @api public
|
|
74
|
+
#: () -> Elements::Row?
|
|
75
|
+
def last_row
|
|
76
|
+
rows.max_by(&:index)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Returns the raw cell value at the given Excel-style reference (e.g. "A1").
|
|
80
|
+
#
|
|
81
|
+
# @example
|
|
82
|
+
# sheet.cell_value("A1") #=> "Sales Report"
|
|
83
|
+
#
|
|
84
|
+
# @param ref [String] Cell reference (e.g. "A1").
|
|
85
|
+
# @return [Object, nil]
|
|
86
|
+
# @api public
|
|
87
|
+
#: (String ref) -> untyped
|
|
88
|
+
def cell_value(ref)
|
|
89
|
+
parsed = Cell.parse_ref(ref)
|
|
90
|
+
return nil unless parsed
|
|
91
|
+
|
|
92
|
+
row_idx, col_idx = parsed
|
|
93
|
+
row = row_at(row_idx)
|
|
94
|
+
return nil unless row
|
|
95
|
+
|
|
96
|
+
cell = row.cell_at(col_idx)
|
|
97
|
+
cell&.value
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
@@ -42,6 +42,7 @@ module Xlsxrb
|
|
|
42
42
|
def each(&)
|
|
43
43
|
sheets.each(&)
|
|
44
44
|
end
|
|
45
|
+
alias_method :each_sheet, :each
|
|
45
46
|
|
|
46
47
|
# Returns whether the workbook is valid according to ECMA-376 rules.
|
|
47
48
|
#
|
|
@@ -71,6 +72,22 @@ module Xlsxrb
|
|
|
71
72
|
end
|
|
72
73
|
alias_method :[], :sheet
|
|
73
74
|
|
|
75
|
+
# Loads all sheets into memory, returning an Elements::Workbook where every
|
|
76
|
+
# worksheet is a fully-parsed Elements::Worksheet supporting coordinate random access.
|
|
77
|
+
#
|
|
78
|
+
# @example
|
|
79
|
+
# wb = Xlsxrb.read("file.xlsx").load
|
|
80
|
+
# puts wb["Sheet1"]["A1"].value
|
|
81
|
+
#
|
|
82
|
+
# @return [Elements::Workbook]
|
|
83
|
+
# @api public
|
|
84
|
+
#: () -> Elements::Workbook
|
|
85
|
+
def load
|
|
86
|
+
loaded_sheets = sheets.map { |s| s.respond_to?(:load) ? s.load : s }
|
|
87
|
+
with(sheets: loaded_sheets)
|
|
88
|
+
end
|
|
89
|
+
alias_method :to_workbook, :load
|
|
90
|
+
|
|
74
91
|
# Returns a new Workbook with the specified sheet updated.
|
|
75
92
|
# Yields the matched worksheet to the block, which must return a new Worksheet.
|
|
76
93
|
#
|
|
@@ -92,10 +109,11 @@ module Xlsxrb
|
|
|
92
109
|
sheet_to_update = sheet(identifier)
|
|
93
110
|
raise ArgumentError, "sheet not found: #{identifier}" unless sheet_to_update
|
|
94
111
|
|
|
112
|
+
sheet_to_update = sheet_to_update.load if sheet_to_update.respond_to?(:load)
|
|
95
113
|
new_sheet = yield sheet_to_update
|
|
96
114
|
raise TypeError, "block must return a Worksheet" unless new_sheet.is_a?(Worksheet)
|
|
97
115
|
|
|
98
|
-
new_sheets = sheets.map { |s| s == sheet_to_update ? new_sheet : s }
|
|
116
|
+
new_sheets = sheets.map { |s| s.name == sheet_to_update.name ? new_sheet : s }
|
|
99
117
|
with(sheets: new_sheets)
|
|
100
118
|
end
|
|
101
119
|
|
|
@@ -4,16 +4,20 @@
|
|
|
4
4
|
|
|
5
5
|
module Xlsxrb
|
|
6
6
|
module Elements
|
|
7
|
-
# Represents a single worksheet in a workbook.
|
|
7
|
+
# Represents a single fully parsed, in-memory worksheet in a workbook.
|
|
8
|
+
# Provides coordinate random access (sheet["A1"]), row lookups (row_at),
|
|
9
|
+
# and immutable cell updates (update_cell).
|
|
8
10
|
#
|
|
9
11
|
# @example Access cells and rows
|
|
10
|
-
# sheet = workbook.sheet(0)
|
|
12
|
+
# sheet = workbook.sheet(0).load
|
|
11
13
|
# cell = sheet["A1"]
|
|
12
|
-
#
|
|
14
|
+
# row = sheet.row_at(0)
|
|
13
15
|
#
|
|
14
16
|
# @api public
|
|
15
|
-
Worksheet
|
|
16
|
-
include
|
|
17
|
+
class Worksheet
|
|
18
|
+
[Enumerable, CoordinateAccess].each { |m| include m }
|
|
19
|
+
|
|
20
|
+
attr_reader :name, :rows, :columns, :charts, :unmapped_data, :errors
|
|
17
21
|
|
|
18
22
|
# @param name [String] The worksheet name (max 31 characters).
|
|
19
23
|
# @param rows [Array<Elements::Row>] Rows in the sheet.
|
|
@@ -23,85 +27,32 @@ module Xlsxrb
|
|
|
23
27
|
# @param errors [Array<String>, nil] Validation errors.
|
|
24
28
|
#: (name: String, ?rows: Array[Elements::Row], ?columns: Array[Elements::Column], ?charts: Array[Hash[Symbol, untyped]], ?unmapped_data: Hash[untyped, untyped], ?errors: Array[String]?) -> void
|
|
25
29
|
def initialize(name:, rows: [], columns: [], charts: [], unmapped_data: {}, errors: nil)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
# @return [Hash<String, Elements::Cell>]
|
|
34
|
-
#: () -> Hash[String, Elements::Cell]
|
|
35
|
-
def cells_hash
|
|
36
|
-
h = {}
|
|
37
|
-
rows.each do |r|
|
|
38
|
-
r.cells.each do |c|
|
|
39
|
-
ref = "#{Cell.column_letter(c.column_index)}#{c.row_index + 1}"
|
|
40
|
-
h[ref] = c
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
h
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
# Returns all cells ordered by row and column index.
|
|
47
|
-
#
|
|
48
|
-
# @return [Array<Elements::Cell>]
|
|
49
|
-
# @api public
|
|
50
|
-
#: () -> Array[Elements::Cell]
|
|
51
|
-
def cells
|
|
52
|
-
# Ensure ordered traversal
|
|
53
|
-
cells_hash.values.sort_by { |c| [c.row_index, c.column_index] }
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
# Access a cell by its Excel-style reference (e.g. "A1").
|
|
57
|
-
#
|
|
58
|
-
# @example
|
|
59
|
-
# sheet["A1"] #=> #<Elements::Cell value="Hello">
|
|
60
|
-
#
|
|
61
|
-
# @param ref [String, Symbol] Cell reference (e.g. "A1" or :A1).
|
|
62
|
-
# @return [Elements::Cell, nil]
|
|
63
|
-
# @api public
|
|
64
|
-
#: (String | Symbol ref) -> Elements::Cell?
|
|
65
|
-
def [](ref)
|
|
66
|
-
cells_hash[ref.to_s.upcase]
|
|
30
|
+
@name = name
|
|
31
|
+
@rows = (rows || []).freeze
|
|
32
|
+
@columns = (columns || []).freeze
|
|
33
|
+
@charts = (charts || []).freeze
|
|
34
|
+
@unmapped_data = (unmapped_data || {}).freeze
|
|
35
|
+
computed_errors = errors || self.class.validate(@name, @rows)
|
|
36
|
+
@errors = computed_errors.freeze
|
|
67
37
|
end
|
|
68
38
|
|
|
69
|
-
# Iterate over
|
|
39
|
+
# Iterate over rows in the worksheet.
|
|
70
40
|
#
|
|
71
41
|
# @example
|
|
72
|
-
# sheet.each do |
|
|
73
|
-
# puts
|
|
42
|
+
# sheet.each do |row|
|
|
43
|
+
# puts row.to_a.inspect
|
|
74
44
|
# end
|
|
75
45
|
#
|
|
76
|
-
# @yield [
|
|
77
|
-
# @yieldparam
|
|
46
|
+
# @yield [row]
|
|
47
|
+
# @yieldparam row [Elements::Row]
|
|
78
48
|
# @return [Enumerator, void]
|
|
79
49
|
# @api public
|
|
80
|
-
#: () { (Elements::
|
|
81
|
-
#: | () -> Enumerator[Elements::
|
|
50
|
+
#: () { (Elements::Row) -> void } -> void
|
|
51
|
+
#: | () -> Enumerator[Elements::Row, void]
|
|
82
52
|
def each(&)
|
|
83
53
|
return to_enum(:each) unless block_given?
|
|
84
54
|
|
|
85
|
-
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
# Iterate over cells in the worksheet.
|
|
89
|
-
#
|
|
90
|
-
# @example
|
|
91
|
-
# sheet.each_cell do |cell|
|
|
92
|
-
# puts "#{cell.ref}: #{cell.value}"
|
|
93
|
-
# end
|
|
94
|
-
#
|
|
95
|
-
# @yield [cell]
|
|
96
|
-
# @yieldparam cell [Elements::Cell]
|
|
97
|
-
# @return [Enumerator, void]
|
|
98
|
-
# @api public
|
|
99
|
-
#: () { (Elements::Cell) -> void } -> void
|
|
100
|
-
#: | () -> Enumerator[Elements::Cell, void]
|
|
101
|
-
def each_cell(&)
|
|
102
|
-
return to_enum(:each_cell) unless block_given?
|
|
103
|
-
|
|
104
|
-
cells.each(&)
|
|
55
|
+
rows.each(&)
|
|
105
56
|
end
|
|
106
57
|
|
|
107
58
|
# Iterate over rows in the worksheet.
|
|
@@ -123,61 +74,26 @@ module Xlsxrb
|
|
|
123
74
|
rows.each(&)
|
|
124
75
|
end
|
|
125
76
|
|
|
126
|
-
#
|
|
77
|
+
# Iterate over all cells across rows.
|
|
127
78
|
#
|
|
128
|
-
# @
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
errors.empty?
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
# Returns the row at the given 0-based index, or nil.
|
|
135
|
-
#
|
|
136
|
-
# @param index [Integer] 0-based row index.
|
|
137
|
-
# @return [Elements::Row, nil]
|
|
138
|
-
# @api public
|
|
139
|
-
#: (Integer index) -> Elements::Row?
|
|
140
|
-
def row_at(index)
|
|
141
|
-
rows.find { |r| r.index == index }
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
# Returns the first row in the sheet, or nil.
|
|
145
|
-
#
|
|
146
|
-
# @return [Elements::Row, nil]
|
|
79
|
+
# @yield [cell]
|
|
80
|
+
# @yieldparam cell [Elements::Cell]
|
|
81
|
+
# @return [Enumerator, void]
|
|
147
82
|
# @api public
|
|
148
|
-
#: ()
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
83
|
+
#: () { (Elements::Cell) -> void } -> void
|
|
84
|
+
#: | () -> Enumerator[Elements::Cell, void]
|
|
85
|
+
def each_cell(&)
|
|
86
|
+
return to_enum(:each_cell) unless block_given?
|
|
152
87
|
|
|
153
|
-
|
|
154
|
-
#
|
|
155
|
-
# @return [Elements::Row, nil]
|
|
156
|
-
# @api public
|
|
157
|
-
#: () -> Elements::Row?
|
|
158
|
-
def last_row
|
|
159
|
-
rows.max_by(&:index)
|
|
88
|
+
cells.each(&)
|
|
160
89
|
end
|
|
161
90
|
|
|
162
|
-
# Returns the
|
|
163
|
-
#
|
|
164
|
-
# @example
|
|
165
|
-
# sheet.cell_value("A1") #=> "Sales Report"
|
|
91
|
+
# Returns whether the worksheet is valid according to OOXML specifications.
|
|
166
92
|
#
|
|
167
|
-
# @
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
def cell_value(ref)
|
|
172
|
-
parsed = Cell.parse_ref(ref)
|
|
173
|
-
return nil unless parsed
|
|
174
|
-
|
|
175
|
-
row_idx, col_idx = parsed
|
|
176
|
-
row = row_at(row_idx)
|
|
177
|
-
return nil unless row
|
|
178
|
-
|
|
179
|
-
cell = row.cell_at(col_idx)
|
|
180
|
-
cell&.value
|
|
93
|
+
# @return [Boolean]
|
|
94
|
+
#: () -> bool
|
|
95
|
+
def valid?
|
|
96
|
+
errors.empty?
|
|
181
97
|
end
|
|
182
98
|
|
|
183
99
|
# Returns a new Worksheet with the specified cell updated.
|
|
@@ -227,6 +143,60 @@ module Xlsxrb
|
|
|
227
143
|
with(rows: new_rows)
|
|
228
144
|
end
|
|
229
145
|
|
|
146
|
+
# Returns a new Worksheet with attributes replaced (Data-like behavior).
|
|
147
|
+
#
|
|
148
|
+
# @param changes [Hash]
|
|
149
|
+
# @return [Worksheet]
|
|
150
|
+
# @api public
|
|
151
|
+
#: (**untyped) -> Elements::Worksheet
|
|
152
|
+
def with(**changes)
|
|
153
|
+
new_name = changes.key?(:name) ? changes[:name] : name
|
|
154
|
+
new_rows = changes.key?(:rows) ? changes[:rows] : rows
|
|
155
|
+
new_cols = changes.key?(:columns) ? changes[:columns] : columns
|
|
156
|
+
new_charts = changes.key?(:charts) ? changes[:charts] : charts
|
|
157
|
+
new_unmapped = changes.key?(:unmapped_data) ? changes[:unmapped_data] : unmapped_data
|
|
158
|
+
new_errors = changes.key?(:errors) ? changes[:errors] : errors
|
|
159
|
+
|
|
160
|
+
self.class.new(
|
|
161
|
+
name: new_name,
|
|
162
|
+
rows: new_rows,
|
|
163
|
+
columns: new_cols,
|
|
164
|
+
charts: new_charts,
|
|
165
|
+
unmapped_data: new_unmapped,
|
|
166
|
+
errors: new_errors
|
|
167
|
+
)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Support pattern matching.
|
|
171
|
+
#: (Array[Symbol]?) -> Hash[Symbol, untyped]
|
|
172
|
+
def deconstruct_keys(_keys)
|
|
173
|
+
{ name: name, rows: rows, columns: columns, charts: charts, unmapped_data: unmapped_data, errors: errors }
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# Compare worksheets for equality.
|
|
177
|
+
#: (untyped other) -> bool
|
|
178
|
+
def ==(other)
|
|
179
|
+
return false unless other.is_a?(Worksheet)
|
|
180
|
+
|
|
181
|
+
name == other.name && rows == other.rows && columns == other.columns && charts == other.charts
|
|
182
|
+
end
|
|
183
|
+
alias eql? ==
|
|
184
|
+
|
|
185
|
+
#: () -> Integer
|
|
186
|
+
def hash
|
|
187
|
+
[self.class, name, rows, columns, charts].hash
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# Returns self when load is called on an already in-memory Worksheet.
|
|
191
|
+
#
|
|
192
|
+
# @return [Elements::Worksheet]
|
|
193
|
+
# @api public
|
|
194
|
+
#: () -> Elements::Worksheet
|
|
195
|
+
def load
|
|
196
|
+
self
|
|
197
|
+
end
|
|
198
|
+
alias to_worksheet load
|
|
199
|
+
|
|
230
200
|
# Validates worksheet name and rows against OOXML limits.
|
|
231
201
|
#
|
|
232
202
|
# @param name [String]
|
data/lib/xlsxrb/elements.rb
CHANGED
|
@@ -6,6 +6,7 @@ require_relative "elements/types"
|
|
|
6
6
|
require_relative "elements/cell"
|
|
7
7
|
require_relative "elements/row"
|
|
8
8
|
require_relative "elements/column"
|
|
9
|
+
require_relative "elements/coordinate_access"
|
|
9
10
|
require_relative "elements/worksheet"
|
|
10
11
|
require_relative "elements/workbook"
|
|
11
12
|
|
|
@@ -515,17 +515,17 @@ module Xlsxrb
|
|
|
515
515
|
row_end = xml.index("</row>", tag_end + 1)
|
|
516
516
|
break unless row_end
|
|
517
517
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
row_obj = Elements::Row.new(
|
|
518
|
+
{ part: part_name, row: row_index }
|
|
519
|
+
row_obj = StreamRow.new(
|
|
522
520
|
index: row_index,
|
|
523
|
-
|
|
521
|
+
xml_bytes: xml,
|
|
522
|
+
from: tag_end + 1,
|
|
523
|
+
to: row_end,
|
|
524
|
+
shared_strings: shared_strings,
|
|
524
525
|
height: attrs[:height],
|
|
525
526
|
hidden: attrs[:hidden] || false,
|
|
526
527
|
custom_height: attrs[:custom_height] || false,
|
|
527
|
-
outline_level: attrs[:outline_level]
|
|
528
|
-
errors: Elements::EMPTY_ERRORS
|
|
528
|
+
outline_level: attrs[:outline_level]
|
|
529
529
|
)
|
|
530
530
|
block.call(row_obj)
|
|
531
531
|
|
|
@@ -537,7 +537,13 @@ module Xlsxrb
|
|
|
537
537
|
|
|
538
538
|
def self.fast_parse_cells_direct(xml, from, to, shared_strings, row_source)
|
|
539
539
|
cells = []
|
|
540
|
+
fast_scan_cells_direct(xml, from, to, shared_strings, row_source) { |c| cells << c }
|
|
541
|
+
cells
|
|
542
|
+
end
|
|
543
|
+
|
|
544
|
+
def self.fast_scan_cells_direct(xml, from, to, shared_strings, row_source, &block)
|
|
540
545
|
pos = from
|
|
546
|
+
cell_count = 0
|
|
541
547
|
|
|
542
548
|
while pos < to
|
|
543
549
|
c_start = xml.index("<c", pos)
|
|
@@ -589,7 +595,6 @@ module Xlsxrb
|
|
|
589
595
|
|
|
590
596
|
row_idx = (row_idx * 10) + (cb - 48)
|
|
591
597
|
ai += 1
|
|
592
|
-
|
|
593
598
|
end
|
|
594
599
|
row_idx -= 1
|
|
595
600
|
ai += 1 if xml.getbyte(ai) == 34
|
|
@@ -619,7 +624,6 @@ module Xlsxrb
|
|
|
619
624
|
|
|
620
625
|
style_index = (style_index * 10) + (cb - 48)
|
|
621
626
|
ai += 1
|
|
622
|
-
|
|
623
627
|
end
|
|
624
628
|
ai += 1 if xml.getbyte(ai) == 34
|
|
625
629
|
else
|
|
@@ -629,13 +633,15 @@ module Xlsxrb
|
|
|
629
633
|
|
|
630
634
|
# Self-closing <c ... />
|
|
631
635
|
if xml.getbyte(c_tag_end - 1) == 47
|
|
632
|
-
|
|
636
|
+
cell_obj = Elements::Cell.new(
|
|
633
637
|
row_index: row_idx || row_source[:row],
|
|
634
|
-
column_index: col_idx ||
|
|
638
|
+
column_index: col_idx || cell_count,
|
|
635
639
|
value: nil,
|
|
636
640
|
style_index: style_index,
|
|
637
641
|
errors: Elements::EMPTY_ERRORS
|
|
638
642
|
)
|
|
643
|
+
cell_count += 1
|
|
644
|
+
block.call(cell_obj)
|
|
639
645
|
pos = c_tag_end + 1
|
|
640
646
|
next
|
|
641
647
|
end
|
|
@@ -721,19 +727,19 @@ module Xlsxrb
|
|
|
721
727
|
end
|
|
722
728
|
|
|
723
729
|
val_to_use = inline_str || value
|
|
724
|
-
|
|
730
|
+
cell_obj = Elements::Cell.new(
|
|
725
731
|
row_index: row_idx || row_source[:row],
|
|
726
|
-
column_index: col_idx ||
|
|
732
|
+
column_index: col_idx || cell_count,
|
|
727
733
|
value: val_to_use,
|
|
728
734
|
formula: formula,
|
|
729
735
|
style_index: style_index,
|
|
730
736
|
errors: Elements::EMPTY_ERRORS
|
|
731
737
|
)
|
|
738
|
+
cell_count += 1
|
|
739
|
+
block.call(cell_obj)
|
|
732
740
|
|
|
733
741
|
pos = c_end + 4
|
|
734
742
|
end
|
|
735
|
-
|
|
736
|
-
cells
|
|
737
743
|
end
|
|
738
744
|
|
|
739
745
|
private_class_method :fast_parse_cells_direct
|