spreadsheet 1.1.3 → 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: d963aae672b717dc7a279a1e14efec5cce64a272
4
- data.tar.gz: 18009a3af345b0051e4ad6efe2f85739ec87dda3
2
+ SHA256:
3
+ metadata.gz: c0291eb7283e45bbe612232b8ee760af808b65440ec47b536236638b6f2ed96c
4
+ data.tar.gz: 5fe1c14cc4898d924e69a7b4c4d5d1590e5e822f04e9991222631c674399ad45
5
5
  SHA512:
6
- metadata.gz: e22611671910b290869e586f214b92d00beb40d486b1b830face971f8dc35fdeb60e064fa44c7e0e27393eab5217890fcf595d990597ef1e324be2565048fc93
7
- data.tar.gz: 253242666e44ffcc7ef180c542e2f7ee30183db5d00d4277de99e2a2736d519af1a61f4b36404c0a6173ab2883e197c699a96d90cdb02013619691fe07ee81d4
6
+ metadata.gz: 9d77e1dd7a9b4bce2007d99e3a2a829fb27f51f3739dca76d877a5279999392ffe72206a1be2b6cabc0e2432fa3e4705f3bdf4a2060b9a0e66b4242c719438c2
7
+ data.tar.gz: f85e21c6b636713a9bcba68d436edbce67e3aab4fa01790be36a1b776e2cb0508fa9bbd4904c9d551258640109dbd574fb671503c6c6d62bd3af848dcbc955fe
data/Manifest.txt CHANGED
@@ -49,6 +49,7 @@ lib/spreadsheet/link.rb
49
49
  lib/spreadsheet/note.rb
50
50
  lib/spreadsheet/noteObject.rb
51
51
  lib/spreadsheet/row.rb
52
+ lib/spreadsheet/version.rb
52
53
  lib/spreadsheet/workbook.rb
53
54
  lib/spreadsheet/worksheet.rb
54
55
  lib/spreadsheet/writer.rb
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
- require 'spreadsheet'
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
- source, target = ARGV
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
6
14
 
7
- if source.nil?
8
- puts "Usage: #{$0} <source> [<target>]"
9
- exit -1
10
- end
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
11
16
 
12
- target = target ? File.open(target, 'w') : STDOUT
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
- reader = Spreadsheet::Excel::Reader.new :print_opcodes => target
15
- reader.setup File.open(source)
26
+ require "rubygems"
27
+ require "bundler/setup"
16
28
 
17
- while tuple = reader.get_next_chunk
18
- end
29
+ load Gem.bin_path("spreadsheet", "xlsopcodes")
@@ -54,7 +54,7 @@ module Internals
54
54
  32768 => "MACROMAN",
55
55
  32769 => "WINDOWS-1252", #(Latin I) (BIFF2-BIFF3)
56
56
  }
57
- SEGAPEDOC = CODEPAGES.invert
57
+ SEGAPEDOC = CODEPAGES.reject { |k, _v| k >= 21010 }.invert
58
58
  # color_codes according to http://support.softartisans.com/kbview_1205.aspx
59
59
  # synonyms are in comments when reverse lookup
60
60
  COLOR_CODES = {
@@ -196,7 +196,7 @@ module Biff8
196
196
  ##
197
197
  # Insert null-characters into a compressed UTF-16 string
198
198
  def wide string
199
- data = ''
199
+ data = ''.dup
200
200
  string.each_byte do |byte| data << byte.chr << 0.chr end
201
201
  data
202
202
  end
@@ -56,7 +56,7 @@ class Reader
56
56
  ## remove two bits
57
57
  integer, = work.unpack 'V'
58
58
  integer &= 0xfffffffc
59
- value, = ("\0\0\0\0" << [integer].pack('V')).unpack EIGHT_BYTE_DOUBLE
59
+ value, = ("\0\0\0\0" + [integer].pack('V')).unpack EIGHT_BYTE_DOUBLE
60
60
  else
61
61
  ## I can't find a format for unpacking a little endian signed integer.
62
62
  # 'V' works for packing, but not for unpacking. But the following works
@@ -125,11 +125,12 @@ class Reader
125
125
  #So link the noteObject(text) to the note (with author, position)
126
126
  #TODO
127
127
  @noteList.each do |i|
128
- matching_obj = @noteObjList.select {|j| j.objID == i.objID}
129
- if matching_obj.length > 1
128
+ matching_objs = @noteObjList.select { |j| j.objID == i.objID }
129
+ if matching_objs.length > 1
130
130
  puts "ERROR - more than one matching object ID!"
131
131
  end
132
- i.text = matching_obj.first.text
132
+ matching_obj = matching_objs.first
133
+ i.text = matching_obj.nil? ? '' : matching_obj.text
133
134
  worksheet.add_note i.row, i.col, i.text
134
135
  end
135
136
  end
@@ -398,10 +399,10 @@ class Reader
398
399
  end
399
400
  formula.value = value
400
401
  elsif rtype == 0
401
- pos, op, len, work = get_next_chunk
402
+ pos, op, _len, work = get_next_chunk
402
403
  if op == :sharedfmla
403
404
  ## TODO: formula-support in 0.8.0
404
- pos, op, len, work = get_next_chunk
405
+ pos, op, _len, work = get_next_chunk
405
406
  end
406
407
  if op == :string
407
408
  formula.value = client read_string(work, 2), @workbook.encoding
@@ -851,6 +852,7 @@ class Reader
851
852
  @detected_rows = {}
852
853
  @noteObjList = []
853
854
  @noteList = []
855
+ @noteObject = nil
854
856
  previous = nil
855
857
  while tuple = get_next_chunk
856
858
  pos, op, len, work = tuple
@@ -1273,11 +1275,11 @@ class Reader
1273
1275
  end
1274
1276
  def setup io
1275
1277
  ## Reading from StringIO fails without forced encoding
1276
- if io.respond_to?(:string) && (str = io.string) \
1277
- && str.respond_to?(:force_encoding)
1278
- str.force_encoding 'ASCII-8BIT'
1278
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.3.0')
1279
+ io.set_encoding('ASCII-8BIT')
1280
+ elsif io.respond_to?(:string) && (str = io.string) && str.respond_to?(:force_encoding)
1281
+ str.force_encoding('ASCII-8BIT')
1279
1282
  end
1280
- ##
1281
1283
  io.rewind
1282
1284
  @ole = Ole::Storage.open io
1283
1285
  @workbook = Workbook.new io, {}
@@ -28,8 +28,7 @@ class Workbook < Spreadsheet::Workbook
28
28
  attr_accessor :bof, :ole
29
29
  attr_writer :date_base
30
30
  def Workbook.open io, opts = {}
31
- @reader = Reader.new opts
32
- @reader.read io
31
+ Reader.new(opts).read(io)
33
32
  end
34
33
  def initialize *args
35
34
  super
@@ -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 ''
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 = [
@@ -396,7 +309,7 @@ class Workbook < Spreadsheet::Writer
396
309
  sanitize_worksheets workbook.worksheets
397
310
  collect_formats workbook
398
311
  sheets = worksheets workbook
399
- buffer1 = StringIO.new ''
312
+ buffer1 = StringIO.new ''.dup
400
313
  # ● BOF Type = workbook globals (➜ 6.8)
401
314
  write_bof workbook, buffer1, :globals
402
315
  # ○ File Protection Block ➜ 4.19
@@ -441,7 +354,7 @@ class Workbook < Spreadsheet::Writer
441
354
  # ○ USESELFS ➜ 5.106
442
355
  buffer1.rewind
443
356
  # ●● BOUNDSHEET ➜ 5.95
444
- buffer2 = StringIO.new ''
357
+ buffer2 = StringIO.new ''.dup
445
358
  # ○ COUNTRY ➜ 5.22
446
359
  # ○ Link Table ➜ 4.10.3
447
360
  # ○○ NAME ➜ 6.66
@@ -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 or #write_changes
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
- write_changes workbook, io
565
+ @date_base = Date.new 1899, 12, 31
566
+ write_from_scratch workbook, io
654
567
  end
655
568
  end
656
569
  ensure