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 +4 -4
- data/.github/workflows/test.yml +5 -1
- data/.gitignore +3 -0
- data/.octocov.yml +28 -0
- data/CHANGELOG.md +7 -0
- data/Gemfile +4 -2
- data/examples/comment_options.rb +39 -0
- data/fast_excel.gemspec +3 -2
- data/lib/fast_excel/binding/workbook.rb +44 -6
- data/lib/fast_excel/binding/worksheet.rb +26 -2
- data/lib/fast_excel/binding.rb +100 -0
- data/lib/fast_excel.rb +13 -12
- data/sonar-project.properties +4 -0
- data/test/color_to_hex_test.rb +15 -0
- data/test/comment_opt_test.rb +76 -0
- data/test/date_test.rb +14 -0
- data/test/format_test.rb +5 -1
- data/test/get_worksheet_test.rb +28 -0
- data/test/test_helper.rb +7 -4
- data/test/tmpdir_test.rb +32 -0
- data/test/validations_test.rb +22 -16
- metadata +32 -9
- data/test/reopen_test.rb +0 -22
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f3735cb9c55d31df98975baa51a0547f67ca33fb1519b7bbd986af3ea9d78658
|
|
4
|
+
data.tar.gz: 9e79dcc1be146f889e86f373d87959754b1ffbfb4a617cbf363db04652fbfc45
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b91c2d94389477e2aa48ecf5354783c5ad4d003f20646e1ee9265a2d79ff88c66811465755b9dd62f32691d3caab4f4fb04c708722da4cc41b70b7de29f2167b
|
|
7
|
+
data.tar.gz: f84e5a0db01a38502b1325ec019725ada1ab87700d79ecfded77570d495da12b533387e963439bde75b93b9168cf6e899e16091bf2bf4c024d621ca2ede250c9
|
data/.github/workflows/test.yml
CHANGED
|
@@ -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,
|
|
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
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 '
|
|
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.
|
|
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.
|
|
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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
data/lib/fast_excel/binding.rb
CHANGED
|
@@ -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(
|
|
338
|
-
|
|
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
|
-
|
|
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(
|
|
547
|
+
autofilter(0, start_col, @last_row_number, end_col)
|
|
547
548
|
end
|
|
548
549
|
|
|
549
550
|
def close
|
|
@@ -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
|
-
|
|
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
|
)
|
data/test/tmpdir_test.rb
ADDED
|
@@ -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
|
data/test/validations_test.rb
CHANGED
|
@@ -2,12 +2,14 @@ require_relative 'test_helper'
|
|
|
2
2
|
|
|
3
3
|
describe "FastExcel validations" do
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
workbook = FastExcel.open(constant_memory: true)
|
|
5
|
+
before do
|
|
6
|
+
@workbook = FastExcel.open(constant_memory: true)
|
|
7
|
+
end
|
|
7
8
|
|
|
8
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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:
|
|
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.
|
|
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.
|
|
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/
|
|
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:
|
|
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
|