excel-esv 3.0.1 → 3.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 61b9d8716af48b7a32382ba6e9558a5f9f2afc71cb6ec0e6a380686dd91ea308
4
- data.tar.gz: 8d737947eb7b20510cd234a5c23a033c5eaec2a8f90d22152c8c6892de99e271
3
+ metadata.gz: d46877da5cc1642f15c16ed055a62a15656ff495eb5d3854a606134668f988df
4
+ data.tar.gz: 46c7e0920178b82d593a6a1d1dfef31d929a914ef22ed4ea23efd5a675526eba
5
5
  SHA512:
6
- metadata.gz: e72fa2c2685e9833c15d4ea0c6278b41ca0b8f45fe296ff81f6691652cd0b477f68e69365b9bc42b3d70024738361cd8805ab0d21885de875b028febab293d0d
7
- data.tar.gz: 2dacf749dcc74944f9ad3cf2ef671e123a16f8665ecfab299541cd22c702663b9e168218675cfd75cc56ef1bac455b3d90f6f554f0d3549f71928931074808ea
6
+ metadata.gz: 7dcd7941790d2a1082105f03eb7813b62a91dce96a5624fb124b0819431f7c6261e8e848a78fffd0ac03759bd3bbc8697d32fd05bba9463842fff2e07c445a27
7
+ data.tar.gz: a279ac0df840b36fbb719c3e210696bf6c261e80e80970d9d2accdfa0fea4b5e592542da1cbbb86dbf4d1531266c18294c1726f99c16da872b575edf41c5f399
@@ -0,0 +1,6 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "github-actions"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
@@ -7,16 +7,22 @@ on:
7
7
  branches: [ master ]
8
8
 
9
9
  jobs:
10
- test:
10
+ ruby-versions:
11
+ uses: ruby/actions/.github/workflows/ruby_versions.yml@master
12
+ with:
13
+ min_version: 3.2
14
+ engine: cruby
11
15
 
16
+ test:
17
+ needs: ruby-versions
12
18
  runs-on: ubuntu-latest
13
19
 
14
20
  strategy:
15
21
  matrix:
16
- ruby-version: ["3.0", "2.7", "2.6", "2.5"]
17
-
22
+ ruby-version: ${{ fromJson(needs.ruby-versions.outputs.versions) }}
23
+
18
24
  steps:
19
- - uses: actions/checkout@v2
25
+ - uses: actions/checkout@v7
20
26
  - name: Set up Ruby ${{ matrix.ruby-version }}
21
27
  uses: ruby/setup-ruby@v1
22
28
  with:
data/.gitignore CHANGED
@@ -11,4 +11,5 @@
11
11
  *.so
12
12
  *.o
13
13
  *.a
14
+ *.gem
14
15
  mkmf.log
data/CHANGELOG.md CHANGED
@@ -1,12 +1,32 @@
1
- # 3.0.0
1
+ # Changelog
2
+
3
+ ## 3.3.0 (Aug 28, 2026)
4
+
5
+ * Fix Numbers.app misrendering by formatting date cells as ISO 8601 ("2026-08-28") and time cells as ISO-like ("2026-08-28 13:45").
6
+
7
+ ## 3.2.0 (Nov 12, 2025)
8
+
9
+ * Support `worksheet_index:` in `.parse_file`, too.
10
+
11
+ ## 3.1.0 (Nov 12, 2025)
12
+
13
+ * Support specifying worksheet index when there are multiple: `ESV.parse(data, worksheet_index: 0)`.
14
+
15
+ ## 3.0.1 (Nov 19, 2021)
16
+
17
+ * Add `ESV.parse(data, header_converters:)` [#9]
18
+
19
+ [#9]: https://github.com/barsoom/excel-esv/pull/9
20
+
21
+ ## 3.0.0 (Nov 20, 2018)
2
22
 
3
23
  * Returns the last value of any formula cells instead of returning a `Spreadsheet::Formula`.
4
24
  * Returns the URL of any link cells instead of returning a `Spreadsheet::Link`.
5
25
 
6
- # 2.0.0
26
+ ## 2.0.0 (Nov 19, 2018)
7
27
 
8
28
  * `parse` now returns an actual nested `Array`, not array-like `Spreadsheet::Row` records.
9
29
 
10
- # 1.0.0
30
+ ## 1.0.0 (Dec 8, 2017)
11
31
 
12
32
  * `send_excel` now supports a `filename:` argument, e.g. `send_excel(data, filename: "salaries.xls")`.
data/Gemfile CHANGED
@@ -4,7 +4,7 @@ source "https://rubygems.org"
4
4
  gemspec
5
5
 
6
6
  group :development do
7
- gem "barsoom_utils", github: "barsoom/barsoom_utils"
7
+ gem "barsoom_utils"
8
8
  gem "bundler"
9
9
  gem "rake"
10
10
  gem "rspec"
data/README.md CHANGED
@@ -45,7 +45,31 @@ output = ESV.parse(data)
45
45
  # => [ [ "Name", "Dogs", … ], … ]
46
46
  ```
47
47
 
48
- This assumes a file with a single worksheet and will raise otherwise.
48
+ This will raise for a file with multiple worksheets unless you explicitly specify the one you want (the first worksheet is index 0):
49
+
50
+ ``` ruby
51
+ ESV.parse(data, worksheet_index: 0)
52
+ ```
53
+
54
+ `.parse` supports the `header_converters:` keyword argument, which takes the same arguments as `CSV.parse` does:
55
+
56
+ - a Symbol name for a registered header converter
57
+ - a Proc which takes the value and returns the converted value
58
+ - an Array of Symbol names for registered header converters
59
+
60
+ ``` ruby
61
+ require "esv"
62
+
63
+ data = File.read("/tmp/test.xls")
64
+ output = ESV.parse(data, header_converters: :symbol)
65
+ # => [ [ :name, :dogs, … ], … ]
66
+ ```
67
+
68
+ Registering a new converter:
69
+
70
+ ``` ruby
71
+ ESV::HEADER_CONVERTERS[:upcase] = ->(value) { value.upcase }
72
+ ```
49
73
 
50
74
  ### Parse file
51
75
 
@@ -56,7 +80,7 @@ output = ESV.parse_file("/tmp/test.xls")
56
80
  # => [ [ "Name", "Dogs", … ], … ]
57
81
  ```
58
82
 
59
- This assumes a file with a single worksheet and will raise otherwise.
83
+ This is a thin wrapper around `ESV.parse` and takes the same arguments.
60
84
 
61
85
  ### Generate in Ruby on Rails
62
86
 
data/excel-esv.gemspec CHANGED
@@ -12,9 +12,11 @@ Gem::Specification.new do |spec|
12
12
  spec.homepage = "https://github.com/barsoom/excel-esv"
13
13
  spec.license = "MIT"
14
14
  spec.metadata = { "rubygems_mfa_required" => "true" }
15
+ spec.required_ruby_version = ">= 3.1.0"
15
16
 
16
17
  spec.files = `git ls-files -z`.split("\x0")
17
18
  spec.require_paths = [ "lib" ]
18
19
 
19
- spec.add_dependency "spreadsheet"
20
+ spec.add_runtime_dependency "logger"
21
+ spec.add_runtime_dependency "spreadsheet"
20
22
  end
data/lib/esv/generator.rb CHANGED
@@ -1,4 +1,10 @@
1
1
  class ESV::Generator
2
+ # The spreadsheet gem otherwise formats date and time cells as "DD.MM.YYYY".
3
+ # Excel reads that case-insensitively, but Numbers.app only recognises the "MM", so it renders e.g. "DD.06.YYYY". Lowercase "dd" and "yyyy" work in both.
4
+ # "hh" is confirmed to render as 24-hour time in Numbers.app.
5
+ DATE_FORMAT = "yyyy-MM-dd"
6
+ DATE_TIME_FORMAT = "yyyy-MM-dd hh:mm:ss"
7
+
2
8
  def initialize
3
9
  @data_rows = []
4
10
  end
@@ -14,6 +20,7 @@ class ESV::Generator
14
20
  @data_rows.each_with_index do |data_row, index|
15
21
  row = sheet.row(index)
16
22
  row.push(*data_row)
23
+ format_dates_and_times(row, data_row)
17
24
  end
18
25
 
19
26
  content = ""
@@ -21,4 +28,23 @@ class ESV::Generator
21
28
  book.write(fake_file)
22
29
  content
23
30
  end
31
+
32
+ private
33
+
34
+ def format_dates_and_times(row, data_row)
35
+ data_row.each_with_index do |value, index|
36
+ format =
37
+ case value
38
+ # DateTime is a Date, so it has to be matched first.
39
+ # Rails' `ActiveSupport::TimeWithZone` is matched by `when Time` since ActiveSupport patches `Time.===`.
40
+ when DateTime, Time then date_time_format
41
+ when Date then date_format
42
+ end
43
+
44
+ row.set_format(index, format) if format
45
+ end
46
+ end
47
+
48
+ def date_format = @date_format ||= Spreadsheet::Format.new(number_format: DATE_FORMAT)
49
+ def date_time_format = @date_time_format ||= Spreadsheet::Format.new(number_format: DATE_TIME_FORMAT)
24
50
  end
@@ -10,7 +10,7 @@ module ESV
10
10
  data,
11
11
  type: ESV::CONTENT_TYPE,
12
12
  disposition: "attachment",
13
- filename: filename,
13
+ filename:,
14
14
  )
15
15
  end
16
16
  end
data/lib/esv/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module ESV
2
- VERSION = "3.0.1"
2
+ VERSION = "3.3.0"
3
3
  end
data/lib/esv.rb CHANGED
@@ -16,27 +16,78 @@ module ESV
16
16
  end
17
17
  end
18
18
 
19
- def self.parse(data)
19
+ # You can register your own header converters in this Hash.
20
+ #
21
+ # @see https://rubyapi.org/3.2/o/csv#class-CSV-label-Custom+Header+Converters
22
+ HEADER_CONVERTERS = {
23
+ downcase: ->(value) {
24
+ value.respond_to?(:downcase) ? value.downcase : value
25
+ },
26
+ # Details:
27
+ #
28
+ # Strips leading and trailing whitespace.
29
+ # Downcases the header.
30
+ # Replaces embedded spaces with underscores.
31
+ # Removes non-word characters.
32
+ # Makes the string into a Symbol.
33
+ symbol: ->(value) {
34
+ value.to_s.strip.downcase.tr(" ", "_").gsub(/\W+/, "").to_sym
35
+ },
36
+ }
37
+
38
+ # @param data [Object] Spreadsheet data to be parsed.
39
+ # @param header_converters [nil, Symbol, Proc, Array<Symbol>] If given, can take these forms:
40
+ # - a Symbol name for a registered header converter
41
+ # - a Proc which takes the value and returns the converted value
42
+ # - an Array of Symbol names for registered header converters
43
+ # @param worksheet_index [nil, Integer] If given, specifies which worksheet index to parse (first is 0). If nil, expects exactly one worksheet.
44
+ # @return [Array<Array>] a list of rows
45
+ def self.parse(data, header_converters: nil, worksheet_index: nil)
20
46
  fake_file = StringIO.new(data)
21
47
  book = Spreadsheet.open(fake_file)
22
48
 
23
- # We could support multiple worksheets, but let's not until we actually need it.
24
- # Until then, we prefer raising to silently ignoring worksheets.
25
- worksheet_count = book.worksheets.length
26
- raise "Expected 1 worksheet, found #{worksheet_count}." if worksheet_count > 1
27
-
28
- book.worksheet(0).to_a.map(&:to_a).map { |row|
29
- row.map { |cell|
30
- case cell
31
- when Spreadsheet::Formula then cell.value
32
- when Spreadsheet::Link then cell.href
33
- else cell
49
+ # We prefer raising to silently ignoring worksheets.
50
+ if !worksheet_index && book.worksheets.length > 1
51
+ raise "Expected 1 worksheet, found #{book.worksheets.length}."
52
+ end
53
+
54
+ worksheet_index ||= 0
55
+
56
+ is_first_row = true
57
+ book.worksheet(worksheet_index).to_a.map(&:to_a).map { |row|
58
+ row.each_with_index.map { |cell, index|
59
+ value =
60
+ case cell
61
+ when Spreadsheet::Formula then cell.value
62
+ when Spreadsheet::Link then cell.href
63
+ else cell
64
+ end
65
+
66
+ if header_converters && is_first_row
67
+ case header_converters
68
+ when Proc then
69
+ value = header_converters.call(value)
70
+ when Symbol then
71
+ value = HEADER_CONVERTERS[header_converters].call(value)
72
+ when Enumerable then
73
+ # Apply the converters in order.
74
+ header_converters.each { |name|
75
+ value = HEADER_CONVERTERS.fetch(name).call(value)
76
+ }
77
+ else
78
+ raise "Unsupported kind of header_converters #{header_converters.inspect}"
79
+ end
80
+ value
81
+ else
82
+ value
34
83
  end
84
+ }.tap {
85
+ is_first_row = false
35
86
  }
36
87
  }
37
88
  end
38
89
 
39
- def self.parse_file(path)
40
- parse File.read(path)
90
+ def self.parse_file(path, header_converters: nil, worksheet_index: nil)
91
+ parse(File.read(path), header_converters:, worksheet_index:)
41
92
  end
42
93
  end
data/spec/esv_spec.rb CHANGED
@@ -1,114 +1,262 @@
1
1
  require "esv"
2
2
 
3
- RSpec.describe ESV, ".generate and .parse" do
4
- it "works" do
5
- data = ESV.generate do |esv|
6
- esv << [ "Dogs", "Cats" ]
7
- esv << [ 1, 2 ]
3
+ RSpec.describe ESV do
4
+ describe ".generate and .parse" do
5
+ it "works" do
6
+ data = ESV.generate do |esv|
7
+ esv << [ "Dogs", "Cats" ]
8
+ esv << [ 1, 2 ]
9
+ end
10
+
11
+ output = ESV.parse(data)
12
+
13
+ expect(output).to eq [
14
+ [ "Dogs", "Cats" ],
15
+ [ 1, 2 ],
16
+ ]
17
+ end
18
+
19
+ it "keeps date and time cells readable as such, rather than as text" do
20
+ data = ESV.generate do |esv|
21
+ esv << [ Date.new(2026, 6, 24), DateTime.new(2026, 6, 24, 13, 30, 5) ]
22
+ end
23
+
24
+ expect(ESV.parse(data)).to eq([ [ Date.new(2026, 6, 24), DateTime.new(2026, 6, 24, 13, 30, 5) ] ])
8
25
  end
9
26
 
10
- output = ESV.parse(data)
27
+ it "reads a Time back as a DateTime" do
28
+ data = ESV.generate { |esv| esv << [ Time.utc(2026, 6, 24, 13, 30, 5) ] }
11
29
 
12
- expect(output).to eq [
13
- [ "Dogs", "Cats" ],
14
- [ 1, 2 ],
15
- ]
30
+ expect(ESV.parse(data)).to eq([ [ DateTime.new(2026, 6, 24, 13, 30, 5) ] ])
31
+ end
16
32
  end
17
- end
18
33
 
19
- RSpec.describe ESV, ".parse" do
20
- it "raises if there's more than one worksheet" do
21
- excel_file_with_two_worksheets = generate_excel_file do |sheet, book|
22
- book.create_worksheet
34
+ describe ".generate" do
35
+ it "formats date and time cells so that both Excel and Numbers.app render them" do
36
+ data = ESV.generate do |esv|
37
+ esv << [ Date.new(2026, 6, 24), Time.utc(2026, 6, 24, 13, 30), DateTime.new(2026, 6, 24, 13, 30), "Dogs", 1 ]
38
+ end
39
+
40
+ expect(number_formats_in(data)).to eq([
41
+ "yyyy-MM-dd",
42
+ "yyyy-MM-dd hh:mm:ss",
43
+ "yyyy-MM-dd hh:mm:ss",
44
+ "GENERAL",
45
+ "GENERAL",
46
+ ])
23
47
  end
24
48
 
25
- expect {
26
- ESV.parse(excel_file_with_two_worksheets)
27
- }.to raise_error(/Expected 1 worksheet, found 2/)
49
+ private
50
+
51
+ def number_formats_in(data)
52
+ row = Spreadsheet.open(StringIO.new(data)).worksheet(0).row(0)
53
+
54
+ row.each_with_index.map { |_value, index| row.format(index).number_format }
55
+ end
28
56
  end
29
57
 
30
- it "ignores formatting, always returning a plain array of data" do
31
- excel_file_with_formatting = generate_excel_file do |sheet|
32
- sheet.row(0).replace([ 1, 2 ])
33
- sheet.row(0).default_format = Spreadsheet::Format.new(color: :blue)
58
+ describe "::HEADER_CONVERTERS" do
59
+ context "with :downcase" do
60
+ it "downcases string value" do
61
+ expect(described_class::HEADER_CONVERTERS[:downcase].call("CAT")).to eq("cat")
62
+ end
63
+
64
+ it "returns a non-string value" do
65
+ expect(described_class::HEADER_CONVERTERS[:downcase].call(1)).to eq(1)
66
+ end
34
67
  end
35
68
 
36
- output = ESV.parse(excel_file_with_formatting)
69
+ context "with :symbol" do
70
+ it "stringifies before symbolizing given value" do
71
+ expect(described_class::HEADER_CONVERTERS[:symbol].call(1)).to eq(:"1")
72
+ end
37
73
 
38
- expect(output).to eq [
39
- [ 1, 2 ],
40
- ]
74
+ it "symbolizes given value" do
75
+ expect(described_class::HEADER_CONVERTERS[:symbol].call("cat")).to eq(:cat)
76
+ end
41
77
 
42
- expect(output[0].class).to eq Array
78
+ context "symbolizes and" do
79
+ it "downcases given value" do
80
+ expect(described_class::HEADER_CONVERTERS[:symbol].call("CAT")).to eq(:cat)
81
+ end
82
+
83
+ it "strips any spaces around value" do
84
+ expect(described_class::HEADER_CONVERTERS[:symbol].call(" CAT ")).to eq(:cat)
85
+ end
86
+
87
+ it "replaces embedded spaces with underscores" do
88
+ expect(described_class::HEADER_CONVERTERS[:symbol].call("CAT CAT")).to eq(:cat_cat)
89
+ end
90
+
91
+ it "removes non-word characters" do
92
+ expect(described_class::HEADER_CONVERTERS[:symbol].call("CAT?")).to eq(:cat)
93
+ end
94
+ end
95
+ end
43
96
  end
44
97
 
45
- it "returns the last value of a formula cell" do
46
- excel_file_with_formula = generate_excel_file do |sheet|
47
- formula = Spreadsheet::Formula.new
48
- formula.value = "two"
49
- sheet.row(0).replace([ "one", formula ])
98
+ describe ".parse" do
99
+ describe "worksheet handling" do
100
+ context "with more than one worksheet" do
101
+ let(:excel_file_with_two_worksheets) {
102
+ generate_excel_file do |sheet_0, book|
103
+ sheet_0.row(0).replace([ "I am worksheet 0" ])
104
+
105
+ sheet_1 = book.create_worksheet
106
+ sheet_1.row(0).replace([ "I am worksheet 1" ])
107
+ end
108
+ }
109
+
110
+ it "raises when not given a worksheet index" do
111
+ expect {
112
+ ESV.parse(excel_file_with_two_worksheets)
113
+ }.to raise_error(/Expected 1 worksheet, found 2/)
114
+ end
115
+
116
+ it "allows specifying a worksheet index" do
117
+ output = ESV.parse(excel_file_with_two_worksheets, worksheet_index: 0)
118
+ expect(output).to eq [ [ "I am worksheet 0" ] ]
119
+
120
+ output = ESV.parse(excel_file_with_two_worksheets, worksheet_index: 1)
121
+ expect(output).to eq [ [ "I am worksheet 1" ] ]
122
+ end
123
+ end
50
124
  end
51
125
 
52
- output = ESV.parse(excel_file_with_formula)
126
+ it "ignores formatting, always returning a plain array of data" do
127
+ excel_file_with_formatting = generate_excel_file do |sheet|
128
+ sheet.row(0).replace([ 1, 2 ])
129
+ sheet.row(0).default_format = Spreadsheet::Format.new(color: :blue)
130
+ end
53
131
 
54
- expect(output).to eq [
55
- [ "one", "two" ],
56
- ]
57
- expect(output[0].class).to eq Array
58
- end
132
+ output = ESV.parse(excel_file_with_formatting)
59
133
 
134
+ expect(output).to eq [
135
+ [ 1, 2 ],
136
+ ]
60
137
 
61
- it "returns the URL of a link cell" do
62
- excel_file_with_link = generate_excel_file do |sheet|
63
- link = Spreadsheet::Link.new("https://example.com", "desc", "foo")
64
- sheet.row(0).replace([ "one", link ])
138
+ expect(output[0].class).to eq Array
65
139
  end
66
- output = ESV.parse(excel_file_with_link)
67
- expect(output).to eq [
68
- [ "one", "https://example.com#foo" ],
69
- ]
70
140
 
71
- expect(output[0][1].class).to eq String
72
- end
141
+ it "returns the last value of a formula cell" do
142
+ excel_file_with_formula = generate_excel_file do |sheet|
143
+ formula = Spreadsheet::Formula.new
144
+ formula.value = "two"
145
+ sheet.row(0).replace([ "one", formula ])
146
+ end
73
147
 
74
- private
148
+ output = ESV.parse(excel_file_with_formula)
75
149
 
76
- def generate_excel_file(&block)
77
- book = Spreadsheet::Workbook.new
78
- sheet = book.create_worksheet
150
+ expect(output).to eq [
151
+ [ "one", "two" ],
152
+ ]
153
+ expect(output[0].class).to eq Array
154
+ end
79
155
 
80
- block.call(sheet, book)
81
156
 
82
- data = ""
83
- fake_file = StringIO.new(data)
84
- book.write(fake_file)
85
- data
86
- end
87
- end
157
+ it "returns the URL of a link cell" do
158
+ excel_file_with_link = generate_excel_file do |sheet|
159
+ link = Spreadsheet::Link.new("https://example.com", "desc", "foo")
160
+ sheet.row(0).replace([ "one", link ])
161
+ end
162
+ output = ESV.parse(excel_file_with_link)
163
+ expect(output).to eq [
164
+ [ "one", "https://example.com#foo" ],
165
+ ]
88
166
 
89
- RSpec.describe ESV, ".generate_file and .parse_file" do
90
- before do
91
- @file = Tempfile.new("esv")
92
- end
167
+ expect(output[0][1].class).to eq String
168
+ end
169
+
170
+ context "when given a header_converters: option" do
171
+ let(:data) {
172
+ ESV.generate do |esv|
173
+ esv << [ "Dogs", "Cats cats" ]
174
+ esv << [ 1, 2 ]
175
+ end
176
+ }
177
+
178
+ it "lets you specify header_converters by symbolic name" do
179
+ output = ESV.parse(data, header_converters: :downcase)
180
+
181
+ expect(output).to eq [
182
+ [ "dogs", "cats cats" ],
183
+ [ 1, 2 ],
184
+ ]
185
+ end
186
+
187
+ it "lets you specify header_converters as a proc" do
188
+ output = ESV.parse(data, header_converters: ->(value) { value.upcase })
189
+
190
+ expect(output).to eq [
191
+ [ "DOGS", "CATS CATS" ],
192
+ [ 1, 2 ],
193
+ ]
194
+ end
195
+
196
+ it "lets you register new symbolic names for header_converters and use them" do
197
+ ESV::HEADER_CONVERTERS[:upcase] = ->(value) { value.upcase }
198
+
199
+ output = ESV.parse(data, header_converters: :upcase)
200
+
201
+ expect(output).to eq [
202
+ [ "DOGS", "CATS CATS" ],
203
+ [ 1, 2 ],
204
+ ]
205
+
206
+ ESV::HEADER_CONVERTERS.delete(:upcase)
207
+ end
93
208
 
94
- it "works" do
95
- path = @file.path
209
+ it "lets you specify header_converters by symbolic names as a list and have them apply in order" do
210
+ ESV::HEADER_CONVERTERS[:reverse] = ->(value) { value.reverse }
211
+ output = ESV.parse(data, header_converters: [ :downcase, :reverse, :symbol ])
96
212
 
97
- ESV.generate_file(path) do |esv|
98
- esv << [ "Dogs", "Cats" ]
99
- esv << [ 1, 2 ]
213
+ expect(output).to eq [
214
+ [ :sgod, :stac_stac ],
215
+ [ 1, 2 ],
216
+ ]
217
+ ESV::HEADER_CONVERTERS.delete(:reverse)
218
+ end
100
219
  end
101
220
 
102
- output = ESV.parse_file(path)
221
+ private
103
222
 
104
- expect(output).to eq [
105
- [ "Dogs", "Cats" ],
106
- [ 1, 2 ],
107
- ]
223
+ def generate_excel_file(&block)
224
+ book = Spreadsheet::Workbook.new
225
+ sheet = book.create_worksheet
226
+
227
+ block.call(sheet, book)
228
+
229
+ data = ""
230
+ fake_file = StringIO.new(data)
231
+ book.write(fake_file)
232
+ data
233
+ end
108
234
  end
109
235
 
110
- after do
111
- @file.close
112
- @file.unlink
236
+ describe ".generate_file and .parse_file" do
237
+ before do
238
+ @file = Tempfile.new("esv")
239
+ end
240
+
241
+ it "works" do
242
+ path = @file.path
243
+
244
+ ESV.generate_file(path) do |esv|
245
+ esv << [ "Dogs", "Cats" ]
246
+ esv << [ 1, 2 ]
247
+ end
248
+
249
+ output = ESV.parse_file(path, worksheet_index: 0)
250
+
251
+ expect(output).to eq [
252
+ [ "Dogs", "Cats" ],
253
+ [ 1, 2 ],
254
+ ]
255
+ end
256
+
257
+ after do
258
+ @file.close
259
+ @file.unlink
260
+ end
113
261
  end
114
262
  end
metadata CHANGED
@@ -1,15 +1,28 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: excel-esv
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.1
4
+ version: 3.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Henrik Nyh
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2021-11-19 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: logger
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
13
26
  - !ruby/object:Gem::Dependency
14
27
  name: spreadsheet
15
28
  requirement: !ruby/object:Gem::Requirement
@@ -24,13 +37,13 @@ dependencies:
24
37
  - - ">="
25
38
  - !ruby/object:Gem::Version
26
39
  version: '0'
27
- description:
28
40
  email:
29
41
  - henrik@nyh.se
30
42
  executables: []
31
43
  extensions: []
32
44
  extra_rdoc_files: []
33
45
  files:
46
+ - ".github/dependabot.yml"
34
47
  - ".github/workflows/ci.yml"
35
48
  - ".gitignore"
36
49
  - ".rspec"
@@ -53,7 +66,6 @@ licenses:
53
66
  - MIT
54
67
  metadata:
55
68
  rubygems_mfa_required: 'true'
56
- post_install_message:
57
69
  rdoc_options: []
58
70
  require_paths:
59
71
  - lib
@@ -61,15 +73,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
61
73
  requirements:
62
74
  - - ">="
63
75
  - !ruby/object:Gem::Version
64
- version: '0'
76
+ version: 3.1.0
65
77
  required_rubygems_version: !ruby/object:Gem::Requirement
66
78
  requirements:
67
79
  - - ">="
68
80
  - !ruby/object:Gem::Version
69
81
  version: '0'
70
82
  requirements: []
71
- rubygems_version: 3.2.28
72
- signing_key:
83
+ rubygems_version: 4.0.9
73
84
  specification_version: 4
74
85
  summary: Excel parsing and generation with the ease of CSV.
75
86
  test_files: []