xlsxrb 0.1.12 → 0.1.13

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.
Files changed (153) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +59 -42
  3. data/README.md +26 -22
  4. data/lib/xlsxrb/dsl_helpers.rb +59 -0
  5. data/lib/xlsxrb/elements/workbook.rb +11 -0
  6. data/lib/xlsxrb/ooxml/shared_strings_parser.rb +3 -5
  7. data/lib/xlsxrb/ooxml/workbook_writer.rb +5 -7
  8. data/lib/xlsxrb/ooxml/worksheet_parser.rb +172 -9
  9. data/lib/xlsxrb/ooxml/writer.rb +2 -1
  10. data/lib/xlsxrb/ooxml/xml_builder.rb +20 -0
  11. data/lib/xlsxrb/ooxml/zip_reader.rb +364 -78
  12. data/lib/xlsxrb/ooxml/zip_writer.rb +32 -5
  13. data/lib/xlsxrb/stream_sheet.rb +94 -6
  14. data/lib/xlsxrb/stream_writer.rb +33 -66
  15. data/lib/xlsxrb/version.rb +1 -1
  16. data/lib/xlsxrb/workbook_builder.rb +1 -1
  17. data/lib/xlsxrb/worksheet_builder.rb +3 -31
  18. data/lib/xlsxrb.rb +448 -171
  19. data/sig/generated/xlsxrb/dsl_helpers.rbs +32 -0
  20. data/sig/generated/xlsxrb/elements/workbook.rbs +7 -0
  21. data/sig/generated/xlsxrb/ooxml/shared_strings_parser.rbs +0 -2
  22. data/sig/generated/xlsxrb/ooxml/worksheet_parser.rbs +5 -4
  23. data/sig/generated/xlsxrb/ooxml/xml_builder.rbs +11 -0
  24. data/sig/generated/xlsxrb/ooxml/zip_reader.rbs +96 -8
  25. data/sig/generated/xlsxrb/ooxml/zip_writer.rbs +5 -1
  26. data/sig/generated/xlsxrb/stream_sheet.rbs +43 -3
  27. data/sig/generated/xlsxrb.rbs +18 -11
  28. metadata +6 -146
  29. data/.devcontainer/Dockerfile +0 -65
  30. data/.devcontainer/devcontainer.json +0 -17
  31. data/.gem_rbs_collection/ast/2.4/.rbs_meta.yaml +0 -9
  32. data/.gem_rbs_collection/ast/2.4/ast.rbs +0 -73
  33. data/.gem_rbs_collection/concurrent-ruby/1.1/.rbs_meta.yaml +0 -9
  34. data/.gem_rbs_collection/concurrent-ruby/1.1/array.rbs +0 -4
  35. data/.gem_rbs_collection/concurrent-ruby/1.1/atomic_reference.rbs +0 -16
  36. data/.gem_rbs_collection/concurrent-ruby/1.1/executor.rbs +0 -96
  37. data/.gem_rbs_collection/concurrent-ruby/1.1/hash.rbs +0 -4
  38. data/.gem_rbs_collection/concurrent-ruby/1.1/map.rbs +0 -68
  39. data/.gem_rbs_collection/concurrent-ruby/1.1/promises.rbs +0 -249
  40. data/.gem_rbs_collection/concurrent-ruby/1.1/set.rbs +0 -4
  41. data/.gem_rbs_collection/concurrent-ruby/1.1/timer_task.rbs +0 -47
  42. data/.gem_rbs_collection/concurrent-ruby/1.1/utility/processor_counter.rbs +0 -5
  43. data/.gem_rbs_collection/csv/3.3/.rbs_meta.yaml +0 -9
  44. data/.gem_rbs_collection/csv/3.3/csv.rbs +0 -3871
  45. data/.gem_rbs_collection/csv/3.3/manifest.yaml +0 -3
  46. data/.gem_rbs_collection/lint_roller/1.1/.rbs_meta.yaml +0 -9
  47. data/.gem_rbs_collection/lint_roller/1.1/lint_roller.rbs +0 -48
  48. data/.gem_rbs_collection/listen/3.9/.rbs_meta.yaml +0 -9
  49. data/.gem_rbs_collection/listen/3.9/listen.rbs +0 -25
  50. data/.gem_rbs_collection/listen/3.9/listener.rbs +0 -24
  51. data/.gem_rbs_collection/logger/1.7/.rbs_meta.yaml +0 -9
  52. data/.gem_rbs_collection/logger/1.7/formatter.rbs +0 -45
  53. data/.gem_rbs_collection/logger/1.7/log_device.rbs +0 -100
  54. data/.gem_rbs_collection/logger/1.7/logger.rbs +0 -796
  55. data/.gem_rbs_collection/logger/1.7/manifest.yaml +0 -2
  56. data/.gem_rbs_collection/logger/1.7/period.rbs +0 -17
  57. data/.gem_rbs_collection/logger/1.7/severity.rbs +0 -34
  58. data/.gem_rbs_collection/nokogiri/1.11/.rbs_meta.yaml +0 -9
  59. data/.gem_rbs_collection/nokogiri/1.11/nokogiri.rbs +0 -2332
  60. data/.gem_rbs_collection/nokogiri/1.11/patch.rbs +0 -4
  61. data/.gem_rbs_collection/parallel/1.20/.rbs_meta.yaml +0 -9
  62. data/.gem_rbs_collection/parallel/1.20/parallel.rbs +0 -86
  63. data/.gem_rbs_collection/parser/3.2/.rbs_meta.yaml +0 -9
  64. data/.gem_rbs_collection/parser/3.2/manifest.yaml +0 -7
  65. data/.gem_rbs_collection/parser/3.2/parser.rbs +0 -194
  66. data/.gem_rbs_collection/parser/3.2/polyfill.rbs +0 -4
  67. data/.gem_rbs_collection/rainbow/3.0/.rbs_meta.yaml +0 -9
  68. data/.gem_rbs_collection/rainbow/3.0/global.rbs +0 -7
  69. data/.gem_rbs_collection/rainbow/3.0/presenter.rbs +0 -209
  70. data/.gem_rbs_collection/rainbow/3.0/rainbow.rbs +0 -5
  71. data/.gem_rbs_collection/rake/13.0/.rbs_meta.yaml +0 -9
  72. data/.gem_rbs_collection/rake/13.0/manifest.yaml +0 -2
  73. data/.gem_rbs_collection/rake/13.0/rake.rbs +0 -39
  74. data/.gem_rbs_collection/regexp_parser/2.8/.rbs_meta.yaml +0 -9
  75. data/.gem_rbs_collection/regexp_parser/2.8/regexp_parser.rbs +0 -17
  76. data/.gem_rbs_collection/rubocop/1.57/.rbs_meta.yaml +0 -9
  77. data/.gem_rbs_collection/rubocop/1.57/rubocop.rbs +0 -208
  78. data/.gem_rbs_collection/rubocop-ast/1.46/.rbs_meta.yaml +0 -9
  79. data/.gem_rbs_collection/rubocop-ast/1.46/rubocop-ast.rbs +0 -903
  80. data/.gem_rbs_collection/rubyzip/3.2/.rbs_meta.yaml +0 -9
  81. data/.gem_rbs_collection/rubyzip/3.2/manifest.yaml +0 -8
  82. data/.gem_rbs_collection/rubyzip/3.2/zip/central_directory.rbs +0 -42
  83. data/.gem_rbs_collection/rubyzip/3.2/zip/compressor.rbs +0 -5
  84. data/.gem_rbs_collection/rubyzip/3.2/zip/constants.rbs +0 -47
  85. data/.gem_rbs_collection/rubyzip/3.2/zip/crypto/aes_encryption.rbs +0 -30
  86. data/.gem_rbs_collection/rubyzip/3.2/zip/crypto/decrypted_io.rbs +0 -9
  87. data/.gem_rbs_collection/rubyzip/3.2/zip/crypto/encryption.rbs +0 -7
  88. data/.gem_rbs_collection/rubyzip/3.2/zip/crypto/null_encryption.rbs +0 -19
  89. data/.gem_rbs_collection/rubyzip/3.2/zip/crypto/traditional_encryption.rbs +0 -31
  90. data/.gem_rbs_collection/rubyzip/3.2/zip/decompressor.rbs +0 -18
  91. data/.gem_rbs_collection/rubyzip/3.2/zip/deflater.rbs +0 -12
  92. data/.gem_rbs_collection/rubyzip/3.2/zip/dirtyable.rbs +0 -11
  93. data/.gem_rbs_collection/rubyzip/3.2/zip/dos_time.rbs +0 -13
  94. data/.gem_rbs_collection/rubyzip/3.2/zip/entry.rbs +0 -95
  95. data/.gem_rbs_collection/rubyzip/3.2/zip/entry_set.rbs +0 -31
  96. data/.gem_rbs_collection/rubyzip/3.2/zip/errors.rbs +0 -58
  97. data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/aes.rbs +0 -24
  98. data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/generic.rbs +0 -17
  99. data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/ntfs.rbs +0 -23
  100. data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/old_unix.rbs +0 -22
  101. data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/universal_time.rbs +0 -30
  102. data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/unix.rbs +0 -20
  103. data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/unknown.rbs +0 -15
  104. data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/zip64.rbs +0 -26
  105. data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field.rbs +0 -21
  106. data/.gem_rbs_collection/rubyzip/3.2/zip/file.rbs +0 -131
  107. data/.gem_rbs_collection/rubyzip/3.2/zip/file_split.rbs +0 -14
  108. data/.gem_rbs_collection/rubyzip/3.2/zip/filesystem/dir.rbs +0 -33
  109. data/.gem_rbs_collection/rubyzip/3.2/zip/filesystem/directory_iterator.rbs +0 -21
  110. data/.gem_rbs_collection/rubyzip/3.2/zip/filesystem/file.rbs +0 -63
  111. data/.gem_rbs_collection/rubyzip/3.2/zip/filesystem/file_stat.rbs +0 -55
  112. data/.gem_rbs_collection/rubyzip/3.2/zip/filesystem/zip_file_name_mapper.rbs +0 -35
  113. data/.gem_rbs_collection/rubyzip/3.2/zip/filesystem.rbs +0 -7
  114. data/.gem_rbs_collection/rubyzip/3.2/zip/inflater.rbs +0 -10
  115. data/.gem_rbs_collection/rubyzip/3.2/zip/input_stream.rbs +0 -22
  116. data/.gem_rbs_collection/rubyzip/3.2/zip/ioextras/abstract_input_stream.rbs +0 -29
  117. data/.gem_rbs_collection/rubyzip/3.2/zip/ioextras/abstract_output_stream.rbs +0 -17
  118. data/.gem_rbs_collection/rubyzip/3.2/zip/ioextras.rbs +0 -13
  119. data/.gem_rbs_collection/rubyzip/3.2/zip/null_compressor.rbs +0 -10
  120. data/.gem_rbs_collection/rubyzip/3.2/zip/null_decompressor.rbs +0 -8
  121. data/.gem_rbs_collection/rubyzip/3.2/zip/null_input_stream.rbs +0 -6
  122. data/.gem_rbs_collection/rubyzip/3.2/zip/output_stream.rbs +0 -30
  123. data/.gem_rbs_collection/rubyzip/3.2/zip/pass_thru_compressor.rbs +0 -10
  124. data/.gem_rbs_collection/rubyzip/3.2/zip/pass_thru_decompressor.rbs +0 -10
  125. data/.gem_rbs_collection/rubyzip/3.2/zip/streamable_directory.rbs +0 -5
  126. data/.gem_rbs_collection/rubyzip/3.2/zip/streamable_stream.rbs +0 -15
  127. data/.gem_rbs_collection/rubyzip/3.2/zip/version.rbs +0 -3
  128. data/.gem_rbs_collection/rubyzip/3.2/zip.rbs +0 -40
  129. data/.mutant.yml +0 -8
  130. data/Rakefile +0 -633
  131. data/Steepfile +0 -18
  132. data/benchmark.rb +0 -406
  133. data/docs/ARCHITECTURE.md +0 -514
  134. data/docs/DEVELOPMENT.md +0 -137
  135. data/docs/MUTATION_TESTING.md +0 -52
  136. data/docs/PEER_LIBRARIES.md +0 -121
  137. data/docs/QUALITY_ASSURANCE.md +0 -26
  138. data/docs/SPEC_SOURCES.md +0 -48
  139. data/docs/assets/benchmark_results.svg +0 -144
  140. data/docs/assets/lsp_autocompletion.png +0 -0
  141. data/docs/assets/playground_preview.png +0 -0
  142. data/docs/coi-serviceworker.js +0 -82
  143. data/docs/office_thread.js +0 -77
  144. data/docs/preview.html +0 -719
  145. data/docs/visual/VisualGallery.md +0 -4683
  146. data/docs/wasm/ruby.wasm +0 -0
  147. data/docs/wasm/wasm_doc_helper.css +0 -351
  148. data/docs/wasm/wasm_doc_helper.js +0 -439
  149. data/docs/zeta.js +0 -1107
  150. data/rbs_collection.lock.yaml +0 -252
  151. data/rbs_collection.yaml +0 -19
  152. data/vendor/sdk_runner/Program.cs +0 -93
  153. data/vendor/sdk_runner/sdk_runner.csproj +0 -13
@@ -56,5 +56,37 @@ module Xlsxrb
56
56
  # @return [Hash]
57
57
  # : (String ref, columns: untyped, ?name: String?, ?display_name: String?, ?style: String?, **untyped opts) -> Hash[Symbol, untyped]
58
58
  def self.normalize_table_options: (String ref, columns: untyped, ?name: String?, ?display_name: String?, ?style: String?, **untyped opts) -> Hash[Symbol, untyped]
59
+
60
+ # Converts a cell range (e.g. "A1:B2" or "A1") to an absolute reference format (e.g. "$A$1:$B$2" or "$A$1").
61
+ #
62
+ # @param range [String]
63
+ # @return [String]
64
+ # : (String range) -> String
65
+ def self.absolute_range: (String range) -> String
66
+
67
+ # Normalizes row values: if given a column-keyed Hash, converts to a sparse Array.
68
+ # If already an Array or other non-Hash enumerable, returns as-is without allocations.
69
+ #
70
+ # @param values [Array<Object>, Hash{String, Integer, Symbol => Object}, nil]
71
+ # @return [Array<Object>, nil]
72
+ # : (untyped values) -> untyped
73
+ def self.normalize_row_values: (untyped values) -> untyped
74
+
75
+ # Normalizes row styles: if given a Hash of column-keyed styles (including Ranges/Arrays),
76
+ # expands to a sparse Array of styles. If already an Array or nil, returns as-is without allocations.
77
+ #
78
+ # @param styles [untyped]
79
+ # @return [untyped]
80
+ # : (untyped styles) -> untyped
81
+ def self.normalize_row_styles: (untyped styles) -> untyped
82
+
83
+ # Validates row index and height against Excel limits in strict mode.
84
+ #
85
+ # @param row_index [Integer]
86
+ # @param height [Float, Integer, nil]
87
+ # @param strict_excel_mode [Boolean]
88
+ # @return [void]
89
+ # : (Integer row_index, Float | Integer | nil height, ?strict_excel_mode: bool) -> void
90
+ def self.validate_row_bounds!: (Integer row_index, Float | Integer | nil height, ?strict_excel_mode: bool) -> void
59
91
  end
60
92
  end
@@ -71,6 +71,13 @@ module Xlsxrb
71
71
 
72
72
  alias to_workbook load
73
73
 
74
+ # Closes any streaming resources associated with worksheets.
75
+ #
76
+ # @return [void]
77
+ # @api public
78
+ # : () -> void
79
+ def close: () -> void
80
+
74
81
  # Returns a new Workbook with the specified sheet updated.
75
82
  # Yields the matched worksheet to the block, which must return a new Worksheet.
76
83
  #
@@ -5,8 +5,6 @@ module Xlsxrb
5
5
  # SAX-based parser for xl/sharedStrings.xml.
6
6
  # Returns an Array of strings (index = SST index).
7
7
  class SharedStringsParser
8
- XML_ENTITIES: untyped
9
-
10
8
  # Parses all shared strings and returns an Array of strings.
11
9
  def self.parse: (untyped xml_string, ?_part_name: untyped) -> untyped
12
10
 
@@ -16,7 +16,7 @@ module Xlsxrb
16
16
  def self.parse: (untyped xml_string, ?shared_strings: untyped) -> untyped
17
17
 
18
18
  # Streaming parse: yields one raw row hash at a time.
19
- def self.each_row: (untyped xml_string, ?shared_strings: untyped, ?part_name: untyped) ?{ (?) -> untyped } -> untyped
19
+ def self.each_row: (untyped xml_source, ?shared_strings: untyped, ?part_name: untyped) ?{ (?) -> untyped } -> untyped
20
20
 
21
21
  # Parses column definitions (<cols>) from a worksheet.
22
22
  def self.parse_columns: (untyped xml_string, ?part_name: untyped) -> untyped
@@ -37,12 +37,11 @@ module Xlsxrb
37
37
 
38
38
  def self.resolve_fast_value: (untyped raw, untyped type, untyped shared_strings) -> untyped
39
39
 
40
- XML_ENTITIES: untyped
41
-
42
40
  # SECURITY NOTE: Decodes only standard predefined XML entities in a single pass.
43
41
  # This completely prevents "Billion Laughs" attacks (exponential entity expansion)
44
42
  # because it avoids recursive expansion and ignores custom entities entirely.
45
- def self.decode_xml_entities: (untyped str) -> untyped
43
+ # : (String str) -> String
44
+ def self.decode_xml_entities: (String str) -> String
46
45
 
47
46
  # Parses <cols> section for column definitions.
48
47
  class ColumnsListener
@@ -61,6 +60,8 @@ module Xlsxrb
61
60
 
62
61
  def self.fast_scan_rows_direct: (untyped xml_src, untyped shared_strings, untyped _part_name) ?{ (?) -> untyped } -> untyped
63
62
 
63
+ def self.scan_rows_stream: (untyped source, untyped shared_strings, untyped _part_name) ?{ (?) -> untyped } -> untyped
64
+
64
65
  COL_LETTERS: untyped
65
66
 
66
67
  COL_MAP: untyped
@@ -35,6 +35,10 @@ module Xlsxrb
35
35
 
36
36
  def to_s: () -> untyped
37
37
 
38
+ UNESCAPE_MAP: untyped
39
+
40
+ UNESCAPE_RE: ::Regexp
41
+
38
42
  # Escapes XML special characters in a string.
39
43
  #
40
44
  # @param value [Object]
@@ -42,6 +46,13 @@ module Xlsxrb
42
46
  # : (untyped value) -> String
43
47
  def self.escape: (untyped value) -> String
44
48
 
49
+ # Unescapes predefined XML entities in a string in a single pass.
50
+ #
51
+ # @param value [Object]
52
+ # @return [String]
53
+ # : (untyped value) -> String
54
+ def self.unescape: (untyped value) -> String
55
+
45
56
  private
46
57
 
47
58
  def write_attrs: (untyped attrs) -> untyped
@@ -3,7 +3,7 @@
3
3
  module Xlsxrb
4
4
  module Ooxml
5
5
  # Reads ZIP archives using only stdlib (zlib).
6
- # Scans local file headers sequentially — works with non-seekable IO.
6
+ # Supports streaming entry decompression with bounded memory consumption.
7
7
  class ZipReader
8
8
  LOCAL_HEADER_SIG: untyped
9
9
 
@@ -11,29 +11,117 @@ module Xlsxrb
11
11
 
12
12
  attr_accessor max_uncompressed_size: untyped
13
13
 
14
+ # Metadata record for a single archive entry.
15
+ class Entry
16
+ attr_reader name: untyped
17
+
18
+ attr_reader method: untyped
19
+
20
+ attr_reader compressed_size: untyped
21
+
22
+ attr_reader uncompressed_size: untyped
23
+
24
+ attr_reader crc32: untyped
25
+
26
+ attr_reader local_header_offset: untyped
27
+
28
+ attr_reader data_offset: untyped
29
+
30
+ # : (name: String, method: Integer, compressed_size: Integer, uncompressed_size: Integer, crc32: Integer, local_header_offset: Integer, data_offset: Integer) -> void
31
+ def initialize: (name: String, method: Integer, compressed_size: Integer, uncompressed_size: Integer, crc32: Integer, local_header_offset: Integer, data_offset: Integer) -> void
32
+ end
33
+
34
+ # IO-like stream wrapper that decompresses entry chunks on demand without full buffering.
35
+ class EntryStreamIO
36
+ DEFAULT_CHUNK_SIZE: ::Integer
37
+
38
+ attr_reader data_offset: untyped
39
+
40
+ attr_reader compressed_size: untyped
41
+
42
+ attr_reader compression_method: untyped
43
+
44
+ # : (untyped io, Integer data_offset, Integer compressed_size, Integer compression_method, ?max_uncompressed_size: Integer?) -> void
45
+ def initialize: (untyped io, Integer data_offset, Integer compressed_size, Integer compression_method, ?max_uncompressed_size: Integer?) -> void
46
+
47
+ # : (?Integer? length) -> String?
48
+ def read: (?Integer? length) -> String?
49
+
50
+ # : (?Integer chunk_size) ?{ (String) -> void } -> (void | Enumerator[String, void])
51
+ def each_chunk: (?untyped chunk_size) ?{ (?) -> untyped } -> untyped
52
+
53
+ # : () -> void
54
+ def close: () -> void
55
+
56
+ # : () -> bool
57
+ def closed?: () -> bool
58
+
59
+ # : () -> bool
60
+ def eof?: () -> bool
61
+
62
+ private
63
+
64
+ def fetch_chunk: (untyped chunk_size) -> untyped
65
+ end
66
+
14
67
  # Opens a ZIP from a file path or IO and yields the reader.
15
68
  # : (untyped source, ?max_uncompressed_size: Integer) ?{ (ZipReader) -> untyped } -> (ZipReader | untyped)
16
69
  def self.open: (untyped source, ?max_uncompressed_size: Integer) ?{ (ZipReader) -> untyped } -> (ZipReader | untyped)
17
70
 
18
- # : (untyped io, ?max_uncompressed_size: Integer) -> void
19
- def initialize: (untyped io, ?max_uncompressed_size: Integer) -> void
71
+ # : (untyped io, ?max_uncompressed_size: Integer, ?should_close_io: bool) -> void
72
+ def initialize: (untyped io, ?max_uncompressed_size: Integer, ?should_close_io: bool) -> void
20
73
 
21
74
  # Returns a Hash { entry_name => raw_bytes } for all entries.
22
- def read_all: () -> untyped
75
+ # : () -> Hash[String, String?]
76
+ def read_all: () -> Hash[String, String?]
23
77
 
24
78
  # Returns raw bytes for a single entry, or nil if not found.
25
- def read_entry: (untyped name) -> untyped
79
+ # : (String name) -> String?
80
+ def read_entry: (String name) -> String?
26
81
 
27
82
  # Yields (entry_name, data_string) for each file in the archive.
83
+ # : () ?{ (String, String?) -> void } -> (void | Enumerator[[String, String?], void])
28
84
  def each_entry: () ?{ (?) -> untyped } -> untyped
29
85
 
86
+ # Opens an EntryStreamIO for an entry by name.
87
+ # : (String entry_name) -> EntryStreamIO
88
+ def open_entry_io: (String entry_name) -> EntryStreamIO
89
+
90
+ # Yields inflated binary chunks directly from the compressed stream.
91
+ # : (String entry_name, ?chunk_size: Integer) ?{ (String) -> void } -> (void | Enumerator[String, void])
92
+ def each_entry_chunk: (untyped entry_name, ?chunk_size: untyped) ?{ (?) -> untyped } -> untyped
93
+
94
+ # Returns true if the archive contains the specified entry.
95
+ # : (String name) -> bool
96
+ def entry?: (String name) -> bool
97
+
98
+ # Returns entry metadata catalog.
99
+ # : () -> Hash[String, Entry]
100
+ def entry_catalog: () -> Hash[String, Entry]
101
+
102
+ # Returns array of all entry names.
103
+ # : () -> Array[String]
104
+ def entry_names: () -> Array[String]
105
+
106
+ # Copies the specified entry to a ZipWriter directly without decompression.
107
+ # : (String entry_name, ZipWriter writer, ?target_path: String?) -> void
108
+ def copy_to_writer: (String entry_name, ZipWriter writer, ?target_path: String?) -> void
109
+
110
+ # Closes the archive reader and cleans up any temporary resources.
111
+ # : () -> void
112
+ def close: () -> void
113
+
30
114
  private
31
115
 
32
- def entries: () -> untyped
116
+ def io: () -> untyped
117
+
118
+ def catalog: () -> untyped
119
+
120
+ def parse_catalog: () -> untyped
33
121
 
34
- def parse_entries: () -> untyped
122
+ def parse_catalog_from_central_directory: (untyped io) -> untyped
35
123
 
36
- def parse_from_central_directory: (untyped io) -> untyped
124
+ def parse_catalog_from_local_headers: (untyped io) -> untyped
37
125
 
38
126
  def find_data_descriptor_stream: (untyped io, untyped method) -> untyped
39
127
 
@@ -23,6 +23,10 @@ module Xlsxrb
23
23
 
24
24
  def finish_entry: () -> untyped
25
25
 
26
+ # Copies an entry from an existing archive IO without decompressing or recompressing.
27
+ # : (String path, untyped source_io, data_offset: Integer, compressed_size: Integer, uncompressed_size: Integer, crc32: Integer, ?method: Integer) -> void
28
+ def copy_raw_entry: (String path, untyped source_io, data_offset: Integer, compressed_size: Integer, uncompressed_size: Integer, crc32: Integer, ?method: Integer) -> void
29
+
26
30
  def close: () -> untyped
27
31
 
28
32
  private
@@ -35,7 +39,7 @@ module Xlsxrb
35
39
 
36
40
  def deflate: (untyped content) -> untyped
37
41
 
38
- def write_local_header: (untyped path, untyped crc, untyped compressed_size, untyped uncompressed_size, ?gp_flag: untyped, ?count_bytes: untyped) -> untyped
42
+ def write_local_header: (untyped path, untyped crc, untyped compressed_size, untyped uncompressed_size, ?gp_flag: untyped, ?count_bytes: untyped, ?method: untyped) -> untyped
39
43
 
40
44
  def write_central_directory: () -> untyped
41
45
 
@@ -32,11 +32,13 @@ module Xlsxrb
32
32
  # Initializes a streaming worksheet context.
33
33
  #
34
34
  # @param name [String] The sheet name.
35
- # @param sheet_xml [String] Raw XML content of the worksheet.
35
+ # @param sheet_source [String, Proc, IO, nil] Raw XML content or chunk supplier/stream.
36
36
  # @param shared_strings [Array<String>] Shared strings table.
37
37
  # @param styles [Hash, nil] Optional parsed styles hash.
38
- # : (String name, String sheet_xml, Array[String] shared_strings, ?Hash[untyped, untyped]? styles) -> void
39
- def initialize: (String name, String sheet_xml, Array[String] shared_strings, ?Hash[untyped, untyped]? styles) -> void
38
+ # @param zip_reader [Ooxml::ZipReader, nil] Optional ZipReader context.
39
+ # @param entry_name [String, nil] Archive entry name for this sheet.
40
+ # : (String name, untyped sheet_source, Array[String] shared_strings, ?Hash[untyped, untyped]? styles, ?zip_reader: Ooxml::ZipReader?, ?entry_name: String?) -> void
41
+ def initialize: (String name, untyped sheet_source, Array[String] shared_strings, ?Hash[untyped, untyped]? styles, ?zip_reader: Ooxml::ZipReader?, ?entry_name: String?) -> void
40
42
 
41
43
  # Iterates over rows in this streaming worksheet with O(1) memory.
42
44
  #
@@ -96,5 +98,43 @@ module Xlsxrb
96
98
  def load: () -> Elements::Worksheet
97
99
 
98
100
  alias to_worksheet load
101
+
102
+ # Returns merged cell ranges (e.g. ["A1:B2"]) for this worksheet.
103
+ #
104
+ # @return [Array<String>]
105
+ # @api public
106
+ # : () -> Array[String]
107
+ def merged_cells: () -> Array[String]
108
+
109
+ # Returns the auto-filter range (e.g. "A1:E100") for this worksheet, or nil if none.
110
+ #
111
+ # @return [String, nil]
112
+ # @api public
113
+ # : () -> String?
114
+ def auto_filter: () -> String?
115
+
116
+ # Returns data validation rules configured for this worksheet.
117
+ #
118
+ # @return [Array<Hash[Symbol, untyped]>]
119
+ # @api public
120
+ # : () -> Array[Hash[Symbol, untyped]]
121
+ def data_validations: () -> Array[Hash[Symbol, untyped]]
122
+
123
+ # Returns conditional formatting rules configured for this worksheet.
124
+ #
125
+ # @return [Array<Hash[Symbol, untyped]>]
126
+ # @api public
127
+ # : () -> Array[Hash[Symbol, untyped]]
128
+ def conditional_formats: () -> Array[Hash[Symbol, untyped]]
129
+
130
+ # Closes any underlying reader resources.
131
+ # : () -> void
132
+ def close: () -> void
133
+
134
+ private
135
+
136
+ # Returns the full raw XML string for this worksheet, loaded on demand.
137
+ # : () -> String
138
+ def raw_sheet_xml: () -> String
99
139
  end
100
140
  end
@@ -49,17 +49,6 @@ module Xlsxrb
49
49
  class DecryptionError < EncryptedFileError
50
50
  end
51
51
 
52
- TRACER: untyped
53
-
54
- # Executes the block within an OpenTelemetry tracer span if tracing is configured.
55
- #
56
- # @param name [String] The span name.
57
- # @param attributes [Hash, nil] Optional telemetry attributes.
58
- # @yield Block to execute inside the tracing span.
59
- # @return [Object] The result of the block.
60
- # : (String name, ?attributes: Hash[String, untyped]?) { (*untyped) -> untyped } -> untyped
61
- def self.in_span: (String name, ?attributes: Hash[String, untyped]?) { (*untyped) -> untyped } -> untyped
62
-
63
52
  # Helper to construct {Elements::RichText} objects with formatted text runs.
64
53
  #
65
54
  # @example Create multi-run rich text
@@ -236,6 +225,24 @@ module Xlsxrb
236
225
  # : (Elements::Row row) -> Hash[Symbol, untyped]
237
226
  private def self.build_row_attrs: (Elements::Row row) -> Hash[Symbol, untyped]
238
227
 
228
+ # : (untyped source, String? password) -> untyped
229
+ private def self.prepare_source_io: (untyped source, String? password) -> untyped
230
+
231
+ # : (untyped dest, Ooxml::ZipReader zip_reader, Hash[String, String] replaced_entries, ?password: String?) -> void
232
+ private def self.perform_modify_write: (untyped dest, Ooxml::ZipReader zip_reader, Hash[String, String] replaced_entries, ?password: String?) -> void
233
+
234
+ # : (String sst_xml, Array[untyped] new_strings) -> String
235
+ private def self.append_to_shared_strings_xml: (String sst_xml, Array[untyped] new_strings) -> String
236
+
237
+ # : (String sheet_xml, String new_sheet_data_xml) -> String
238
+ private def self.replace_sheet_data: (String sheet_xml, String new_sheet_data_xml) -> String
239
+
240
+ # : (String sheet_xml, Array[Elements::Row] rows) -> String
241
+ private def self.update_dimension: (String sheet_xml, Array[Elements::Row] rows) -> String
242
+
243
+ # : (Array[Elements::Row] rows, Array[untyped] shared_strings, Hash[untyped, Integer] sst_index, ?use_sst: bool) -> String
244
+ private def self.serialize_sheet_data_xml: (Array[Elements::Row] rows, Array[untyped] shared_strings, Hash[untyped, Integer] sst_index, ?use_sst: bool) -> String
245
+
239
246
  # Builds a raw cell hash from a value for streaming writes.
240
247
  #
241
248
  # @param row_index [Integer] 0-based row index.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xlsxrb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.12
4
+ version: 0.1.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - niku
@@ -24,166 +24,31 @@ dependencies:
24
24
  - !ruby/object:Gem::Version
25
25
  version: '4.1'
26
26
  - !ruby/object:Gem::Dependency
27
- name: opentelemetry-api
27
+ name: rexml
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
30
  - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: '1.4'
32
+ version: '3.0'
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '1.4'
40
- - !ruby/object:Gem::Dependency
41
- name: rexml
42
- requirement: !ruby/object:Gem::Requirement
43
- requirements:
44
- - - ">="
45
- - !ruby/object:Gem::Version
46
- version: '0'
47
- type: :runtime
48
- prerelease: false
49
- version_requirements: !ruby/object:Gem::Requirement
50
- requirements:
51
- - - ">="
52
- - !ruby/object:Gem::Version
53
- version: '0'
54
- description: A minimal dependency XLSX reading and writing library for Ruby, relying
55
- on standard libraries for core logic and opentelemetry-api for observability.
39
+ version: '3.0'
40
+ description: A streaming-capable, low-memory XLSX reading and writing library for
41
+ Ruby, relying solely on standard libraries and bundled gems.
56
42
  email:
57
43
  - 10890+niku@users.noreply.github.com
58
44
  executables: []
59
45
  extensions: []
60
46
  extra_rdoc_files: []
61
47
  files:
62
- - ".devcontainer/Dockerfile"
63
- - ".devcontainer/devcontainer.json"
64
- - ".gem_rbs_collection/ast/2.4/.rbs_meta.yaml"
65
- - ".gem_rbs_collection/ast/2.4/ast.rbs"
66
- - ".gem_rbs_collection/concurrent-ruby/1.1/.rbs_meta.yaml"
67
- - ".gem_rbs_collection/concurrent-ruby/1.1/array.rbs"
68
- - ".gem_rbs_collection/concurrent-ruby/1.1/atomic_reference.rbs"
69
- - ".gem_rbs_collection/concurrent-ruby/1.1/executor.rbs"
70
- - ".gem_rbs_collection/concurrent-ruby/1.1/hash.rbs"
71
- - ".gem_rbs_collection/concurrent-ruby/1.1/map.rbs"
72
- - ".gem_rbs_collection/concurrent-ruby/1.1/promises.rbs"
73
- - ".gem_rbs_collection/concurrent-ruby/1.1/set.rbs"
74
- - ".gem_rbs_collection/concurrent-ruby/1.1/timer_task.rbs"
75
- - ".gem_rbs_collection/concurrent-ruby/1.1/utility/processor_counter.rbs"
76
- - ".gem_rbs_collection/csv/3.3/.rbs_meta.yaml"
77
- - ".gem_rbs_collection/csv/3.3/csv.rbs"
78
- - ".gem_rbs_collection/csv/3.3/manifest.yaml"
79
- - ".gem_rbs_collection/lint_roller/1.1/.rbs_meta.yaml"
80
- - ".gem_rbs_collection/lint_roller/1.1/lint_roller.rbs"
81
- - ".gem_rbs_collection/listen/3.9/.rbs_meta.yaml"
82
- - ".gem_rbs_collection/listen/3.9/listen.rbs"
83
- - ".gem_rbs_collection/listen/3.9/listener.rbs"
84
- - ".gem_rbs_collection/logger/1.7/.rbs_meta.yaml"
85
- - ".gem_rbs_collection/logger/1.7/formatter.rbs"
86
- - ".gem_rbs_collection/logger/1.7/log_device.rbs"
87
- - ".gem_rbs_collection/logger/1.7/logger.rbs"
88
- - ".gem_rbs_collection/logger/1.7/manifest.yaml"
89
- - ".gem_rbs_collection/logger/1.7/period.rbs"
90
- - ".gem_rbs_collection/logger/1.7/severity.rbs"
91
- - ".gem_rbs_collection/nokogiri/1.11/.rbs_meta.yaml"
92
- - ".gem_rbs_collection/nokogiri/1.11/nokogiri.rbs"
93
- - ".gem_rbs_collection/nokogiri/1.11/patch.rbs"
94
- - ".gem_rbs_collection/parallel/1.20/.rbs_meta.yaml"
95
- - ".gem_rbs_collection/parallel/1.20/parallel.rbs"
96
- - ".gem_rbs_collection/parser/3.2/.rbs_meta.yaml"
97
- - ".gem_rbs_collection/parser/3.2/manifest.yaml"
98
- - ".gem_rbs_collection/parser/3.2/parser.rbs"
99
- - ".gem_rbs_collection/parser/3.2/polyfill.rbs"
100
- - ".gem_rbs_collection/rainbow/3.0/.rbs_meta.yaml"
101
- - ".gem_rbs_collection/rainbow/3.0/global.rbs"
102
- - ".gem_rbs_collection/rainbow/3.0/presenter.rbs"
103
- - ".gem_rbs_collection/rainbow/3.0/rainbow.rbs"
104
- - ".gem_rbs_collection/rake/13.0/.rbs_meta.yaml"
105
- - ".gem_rbs_collection/rake/13.0/manifest.yaml"
106
- - ".gem_rbs_collection/rake/13.0/rake.rbs"
107
- - ".gem_rbs_collection/regexp_parser/2.8/.rbs_meta.yaml"
108
- - ".gem_rbs_collection/regexp_parser/2.8/regexp_parser.rbs"
109
- - ".gem_rbs_collection/rubocop-ast/1.46/.rbs_meta.yaml"
110
- - ".gem_rbs_collection/rubocop-ast/1.46/rubocop-ast.rbs"
111
- - ".gem_rbs_collection/rubocop/1.57/.rbs_meta.yaml"
112
- - ".gem_rbs_collection/rubocop/1.57/rubocop.rbs"
113
- - ".gem_rbs_collection/rubyzip/3.2/.rbs_meta.yaml"
114
- - ".gem_rbs_collection/rubyzip/3.2/manifest.yaml"
115
- - ".gem_rbs_collection/rubyzip/3.2/zip.rbs"
116
- - ".gem_rbs_collection/rubyzip/3.2/zip/central_directory.rbs"
117
- - ".gem_rbs_collection/rubyzip/3.2/zip/compressor.rbs"
118
- - ".gem_rbs_collection/rubyzip/3.2/zip/constants.rbs"
119
- - ".gem_rbs_collection/rubyzip/3.2/zip/crypto/aes_encryption.rbs"
120
- - ".gem_rbs_collection/rubyzip/3.2/zip/crypto/decrypted_io.rbs"
121
- - ".gem_rbs_collection/rubyzip/3.2/zip/crypto/encryption.rbs"
122
- - ".gem_rbs_collection/rubyzip/3.2/zip/crypto/null_encryption.rbs"
123
- - ".gem_rbs_collection/rubyzip/3.2/zip/crypto/traditional_encryption.rbs"
124
- - ".gem_rbs_collection/rubyzip/3.2/zip/decompressor.rbs"
125
- - ".gem_rbs_collection/rubyzip/3.2/zip/deflater.rbs"
126
- - ".gem_rbs_collection/rubyzip/3.2/zip/dirtyable.rbs"
127
- - ".gem_rbs_collection/rubyzip/3.2/zip/dos_time.rbs"
128
- - ".gem_rbs_collection/rubyzip/3.2/zip/entry.rbs"
129
- - ".gem_rbs_collection/rubyzip/3.2/zip/entry_set.rbs"
130
- - ".gem_rbs_collection/rubyzip/3.2/zip/errors.rbs"
131
- - ".gem_rbs_collection/rubyzip/3.2/zip/extra_field.rbs"
132
- - ".gem_rbs_collection/rubyzip/3.2/zip/extra_field/aes.rbs"
133
- - ".gem_rbs_collection/rubyzip/3.2/zip/extra_field/generic.rbs"
134
- - ".gem_rbs_collection/rubyzip/3.2/zip/extra_field/ntfs.rbs"
135
- - ".gem_rbs_collection/rubyzip/3.2/zip/extra_field/old_unix.rbs"
136
- - ".gem_rbs_collection/rubyzip/3.2/zip/extra_field/universal_time.rbs"
137
- - ".gem_rbs_collection/rubyzip/3.2/zip/extra_field/unix.rbs"
138
- - ".gem_rbs_collection/rubyzip/3.2/zip/extra_field/unknown.rbs"
139
- - ".gem_rbs_collection/rubyzip/3.2/zip/extra_field/zip64.rbs"
140
- - ".gem_rbs_collection/rubyzip/3.2/zip/file.rbs"
141
- - ".gem_rbs_collection/rubyzip/3.2/zip/file_split.rbs"
142
- - ".gem_rbs_collection/rubyzip/3.2/zip/filesystem.rbs"
143
- - ".gem_rbs_collection/rubyzip/3.2/zip/filesystem/dir.rbs"
144
- - ".gem_rbs_collection/rubyzip/3.2/zip/filesystem/directory_iterator.rbs"
145
- - ".gem_rbs_collection/rubyzip/3.2/zip/filesystem/file.rbs"
146
- - ".gem_rbs_collection/rubyzip/3.2/zip/filesystem/file_stat.rbs"
147
- - ".gem_rbs_collection/rubyzip/3.2/zip/filesystem/zip_file_name_mapper.rbs"
148
- - ".gem_rbs_collection/rubyzip/3.2/zip/inflater.rbs"
149
- - ".gem_rbs_collection/rubyzip/3.2/zip/input_stream.rbs"
150
- - ".gem_rbs_collection/rubyzip/3.2/zip/ioextras.rbs"
151
- - ".gem_rbs_collection/rubyzip/3.2/zip/ioextras/abstract_input_stream.rbs"
152
- - ".gem_rbs_collection/rubyzip/3.2/zip/ioextras/abstract_output_stream.rbs"
153
- - ".gem_rbs_collection/rubyzip/3.2/zip/null_compressor.rbs"
154
- - ".gem_rbs_collection/rubyzip/3.2/zip/null_decompressor.rbs"
155
- - ".gem_rbs_collection/rubyzip/3.2/zip/null_input_stream.rbs"
156
- - ".gem_rbs_collection/rubyzip/3.2/zip/output_stream.rbs"
157
- - ".gem_rbs_collection/rubyzip/3.2/zip/pass_thru_compressor.rbs"
158
- - ".gem_rbs_collection/rubyzip/3.2/zip/pass_thru_decompressor.rbs"
159
- - ".gem_rbs_collection/rubyzip/3.2/zip/streamable_directory.rbs"
160
- - ".gem_rbs_collection/rubyzip/3.2/zip/streamable_stream.rbs"
161
- - ".gem_rbs_collection/rubyzip/3.2/zip/version.rbs"
162
- - ".mutant.yml"
163
48
  - CHANGELOG.md
164
49
  - CODE_OF_CONDUCT.md
165
50
  - LICENSE.txt
166
51
  - README.md
167
- - Rakefile
168
- - Steepfile
169
- - benchmark.rb
170
- - docs/ARCHITECTURE.md
171
- - docs/DEVELOPMENT.md
172
- - docs/MUTATION_TESTING.md
173
- - docs/PEER_LIBRARIES.md
174
- - docs/QUALITY_ASSURANCE.md
175
- - docs/SPEC_SOURCES.md
176
- - docs/assets/benchmark_results.svg
177
- - docs/assets/lsp_autocompletion.png
178
- - docs/assets/playground_preview.png
179
- - docs/coi-serviceworker.js
180
- - docs/office_thread.js
181
- - docs/preview.html
182
- - docs/visual/VisualGallery.md
183
- - docs/wasm/ruby.wasm
184
- - docs/wasm/wasm_doc_helper.css
185
- - docs/wasm/wasm_doc_helper.js
186
- - docs/zeta.js
187
52
  - lib/ruby_lsp/xlsxrb/addon.rb
188
53
  - lib/ruby_lsp/xlsxrb/completion_listener.rb
189
54
  - lib/xlsxrb.rb
@@ -231,8 +96,6 @@ files:
231
96
  - lib/xlsxrb/version.rb
232
97
  - lib/xlsxrb/workbook_builder.rb
233
98
  - lib/xlsxrb/worksheet_builder.rb
234
- - rbs_collection.lock.yaml
235
- - rbs_collection.yaml
236
99
  - sig/generated/xlsxrb.rbs
237
100
  - sig/generated/xlsxrb/chart_builder.rbs
238
101
  - sig/generated/xlsxrb/dsl_helpers.rbs
@@ -279,14 +142,11 @@ files:
279
142
  - sig/generated/xlsxrb/workbook_builder.rbs
280
143
  - sig/generated/xlsxrb/worksheet_builder.rbs
281
144
  - sig/rexml.rbs
282
- - vendor/sdk_runner/Program.cs
283
- - vendor/sdk_runner/sdk_runner.csproj
284
145
  homepage: https://github.com/niku/xlsxrb
285
146
  licenses:
286
147
  - MIT
287
148
  metadata:
288
149
  allowed_push_host: https://rubygems.org
289
- homepage_uri: https://github.com/niku/xlsxrb
290
150
  source_code_uri: https://github.com/niku/xlsxrb
291
151
  changelog_uri: https://github.com/niku/xlsxrb/blob/main/CHANGELOG.md
292
152
  documentation_uri: https://niku.github.io/xlsxrb/
@@ -1,65 +0,0 @@
1
- FROM ruby:4.0.5
2
-
3
- ARG USERNAME=vscode
4
- ARG USER_UID=1000
5
- ARG USER_GID=$USER_UID
6
-
7
- # Create a non-root user (vscode) with passwordless sudo privileges
8
- # following Microsoft's Dev Container guidelines to prevent file permission conflicts.
9
- RUN apt-get update && apt-get install -y sudo ca-certificates \
10
- # Check if GID already exists, otherwise create it
11
- && if [ "$(getent group ${USER_GID})" ]; then \
12
- echo "GID ${USER_GID} already exists."; \
13
- else \
14
- groupadd --gid ${USER_GID} ${USERNAME}; \
15
- fi \
16
- # Check if UID already exists, otherwise create user
17
- && if [ "$(getent passwd ${USER_UID})" ]; then \
18
- echo "UID ${USER_UID} already exists."; \
19
- else \
20
- useradd --uid ${USER_UID} --gid ${USER_GID} -m ${USERNAME} -s /bin/bash; \
21
- fi \
22
- # Grant passwordless sudo permissions
23
- && echo "${USERNAME} ALL=(root) NOPASSWD:ALL" > /etc/sudoers.d/${USERNAME} \
24
- && chmod 0440 /etc/sudoers.d/${USERNAME} \
25
- && apt-get clean && rm -rf /var/lib/apt/lists/*
26
-
27
- # Install .NET SDK for E2E testing with Open-XML-SDK.
28
- # Use dotnet-install so the container works on both arm64 and amd64 hosts.
29
- RUN apt-get update && apt-get install -y curl ca-certificates && \
30
- curl -sSL https://dot.net/v1/dotnet-install.sh -o /tmp/dotnet-install.sh && \
31
- bash /tmp/dotnet-install.sh --channel 8.0 --quality ga --install-dir /usr/share/dotnet && \
32
- ln -s /usr/share/dotnet/dotnet /usr/bin/dotnet && \
33
- rm -f /tmp/dotnet-install.sh && \
34
- apt-get clean && rm -rf /var/lib/apt/lists/*
35
-
36
- # Install LibreOffice, poppler-utils, ImageMagick, and fonts for Visual Examples/VRT
37
- RUN apt-get update && apt-get install -y \
38
- libreoffice-calc \
39
- poppler-utils \
40
- imagemagick \
41
- fonts-liberation \
42
- fonts-noto-cjk \
43
- brotli \
44
- && apt-get clean && rm -rf /var/lib/apt/lists/*
45
-
46
- # Pre-create the workspace folder and assign ownership to the vscode user
47
- RUN mkdir -p /workspaces/xlsxrb && chown -R ${USERNAME}:${USERNAME} /workspaces
48
-
49
- # Set up the workspace
50
- USER ${USERNAME}
51
- WORKDIR /workspaces/xlsxrb
52
-
53
- # Pre-download DocumentFormat.OpenXml package to the NuGet cache
54
- RUN mkdir /tmp/nuget_warmup && cd /tmp/nuget_warmup && \
55
- dotnet new console && \
56
- dotnet add package DocumentFormat.OpenXml --version 3.5.1 && \
57
- cd / && rm -rf /tmp/nuget_warmup
58
-
59
- # Install gems (Respect Gemfile.lock, maintain correct user ownership)
60
- COPY --chown=vscode:vscode Gemfile xlsxrb.gemspec ./
61
- COPY --chown=vscode:vscode lib/xlsxrb/version.rb ./lib/xlsxrb/
62
- RUN bundle install
63
-
64
- # Copy the remaining project application files
65
- COPY --chown=vscode:vscode . .
@@ -1,17 +0,0 @@
1
- {
2
- "name": "xlsxrb Development",
3
- "build": {
4
- "dockerfile": "Dockerfile",
5
- "context": ".."
6
- },
7
- "workspaceFolder": "/workspaces/xlsxrb",
8
- "customizations": {
9
- "vscode": {
10
- "extensions": [
11
- "Shopify.ruby-lsp",
12
- ]
13
- }
14
- },
15
- "remoteUser": "vscode",
16
- "postCreateCommand": "bundle install && bin/setup"
17
- }