caxlsx 3.0.4 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -1
- data/README.md +2 -0
- data/lib/axlsx.rb +1 -1
- data/lib/axlsx/package.rb +32 -7
- data/lib/axlsx/util/mime_type_utils.rb +1 -1
- data/lib/axlsx/version.rb +1 -1
- data/lib/axlsx/workbook/worksheet/pivot_table.rb +7 -2
- data/lib/axlsx/workbook/worksheet/pivot_table_cache_definition.rb +1 -1
- data/lib/axlsx/workbook/worksheet/row.rb +5 -3
- data/lib/axlsx/workbook/worksheet/table.rb +1 -1
- data/lib/axlsx/workbook/worksheet/worksheet.rb +4 -0
- data/test/tc_helper.rb +0 -2
- data/test/tc_package.rb +54 -4
- data/test/workbook/worksheet/tc_pivot_table.rb +8 -0
- data/test/workbook/worksheet/tc_pivot_table_cache_definition.rb +8 -0
- data/test/workbook/worksheet/tc_row.rb +21 -0
- data/test/workbook/worksheet/tc_table.rb +10 -0
- metadata +8 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dfea731879b2415d4ed0ac46abfbad17483d7e9f2c27802aef87a93823589af7
|
4
|
+
data.tar.gz: 709606e3d36fe21ac41a8f9381d4017c31103d6ce0a8686eb195a935c3626538
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cd1fd47bfe33dafa4909960d326f81433b4fa3e18d1a6f6f99e7a13617eecc98f212e2a938788d53466a47b52a0a2325a8dfcb3a6c3b52def5325b75ead9d402
|
7
|
+
data.tar.gz: bd9deebebd7cfc2222e64a8485ec9951ece3a69bb695fad5f4a790166324dab45134e835d02dc503e6c37e70b27d586db8bccf0c847448944f50ef37205e53d6
|
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
CHANGELOG
|
2
2
|
---------
|
3
3
|
|
4
|
-
- **
|
4
|
+
- **March.27.21**: 3.1.0
|
5
|
+
- [PR #95](https://github.com/caxlsx/caxlsx/pull/95) - Replace mimemagic with marcel
|
6
|
+
- [PR #87](https://github.com/caxlsx/caxlsx/pull/87) - Implement :offset option for worksheet#add_row
|
7
|
+
- [PR #79](https://github.com/caxlsx/caxlsx/pull/79) - Add support for format in pivot tables
|
8
|
+
- [PR #77](https://github.com/caxlsx/caxlsx/pull/77) - Fix special characters in table header
|
9
|
+
- [PR #57](https://github.com/caxlsx/caxlsx/pull/57) - Deprecate using #serialize with boolean argument: Calls like `Package#serialize("name.xlsx", false)` should be replaced with `Package#serialize("name.xlsx", confirm_valid: false)`.
|
5
10
|
|
6
11
|
- **January.5.21**: 3.0.4
|
7
12
|
- [PR #72](https://github.com/caxlsx/caxlsx/pull/72) - Relax Ruby dependency to allow for Ruby 3. This required Travis to be upgraded from Ubuntu Trusty to Ubuntu Bionic. rbx-3 was dropped.
|
data/README.md
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
[![Build Status](https://travis-ci.com/caxlsx/caxlsx.svg?branch=master)](https://travis-ci.com/caxlsx/caxlsx)
|
3
3
|
[![Gem
|
4
4
|
Version](https://badge.fury.io/rb/caxlsx.svg)](http://badge.fury.io/rb/caxlsx)
|
5
|
+
![Total downloads](http://ruby-gem-downloads-badge.herokuapp.com/caxlsx?type=total)
|
6
|
+
![Downloads for 3.0.4 (latest)](http://ruby-gem-downloads-badge.herokuapp.com/caxlsx/3.0.4?label=downloads%203.0.4)
|
5
7
|
|
6
8
|
## Notice: Community Axlsx Organization
|
7
9
|
|
data/lib/axlsx.rb
CHANGED
data/lib/axlsx/package.rb
CHANGED
@@ -74,13 +74,14 @@ module Axlsx
|
|
74
74
|
# Serialize your workbook to disk as an xlsx document.
|
75
75
|
#
|
76
76
|
# @param [String] output The name of the file you want to serialize your package to
|
77
|
-
# @param [
|
78
|
-
# @
|
77
|
+
# @param [Hash] options
|
78
|
+
# @option options [Boolean] :confirm_valid Validate the package prior to serialization.
|
79
|
+
# @option options [String] :zip_command When `nil`, `#serialize` with RubyZip to
|
79
80
|
# zip the XLSX file contents. When a String, the provided zip command (e.g.,
|
80
81
|
# "zip") is used to zip the file contents (may be faster for large files)
|
81
82
|
# @return [Boolean] False if confirm_valid and validation errors exist. True if the package was serialized
|
82
83
|
# @note A tremendous amount of effort has gone into ensuring that you cannot create invalid xlsx documents.
|
83
|
-
# confirm_valid should be used in the rare case that you cannot open the serialized file.
|
84
|
+
# options[:confirm_valid] should be used in the rare case that you cannot open the serialized file.
|
84
85
|
# @see Package#validate
|
85
86
|
# @example
|
86
87
|
# # This is how easy it is to create a valid xlsx file. Of course you might want to add a sheet or two, and maybe some data, styles and charts.
|
@@ -92,14 +93,15 @@ module Axlsx
|
|
92
93
|
# p.serialize("example.xlsx")
|
93
94
|
#
|
94
95
|
# # Serialize to a file, using a system zip binary
|
95
|
-
# p.serialize("example.xlsx",
|
96
|
-
# p.serialize("example.xlsx",
|
97
|
-
# p.serialize("example.xlsx",
|
96
|
+
# p.serialize("example.xlsx", zip_command: "zip", confirm_valid: false)
|
97
|
+
# p.serialize("example.xlsx", zip_command: "/path/to/zip")
|
98
|
+
# p.serialize("example.xlsx", zip_command: "zip -1")
|
98
99
|
#
|
99
100
|
# # Serialize to a stream
|
100
101
|
# s = p.to_stream()
|
101
102
|
# File.open('example_streamed.xlsx', 'w') { |f| f.write(s.read) }
|
102
|
-
def serialize(output,
|
103
|
+
def serialize(output, options = {}, secondary_options = nil)
|
104
|
+
confirm_valid, zip_command = parse_serialize_options(options, secondary_options)
|
103
105
|
return false unless !confirm_valid || self.validate.empty?
|
104
106
|
zip_provider = if zip_command
|
105
107
|
ZipCommand.new(zip_command)
|
@@ -359,5 +361,28 @@ module Axlsx
|
|
359
361
|
rels.lock
|
360
362
|
rels
|
361
363
|
end
|
364
|
+
|
365
|
+
# Parse the arguments of `#serialize`
|
366
|
+
# @return [Boolean, (String or nil)] Returns an array where the first value is
|
367
|
+
# `confirm_valid` and the second is the `zip_command`.
|
368
|
+
# @private
|
369
|
+
def parse_serialize_options(options, secondary_options)
|
370
|
+
if secondary_options
|
371
|
+
warn "[DEPRECATION] Axlsx::Package#serialize with 3 arguments is deprecated. " +
|
372
|
+
"Use keyword args instead e.g., package.serialize(output, confirm_valid: false, zip_command: 'zip')"
|
373
|
+
end
|
374
|
+
if options.is_a?(Hash)
|
375
|
+
options.merge!(secondary_options || {})
|
376
|
+
invalid_keys = options.keys - [:confirm_valid, :zip_command]
|
377
|
+
if invalid_keys.any?
|
378
|
+
raise ArgumentError.new("Invalid keyword arguments: #{invalid_keys}")
|
379
|
+
end
|
380
|
+
[options.fetch(:confirm_valid, false), options.fetch(:zip_command, nil)]
|
381
|
+
else
|
382
|
+
warn "[DEPRECATION] Axlsx::Package#serialize with confirm_valid as a boolean is deprecated. " +
|
383
|
+
"Use keyword args instead e.g., package.serialize(output, confirm_valid: false)"
|
384
|
+
parse_serialize_options((secondary_options || {}).merge(confirm_valid: options), nil)
|
385
|
+
end
|
386
|
+
end
|
362
387
|
end
|
363
388
|
end
|
data/lib/axlsx/version.rb
CHANGED
@@ -111,8 +111,12 @@ module Axlsx
|
|
111
111
|
if data_field.is_a? String
|
112
112
|
data_field = {:ref => data_field}
|
113
113
|
end
|
114
|
-
data_field.
|
115
|
-
|
114
|
+
data_field.each do |key, value|
|
115
|
+
if key == :num_fmt
|
116
|
+
DataTypeValidator.validate "#{self.class}.data[]", [Integer], value
|
117
|
+
else
|
118
|
+
DataTypeValidator.validate "#{self.class}.data[]", [String], value
|
119
|
+
end
|
116
120
|
end
|
117
121
|
@data << data_field
|
118
122
|
end
|
@@ -212,6 +216,7 @@ module Axlsx
|
|
212
216
|
data.each do |datum_value|
|
213
217
|
# The correct name prefix in ["Sum","Average", etc...]
|
214
218
|
str << "<dataField name='#{(datum_value[:subtotal]||'')} of #{datum_value[:ref]}' fld='#{header_index_of(datum_value[:ref])}' baseField='0' baseItem='0'"
|
219
|
+
str << " numFmtId='#{datum_value[:num_fmt]}'" if datum_value[:num_fmt]
|
215
220
|
str << " subtotal='#{datum_value[:subtotal]}' " if datum_value[:subtotal]
|
216
221
|
str << "/>"
|
217
222
|
end
|
@@ -53,7 +53,7 @@ module Axlsx
|
|
53
53
|
str << '</cacheSource>'
|
54
54
|
str << ( '<cacheFields count="' << pivot_table.header_cells_count.to_s << '">')
|
55
55
|
pivot_table.header_cells.each do |cell|
|
56
|
-
str << ( '<cacheField name="' << cell.
|
56
|
+
str << ( '<cacheField name="' << cell.clean_value << '" numFmtId="0">')
|
57
57
|
str << '<sharedItems count="0">'
|
58
58
|
str << '</sharedItems>'
|
59
59
|
str << '</cacheField>'
|
@@ -25,11 +25,12 @@ module Axlsx
|
|
25
25
|
# @option options [Array, Symbol] types
|
26
26
|
# @option options [Array, Integer] style
|
27
27
|
# @option options [Float] height the row's height (in points)
|
28
|
+
# @option options [Integer] offset - add empty columns before values
|
28
29
|
# @see Row#array_to_cells
|
29
30
|
# @see Cell
|
30
31
|
def initialize(worksheet, values=[], options={})
|
31
32
|
self.worksheet = worksheet
|
32
|
-
super(Cell, nil, values.size)
|
33
|
+
super(Cell, nil, values.size + options[:offset].to_i)
|
33
34
|
self.height = options.delete(:height)
|
34
35
|
worksheet.rows << self
|
35
36
|
array_to_cells(values, options)
|
@@ -147,14 +148,15 @@ module Axlsx
|
|
147
148
|
# @option options [Array, Integer] style
|
148
149
|
def array_to_cells(values, options={})
|
149
150
|
DataTypeValidator.validate :array_to_cells, Array, values
|
150
|
-
types, style, formula_values, escape_formulas = options.delete(:types), options.delete(:style), options.delete(:formula_values), options.delete(:escape_formulas)
|
151
|
+
types, style, formula_values, escape_formulas, offset = options.delete(:types), options.delete(:style), options.delete(:formula_values), options.delete(:escape_formulas), options.delete(:offset)
|
152
|
+
offset.to_i.times { |index| self[index] = Cell.new(self) } if offset
|
151
153
|
values.each_with_index do |value, index|
|
152
154
|
options[:style] = style.is_a?(Array) ? style[index] : style if style
|
153
155
|
options[:type] = types.is_a?(Array) ? types[index] : types if types
|
154
156
|
options[:escape_formulas] = escape_formulas.is_a?(Array) ? escape_formulas[index] : escape_formulas if escape_formulas
|
155
157
|
options[:formula_value] = formula_values[index] if formula_values.is_a?(Array)
|
156
158
|
|
157
|
-
self[index] = Cell.new(self, value, options)
|
159
|
+
self[index + offset.to_i] = Cell.new(self, value, options)
|
158
160
|
end
|
159
161
|
end
|
160
162
|
end
|
@@ -80,7 +80,7 @@ module Axlsx
|
|
80
80
|
str << ('<autoFilter ref="' << @ref << '"/>')
|
81
81
|
str << ('<tableColumns count="' << header_cells.length.to_s << '">')
|
82
82
|
header_cells.each_with_index do |cell,index|
|
83
|
-
str << ('<tableColumn id ="' << (index+1).to_s << '" name="' << cell.
|
83
|
+
str << ('<tableColumn id ="' << (index+1).to_s << '" name="' << cell.clean_value << '"/>')
|
84
84
|
end
|
85
85
|
str << '</tableColumns>'
|
86
86
|
table_style_info.to_xml_string(str)
|
@@ -393,6 +393,9 @@ module Axlsx
|
|
393
393
|
# @example - specify whether a certain cells in a row should escape formulas or not
|
394
394
|
# ws.add_row ['=IF(2+2=4,4,5)', '=IF(13+13=4,4,5)'], :escape_formulas=>[true, false]
|
395
395
|
#
|
396
|
+
# @example - add a column offset when adding a row (inserts 'n' blank, unstyled columns before data)
|
397
|
+
# ws.add_row ['I wish', 'for a fish', 'on my fish wish dish'], offset: 3
|
398
|
+
#
|
396
399
|
# @see Worksheet#column_widths
|
397
400
|
# @return [Row]
|
398
401
|
# @option options [Array] values
|
@@ -400,6 +403,7 @@ module Axlsx
|
|
400
403
|
# @option options [Array, Integer] style
|
401
404
|
# @option options [Array] widths each member of the widths array will affect how auto_fit behavies.
|
402
405
|
# @option options [Float] height the row's height (in points)
|
406
|
+
# @option options [Integer] offset - add empty columns before values
|
403
407
|
# @option options [Array, Boolean] escape_formulas - Whether to treat a value starting with an equal
|
404
408
|
# sign as formula (default) or as simple string.
|
405
409
|
# Allowing user generated data to be interpreted as formulas can be dangerous
|
data/test/tc_helper.rb
CHANGED
data/test/tc_package.rb
CHANGED
@@ -129,25 +129,28 @@ class TestPackage < Test::Unit::TestCase
|
|
129
129
|
def test_serialization
|
130
130
|
@package.serialize(@fname)
|
131
131
|
assert_zip_file_matches_package(@fname, @package)
|
132
|
+
assert_created_with_rubyzip(@fname, @package)
|
132
133
|
File.delete(@fname)
|
133
134
|
end
|
134
135
|
|
135
136
|
def test_serialization_with_zip_command
|
136
|
-
@package.serialize(@fname,
|
137
|
+
@package.serialize(@fname, zip_command: "zip")
|
137
138
|
assert_zip_file_matches_package(@fname, @package)
|
139
|
+
assert_created_with_zip_command(@fname, @package)
|
138
140
|
File.delete(@fname)
|
139
141
|
end
|
140
142
|
|
141
143
|
def test_serialization_with_zip_command_and_absolute_path
|
142
144
|
fname = "#{Dir.tmpdir}/#{@fname}"
|
143
|
-
@package.serialize(fname,
|
145
|
+
@package.serialize(fname, zip_command: "zip")
|
144
146
|
assert_zip_file_matches_package(fname, @package)
|
147
|
+
assert_created_with_zip_command(fname, @package)
|
145
148
|
File.delete(fname)
|
146
149
|
end
|
147
150
|
|
148
151
|
def test_serialization_with_invalid_zip_command
|
149
152
|
assert_raises Axlsx::ZipCommand::ZipError do
|
150
|
-
@package.serialize(@fname,
|
153
|
+
@package.serialize(@fname, zip_command: "invalid_zip")
|
151
154
|
end
|
152
155
|
end
|
153
156
|
|
@@ -156,6 +159,53 @@ class TestPackage < Test::Unit::TestCase
|
|
156
159
|
package.send(:parts).each{ |part| zf.get_entry(part[:entry]) }
|
157
160
|
end
|
158
161
|
|
162
|
+
def assert_created_with_rubyzip(fname, package)
|
163
|
+
assert_equal 2098, get_mtime(fname, package).year, "XLSX files created with RubyZip have 2098 as the file mtime"
|
164
|
+
end
|
165
|
+
|
166
|
+
def assert_created_with_zip_command(fname, package)
|
167
|
+
assert_equal Time.now.utc.year, get_mtime(fname, package).year, "XLSX files created with a zip command have the current year as the file mtime"
|
168
|
+
end
|
169
|
+
|
170
|
+
def get_mtime(fname, package)
|
171
|
+
zf = Zip::File.open(fname)
|
172
|
+
part = package.send(:parts).first
|
173
|
+
entry = zf.get_entry(part[:entry])
|
174
|
+
entry.mtime.utc
|
175
|
+
end
|
176
|
+
|
177
|
+
def test_serialization_with_deprecated_argument
|
178
|
+
warnings = capture_warnings do
|
179
|
+
@package.serialize(@fname, false)
|
180
|
+
end
|
181
|
+
assert_equal 1, warnings.size
|
182
|
+
assert_includes warnings.first, "confirm_valid as a boolean is deprecated"
|
183
|
+
File.delete(@fname)
|
184
|
+
end
|
185
|
+
|
186
|
+
def test_serialization_with_deprecated_three_arguments
|
187
|
+
warnings = capture_warnings do
|
188
|
+
@package.serialize(@fname, true, zip_command: "zip")
|
189
|
+
end
|
190
|
+
assert_zip_file_matches_package(@fname, @package)
|
191
|
+
assert_created_with_zip_command(@fname, @package)
|
192
|
+
assert_equal 2, warnings.size
|
193
|
+
assert_includes warnings.first, "with 3 arguments is deprecated"
|
194
|
+
File.delete(@fname)
|
195
|
+
end
|
196
|
+
|
197
|
+
def capture_warnings(&block)
|
198
|
+
original_warn = Kernel.instance_method(:warn)
|
199
|
+
warnings = []
|
200
|
+
Kernel.send(:define_method, :warn) { |string| warnings << string }
|
201
|
+
block.call
|
202
|
+
original_verbose = $VERBOSE
|
203
|
+
$VERBOSE = nil
|
204
|
+
Kernel.send(:define_method, :warn, original_warn)
|
205
|
+
$VERBOSE = original_verbose
|
206
|
+
warnings
|
207
|
+
end
|
208
|
+
|
159
209
|
# See comment for Package#zip_entry_for_part
|
160
210
|
def test_serialization_creates_identical_files_at_any_time_if_created_at_is_set
|
161
211
|
@package.core.created = Time.now
|
@@ -178,7 +228,7 @@ class TestPackage < Test::Unit::TestCase
|
|
178
228
|
end
|
179
229
|
|
180
230
|
def test_serialization_creates_files_with_excel_mime_type
|
181
|
-
assert_equal(
|
231
|
+
assert_equal(Marcel::MimeType.for(@package.to_stream),
|
182
232
|
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
|
183
233
|
end
|
184
234
|
|
@@ -132,4 +132,12 @@ class TestPivotTable < Test::Unit::TestCase
|
|
132
132
|
end
|
133
133
|
shared_test_pivot_table_xml_validity(pivot_table)
|
134
134
|
end
|
135
|
+
|
136
|
+
def test_add_pivot_table_with_format_options_on_data_field
|
137
|
+
pivot_table = @ws.add_pivot_table('G5:G6', 'A1:E5') do |pt|
|
138
|
+
pt.data = [{:ref=>"Sales", :subtotal => 'sum', num_fmt: 4}]
|
139
|
+
end
|
140
|
+
doc = Nokogiri::XML(pivot_table.to_xml_string)
|
141
|
+
assert_equal('4', doc.at_css('dataFields dataField')['numFmtId'], 'adding format options to pivot_table')
|
142
|
+
end
|
135
143
|
end
|
@@ -51,4 +51,12 @@ class TestPivotTableCacheDefinition < Test::Unit::TestCase
|
|
51
51
|
assert(errors.empty?, "error free validation")
|
52
52
|
end
|
53
53
|
|
54
|
+
def test_to_xml_string_for_special_characters
|
55
|
+
cell = @ws.rows.first.cells.first
|
56
|
+
cell.value = "&><'\""
|
57
|
+
|
58
|
+
doc = Nokogiri::XML(@cache_definition.to_xml_string)
|
59
|
+
errors = doc.errors
|
60
|
+
assert(errors.empty?, "invalid xml: #{errors.map(&:to_s).join(', ')}")
|
61
|
+
end
|
54
62
|
end
|
@@ -136,4 +136,25 @@ class TestRow < Test::Unit::TestCase
|
|
136
136
|
assert_equal(r_s_xml.xpath(".//row[@r=1][@ht=20][@customHeight=1]").size, 1)
|
137
137
|
end
|
138
138
|
|
139
|
+
def test_offsets
|
140
|
+
offset = 3
|
141
|
+
values = [1,2,3,4,5]
|
142
|
+
r = @ws.add_row(values, offset: offset, style: 1)
|
143
|
+
r.cells.each_with_index do |c, index|
|
144
|
+
assert_equal(c.style, index < offset ? 0 : 1)
|
145
|
+
assert_equal(c.value, index < offset ? nil : values[index - offset])
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def test_offsets_with_styles
|
150
|
+
offset = 3
|
151
|
+
values = [1,2,3,4,5]
|
152
|
+
styles = (1..5).map{ @ws.workbook.styles.add_style }
|
153
|
+
r = @ws.add_row(values, offset: offset, style: styles)
|
154
|
+
r.cells.each_with_index do |c, index|
|
155
|
+
assert_equal(c.style, index < offset ? 0 : styles[index-offset])
|
156
|
+
assert_equal(c.value, index < offset ? nil : values[index - offset])
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
139
160
|
end
|
@@ -64,4 +64,14 @@ class TestTable < Test::Unit::TestCase
|
|
64
64
|
end
|
65
65
|
assert(errors.empty?, "error free validation")
|
66
66
|
end
|
67
|
+
|
68
|
+
def test_to_xml_string_for_special_characters
|
69
|
+
cell = @ws.rows.first.cells.first
|
70
|
+
cell.value = "&><'\""
|
71
|
+
|
72
|
+
table = @ws.add_table("A1:D5")
|
73
|
+
doc = Nokogiri::XML(table.to_xml_string)
|
74
|
+
errors = doc.errors
|
75
|
+
assert(errors.empty?, "invalid xml: #{errors.map(&:to_s).join(', ')}")
|
76
|
+
end
|
67
77
|
end
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: caxlsx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0
|
4
|
+
version: 3.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Randy Morgan
|
8
8
|
- Jurriaan Pruis
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2021-
|
12
|
+
date: 2021-03-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: nokogiri
|
@@ -72,19 +72,19 @@ dependencies:
|
|
72
72
|
- !ruby/object:Gem::Version
|
73
73
|
version: 4.3.4
|
74
74
|
- !ruby/object:Gem::Dependency
|
75
|
-
name:
|
75
|
+
name: marcel
|
76
76
|
requirement: !ruby/object:Gem::Requirement
|
77
77
|
requirements:
|
78
78
|
- - "~>"
|
79
79
|
- !ruby/object:Gem::Version
|
80
|
-
version: '0
|
80
|
+
version: '1.0'
|
81
81
|
type: :runtime
|
82
82
|
prerelease: false
|
83
83
|
version_requirements: !ruby/object:Gem::Requirement
|
84
84
|
requirements:
|
85
85
|
- - "~>"
|
86
86
|
- !ruby/object:Gem::Version
|
87
|
-
version: '0
|
87
|
+
version: '1.0'
|
88
88
|
- !ruby/object:Gem::Dependency
|
89
89
|
name: yard
|
90
90
|
requirement: !ruby/object:Gem::Requirement
|
@@ -452,7 +452,7 @@ homepage: https://github.com/caxlsx/caxlsx
|
|
452
452
|
licenses:
|
453
453
|
- MIT
|
454
454
|
metadata: {}
|
455
|
-
post_install_message:
|
455
|
+
post_install_message:
|
456
456
|
rdoc_options: []
|
457
457
|
require_paths:
|
458
458
|
- lib
|
@@ -468,7 +468,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
468
468
|
version: '0'
|
469
469
|
requirements: []
|
470
470
|
rubygems_version: 3.0.3
|
471
|
-
signing_key:
|
471
|
+
signing_key:
|
472
472
|
specification_version: 4
|
473
473
|
summary: Excel OOXML (xlsx) with charts, styles, images and autowidth columns.
|
474
474
|
test_files:
|