fast_excel 0.5.0 → 0.6.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: 792a2afe9492aeeaba9fbb65da941d2b604a2fd14bf934b17662fdf05281ac32
4
- data.tar.gz: 11795006b99d4fc9403fd3f85ab6babff417b1ed49341a2081073852063d2a71
3
+ metadata.gz: f3735cb9c55d31df98975baa51a0547f67ca33fb1519b7bbd986af3ea9d78658
4
+ data.tar.gz: 9e79dcc1be146f889e86f373d87959754b1ffbfb4a617cbf363db04652fbfc45
5
5
  SHA512:
6
- metadata.gz: 7215d937426efb2580ba947c727a60a519fb411a5504eb58162a1646057bd191812eae00394ac9c915a9f7f53a6acf6cfff66e4d773a8ac579bb3494164c3292
7
- data.tar.gz: 9f381f209a7d4f7c22a0994ed241b2be0a67d994c400f7867529fa1fa95fbc6326189a9dc53588f0bfbc376933ffab6fee4eaee37f7ac57d6a4f68a66295c8cc
6
+ metadata.gz: b91c2d94389477e2aa48ecf5354783c5ad4d003f20646e1ee9265a2d79ff88c66811465755b9dd62f32691d3caab4f4fb04c708722da4cc41b70b7de29f2167b
7
+ data.tar.gz: f84e5a0db01a38502b1325ec019725ada1ab87700d79ecfded77570d495da12b533387e963439bde75b93b9168cf6e899e16091bf2bf4c024d621ca2ede250c9
@@ -8,7 +8,7 @@ jobs:
8
8
  fail-fast: false
9
9
  matrix:
10
10
  os: [ubuntu-latest, macos-latest, windows-latest]
11
- ruby: [2.7, '3.0', 3.1, 3.2, 3.3]
11
+ ruby: [2.7, 3.1, 3.3, 3.4]
12
12
 
13
13
  runs-on: ${{ matrix.os }}
14
14
 
@@ -26,3 +26,7 @@ jobs:
26
26
  - run: rake test
27
27
  - run: rake examples
28
28
  - run: gem build fast_excel.gemspec
29
+
30
+ - name: Coverage Report by octocov
31
+ if: ${{ matrix.os == 'ubuntu-latest' && matrix.ruby == '3.4' }}
32
+ uses: k1LoW/octocov-action@v1
data/.gitignore CHANGED
@@ -20,3 +20,6 @@ ext/fast_excel/Makefile
20
20
  ext/fast_excel/text_width_ext.bundle
21
21
  Gemfile.lock
22
22
  lib/libxlsxwriter.dylib
23
+ coverage/
24
+ *.so
25
+ *.time
data/.octocov.yml ADDED
@@ -0,0 +1,28 @@
1
+ coverage:
2
+ paths:
3
+ - coverage/.resultset.json
4
+ codeToTestRatio:
5
+ code:
6
+ - '**/*.rb'
7
+ - '!test/**/*.rb'
8
+ test:
9
+ - 'test/**/*_test.rb'
10
+ testExecutionTime:
11
+ if: true
12
+ diff:
13
+ datastores:
14
+ - artifact://${GITHUB_REPOSITORY}
15
+ comment:
16
+ if: false
17
+ body:
18
+ if: true
19
+ #comment:
20
+ # if: is_pull_request
21
+ # deletePrevious: true
22
+ report:
23
+ if: is_default_branch
24
+ datastores:
25
+ - artifact://${GITHUB_REPOSITORY}
26
+ timeout: 5min
27
+ summary:
28
+ if: true
data/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ #### Version 0.6.0 - 19 oct 2026
2
+
3
+ * Fix segfault in `workbook#get_worksheet_by_name` when sheet does not exist (Thanks to @amberstarlight)
4
+ * Add support for `worksheet_write_comment_opt` with styled comments and hash options (Thanks to @ololoshka12345)
5
+ * Respect current environment's temp directory and add `tmpdir:` option to `FastExcel.open` (Thanks to @spyderdfx)
6
+ * Add tests for `FastExcel.lxw_time`, `color_to_hex`, and pretty print improvements
7
+
1
8
  #### Version 0.5.0 - 02 jan 2024
2
9
 
3
10
  * Support ruby 3.3
data/Gemfile CHANGED
@@ -5,13 +5,15 @@ gemspec
5
5
  gem 'rake'
6
6
 
7
7
  gem 'roo'
8
+ gem 'csv'
9
+ gem 'bigdecimal'
8
10
 
11
+ gem 'simplecov', require: false
9
12
  gem 'minitest'
10
13
  gem 'minitest-reporters'
11
14
 
12
-
13
15
  group :benchmarks do
14
- gem 'axlsx', git: 'https://github.com/randym/axlsx.git'
16
+ gem 'caxlsx', git: 'https://github.com/caxlsx/caxlsx'
15
17
  gem 'write_xlsx'
16
18
  gem 'xlsxtream'
17
19
  gem 'benchmark-ips'
@@ -0,0 +1,39 @@
1
+ require_relative '../lib/fast_excel'
2
+
3
+ workbook = FastExcel.open('comment_options.xlsx', constant_memory: true)
4
+ worksheet = workbook.add_worksheet('Comment Options')
5
+
6
+ worksheet.write_value(0, 0, 'Cell with basic comment')
7
+ worksheet.write_comment(0, 0, 'Very basic comment.')
8
+
9
+ options = Libxlsxwriter::CommentOptions.new
10
+ options.author = 'Lol'
11
+ options.visible = 1
12
+
13
+ worksheet.write_value(2, 0, 'Cell with visible comment and custom author')
14
+ worksheet.write_comment_opt(2, 0, 'This comment is visible and has a custom author', options)
15
+
16
+ options = Libxlsxwriter::CommentOptions.new
17
+ options.author = 'Kek'
18
+ options.width = 250
19
+ options.height = 100
20
+ options.color = '#FF0000'
21
+ options.font_name = 'Courier New'
22
+ options.font_size = 10.0
23
+ options.visible = 1
24
+
25
+ worksheet.write_value(5, 0, 'Cell with styled comment')
26
+ worksheet.write_comment_opt(5, 0, 'If a song plants an idea or a feeling in a mind, it has already changed the world.', options)
27
+
28
+ options = Libxlsxwriter::CommentOptions.new
29
+ options.start_row = 10
30
+ options.start_col = 2
31
+ options.x_offset = 20
32
+ options.y_offset = 20
33
+ options.visible = 1
34
+
35
+ worksheet.write_value(10, 0, 'Cell with repositioned comment')
36
+ worksheet.write_comment_opt(10, 0, 'This comment is positioned away from the cell.', options)
37
+
38
+ workbook.close
39
+ puts 'Saved to file comment_options.xlsx'
data/fast_excel.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "fast_excel"
3
- s.version = "0.5.0"
3
+ s.version = "0.6.0"
4
4
  s.author = ["Pavel Evstigneev"]
5
5
  s.email = ["pavel.evst@gmail.com"]
6
6
  s.homepage = "https://github.com/paxa/fast_excel"
@@ -15,5 +15,6 @@ Gem::Specification.new do |s|
15
15
  s.require_paths = ["lib"]
16
16
  s.extensions = ["extconf.rb"]
17
17
 
18
- s.add_runtime_dependency "ffi", ["> 1.9", "< 2"]
18
+ s.add_runtime_dependency "ffi", ["> 1.17", "< 2"]
19
+ s.add_runtime_dependency "base64", [">= 0.2", "< 2"]
19
20
  end
@@ -1,15 +1,52 @@
1
1
  module Libxlsxwriter
2
+ # Data converters
3
+ module UTF8StringPointer
4
+ extend FFI::DataConverter
5
+ native_type FFI::Type::POINTER
6
+
7
+ class << self
8
+ # Given either a String or nil, make an actual FFI::Pointer
9
+ # of that value.
10
+ #
11
+ # @param [#to_str, nil] value
12
+ # @param ctx
13
+ # @return [FFI::Pointer]
14
+ def to_native(value, ctx)
15
+ value && FFI::MemoryPointer.from_string(value.to_str.encode(Encoding::UTF_8))
16
+ end
17
+
18
+ # Given a pointer, read out it’s string.
19
+ #
20
+ # @param [FFI::Pointer] value
21
+ # @param ctx
22
+ # @return [String, nil]
23
+ def from_native(value, ctx)
24
+ value.read_string.force_encoding(Encoding::UTF_8) unless value.null?
25
+ end
26
+
27
+ # Used by FFI::StructLayoutField to know if this field
28
+ # requires the reference to be maintained by FFI. If we
29
+ # return false here, the MemoryPointer from to_native
30
+ # will be garbage collected before the struct.
31
+ def reference_required?
32
+ true
33
+ end
34
+ end
35
+ end
36
+
2
37
  # = Fields:
3
38
  # :constant_memory ::
4
39
  # (Integer) Optimize the workbook to use constant memory for worksheets
5
40
  # :tmpdir ::
6
41
  # (String) Directory to use for the temporary files created by libxlsxwriter.
7
42
  class WorkbookOptions < FFI::Struct
8
- layout :constant_memory, :uchar,
9
- :tmpdir, :string,
10
- :use_zip64, :uchar,
11
- :output_buffer, :pointer,
12
- :output_buffer_size, :pointer
43
+ conf = {}
44
+ conf[:constant_memory] = :uchar
45
+ conf[:tmpdir] = UTF8StringPointer
46
+ conf[:use_zip64] = :uchar
47
+ conf[:output_buffer] = :pointer
48
+ conf[:output_buffer_size] = :pointer
49
+ layout(conf)
13
50
  end
14
51
 
15
52
  # = Fields:
@@ -143,7 +180,8 @@ module Libxlsxwriter
143
180
  # @param [String] name
144
181
  # @return [Worksheet]
145
182
  def get_worksheet_by_name(name)
146
- Worksheet.new Libxlsxwriter.workbook_get_worksheet_by_name(self, name)
183
+ ptr = Libxlsxwriter.workbook_get_worksheet_by_name(self, name)
184
+ ptr.null? ? nil : Worksheet.new(ptr)
147
185
  end
148
186
 
149
187
  # @param [String] sheetname
@@ -210,8 +210,22 @@ module Libxlsxwriter
210
210
  Libxlsxwriter.worksheet_write_string(self, row, col, string, format)
211
211
  end
212
212
 
213
- def write_comment(row, col, string)
214
- Libxlsxwriter.worksheet_write_comment(self, row, col, string)
213
+ def write_comment(row, col, string, options = nil)
214
+ if options
215
+ write_comment_opt(row, col, string, options)
216
+ else
217
+ Libxlsxwriter.worksheet_write_comment(self, row, col, string)
218
+ end
219
+ end
220
+
221
+ # @param [Integer] row
222
+ # @param [Integer] col
223
+ # @param [String] string
224
+ # @param [CommentOptions, Hash] options
225
+ # @return [Symbol from _enum_error_]
226
+ def write_comment_opt(row, col, string, options)
227
+ options = Libxlsxwriter::CommentOptions.new(options) if options.is_a?(Hash)
228
+ Libxlsxwriter.worksheet_write_comment_opt(self, row, col, string, options)
215
229
  end
216
230
 
217
231
  # @param [Integer] row
@@ -1032,6 +1046,16 @@ module Libxlsxwriter
1032
1046
 
1033
1047
  attach_function :worksheet_write_comment, :worksheet_write_comment, [Worksheet, :uint32, :ushort, :string], :error
1034
1048
 
1049
+ # @method worksheet_write_comment_opt(worksheet, row, col, string, options)
1050
+ # @param [Worksheet] worksheet
1051
+ # @param [Integer] row
1052
+ # @param [Integer] col
1053
+ # @param [String] string
1054
+ # @param [CommentOptions] options
1055
+ # @return [Symbol from _enum_error_]
1056
+ # @scope class
1057
+ attach_function :worksheet_write_comment_opt, :worksheet_write_comment_opt, [Worksheet, :uint32, :ushort, :string, CommentOptions], :error
1058
+
1035
1059
  # @method worksheet_write_formula(worksheet, row, col, formula, format)
1036
1060
  # @param [Worksheet] worksheet
1037
1061
  # @param [Integer] row
@@ -1153,6 +1153,106 @@ module Libxlsxwriter
1153
1153
  :collapsed, :uchar
1154
1154
  end
1155
1155
 
1156
+ # = Fields:
1157
+ # :visible ::
1158
+ # (Integer) Make the comment visible.
1159
+ # :author ::
1160
+ # (String) Author of the comment.
1161
+ # :width ::
1162
+ # (Integer) Width of the comment box.
1163
+ # :height ::
1164
+ # (Integer) Height of the comment box.
1165
+ # :x_scale ::
1166
+ # (Float) X scale of the comment.
1167
+ # :y_scale ::
1168
+ # (Float) Y scale of the comment.
1169
+ # :color ::
1170
+ # (Integer) Background color of the comment box.
1171
+ # :font_name ::
1172
+ # (String) Font name for the comment.
1173
+ # :font_size ::
1174
+ # (Float) Font size for the comment.
1175
+ # :font_family ::
1176
+ # (Integer) Font family for the comment.
1177
+ # :start_row ::
1178
+ # (Integer) Start row for the comment box.
1179
+ # :start_col ::
1180
+ # (Integer) Start column for the comment box.
1181
+ # :x_offset ::
1182
+ # (Integer) X offset for the comment box.
1183
+ # :y_offset ::
1184
+ # (Integer) Y offset for the comment box.
1185
+ class CommentOptions < FFI::Struct
1186
+ layout :visible, :uchar,
1187
+ :author, :pointer,
1188
+ :width, :ushort,
1189
+ :height, :ushort,
1190
+ :x_scale, :double,
1191
+ :y_scale, :double,
1192
+ :color, :uint32,
1193
+ :font_name, :pointer,
1194
+ :font_size, :double,
1195
+ :font_family, :uchar,
1196
+ :start_row, :uint32,
1197
+ :start_col, :ushort,
1198
+ :x_offset, :int32,
1199
+ :y_offset, :int32
1200
+
1201
+ def initialize(*args)
1202
+ if args.first.is_a?(Hash)
1203
+ super()
1204
+ @pointers = {}
1205
+ set(args.first)
1206
+ else
1207
+ super(*args)
1208
+ @pointers = {}
1209
+ end
1210
+ end
1211
+
1212
+ def set(options)
1213
+ options.each do |k, v|
1214
+ send("#{k}=", v) if respond_to?("#{k}=")
1215
+ end
1216
+ self
1217
+ end
1218
+
1219
+ [:visible, :width, :height, :x_scale, :y_scale, :font_size, :font_family, :start_row, :start_col, :x_offset, :y_offset].each do |prop|
1220
+ define_method(prop) do
1221
+ self[prop]
1222
+ end
1223
+ define_method("#{prop}=") do |value|
1224
+ self[prop] = value
1225
+ end
1226
+ end
1227
+
1228
+ [:author, :font_name].each do |prop|
1229
+ define_method(prop) do
1230
+ ptr = self[prop]
1231
+ ptr.read_string unless ptr.null?
1232
+ end
1233
+
1234
+ define_method("#{prop}=") do |value|
1235
+ @pointers ||= {}
1236
+ if value.nil?
1237
+ @pointers.delete(prop)
1238
+ self[prop] = nil
1239
+ else
1240
+ ptr = FFI::MemoryPointer.from_string(value.to_s)
1241
+ @pointers[prop] = ptr
1242
+ self[prop] = ptr
1243
+ end
1244
+ end
1245
+ end
1246
+
1247
+ def color
1248
+ self[:color]
1249
+ end
1250
+
1251
+ def color=(value)
1252
+ self[:color] = FastExcel.color_to_hex(value)
1253
+ end
1254
+ end
1255
+
1156
1256
  require_relative 'binding/format'
1157
1257
 
1158
1258
  #
data/lib/fast_excel.rb CHANGED
@@ -1,8 +1,6 @@
1
1
  require_relative './fast_excel/binding'
2
2
  require 'set'
3
-
4
- # not used for now
5
- #require_relative '../ext/fast_excel/text_width_ext'
3
+ require 'tmpdir'
6
4
 
7
5
  module FastExcel
8
6
 
@@ -22,14 +20,13 @@ module FastExcel
22
20
 
23
21
  DEF_COL_WIDTH = 8.43
24
22
 
25
- def self.open(filename = nil, constant_memory: false, default_format: nil)
23
+ def self.open(filename = nil, constant_memory: false, default_format: nil, tmpdir: nil)
26
24
  tmp_file = false
27
25
  if filename
28
26
  if File.exist?(filename) && File.size(filename) > 0
29
27
  raise ArgumentError, "File '#{filename}' already exists. FastExcel can not open existing files, only create new files"
30
28
  end
31
29
  else
32
- require 'tmpdir'
33
30
  filename = "#{Dir.mktmpdir}/fast_excel.xlsx"
34
31
  tmp_file = true
35
32
  end
@@ -38,6 +35,7 @@ module FastExcel
38
35
 
39
36
  opt = Libxlsxwriter::WorkbookOptions.new
40
37
  opt[:constant_memory] = constant_memory ? 1 : 0
38
+ opt[:tmpdir] = tmpdir || Dir.tmpdir
41
39
  workbook = Libxlsxwriter.workbook_new_opt(filename, opt)
42
40
 
43
41
  result = Libxlsxwriter::Workbook.new(workbook)
@@ -295,8 +293,8 @@ module FastExcel
295
293
  return EXTRA_COLORS[value.to_sym]
296
294
  elsif COLOR_ENUM.find(value.to_sym)
297
295
  return COLOR_ENUM.find(value.to_sym)
298
- elsif COLOR_ENUM.find("color_#{value.to_sym}")
299
- return COLOR_ENUM.find("color_#{value.to_sym}")
296
+ elsif COLOR_ENUM.find("color_#{value}".to_sym)
297
+ return COLOR_ENUM.find("color_#{value}".to_sym)
300
298
  elsif value =~ /^#?(0x)?([\da-f]){6}$/i
301
299
  value = value.sub('#', '') if value.start_with?('#')
302
300
  return value.start_with?('0x') ? value.to_i(16) : "0x#{value}".to_i(16)
@@ -334,8 +332,8 @@ module FastExcel
334
332
  res
335
333
  end
336
334
 
337
- def pretty_print(pp)
338
- pp fields_hash
335
+ def pretty_print(pp_obj)
336
+ fields_hash.pretty_print(pp_obj)
339
337
  end
340
338
  end
341
339
 
@@ -390,9 +388,12 @@ module FastExcel
390
388
  end
391
389
 
392
390
  def get_worksheet_by_name(name)
393
- sheet = super(name)
394
- sheet.workbook = self
391
+ return nil if name.nil? || !@sheet_names.include?(name.to_s)
395
392
 
393
+ sheet = super(name.to_s)
394
+ return nil if sheet.nil?
395
+
396
+ sheet.workbook = self
396
397
  sheet
397
398
  end
398
399
 
@@ -543,7 +544,7 @@ module FastExcel
543
544
  end
544
545
 
545
546
  def enable_filters!(start_col: 0, end_col:)
546
- autofilter(start_col, 0, @last_row_number, end_col)
547
+ autofilter(0, start_col, @last_row_number, end_col)
547
548
  end
548
549
 
549
550
  def close
@@ -0,0 +1,4 @@
1
+ sonar.sources=.
2
+ sonar.language=ruby
3
+ sonar.ruby.coverage.reportPaths=coverage/.resultset.json
4
+ sonar.exclusions=**/*_test.rb,**/coverage/**
@@ -0,0 +1,15 @@
1
+ require_relative 'test_helper'
2
+
3
+ describe "FastExcel.color_to_hex" do
4
+ it "should convert hex number color to hex" do
5
+ assert_equal(FastExcel.color_to_hex(0xFF0000), 0xFF0000)
6
+ end
7
+
8
+ it "should convert color name to hex" do
9
+ assert_equal(FastExcel.color_to_hex("color_lime"), 0x00FF00)
10
+ end
11
+
12
+ it "should convert color name (extra colors) to hex" do
13
+ assert_equal(FastExcel.color_to_hex("steel_blue"), 0x4682B4)
14
+ end
15
+ end
@@ -0,0 +1,76 @@
1
+ require_relative 'test_helper'
2
+
3
+ describe 'FastExcel::Worksheet write_comment_opt' do
4
+ let(:workbook) { FastExcel.open(constant_memory: true) }
5
+ let(:worksheet) { workbook.add_worksheet }
6
+ let(:options) do
7
+ Libxlsxwriter::CommentOptions.new.tap do |opts|
8
+ opts.author = 'Lolo'
9
+ opts.visible = 1
10
+ opts.width = 200
11
+ opts.height = 100
12
+ opts.x_scale = 1.5
13
+ opts.y_scale = 1.5
14
+ opts.color = '0xFFFF00'
15
+ opts.font_name = 'Arial'
16
+ opts.font_size = 12.0
17
+ opts.font_family = 2
18
+ opts.start_row = 0
19
+ opts.start_col = 1
20
+ opts.x_offset = 10
21
+ opts.y_offset = 10
22
+ end
23
+ end
24
+
25
+ it 'should write a comment with options struct' do
26
+ assert_equal(:no_error, worksheet.write_comment_opt(0, 0, 'Hello with options', options))
27
+ end
28
+
29
+ it 'should write a comment with hash options' do
30
+ assert_equal(:no_error, worksheet.write_comment_opt(1, 0, 'Comment via hash', author: 'Author1', visible: 1, color: '#FF0000'))
31
+ end
32
+
33
+ it 'should write a comment using write_comment with optional options' do
34
+ assert_equal(:no_error, worksheet.write_comment(2, 0, 'Simple comment'))
35
+ assert_equal(:no_error, worksheet.write_comment(3, 0, 'Comment with hash', author: 'Alice', color: 'lime'))
36
+ end
37
+
38
+ it 'handles nil author and font_name safely' do
39
+ opts = Libxlsxwriter::CommentOptions.new
40
+ opts.author = nil
41
+ opts.font_name = nil
42
+ assert_nil opts.author
43
+ assert_nil opts.font_name
44
+
45
+ opts.author = 'Bob'
46
+ assert_equal 'Bob', opts.author
47
+ opts.author = nil
48
+ assert_nil opts.author
49
+ end
50
+
51
+ it 'preserves string pointers across garbage collection' do
52
+ opts = Libxlsxwriter::CommentOptions.new(author: "Temporary #{rand} Author", font_name: 'Courier New')
53
+ # Run full GC cycles to ensure MemoryPointer is not collected prematurely
54
+ 10.times { GC.start }
55
+
56
+ assert opts.author.start_with?('Temporary')
57
+ assert_equal 'Courier New', opts.font_name
58
+ assert_equal :no_error, worksheet.write_comment_opt(4, 0, 'GC test comment', opts)
59
+ end
60
+
61
+ it 'generates a valid excel file with styled comments' do
62
+ temp_file = File.join(Dir.tmpdir, "test_comments_#{Time.now.to_i}.xlsx")
63
+ begin
64
+ wb = FastExcel.open(temp_file)
65
+ ws = wb.add_worksheet
66
+ ws.write_value(0, 0, 'Data')
67
+ ws.write_comment(0, 0, 'Styled comment', author: 'Tester', visible: 1, color: 'yellow', font_name: 'Arial')
68
+ wb.close
69
+
70
+ assert File.exist?(temp_file)
71
+ assert File.size(temp_file) > 0
72
+ ensure
73
+ File.delete(temp_file) if File.exist?(temp_file)
74
+ end
75
+ end
76
+ end
data/test/date_test.rb CHANGED
@@ -54,3 +54,17 @@ describe "FastExcel.write_value" do
54
54
  end
55
55
 
56
56
  end
57
+
58
+ describe "FastExcel.lxw_time" do
59
+ it "should make Libxlsxwriter::Datetime" do
60
+ time = Time.at(610421163).utc
61
+ lxw_time = FastExcel.lxw_time(time)
62
+
63
+ assert_equal(lxw_time[:year], 1989)
64
+ assert_equal(lxw_time[:month], 5)
65
+ assert_equal(lxw_time[:day], 6)
66
+ assert_equal(lxw_time[:hour], 1)
67
+ assert_equal(lxw_time[:min], 26)
68
+ assert_equal(lxw_time[:sec], 3.0)
69
+ end
70
+ end
data/test/format_test.rb CHANGED
@@ -112,7 +112,11 @@ describe "FastExcel::FormatExt colors" do
112
112
  @format.font_color = {aaa: 1}
113
113
  end
114
114
 
115
- assert_equal(error.message, "Can not use Hash ({:aaa=>1}) for color value, expected String or Hex Number")
115
+ if error.message =~ /=>/
116
+ assert_equal(error.message, "Can not use Hash ({:aaa=>1}) for color value, expected String or Hex Number")
117
+ else
118
+ assert_equal(error.message, "Can not use Hash ({aaa: 1}) for color value, expected String or Hex Number")
119
+ end
116
120
  end
117
121
 
118
122
  it "should raise for unexpected color" do
@@ -0,0 +1,28 @@
1
+ require_relative 'test_helper'
2
+
3
+ describe "FastExcel::Worksheet" do
4
+ before do
5
+ @workbook = FastExcel.open(constant_memory: true)
6
+ end
7
+
8
+ describe "#get_worksheet_by_name" do
9
+ it "should return nil if worksheet does not exist" do
10
+ ws = @workbook.get_worksheet_by_name("Page1")
11
+ assert_nil(ws)
12
+
13
+ assert_nil(@workbook.get_worksheet_by_name(nil))
14
+ assert_nil(@workbook.get_worksheet_by_name(:Page1))
15
+ end
16
+
17
+ it "should return worksheet if worksheet does exist" do
18
+ @workbook.add_worksheet("Page1")
19
+
20
+ ws = @workbook.get_worksheet_by_name("Page1")
21
+ ws.write_row(0, ['1'])
22
+ assert_kind_of(Libxlsxwriter::Worksheet, ws)
23
+
24
+ ws_by_sym = @workbook.get_worksheet_by_name(:Page1)
25
+ assert_kind_of(Libxlsxwriter::Worksheet, ws_by_sym)
26
+ end
27
+ end
28
+ end
data/test/test_helper.rb CHANGED
@@ -1,13 +1,16 @@
1
+ require "simplecov"
2
+
3
+ SimpleCov.start do
4
+ add_filter 'test'
5
+ end
6
+
1
7
  require 'bundler/setup'
2
8
  require 'minitest/autorun'
3
9
  require "minitest/reporters"
4
10
  require 'pp'
5
-
6
- ##Encoding.default_external = Encoding::UTF_8
7
- ##Encoding.default_internal = Encoding::UTF_8
8
-
9
11
  require 'date'
10
12
 
13
+
11
14
  Minitest::Reporters.use!(
12
15
  Minitest::Reporters::DefaultReporter.new(color: true)
13
16
  )
@@ -0,0 +1,32 @@
1
+ require_relative 'test_helper'
2
+ require 'tmpdir'
3
+
4
+ describe "FastExcel tmpdir option" do
5
+ it "uses system Dir.tmpdir by default without creating extra temp directories" do
6
+ temp_file = File.join(Dir.tmpdir, "test_default_tmpdir_#{Time.now.to_i}.xlsx")
7
+ begin
8
+ wb = FastExcel.open(temp_file, constant_memory: true)
9
+ ws = wb.add_worksheet
10
+ ws.append_row(["test", 123])
11
+ wb.close
12
+
13
+ assert File.exist?(temp_file)
14
+ assert File.size(temp_file) > 0
15
+ ensure
16
+ File.delete(temp_file) if File.exist?(temp_file)
17
+ end
18
+ end
19
+
20
+ it "accepts custom tmpdir option" do
21
+ Dir.mktmpdir do |custom_tmp|
22
+ temp_file = File.join(custom_tmp, "test_custom_tmpdir.xlsx")
23
+ wb = FastExcel.open(temp_file, constant_memory: true, tmpdir: custom_tmp)
24
+ ws = wb.add_worksheet
25
+ ws.append_row(["hello", "world"])
26
+ wb.close
27
+
28
+ assert File.exist?(temp_file)
29
+ assert File.size(temp_file) > 0
30
+ end
31
+ end
32
+ end
@@ -2,12 +2,14 @@ require_relative 'test_helper'
2
2
 
3
3
  describe "FastExcel validations" do
4
4
 
5
- it "should raise error when duplicate sheet name" do
6
- workbook = FastExcel.open(constant_memory: true)
5
+ before do
6
+ @workbook = FastExcel.open(constant_memory: true)
7
+ end
7
8
 
8
- workbook.add_worksheet("Payments Report")
9
+ it "should raise error when duplicate sheet name" do
10
+ @workbook.add_worksheet("Payments Report")
9
11
  error = assert_raises do
10
- workbook.add_worksheet("Payments Report")
12
+ @workbook.add_worksheet("Payments Report")
11
13
  end
12
14
 
13
15
  assert_equal(ArgumentError, error.class)
@@ -15,10 +17,8 @@ describe "FastExcel validations" do
15
17
  end
16
18
 
17
19
  it "should not raise error when worksheet name is null" do
18
- workbook = FastExcel.open(constant_memory: true)
19
-
20
- ws1 = workbook.add_worksheet()
21
- ws2 = workbook.add_worksheet()
20
+ ws1 = @workbook.add_worksheet()
21
+ ws2 = @workbook.add_worksheet()
22
22
  ws2.write_value(0, 2, "aaa")
23
23
 
24
24
  assert_equal("Sheet1", ws1[:name])
@@ -26,10 +26,8 @@ describe "FastExcel validations" do
26
26
  end
27
27
 
28
28
  it "should raise error when the sheet name exceeds maximum length" do
29
- workbook = FastExcel.open(constant_memory: true)
30
-
31
29
  error = assert_raises do
32
- workbook.add_worksheet("ABCDEFGHIJKLMNOPQRSTUVWXYZ012345")
30
+ @workbook.add_worksheet("ABCDEFGHIJKLMNOPQRSTUVWXYZ012345")
33
31
  end
34
32
 
35
33
  assert_equal(ArgumentError, error.class)
@@ -37,22 +35,30 @@ describe "FastExcel validations" do
37
35
  end
38
36
 
39
37
  it "should not raise error when the sheet name is at maximum length" do
40
- workbook = FastExcel.open(constant_memory: true)
41
-
42
- worksheet = workbook.add_worksheet("ABCDEFGHIJKLMNOPQRSTUVWXYZ01234")
38
+ worksheet = @workbook.add_worksheet("ABCDEFGHIJKLMNOPQRSTUVWXYZ01234")
43
39
  worksheet.append_row(["aaa", "bbb", "ccc"])
44
40
 
45
41
  assert_equal("ABCDEFGHIJKLMNOPQRSTUVWXYZ01234", worksheet[:name])
46
42
  end
47
43
 
48
44
  it "should validate using Libxlsxwriter validation" do
49
- workbook = FastExcel.open(constant_memory: true)
50
45
  error = assert_raises do
51
- worksheet = workbook.add_worksheet('a?')
46
+ worksheet = @workbook.add_worksheet('a?')
52
47
  worksheet.write_value(1, 1, 'a') # without the validation, this method will crash the process
53
48
  end
54
49
 
55
50
  assert_equal(ArgumentError, error.class)
56
51
  assert_equal("Invalid worksheet name 'a?': (15 - error_invalid_sheetname_character) Worksheet name cannot contain invalid characters: '[ ] : * ? / \\'", error.message)
57
52
  end
53
+
54
+ it "should raise error when reopening workbook" do
55
+ @workbook.close
56
+
57
+ error = assert_raises do
58
+ FastExcel.open(@workbook.filename, constant_memory: true)
59
+ end
60
+
61
+ assert_equal(error.class, ArgumentError)
62
+ assert_equal(error.message, "File '#{@workbook.filename}' already exists. FastExcel can not open existing files, only create new files")
63
+ end
58
64
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fast_excel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pavel Evstigneev
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-01-01 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: ffi
@@ -16,7 +15,7 @@ dependencies:
16
15
  requirements:
17
16
  - - ">"
18
17
  - !ruby/object:Gem::Version
19
- version: '1.9'
18
+ version: '1.17'
20
19
  - - "<"
21
20
  - !ruby/object:Gem::Version
22
21
  version: '2'
@@ -26,7 +25,27 @@ dependencies:
26
25
  requirements:
27
26
  - - ">"
28
27
  - !ruby/object:Gem::Version
29
- version: '1.9'
28
+ version: '1.17'
29
+ - - "<"
30
+ - !ruby/object:Gem::Version
31
+ version: '2'
32
+ - !ruby/object:Gem::Dependency
33
+ name: base64
34
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: '0.2'
39
+ - - "<"
40
+ - !ruby/object:Gem::Version
41
+ version: '2'
42
+ type: :runtime
43
+ prerelease: false
44
+ version_requirements: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0.2'
30
49
  - - "<"
31
50
  - !ruby/object:Gem::Version
32
51
  version: '2'
@@ -41,6 +60,7 @@ files:
41
60
  - ".dockerignore"
42
61
  - ".github/workflows/test.yml"
43
62
  - ".gitignore"
63
+ - ".octocov.yml"
44
64
  - CHANGELOG.md
45
65
  - Dockerfile.test
46
66
  - Gemfile
@@ -55,6 +75,7 @@ files:
55
75
  - benchmarks/memory.rb
56
76
  - benchmarks/profiler.rb
57
77
  - benchmarks/write_value.rb
78
+ - examples/comment_options.rb
58
79
  - examples/example.rb
59
80
  - examples/example_align.rb
60
81
  - examples/example_auto_width.rb
@@ -194,12 +215,16 @@ files:
194
215
  - libxlsxwriter/third_party/tmpfileplus/tmpfileplus.c
195
216
  - libxlsxwriter/third_party/tmpfileplus/tmpfileplus.h
196
217
  - libxlsxwriter/version.txt
218
+ - sonar-project.properties
197
219
  - test/auto_width_test.rb
220
+ - test/color_to_hex_test.rb
221
+ - test/comment_opt_test.rb
198
222
  - test/date_test.rb
199
223
  - test/default_format_test.rb
200
224
  - test/format_test.rb
201
- - test/reopen_test.rb
225
+ - test/get_worksheet_test.rb
202
226
  - test/test_helper.rb
227
+ - test/tmpdir_test.rb
203
228
  - test/tmpfile_test.rb
204
229
  - test/validations_test.rb
205
230
  - test/worksheet_test.rb
@@ -207,7 +232,6 @@ homepage: https://github.com/paxa/fast_excel
207
232
  licenses:
208
233
  - MIT
209
234
  metadata: {}
210
- post_install_message:
211
235
  rdoc_options: []
212
236
  require_paths:
213
237
  - lib
@@ -222,8 +246,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
222
246
  - !ruby/object:Gem::Version
223
247
  version: '0'
224
248
  requirements: []
225
- rubygems_version: 3.5.3
226
- signing_key:
249
+ rubygems_version: 4.0.16
227
250
  specification_version: 4
228
251
  summary: Ultra Fast Excel Writer
229
252
  test_files: []
data/test/reopen_test.rb DELETED
@@ -1,22 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- describe "FastExcel::Worksheet" do
4
-
5
- it "should get_worksheet_by_name" do
6
- workbook = FastExcel.open(constant_memory: false)
7
- workbook.add_worksheet("Page1")
8
-
9
- ws = workbook.get_worksheet_by_name("Page1")
10
- ws.write_row(0, ['1'])
11
-
12
- workbook.close
13
-
14
- error = assert_raises do
15
- FastExcel.open(workbook.filename, constant_memory: false)
16
- end
17
-
18
- assert_equal(error.class, ArgumentError)
19
- assert_equal(error.message, "File '#{workbook.filename}' already exists. FastExcel can not open existing files, only create new files")
20
- end
21
-
22
- end