fast_excel 0.2.1 → 0.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.
Files changed (106) hide show
  1. checksums.yaml +5 -5
  2. data/.dockerignore +2 -0
  3. data/.gitignore +7 -0
  4. data/.travis.yml +44 -0
  5. data/CHANGELOG.md +41 -1
  6. data/Dockerfile.test +16 -0
  7. data/Gemfile +5 -2
  8. data/Gemfile.lock +30 -23
  9. data/LICENSE +21 -0
  10. data/Makefile +13 -0
  11. data/README.md +177 -40
  12. data/Rakefile +16 -0
  13. data/appveyor.yml +25 -0
  14. data/benchmarks/1k_rows.rb +17 -4
  15. data/benchmarks/20k_rows.rb +4 -0
  16. data/benchmarks/auto_width.rb +37 -0
  17. data/benchmarks/init.rb +14 -2
  18. data/benchmarks/memory.rb +8 -0
  19. data/benchmarks/profiler.rb +27 -0
  20. data/benchmarks/write_value.rb +62 -0
  21. data/examples/example.rb +3 -4
  22. data/examples/example_align.rb +23 -0
  23. data/examples/example_auto_width.rb +26 -0
  24. data/examples/example_colors.rb +37 -0
  25. data/examples/example_filters.rb +36 -0
  26. data/examples/example_formula.rb +1 -5
  27. data/examples/example_hyperlink.rb +20 -0
  28. data/examples/example_image.rb +1 -1
  29. data/examples/example_styles.rb +27 -0
  30. data/examples/logo.png +0 -0
  31. data/ext/fast_excel/extconf.rb +3 -0
  32. data/ext/fast_excel/text_width_ext.c +460 -0
  33. data/fast_excel.gemspec +2 -3
  34. data/letters.html +114 -0
  35. data/lib/fast_excel.rb +455 -78
  36. data/lib/fast_excel/binding.rb +31 -21
  37. data/lib/fast_excel/binding/chart.rb +20 -1
  38. data/lib/fast_excel/binding/format.rb +11 -4
  39. data/lib/fast_excel/binding/workbook.rb +10 -2
  40. data/lib/fast_excel/binding/worksheet.rb +44 -27
  41. data/libxlsxwriter/.gitignore +1 -0
  42. data/libxlsxwriter/.indent.pro +8 -0
  43. data/libxlsxwriter/.travis.yml +12 -0
  44. data/libxlsxwriter/CMakeLists.txt +338 -0
  45. data/libxlsxwriter/CONTRIBUTING.md +1 -1
  46. data/libxlsxwriter/Changes.txt +162 -0
  47. data/libxlsxwriter/LICENSE.txt +65 -4
  48. data/libxlsxwriter/Makefile +33 -11
  49. data/libxlsxwriter/Readme.md +3 -1
  50. data/libxlsxwriter/cocoapods/libxlsxwriter-umbrella.h +2 -1
  51. data/libxlsxwriter/cocoapods/libxlsxwriter.modulemap +2 -2
  52. data/libxlsxwriter/include/xlsxwriter.h +2 -2
  53. data/libxlsxwriter/include/xlsxwriter/app.h +2 -2
  54. data/libxlsxwriter/include/xlsxwriter/chart.h +164 -13
  55. data/libxlsxwriter/include/xlsxwriter/chartsheet.h +544 -0
  56. data/libxlsxwriter/include/xlsxwriter/common.h +35 -6
  57. data/libxlsxwriter/include/xlsxwriter/content_types.h +5 -2
  58. data/libxlsxwriter/include/xlsxwriter/core.h +2 -2
  59. data/libxlsxwriter/include/xlsxwriter/custom.h +2 -2
  60. data/libxlsxwriter/include/xlsxwriter/drawing.h +3 -2
  61. data/libxlsxwriter/include/xlsxwriter/format.h +8 -8
  62. data/libxlsxwriter/include/xlsxwriter/hash_table.h +1 -1
  63. data/libxlsxwriter/include/xlsxwriter/packager.h +18 -8
  64. data/libxlsxwriter/include/xlsxwriter/relationships.h +2 -2
  65. data/libxlsxwriter/include/xlsxwriter/shared_strings.h +5 -3
  66. data/libxlsxwriter/include/xlsxwriter/styles.h +10 -5
  67. data/libxlsxwriter/include/xlsxwriter/theme.h +2 -2
  68. data/libxlsxwriter/include/xlsxwriter/utility.h +35 -5
  69. data/libxlsxwriter/include/xlsxwriter/workbook.h +234 -57
  70. data/libxlsxwriter/include/xlsxwriter/worksheet.h +780 -91
  71. data/libxlsxwriter/include/xlsxwriter/xmlwriter.h +4 -2
  72. data/libxlsxwriter/libxlsxwriter.podspec +4 -2
  73. data/libxlsxwriter/src/Makefile +31 -6
  74. data/libxlsxwriter/src/app.c +2 -2
  75. data/libxlsxwriter/src/chart.c +116 -23
  76. data/libxlsxwriter/src/chartsheet.c +508 -0
  77. data/libxlsxwriter/src/content_types.c +12 -4
  78. data/libxlsxwriter/src/core.c +11 -11
  79. data/libxlsxwriter/src/custom.c +3 -3
  80. data/libxlsxwriter/src/drawing.c +114 -17
  81. data/libxlsxwriter/src/format.c +5 -5
  82. data/libxlsxwriter/src/hash_table.c +1 -1
  83. data/libxlsxwriter/src/packager.c +378 -61
  84. data/libxlsxwriter/src/relationships.c +2 -2
  85. data/libxlsxwriter/src/shared_strings.c +18 -4
  86. data/libxlsxwriter/src/styles.c +59 -12
  87. data/libxlsxwriter/src/theme.c +2 -2
  88. data/libxlsxwriter/src/utility.c +93 -6
  89. data/libxlsxwriter/src/workbook.c +379 -61
  90. data/libxlsxwriter/src/worksheet.c +1240 -174
  91. data/libxlsxwriter/src/xmlwriter.c +18 -9
  92. data/libxlsxwriter/third_party/minizip/Makefile +6 -1
  93. data/libxlsxwriter/third_party/minizip/ioapi.c +10 -0
  94. data/libxlsxwriter/third_party/minizip/zip.c +2 -0
  95. data/libxlsxwriter/third_party/tmpfileplus/tmpfileplus.c +2 -2
  96. data/libxlsxwriter/version.txt +1 -1
  97. data/test/auto_width_test.rb +19 -0
  98. data/test/date_test.rb +34 -0
  99. data/test/format_test.rb +179 -0
  100. data/test/reopen_test.rb +22 -0
  101. data/test/test_helper.rb +23 -4
  102. data/test/text_width_test.rb +80 -0
  103. data/test/tmpfile_test.rb +1 -0
  104. data/test/validations_test.rb +47 -0
  105. data/test/worksheet_test.rb +129 -0
  106. metadata +34 -5
data/Rakefile CHANGED
@@ -16,3 +16,19 @@ Rake::TestTask.new do |test|
16
16
  end
17
17
 
18
18
  #task :default => :test
19
+
20
+ desc "Run all examples"
21
+ task :examples do
22
+ Dir.glob('examples/**/*.rb').each do |file|
23
+ require './' + file.sub(/\.rb$/, '')
24
+ end
25
+ end
26
+
27
+ desc "Compile libxlsxwriter shared library"
28
+ task :compile do
29
+ %x{
30
+ cd ext/fast_excel
31
+ ruby ./extconf.rb
32
+ make
33
+ }
34
+ end
@@ -0,0 +1,25 @@
1
+ install:
2
+ - SET PATH=C:\Ruby%ruby_version%\bin;%PATH%
3
+ - SET PATH=C:\MinGW\bin;%PATH%
4
+ - SET RAKEOPT=-rdevkit
5
+ - copy c:\MinGW\bin\mingw32-make.exe c:\MinGW\bin\make.exe
6
+ - ruby --version
7
+ - gem --version
8
+ - bundle install
9
+ - make
10
+
11
+ build: off
12
+
13
+ test_script:
14
+ - bundle exec rake test
15
+
16
+ environment:
17
+ matrix:
18
+ - ruby_version: "24"
19
+ - ruby_version: "24-x64"
20
+ - ruby_version: "23"
21
+ - ruby_version: "23-x64"
22
+ - ruby_version: "22"
23
+ - ruby_version: "22-x64"
24
+ - ruby_version: "21"
25
+ - ruby_version: "21-x64"
@@ -1,6 +1,6 @@
1
1
  require_relative 'init'
2
2
 
3
- HEADERS = ["id", "name", "age", "date"]
3
+ HEADERS = ["id", "name", "age", "date"].freeze
4
4
 
5
5
  DATA = []
6
6
  1000.times do |n|
@@ -8,15 +8,15 @@ DATA = []
8
8
  end
9
9
 
10
10
  Benchmark.ips do |x|
11
- x.config(time: 10, warmup: 2)
11
+ x.config(time: 10, warmup: 40)
12
12
 
13
13
  x.report("FastExcel") do
14
14
  workbook = FastExcel.open(constant_memory: true)
15
15
  worksheet = workbook.add_worksheet("benchmark")
16
16
 
17
17
  worksheet.write_row(0, HEADERS)
18
- DATA.each_with_index do |row, i|
19
- worksheet.write_row(i + 1, row)
18
+ DATA.each do |row|
19
+ worksheet.append_row(row)
20
20
  end
21
21
  workbook.read_string
22
22
  end
@@ -55,5 +55,18 @@ Benchmark.ips do |x|
55
55
  File.delete(filename)
56
56
  end
57
57
 
58
+ x.report("xlsxtream") do
59
+ filename = "#{Dir.mktmpdir}/xlsxtream.xlsx"
60
+
61
+ Xlsxtream::Workbook.open(filename) do |xlsx|
62
+ xlsx.write_worksheet do |sheet|
63
+ sheet << HEADERS
64
+ DATA.each do |row|
65
+ sheet << row
66
+ end
67
+ end
68
+ end
69
+ end
70
+
58
71
  x.compare!
59
72
  end
@@ -22,5 +22,9 @@ Benchmark.ips do |x|
22
22
  write_xlsx_20k
23
23
  end
24
24
 
25
+ x.report("xlsxtream") do
26
+ write_xlsxtream_20k
27
+ end
28
+
25
29
  x.compare!
26
30
  end
@@ -0,0 +1,37 @@
1
+ require_relative 'init'
2
+
3
+ HEADERS = ["id", "name", "age", "date"]
4
+
5
+ DATA = []
6
+ 1000.times do |n|
7
+ DATA << [n, "String string #{n}", (n * rand * 10).round, Time.at(n * 1000 + 1492922688)]
8
+ end
9
+
10
+ Benchmark.ips do |x|
11
+ x.config(time: 10, warmup: 2)
12
+
13
+ x.report("Normal") do
14
+ workbook = FastExcel.open(constant_memory: true)
15
+ worksheet = workbook.add_worksheet("benchmark")
16
+
17
+ worksheet.write_row(0, HEADERS)
18
+ DATA.each_with_index do |row, i|
19
+ worksheet.write_row(i + 1, row)
20
+ end
21
+ workbook.read_string
22
+ end
23
+
24
+ x.report("With auto_width") do
25
+ workbook = FastExcel.open(constant_memory: true)
26
+ worksheet = workbook.add_worksheet("benchmark")
27
+ worksheet.auto_width = true
28
+
29
+ worksheet.write_row(0, HEADERS)
30
+ DATA.each_with_index do |row, i|
31
+ worksheet.write_row(i + 1, row)
32
+ end
33
+ workbook.read_string
34
+ end
35
+
36
+ x.compare!
37
+ end
@@ -8,10 +8,9 @@ require_relative '../lib/fast_excel'
8
8
  require "benchmark/ips"
9
9
  require 'axlsx'
10
10
  require 'write_xlsx'
11
+ require 'xlsxtream'
11
12
  require 'process_memory'
12
13
 
13
- require_relative 'init'
14
-
15
14
  def write_fast_excel_20k
16
15
  workbook = FastExcel.open(constant_memory: true)
17
16
  worksheet = workbook.add_worksheet("benchmark")
@@ -57,3 +56,16 @@ def write_axlsx_20k
57
56
  File.delete(filename)
58
57
  end
59
58
  end
59
+
60
+ def write_xlsxtream_20k
61
+ filename = "#{Dir.mktmpdir}/xlsxtream.xlsx"
62
+
63
+ Xlsxtream::Workbook.open(filename) do |xlsx|
64
+ xlsx.write_worksheet do |sheet|
65
+ sheet << HEADERS
66
+ DATA.each do |row|
67
+ sheet << row
68
+ end
69
+ end
70
+ end
71
+ end
@@ -11,6 +11,7 @@ puts "warm up..."
11
11
  write_fast_excel_20k
12
12
  write_axlsx_20k
13
13
  write_xlsx_20k
14
+ write_xlsxtream_20k
14
15
 
15
16
  DATA.clear
16
17
  50_000.times do |n|
@@ -47,3 +48,10 @@ sleep 5
47
48
  measure_memory("write_xlsx") do
48
49
  write_xlsx_20k
49
50
  end
51
+
52
+ GC.start
53
+ sleep 5
54
+
55
+ measure_memory("xlsxtream") do
56
+ write_xlsxtream_20k
57
+ end
@@ -0,0 +1,27 @@
1
+ require_relative '../lib/fast_excel'
2
+ require 'ruby-prof'
3
+
4
+ DATA = []
5
+ 1000.times do |n|
6
+ DATA << [n, "String string #{n}", (n * rand * 10).round, Time.at(n * 1000 + 1492922688)]
7
+ end
8
+
9
+ RubyProf.start
10
+
11
+ 100.times do
12
+ workbook = FastExcel.open(constant_memory: true)
13
+ worksheet = workbook.add_worksheet("benchmark")
14
+ worksheet.auto_width = true
15
+
16
+ DATA.each_with_index do |row, i|
17
+ worksheet.write_row(i + 1, row)
18
+ end
19
+ workbook.read_string
20
+
21
+ print '.'
22
+ end
23
+ result = RubyProf.stop
24
+
25
+ # print a flat profile to text
26
+ printer = RubyProf::FlatPrinter.new(result)
27
+ printer.print(STDOUT)
@@ -0,0 +1,62 @@
1
+ require_relative '../lib/fast_excel'
2
+ require "benchmark/memory"
3
+ require "benchmark/ips"
4
+
5
+ DATA = []
6
+ 1000.times do |n|
7
+ DATA << [n, "String string #{n}", (n * rand * 10).round, Time.at(n * 1000 + 1492922688)]
8
+ end
9
+
10
+ 5.times do
11
+ workbook = FastExcel.open(constant_memory: true)
12
+ worksheet = workbook.add_worksheet("benchmark")
13
+
14
+ DATA.each_with_index do |row, row_num|
15
+ row.each_with_index do |val, cell_num|
16
+ worksheet.write_value(row_num + 1, cell_num + 1, val)
17
+ end
18
+ end
19
+ workbook.read_string
20
+ end
21
+
22
+
23
+ workbook = FastExcel.open(constant_memory: true)
24
+ worksheet = workbook.add_worksheet("benchmark")
25
+
26
+ DATA.each_with_index do |row, row_num|
27
+ row.each_with_index do |val, cell_num|
28
+ worksheet.write_value(row_num + 1, cell_num + 1, val)
29
+ end
30
+ end
31
+ workbook.read_string
32
+
33
+ Benchmark.ips do |x|
34
+ #x.config(time: 10, warmup: 2)
35
+
36
+ x.report("Normal") do
37
+ workbook = FastExcel.open(constant_memory: true)
38
+ worksheet = workbook.add_worksheet("benchmark")
39
+
40
+ DATA.each_with_index do |row, row_num|
41
+ row.each_with_index do |val, cell_num|
42
+ worksheet.write_value(row_num + 1, cell_num + 1, val)
43
+ end
44
+ end
45
+ workbook.read_string
46
+ end
47
+
48
+ x.report("Auto-width") do
49
+ workbook = FastExcel.open(constant_memory: true)
50
+ worksheet = workbook.add_worksheet("benchmark")
51
+ worksheet.auto_width = true
52
+
53
+ DATA.each_with_index do |row, row_num|
54
+ row.each_with_index do |val, cell_num|
55
+ worksheet.write_value(row_num + 1, cell_num + 1, val)
56
+ end
57
+ end
58
+ workbook.read_string
59
+ end
60
+
61
+ x.compare!
62
+ end
@@ -1,5 +1,4 @@
1
1
  require_relative '../lib/fast_excel'
2
- require 'pp'
3
2
 
4
3
  workbook = FastExcel.open("example.xlsx", constant_memory: true)
5
4
 
@@ -12,7 +11,7 @@ workbook.default_format.set(
12
11
 
13
12
  worksheet = workbook.add_worksheet("Payments Report")
14
13
 
15
- bold = workbook.bold_cell_format
14
+ bold = workbook.bold_format
16
15
  worksheet.set_column(0, 0, FastExcel::DEF_COL_WIDTH, bold)
17
16
 
18
17
  price = workbook.number_format("#,##0.00")
@@ -21,10 +20,10 @@ worksheet.set_column(1, 1, 20, price)
21
20
  date_format = workbook.number_format("[$-409]m/d/yy h:mm AM/PM;@")
22
21
  worksheet.set_column(2, 2, 20, date_format)
23
22
 
24
- worksheet.write_row(0, ["message", "price", "date"], bold)
23
+ worksheet.write_row(0, ["message", "price", "date", "complete"], bold)
25
24
 
26
25
  for i in 1..1000
27
- worksheet.write_row(i, ["Hello", (rand * 10_000_000).round(2), Time.now])
26
+ worksheet.write_row(i, ["Hello", (rand * 10_000_000).round(2), Time.now, i % 2 == 0])
28
27
 
29
28
  # Or manually
30
29
  # worksheet.write_string(i, 0, "Hello", nil)
@@ -0,0 +1,23 @@
1
+ require_relative '../lib/fast_excel'
2
+
3
+ workbook = FastExcel.open("example_align.xlsx", constant_memory: true)
4
+
5
+ worksheet = workbook.add_worksheet
6
+
7
+ row_format = workbook.add_format
8
+
9
+ row_format.align = {h: :center, v: :center}
10
+ # Can also be called as:
11
+ # row_format.align = :align_center
12
+ # row_format.align = :align_vertical_center
13
+
14
+ print "Align set as: "
15
+ p row_format.align # => {horizontal: :align_center, vertical: :align_vertical_center}
16
+
17
+ worksheet.set_column_width(0, 30)
18
+ worksheet.set_row(0, 30, row_format)
19
+
20
+ worksheet.write_row(0, ["Hello"])
21
+
22
+ workbook.close
23
+ puts "Saved to file example_align.xlsx"
@@ -0,0 +1,26 @@
1
+ require_relative '../lib/fast_excel'
2
+
3
+ workbook = FastExcel.open("example_auto_width.xlsx", constant_memory: false)
4
+
5
+ # this is required to make auto-width works correctly
6
+ workbook.default_format.set(
7
+ font_size: 13,
8
+ font_family: "Arial"
9
+ )
10
+
11
+ worksheet = workbook.add_worksheet
12
+ worksheet.auto_width = true
13
+
14
+ ['Arial', 'Calibri', 'Times New Roman'].each_with_index do |font, index|
15
+ col_format = workbook.add_format(font_family: font, font_size: 17)
16
+ worksheet.set_column(index * 4, index * 4 + 3, 10, col_format)
17
+
18
+ worksheet.write_value(0, index * 4 + 2, font)
19
+ worksheet.write_value(1, index * 4, "tini")
20
+ worksheet.write_value(1, index * 4 + 1, "Longer")
21
+ worksheet.write_value(1, index * 4 + 2, "Some longer text!")
22
+ worksheet.write_value(1, index * 4 + 3, "This gem is FFI binding for libxlsxwriter C library")
23
+ end
24
+
25
+ workbook.close
26
+ puts "Saved to file example_auto_width.xlsx"
@@ -0,0 +1,37 @@
1
+ require_relative '../lib/fast_excel'
2
+
3
+ workbook = FastExcel.open("example_colors.xlsx", constant_memory: true)
4
+
5
+ worksheet = workbook.add_worksheet
6
+
7
+ color_format = workbook.add_format
8
+
9
+ # We can use color names as string and symbols, color hex codes and color hex numbers
10
+
11
+ color_format.set(
12
+ font_color: '9900FF',
13
+ bg_color: '#FFAAAA',
14
+
15
+ border_bottom: :medium,
16
+ border_bottom_color: 'green',
17
+
18
+ border_left: :slant_dash_dot,
19
+ border_left_color: 0x00FF00,
20
+
21
+ border_right: :double,
22
+ border_right_color: :crimson,
23
+
24
+ border_top: :border_hair,
25
+ border_top_color: :medium_blue
26
+ )
27
+
28
+ # Possible border styles:
29
+ # [:none, :thin, :medium, :dashed, :dotted, :thick, :double, :hair, :medium_dashed,
30
+ # :dash_dot, :medium_dash_dot, :dash_dot_dot, :medium_dash_dot_dot, :slant_dash_dot]
31
+
32
+ worksheet.set_column_width(1, 30)
33
+
34
+ worksheet.write_value(1, 1, "Hello", color_format)
35
+
36
+ workbook.close
37
+ puts "Saved to file example_colors.xlsx"
@@ -0,0 +1,36 @@
1
+ require_relative '../lib/fast_excel'
2
+
3
+ `rm example_filters.xlsx` if File.exist?('example_filters.xlsx')
4
+ workbook = FastExcel.open("example_filters.xlsx", constant_memory: false)
5
+
6
+ workbook.default_format.set(
7
+ font_size: 0, # user's default
8
+ #font_family: "Arial"
9
+ )
10
+
11
+ # pp workbook.default_format
12
+
13
+ worksheet = workbook.add_worksheet("Payments Report")
14
+
15
+ p worksheet[:filter_on]
16
+ FastExcel.print_ffi_obj(worksheet)
17
+
18
+ bold = workbook.bold_format
19
+ worksheet.set_column(0, 0, FastExcel::DEF_COL_WIDTH, bold)
20
+
21
+ price = workbook.number_format("#,##0.00")
22
+ worksheet.set_column(1, 1, 20, price)
23
+
24
+ date_format = workbook.number_format("[$-409]m/d/yy h:mm AM/PM;@")
25
+ worksheet.set_column(2, 2, 20, date_format)
26
+
27
+ worksheet.write_row(0, ["message", "price", "date", "complete"], bold)
28
+
29
+ for i in 1..1000
30
+ worksheet.write_row(i, ["Hello", (rand * 10_000_000).round(2), Time.now, i % 2 == 0])
31
+ end
32
+
33
+ worksheet.enable_filters!(end_col: 3)
34
+
35
+ workbook.close
36
+ puts "Saved to file example_filters.xlsx"
@@ -1,6 +1,4 @@
1
1
  require_relative '../lib/fast_excel'
2
- require 'pp'
3
- require 'looksee'
4
2
 
5
3
  workbook = FastExcel.open("example_formula.xlsx", constant_memory: false)
6
4
 
@@ -12,9 +10,7 @@ worksheet.write_row(2, ["Phone", 0.138])
12
10
  worksheet.write_row(3, ["Mouse", 0.099])
13
11
  worksheet.write_row(4, ["Speaker", 2.5])
14
12
  worksheet.write_row(5, ["Camera", 0.383])
15
- worksheet.write_row(6, ["Total", FastExcel::Formula.new("SUM(B2:B6)")], workbook.bold_cell_format)
16
-
17
- bold = workbook.bold_cell_format
13
+ worksheet.write_row(6, ["Total", FastExcel::Formula.new("SUM(B2:B6)")], workbook.bold_format)
18
14
 
19
15
  workbook.close
20
16
  puts "Saved to file example_formula.xlsx"