xlsxrb 0.1.0

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 (44) hide show
  1. checksums.yaml +7 -0
  2. data/.devcontainer/Dockerfile +64 -0
  3. data/.devcontainer/devcontainer.json +17 -0
  4. data/CHANGELOG.md +12 -0
  5. data/CODE_OF_CONDUCT.md +10 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +384 -0
  8. data/Rakefile +290 -0
  9. data/benchmark.rb +390 -0
  10. data/docs/ARCHITECTURE.md +488 -0
  11. data/docs/SPEC_SOURCES.md +42 -0
  12. data/docs/visual/VisualGallery.md +4684 -0
  13. data/docs/wasm/wasm_doc_helper.css +189 -0
  14. data/docs/wasm/wasm_doc_helper.js +320 -0
  15. data/lib/xlsxrb/elements/cell.rb +77 -0
  16. data/lib/xlsxrb/elements/column.rb +28 -0
  17. data/lib/xlsxrb/elements/row.rb +47 -0
  18. data/lib/xlsxrb/elements/types.rb +36 -0
  19. data/lib/xlsxrb/elements/workbook.rb +47 -0
  20. data/lib/xlsxrb/elements/worksheet.rb +50 -0
  21. data/lib/xlsxrb/elements.rb +15 -0
  22. data/lib/xlsxrb/ooxml/reader.rb +8048 -0
  23. data/lib/xlsxrb/ooxml/shared_strings_parser.rb +75 -0
  24. data/lib/xlsxrb/ooxml/styles_parser.rb +194 -0
  25. data/lib/xlsxrb/ooxml/utils.rb +122 -0
  26. data/lib/xlsxrb/ooxml/workbook_parser.rb +78 -0
  27. data/lib/xlsxrb/ooxml/workbook_writer.rb +1000 -0
  28. data/lib/xlsxrb/ooxml/worksheet_parser.rb +455 -0
  29. data/lib/xlsxrb/ooxml/worksheet_writer.rb +1008 -0
  30. data/lib/xlsxrb/ooxml/writer.rb +5450 -0
  31. data/lib/xlsxrb/ooxml/xml_builder.rb +113 -0
  32. data/lib/xlsxrb/ooxml/xml_parser.rb +68 -0
  33. data/lib/xlsxrb/ooxml/zip_generator.rb +162 -0
  34. data/lib/xlsxrb/ooxml/zip_reader.rb +158 -0
  35. data/lib/xlsxrb/ooxml/zip_writer.rb +213 -0
  36. data/lib/xlsxrb/ooxml.rb +22 -0
  37. data/lib/xlsxrb/style_builder.rb +241 -0
  38. data/lib/xlsxrb/version.rb +5 -0
  39. data/lib/xlsxrb.rb +1427 -0
  40. data/measure_memory.rb +42 -0
  41. data/sig/xlsxrb.rbs +23 -0
  42. data/vendor/sdk_runner/Program.cs +91 -0
  43. data/vendor/sdk_runner/sdk_runner.csproj +13 -0
  44. metadata +144 -0
data/measure_memory.rb ADDED
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "opentelemetry/sdk"
4
+ require "objspace"
5
+ require_relative "lib/xlsxrb"
6
+
7
+ # Outputs memory and GC stats for a given tracing span
8
+ class MemorySpanProcessor < OpenTelemetry::SDK::Trace::SpanProcessor
9
+ def on_start(span, _parent_context)
10
+ span.set_attribute("ruby.gc.count.start", GC.stat[:count])
11
+ span.set_attribute("ruby.memory.bytes_allocated.start", ObjectSpace.memsize_of_all)
12
+ end
13
+
14
+ def on_finish(span)
15
+ gc_start = span.attributes["ruby.gc.count.start"]
16
+ mem_start = span.attributes["ruby.memory.bytes_allocated.start"]
17
+
18
+ gc_diff = GC.stat[:count] - (gc_start || 0)
19
+ mem_diff = ObjectSpace.memsize_of_all - (mem_start || 0)
20
+
21
+ mem_mb = mem_diff.to_f / 1024 / 1024
22
+
23
+ puts "[#{span.name}] Memory delta: #{mem_mb.round(2)} MB, GC count: #{gc_diff}"
24
+ end
25
+ end
26
+
27
+ OpenTelemetry::SDK.configure do |c|
28
+ c.add_span_processor(MemorySpanProcessor.new)
29
+ end
30
+
31
+ puts "Generating 100,000 cells (10,000 rows x 10 cols) to measure memory..."
32
+
33
+ # Using a smaller size first so it runs quickly
34
+ Xlsxrb.generate("test_memory.xlsx") do |w|
35
+ w.add_sheet("Data") do
36
+ 10_000.times do |i|
37
+ w.add_row(["A", "B", "C", "D", "E", "F", "G", "H", "I", i])
38
+ end
39
+ end
40
+ end
41
+
42
+ puts "Done."
data/sig/xlsxrb.rbs ADDED
@@ -0,0 +1,23 @@
1
+ module Xlsxrb
2
+ VERSION: String
3
+
4
+ module Ooxml
5
+ class Event
6
+ attr_reader type: Symbol
7
+ attr_reader args: Array[untyped]
8
+ attr_reader source: Hash[Symbol, untyped]
9
+
10
+ def self.new: (type: Symbol, args: Array[untyped], source: Hash[Symbol, untyped]) -> Event
11
+ end
12
+
13
+ class WorksheetParser
14
+ def self.each_event: (String, ?shared_strings: Array[String], ?part_name: String) ?{ (Event) -> void } -> void
15
+ | (String, ?shared_strings: Array[String], ?part_name: String) -> Enumerator[Event, void]
16
+ end
17
+
18
+ class SharedStringsParser
19
+ def self.each_event: (String, ?part_name: String) ?{ (Event) -> void } -> void
20
+ | (String, ?part_name: String) -> Enumerator[Event, void]
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,91 @@
1
+ using Microsoft.CodeAnalysis.CSharp.Scripting;
2
+ using Microsoft.CodeAnalysis.Scripting;
3
+ using DocumentFormat.OpenXml.Packaging;
4
+ using DocumentFormat.OpenXml.Validation;
5
+
6
+ if (args.Length < 2)
7
+ {
8
+ Console.Error.WriteLine("Usage: dotnet run --project vendor/sdk_runner -- <scenario.cs> <xlsx-path>");
9
+ return 2;
10
+ }
11
+
12
+ var scenarioPath = Path.GetFullPath(args[0]);
13
+ var xlsxPath = Path.GetFullPath(args[1]);
14
+
15
+ if (!File.Exists(scenarioPath))
16
+ {
17
+ Console.Error.WriteLine($"Scenario file not found: {scenarioPath}");
18
+ return 2;
19
+ }
20
+
21
+ if (!File.Exists(xlsxPath))
22
+ {
23
+ Console.Error.WriteLine($"XLSX file not found: {xlsxPath}");
24
+ return 2;
25
+ }
26
+
27
+ var code = await File.ReadAllTextAsync(scenarioPath);
28
+ var result = await RunScenario(code, xlsxPath);
29
+ if (result.Success)
30
+ {
31
+ Console.WriteLine("SCENARIO_PASS");
32
+ return 0;
33
+ }
34
+
35
+ Console.Error.WriteLine(result.ErrorOutput);
36
+ return 1;
37
+
38
+
39
+ async Task<ScenarioExecResult> RunScenario(string code, string xlsxPath)
40
+ {
41
+ var globals = new ScenarioContext(xlsxPath);
42
+
43
+ var options = ScriptOptions.Default
44
+ .AddReferences(
45
+ typeof(object).Assembly,
46
+ typeof(Enumerable).Assembly,
47
+ typeof(Console).Assembly,
48
+ typeof(SpreadsheetDocument).Assembly,
49
+ typeof(OpenXmlValidator).Assembly
50
+ )
51
+ .AddImports(
52
+ "System",
53
+ "System.IO",
54
+ "System.Linq",
55
+ "System.Collections.Generic",
56
+ "DocumentFormat.OpenXml",
57
+ "DocumentFormat.OpenXml.Packaging",
58
+ "DocumentFormat.OpenXml.Spreadsheet",
59
+ "DocumentFormat.OpenXml.Validation",
60
+ "DocumentFormat.OpenXml.CustomProperties",
61
+ "DocumentFormat.OpenXml.VariantTypes"
62
+ );
63
+
64
+ try
65
+ {
66
+ await CSharpScript.RunAsync(code, options, globals, typeof(ScenarioContext));
67
+ return new ScenarioExecResult { Success = true };
68
+ }
69
+ catch (CompilationErrorException ex)
70
+ {
71
+ var errorMsg = "SCENARIO_COMPILE_ERROR\n" + string.Join("\n", ex.Diagnostics.Select(d => d.ToString()));
72
+ return new ScenarioExecResult { Success = false, ErrorOutput = errorMsg };
73
+ }
74
+ catch (Exception ex)
75
+ {
76
+ var errorMsg = "SCENARIO_FAIL\n" + ex.ToString();
77
+ return new ScenarioExecResult { Success = false, ErrorOutput = errorMsg };
78
+ }
79
+ }
80
+
81
+ record ScenarioExecResult(bool Success = false, string ErrorOutput = "");
82
+
83
+ public sealed class ScenarioContext
84
+ {
85
+ public ScenarioContext(string xlsxPath)
86
+ {
87
+ XlsxPath = xlsxPath;
88
+ }
89
+
90
+ public string XlsxPath { get; }
91
+ }
@@ -0,0 +1,13 @@
1
+ <Project Sdk="Microsoft.NET.Sdk">
2
+ <PropertyGroup>
3
+ <OutputType>Exe</OutputType>
4
+ <TargetFramework>net8.0</TargetFramework>
5
+ <ImplicitUsings>enable</ImplicitUsings>
6
+ <Nullable>enable</Nullable>
7
+ </PropertyGroup>
8
+
9
+ <ItemGroup>
10
+ <PackageReference Include="DocumentFormat.OpenXml" Version="3.0.2" />
11
+ <PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.11.0" />
12
+ </ItemGroup>
13
+ </Project>
metadata ADDED
@@ -0,0 +1,144 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: xlsxrb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - niku
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: opentelemetry-api
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '1.4'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '1.4'
26
+ - !ruby/object:Gem::Dependency
27
+ name: rexml
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: ruby_wasm
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: webrick
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ description: A minimal dependency XLSX reading and writing library for Ruby, relying
69
+ on standard libraries for core logic and opentelemetry-api for observability.
70
+ email:
71
+ - 10890+niku@users.noreply.github.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".devcontainer/Dockerfile"
77
+ - ".devcontainer/devcontainer.json"
78
+ - CHANGELOG.md
79
+ - CODE_OF_CONDUCT.md
80
+ - LICENSE.txt
81
+ - README.md
82
+ - Rakefile
83
+ - benchmark.rb
84
+ - docs/ARCHITECTURE.md
85
+ - docs/SPEC_SOURCES.md
86
+ - docs/visual/VisualGallery.md
87
+ - docs/wasm/wasm_doc_helper.css
88
+ - docs/wasm/wasm_doc_helper.js
89
+ - lib/xlsxrb.rb
90
+ - lib/xlsxrb/elements.rb
91
+ - lib/xlsxrb/elements/cell.rb
92
+ - lib/xlsxrb/elements/column.rb
93
+ - lib/xlsxrb/elements/row.rb
94
+ - lib/xlsxrb/elements/types.rb
95
+ - lib/xlsxrb/elements/workbook.rb
96
+ - lib/xlsxrb/elements/worksheet.rb
97
+ - lib/xlsxrb/ooxml.rb
98
+ - lib/xlsxrb/ooxml/reader.rb
99
+ - lib/xlsxrb/ooxml/shared_strings_parser.rb
100
+ - lib/xlsxrb/ooxml/styles_parser.rb
101
+ - lib/xlsxrb/ooxml/utils.rb
102
+ - lib/xlsxrb/ooxml/workbook_parser.rb
103
+ - lib/xlsxrb/ooxml/workbook_writer.rb
104
+ - lib/xlsxrb/ooxml/worksheet_parser.rb
105
+ - lib/xlsxrb/ooxml/worksheet_writer.rb
106
+ - lib/xlsxrb/ooxml/writer.rb
107
+ - lib/xlsxrb/ooxml/xml_builder.rb
108
+ - lib/xlsxrb/ooxml/xml_parser.rb
109
+ - lib/xlsxrb/ooxml/zip_generator.rb
110
+ - lib/xlsxrb/ooxml/zip_reader.rb
111
+ - lib/xlsxrb/ooxml/zip_writer.rb
112
+ - lib/xlsxrb/style_builder.rb
113
+ - lib/xlsxrb/version.rb
114
+ - measure_memory.rb
115
+ - sig/xlsxrb.rbs
116
+ - vendor/sdk_runner/Program.cs
117
+ - vendor/sdk_runner/sdk_runner.csproj
118
+ homepage: https://github.com/niku/xlsxrb
119
+ licenses:
120
+ - MIT
121
+ metadata:
122
+ allowed_push_host: https://rubygems.org
123
+ homepage_uri: https://github.com/niku/xlsxrb
124
+ source_code_uri: https://github.com/niku/xlsxrb
125
+ changelog_uri: https://github.com/niku/xlsxrb/blob/main/CHANGELOG.md
126
+ rubygems_mfa_required: 'true'
127
+ rdoc_options: []
128
+ require_paths:
129
+ - lib
130
+ required_ruby_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: 4.0.0
135
+ required_rubygems_version: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ requirements: []
141
+ rubygems_version: 4.0.10
142
+ specification_version: 4
143
+ summary: A streaming-capable, fast, low-memory XLSX reader/writer.
144
+ test_files: []