spreadsheet 1.2.6 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/bin/bundle +114 -0
- data/bin/bundler +17 -0
- data/bin/oletool +29 -0
- data/bin/rake +29 -0
- data/bin/sow +17 -0
- data/bin/xlsopcodes +22 -11
- data/lib/spreadsheet/excel/writer/n_worksheet.rb +0 -75
- data/lib/spreadsheet/excel/writer/workbook.rb +3 -90
- data/lib/spreadsheet/excel/writer/worksheet.rb +0 -78
- data/lib/spreadsheet/excel.rb +0 -6
- data/lib/spreadsheet/version.rb +1 -1
- data/lib/spreadsheet/worksheet.rb +5 -2
- data/test/data/test_compact_format_date.xls +0 -0
- data/test/data/test_compact_many_rows.xls +0 -0
- data/test/data/test_missing_format.xls +0 -0
- data/test/data/test_sizes.xls +0 -0
- data/test/integration.rb +24 -0
- data/test/suite.rb +2 -0
- data/test/worksheet.rb +5 -0
- metadata +43 -48
- data/.gitignore +0 -3
- data/.travis.yml +0 -46
- data/Excel97-2007BinaryFileFormatSpecification.pdf +0 -0
- data/GUIDE.md +0 -339
- data/Gemfile +0 -11
- data/Gemfile.lock +0 -23
- data/History.md +0 -849
- data/README.md +0 -114
- data/Rakefile +0 -24
- data/excelfileformat.pdf +0 -0
- data/spreadsheet.gemspec +0 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: a831e5c252775858cbdba547a3ac3228028cb6c9a56a92a77ab8fdc393de0658
|
4
|
+
data.tar.gz: 1240cd6a3b8362fa9c807c26d36fd6f8df19872e195ce09e98583597f73fa8cc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 35dd4c09f32c793bf85f4290a497eb25a298b2f59e107eb4ecebf3c37e1e6a1ee505eaec3409057c0914754ca9036fb8a4c173c8d251e448ef932e38489d0c04
|
7
|
+
data.tar.gz: b20106050e1370ced689559af16e97efc4b19abde21165091d9f4a1ebea02758625713f09e20be0ccf7b8be2075fc59567c5bf581e583a2250ccc81ee04b2e5f
|
data/bin/bundle
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'bundle' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "rubygems"
|
12
|
+
|
13
|
+
m = Module.new do
|
14
|
+
module_function
|
15
|
+
|
16
|
+
def invoked_as_script?
|
17
|
+
File.expand_path($0) == File.expand_path(__FILE__)
|
18
|
+
end
|
19
|
+
|
20
|
+
def env_var_version
|
21
|
+
ENV["BUNDLER_VERSION"]
|
22
|
+
end
|
23
|
+
|
24
|
+
def cli_arg_version
|
25
|
+
return unless invoked_as_script? # don't want to hijack other binstubs
|
26
|
+
return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
|
27
|
+
bundler_version = nil
|
28
|
+
update_index = nil
|
29
|
+
ARGV.each_with_index do |a, i|
|
30
|
+
if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN
|
31
|
+
bundler_version = a
|
32
|
+
end
|
33
|
+
next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
|
34
|
+
bundler_version = $1
|
35
|
+
update_index = i
|
36
|
+
end
|
37
|
+
bundler_version
|
38
|
+
end
|
39
|
+
|
40
|
+
def gemfile
|
41
|
+
gemfile = ENV["BUNDLE_GEMFILE"]
|
42
|
+
return gemfile if gemfile && !gemfile.empty?
|
43
|
+
|
44
|
+
File.expand_path("../../Gemfile", __FILE__)
|
45
|
+
end
|
46
|
+
|
47
|
+
def lockfile
|
48
|
+
lockfile =
|
49
|
+
case File.basename(gemfile)
|
50
|
+
when "gems.rb" then gemfile.sub(/\.rb$/, gemfile)
|
51
|
+
else "#{gemfile}.lock"
|
52
|
+
end
|
53
|
+
File.expand_path(lockfile)
|
54
|
+
end
|
55
|
+
|
56
|
+
def lockfile_version
|
57
|
+
return unless File.file?(lockfile)
|
58
|
+
lockfile_contents = File.read(lockfile)
|
59
|
+
return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
|
60
|
+
Regexp.last_match(1)
|
61
|
+
end
|
62
|
+
|
63
|
+
def bundler_version
|
64
|
+
@bundler_version ||=
|
65
|
+
env_var_version || cli_arg_version ||
|
66
|
+
lockfile_version
|
67
|
+
end
|
68
|
+
|
69
|
+
def bundler_requirement
|
70
|
+
return "#{Gem::Requirement.default}.a" unless bundler_version
|
71
|
+
|
72
|
+
bundler_gem_version = Gem::Version.new(bundler_version)
|
73
|
+
|
74
|
+
requirement = bundler_gem_version.approximate_recommendation
|
75
|
+
|
76
|
+
return requirement unless Gem::Version.new(Gem::VERSION) < Gem::Version.new("2.7.0")
|
77
|
+
|
78
|
+
requirement += ".a" if bundler_gem_version.prerelease?
|
79
|
+
|
80
|
+
requirement
|
81
|
+
end
|
82
|
+
|
83
|
+
def load_bundler!
|
84
|
+
ENV["BUNDLE_GEMFILE"] ||= gemfile
|
85
|
+
|
86
|
+
activate_bundler
|
87
|
+
end
|
88
|
+
|
89
|
+
def activate_bundler
|
90
|
+
gem_error = activation_error_handling do
|
91
|
+
gem "bundler", bundler_requirement
|
92
|
+
end
|
93
|
+
return if gem_error.nil?
|
94
|
+
require_error = activation_error_handling do
|
95
|
+
require "bundler/version"
|
96
|
+
end
|
97
|
+
return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION))
|
98
|
+
warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`"
|
99
|
+
exit 42
|
100
|
+
end
|
101
|
+
|
102
|
+
def activation_error_handling
|
103
|
+
yield
|
104
|
+
nil
|
105
|
+
rescue StandardError, LoadError => e
|
106
|
+
e
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
m.load_bundler!
|
111
|
+
|
112
|
+
if m.invoked_as_script?
|
113
|
+
load Gem.bin_path("bundler", "bundle")
|
114
|
+
end
|
data/bin/bundler
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
#
|
4
|
+
# This file was generated by Bundler.
|
5
|
+
#
|
6
|
+
# The application 'bundler' is installed as part of a gem, and
|
7
|
+
# this file is here to facilitate running it.
|
8
|
+
#
|
9
|
+
|
10
|
+
require "pathname"
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
12
|
+
Pathname.new(__FILE__).realpath)
|
13
|
+
|
14
|
+
require "rubygems"
|
15
|
+
require "bundler/setup"
|
16
|
+
|
17
|
+
load Gem.bin_path("bundler", "bundler")
|
data/bin/oletool
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'oletool' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("ruby-ole", "oletool")
|
data/bin/rake
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rake' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("rake", "rake")
|
data/bin/sow
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
#
|
4
|
+
# This file was generated by Bundler.
|
5
|
+
#
|
6
|
+
# The application 'sow' is installed as part of a gem, and
|
7
|
+
# this file is here to facilitate running it.
|
8
|
+
#
|
9
|
+
|
10
|
+
require "pathname"
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
12
|
+
Pathname.new(__FILE__).realpath)
|
13
|
+
|
14
|
+
require "rubygems"
|
15
|
+
require "bundler/setup"
|
16
|
+
|
17
|
+
load Gem.bin_path("hoe", "sow")
|
data/bin/xlsopcodes
CHANGED
@@ -1,18 +1,29 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
|
-
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'xlsopcodes' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
4
10
|
|
5
|
-
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
6
14
|
|
7
|
-
|
8
|
-
puts "Usage: #{$0} <source> [<target>]"
|
9
|
-
exit -1
|
10
|
-
end
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
11
16
|
|
12
|
-
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
13
25
|
|
14
|
-
|
15
|
-
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
16
28
|
|
17
|
-
|
18
|
-
end
|
29
|
+
load Gem.bin_path("spreadsheet", "xlsopcodes")
|
@@ -241,81 +241,6 @@ class Worksheet
|
|
241
241
|
end
|
242
242
|
write_multiples row, first_idx, multiples if multiples
|
243
243
|
end
|
244
|
-
def write_changes reader, endpos, sst_status
|
245
|
-
|
246
|
-
## FIXME this is not smart solution to update outline_level.
|
247
|
-
# without this process, outlines in row disappear in MS Excel.
|
248
|
-
@worksheet.row_count.times do |i|
|
249
|
-
if @worksheet.row(i).outline_level > 0
|
250
|
-
@worksheet.row(i).outline_level = @worksheet.row(i).outline_level
|
251
|
-
end
|
252
|
-
end
|
253
|
-
|
254
|
-
reader.seek @worksheet.offset
|
255
|
-
blocks = row_blocks
|
256
|
-
lastpos = reader.pos
|
257
|
-
offsets = {}
|
258
|
-
row_offsets = []
|
259
|
-
changes = @worksheet.changes
|
260
|
-
@worksheet.offsets.each do |key, pair|
|
261
|
-
if changes.include?(key) \
|
262
|
-
|| (sst_status == :complete_update && key.is_a?(Integer))
|
263
|
-
offsets.store pair, key
|
264
|
-
end
|
265
|
-
end
|
266
|
-
## FIXME it may be smarter to simply write all rowblocks, instead of doing a
|
267
|
-
# song-and-dance routine for every row...
|
268
|
-
work = offsets.invert
|
269
|
-
work.each do |key, (pos, len)|
|
270
|
-
case key
|
271
|
-
when Integer
|
272
|
-
row_offsets.push [key, [pos, len]]
|
273
|
-
when :dimensions
|
274
|
-
row_offsets.push [-1, [pos, len]]
|
275
|
-
end
|
276
|
-
end
|
277
|
-
row_offsets.sort!
|
278
|
-
row_offsets.reverse!
|
279
|
-
control = changes.size
|
280
|
-
@worksheet.each do |row|
|
281
|
-
key = row.idx
|
282
|
-
if changes.include?(key) && !work.include?(key)
|
283
|
-
row, pair = row_offsets.find do |idx, _| idx <= key end
|
284
|
-
work.store key, pair
|
285
|
-
end
|
286
|
-
end
|
287
|
-
if changes.size > control
|
288
|
-
warn <<-EOS
|
289
|
-
Your Worksheet was modified while it was being written. This should not happen.
|
290
|
-
Please contact the author (hannes dot wyss at gmail dot com) with a sample file
|
291
|
-
and minimal code that generates this warning. Thanks!
|
292
|
-
EOS
|
293
|
-
end
|
294
|
-
work = work.sort_by do |key, (pos, len)|
|
295
|
-
[pos, key.is_a?(Integer) ? key : -1]
|
296
|
-
end
|
297
|
-
work.each do |key, (pos, len)|
|
298
|
-
@io.write reader.read(pos - lastpos) if pos > lastpos
|
299
|
-
if key.is_a?(Integer)
|
300
|
-
if block = blocks.find do |rows| rows.any? do |row| row.idx == key end end
|
301
|
-
write_rowblock block
|
302
|
-
blocks.delete block
|
303
|
-
end
|
304
|
-
else
|
305
|
-
send "write_#{key}"
|
306
|
-
end
|
307
|
-
lastpos = pos + len
|
308
|
-
reader.seek lastpos
|
309
|
-
end
|
310
|
-
|
311
|
-
# Necessary for outline (grouping) and hiding functions
|
312
|
-
# but these below are not necessary to run
|
313
|
-
# if [Row|Column]#hidden? = false and [Row|Column]#outline_level == 0
|
314
|
-
write_colinfos
|
315
|
-
write_guts
|
316
|
-
|
317
|
-
@io.write reader.read(endpos - lastpos)
|
318
|
-
end
|
319
244
|
def write_colinfo bunch
|
320
245
|
col = bunch.first
|
321
246
|
width = col.width.to_f * 256
|
@@ -164,93 +164,6 @@ class Workbook < Spreadsheet::Writer
|
|
164
164
|
end
|
165
165
|
end
|
166
166
|
##
|
167
|
-
# Copy unchanged data verbatim, adjust offsets and write new records for
|
168
|
-
# changed data.
|
169
|
-
def write_changes workbook, io
|
170
|
-
sanitize_worksheets workbook.worksheets
|
171
|
-
collect_formats workbook, :existing_document => true
|
172
|
-
reader = workbook.ole
|
173
|
-
sheet_data = {}
|
174
|
-
sst_status, sst_total, sst_strings = complete_sst_update? workbook
|
175
|
-
sst = {}
|
176
|
-
sst_strings.each_with_index do |str, idx| sst.store str, idx end
|
177
|
-
sheets = worksheets(workbook)
|
178
|
-
positions = []
|
179
|
-
newsheets = []
|
180
|
-
sheets.each do |sheet|
|
181
|
-
@sst[sheet] = sst
|
182
|
-
pos, len = workbook.offsets[sheet.worksheet]
|
183
|
-
if pos
|
184
|
-
positions.push pos
|
185
|
-
sheet.write_changes reader, pos + len, sst_status
|
186
|
-
else
|
187
|
-
newsheets.push sheet
|
188
|
-
sheet.write_from_scratch
|
189
|
-
end
|
190
|
-
sheet_data[sheet.worksheet] = sheet.data
|
191
|
-
end
|
192
|
-
Ole::Storage.open io do |ole|
|
193
|
-
ole.file.open 'Workbook', 'w' do |writer|
|
194
|
-
reader.seek lastpos = 0
|
195
|
-
workbook.offsets.select do |key, pair|
|
196
|
-
workbook.changes.include? key
|
197
|
-
end.sort_by do |key, (pos, _)|
|
198
|
-
pos
|
199
|
-
end.each do |key, (pos, len)|
|
200
|
-
data = reader.read(pos - lastpos)
|
201
|
-
writer.write data
|
202
|
-
case key
|
203
|
-
when Spreadsheet::Worksheet
|
204
|
-
writer.write sheet_data[key]
|
205
|
-
when :boundsheets
|
206
|
-
## boundsheets are hard to calculate. The offset below is only
|
207
|
-
# correct if there are no more changes in the workbook globals
|
208
|
-
# string after this.
|
209
|
-
oldoffset = positions.min - len
|
210
|
-
lastpos = pos + len
|
211
|
-
bytechange = 0
|
212
|
-
buffer = StringIO.new ''.dup
|
213
|
-
if tuple = workbook.offsets[:sst]
|
214
|
-
write_sst_changes workbook, buffer, writer.pos,
|
215
|
-
sst_total, sst_strings
|
216
|
-
pos, len = tuple
|
217
|
-
if offset = workbook.offsets[:extsst]
|
218
|
-
len += offset[1].to_i
|
219
|
-
end
|
220
|
-
bytechange = buffer.size - len
|
221
|
-
write_boundsheets workbook, writer, oldoffset + bytechange
|
222
|
-
reader.seek lastpos
|
223
|
-
writer.write reader.read(pos - lastpos)
|
224
|
-
buffer.rewind
|
225
|
-
writer.write buffer.read
|
226
|
-
elsif sst.empty? || workbook.biff_version < 8
|
227
|
-
write_boundsheets workbook, writer, oldoffset + bytechange
|
228
|
-
else
|
229
|
-
write_sst workbook, buffer, writer.pos
|
230
|
-
write_boundsheets workbook, writer, oldoffset + buffer.size
|
231
|
-
pos = lastpos
|
232
|
-
len = positions.min - lastpos
|
233
|
-
if len > OPCODE_SIZE
|
234
|
-
reader.seek pos
|
235
|
-
writer.write reader.read(len - OPCODE_SIZE)
|
236
|
-
end
|
237
|
-
buffer.rewind
|
238
|
-
writer.write buffer.read
|
239
|
-
write_eof workbook, writer
|
240
|
-
end
|
241
|
-
else
|
242
|
-
send "write_#{key}", workbook, writer
|
243
|
-
end
|
244
|
-
lastpos = [pos + len, reader.size - 1].min
|
245
|
-
reader.seek lastpos
|
246
|
-
end
|
247
|
-
writer.write reader.read
|
248
|
-
newsheets.each do |sheet|
|
249
|
-
writer.write sheet.data
|
250
|
-
end
|
251
|
-
end
|
252
|
-
end
|
253
|
-
end
|
254
167
|
def write_datemode workbook, writer
|
255
168
|
mode = @date_base.year == 1899 ? 0x00 : 0x01
|
256
169
|
data = [
|
@@ -639,8 +552,7 @@ class Workbook < Spreadsheet::Writer
|
|
639
552
|
write_op writer, 0x003d, data.pack('v*')
|
640
553
|
end
|
641
554
|
##
|
642
|
-
# The main writer method. Calls #write_from_scratch
|
643
|
-
# depending on the class and state of _workbook_.
|
555
|
+
# The main writer method. Calls #write_from_scratch.
|
644
556
|
def write_workbook workbook, io
|
645
557
|
unless workbook.is_a?(Excel::Workbook) && workbook.io
|
646
558
|
@date_base = Date.new 1899, 12, 31
|
@@ -650,7 +562,8 @@ class Workbook < Spreadsheet::Writer
|
|
650
562
|
if workbook.changes.empty?
|
651
563
|
super
|
652
564
|
else
|
653
|
-
|
565
|
+
@date_base = Date.new 1899, 12, 31
|
566
|
+
write_from_scratch workbook, io
|
654
567
|
end
|
655
568
|
end
|
656
569
|
ensure
|
@@ -243,84 +243,6 @@ class Worksheet
|
|
243
243
|
end
|
244
244
|
write_multiples row, first_idx, multiples if multiples
|
245
245
|
end
|
246
|
-
def write_changes reader, endpos, sst_status
|
247
|
-
|
248
|
-
## FIXME this is not smart solution to update outline_level.
|
249
|
-
# without this process, outlines in row disappear in MS Excel.
|
250
|
-
@worksheet.row_count.times do |i|
|
251
|
-
if @worksheet.row(i).outline_level > 0
|
252
|
-
@worksheet.row(i).outline_level = @worksheet.row(i).outline_level
|
253
|
-
end
|
254
|
-
end
|
255
|
-
|
256
|
-
reader.seek @worksheet.offset
|
257
|
-
blocks = row_blocks
|
258
|
-
lastpos = reader.pos
|
259
|
-
offsets = {}
|
260
|
-
row_offsets = []
|
261
|
-
changes = @worksheet.changes
|
262
|
-
@worksheet.offsets.each do |key, pair|
|
263
|
-
if changes.include?(key) \
|
264
|
-
|| (sst_status == :complete_update && key.is_a?(Integer))
|
265
|
-
offsets.store pair, key
|
266
|
-
end
|
267
|
-
end
|
268
|
-
## FIXME it may be smarter to simply write all rowblocks, instead of doing a
|
269
|
-
# song-and-dance routine for every row...
|
270
|
-
work = offsets.invert
|
271
|
-
work.each do |key, (pos, len)|
|
272
|
-
case key
|
273
|
-
when Integer
|
274
|
-
row_offsets.push [key, [pos, len]]
|
275
|
-
when :dimensions
|
276
|
-
row_offsets.push [-1, [pos, len]]
|
277
|
-
end
|
278
|
-
end
|
279
|
-
row_offsets.sort!
|
280
|
-
row_offsets.reverse!
|
281
|
-
control = changes.size
|
282
|
-
@worksheet.each do |row|
|
283
|
-
key = row.idx
|
284
|
-
if changes.include?(key) && !work.include?(key)
|
285
|
-
row, pair = row_offsets.find do |idx, _| idx <= key end
|
286
|
-
work.store key, pair
|
287
|
-
end
|
288
|
-
end
|
289
|
-
if changes.size > control
|
290
|
-
warn <<-EOS
|
291
|
-
Your Worksheet was modified while it was being written. This should not happen.
|
292
|
-
Please contact the author (hannes dot wyss at gmail dot com) with a sample file
|
293
|
-
and minimal code that generates this warning. Thanks!
|
294
|
-
EOS
|
295
|
-
end
|
296
|
-
work = work.sort_by do |key, (pos, _)|
|
297
|
-
[pos, key.is_a?(Integer) ? key : -1]
|
298
|
-
end
|
299
|
-
work.each do |key, (pos, len)|
|
300
|
-
@io.write reader.read(pos - lastpos) if pos > lastpos
|
301
|
-
if key.is_a?(Integer)
|
302
|
-
if block = blocks.find do |rows| rows.any? do |row| row.idx == key end end
|
303
|
-
write_rowblock block
|
304
|
-
blocks.delete block
|
305
|
-
end
|
306
|
-
else
|
307
|
-
send "write_#{key}"
|
308
|
-
end
|
309
|
-
lastpos = pos + len
|
310
|
-
reader.seek lastpos
|
311
|
-
end
|
312
|
-
|
313
|
-
# Necessary for outline (grouping) and hiding functions
|
314
|
-
# but these below are not necessary to run
|
315
|
-
# if [Row|Column]#hidden? = false and [Row|Column]#outline_level == 0
|
316
|
-
write_merged_cells
|
317
|
-
write_pagesetup
|
318
|
-
write_margins
|
319
|
-
write_colinfos
|
320
|
-
write_guts
|
321
|
-
|
322
|
-
@io.write reader.read(endpos - lastpos)
|
323
|
-
end
|
324
246
|
def write_colinfo bunch
|
325
247
|
col = bunch.first
|
326
248
|
width = col.width.to_f * 256
|
data/lib/spreadsheet/excel.rb
CHANGED
@@ -1,11 +1,5 @@
|
|
1
1
|
require 'spreadsheet'
|
2
2
|
|
3
|
-
warn <<-EOS
|
4
|
-
[DEPRECATED] By requiring 'spreadsheet/excel' you are loading a Compatibility
|
5
|
-
layer which provides a drop-in replacement for Spreadsheet::Excel
|
6
|
-
versions <= 0.3.5.1. This code will be removed in Spreadsheet
|
7
|
-
version 1.0.0
|
8
|
-
EOS
|
9
3
|
##
|
10
4
|
# Spreadsheet::Excel Compatibility Layer.
|
11
5
|
# Drop-in replacement for Spreadsheet::Excel version <= 0.3.5.1
|
data/lib/spreadsheet/version.rb
CHANGED
@@ -49,7 +49,7 @@ module Spreadsheet
|
|
49
49
|
:right => 0.75,
|
50
50
|
:bottom => 1
|
51
51
|
}
|
52
|
-
@name = opts[:name] || 'Worksheet'
|
52
|
+
@name = sanitize_invalid_characters(opts[:name] || 'Worksheet')
|
53
53
|
@workbook = opts[:workbook]
|
54
54
|
@rows = []
|
55
55
|
@columns = []
|
@@ -233,7 +233,7 @@ module Spreadsheet
|
|
233
233
|
res
|
234
234
|
end
|
235
235
|
def << cells=[]
|
236
|
-
insert_row
|
236
|
+
insert_row @rows.size, cells
|
237
237
|
end
|
238
238
|
def inspect
|
239
239
|
names = instance_variables
|
@@ -366,6 +366,9 @@ module Spreadsheet
|
|
366
366
|
end
|
367
367
|
|
368
368
|
private
|
369
|
+
def sanitize_invalid_characters(name) # :nodoc:
|
370
|
+
name.gsub(Regexp.new('[\\\/\*\?\:\[\]]'.encode(Spreadsheet.client_encoding)), '_')
|
371
|
+
end
|
369
372
|
def index_of_first ary # :nodoc:
|
370
373
|
return unless ary
|
371
374
|
ary.index(ary.find do |elm| elm end)
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/test/integration.rb
CHANGED
@@ -1401,6 +1401,30 @@ module Spreadsheet
|
|
1401
1401
|
assert_equal(:visible, book2.worksheet(1).visibility)
|
1402
1402
|
end
|
1403
1403
|
|
1404
|
+
def test_append_and_reopen
|
1405
|
+
filename = path = File.join @var, 'test.xls'
|
1406
|
+
sheet_name = 'Test Sheet'
|
1407
|
+
|
1408
|
+
# Create excel
|
1409
|
+
excel = Spreadsheet::Workbook.new(filename)
|
1410
|
+
sheet = excel.create_worksheet(name: sheet_name)
|
1411
|
+
sheet.row(1).replace ['Data']
|
1412
|
+
excel.write(filename)
|
1413
|
+
|
1414
|
+
# Append something
|
1415
|
+
excel = Spreadsheet.open(filename, 'a+')
|
1416
|
+
sheet = excel.worksheet(sheet_name)
|
1417
|
+
sheet.row(2).replace ['Data2']
|
1418
|
+
filename = "test2.xls"
|
1419
|
+
excel.write(filename)
|
1420
|
+
|
1421
|
+
# Reopen
|
1422
|
+
excel = Spreadsheet.open filename
|
1423
|
+
sheet = excel.worksheet sheet_name
|
1424
|
+
ensure
|
1425
|
+
File.delete filename if File.exist? filename
|
1426
|
+
end
|
1427
|
+
|
1404
1428
|
def test_text_drawing
|
1405
1429
|
path = File.join @data, 'test_text_drawing.xls'
|
1406
1430
|
book = Spreadsheet.open path
|
data/test/suite.rb
CHANGED