spreadsheet 1.3.3 → 1.3.4
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/lib/parseexcel/parseexcel.rb +66 -58
- data/lib/parseexcel/parser.rb +1 -1
- data/lib/parseexcel.rb +1 -1
- data/lib/spreadsheet/column.rb +11 -9
- data/lib/spreadsheet/compatibility.rb +3 -1
- data/lib/spreadsheet/datatypes.rb +149 -147
- data/lib/spreadsheet/encodings.rb +20 -16
- data/lib/spreadsheet/errors.rb +2 -2
- data/lib/spreadsheet/excel/error.rb +23 -22
- data/lib/spreadsheet/excel/internals/biff5.rb +11 -11
- data/lib/spreadsheet/excel/internals/biff8.rb +13 -13
- data/lib/spreadsheet/excel/internals.rb +451 -451
- data/lib/spreadsheet/excel/offset.rb +32 -31
- data/lib/spreadsheet/excel/password_hash.rb +18 -18
- data/lib/spreadsheet/excel/reader/biff5.rb +34 -35
- data/lib/spreadsheet/excel/reader/biff8.rb +234 -222
- data/lib/spreadsheet/excel/reader.rb +1320 -1274
- data/lib/spreadsheet/excel/rgb.rb +91 -91
- data/lib/spreadsheet/excel/row.rb +99 -91
- data/lib/spreadsheet/excel/sst_entry.rb +40 -38
- data/lib/spreadsheet/excel/workbook.rb +86 -76
- data/lib/spreadsheet/excel/worksheet.rb +125 -107
- data/lib/spreadsheet/excel/writer/biff8.rb +56 -55
- data/lib/spreadsheet/excel/writer/format.rb +273 -256
- data/lib/spreadsheet/excel/writer/n_worksheet.rb +837 -798
- data/lib/spreadsheet/excel/writer/workbook.rb +671 -635
- data/lib/spreadsheet/excel/writer/worksheet.rb +898 -861
- data/lib/spreadsheet/excel/writer.rb +1 -1
- data/lib/spreadsheet/excel.rb +18 -11
- data/lib/spreadsheet/font.rb +30 -26
- data/lib/spreadsheet/format.rb +74 -59
- data/lib/spreadsheet/link.rb +7 -5
- data/lib/spreadsheet/note.rb +6 -6
- data/lib/spreadsheet/noteObject.rb +5 -5
- data/lib/spreadsheet/row.rb +33 -23
- data/lib/spreadsheet/version.rb +1 -1
- data/lib/spreadsheet/workbook.rb +27 -13
- data/lib/spreadsheet/worksheet.rb +102 -68
- data/lib/spreadsheet/writer.rb +3 -0
- data/lib/spreadsheet.rb +12 -15
- data/test/excel/reader.rb +8 -8
- data/test/excel/row.rb +35 -31
- data/test/excel/writer/workbook.rb +18 -16
- data/test/excel/writer/worksheet.rb +10 -8
- data/test/font.rb +44 -32
- data/test/format.rb +38 -33
- data/test/integration.rb +627 -598
- data/test/row.rb +5 -3
- data/test/suite.rb +7 -7
- data/test/workbook.rb +15 -14
- data/test/workbook_protection.rb +5 -5
- data/test/worksheet.rb +36 -34
- metadata +48 -6
@@ -1,115 +1,133 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require "spreadsheet/excel/offset"
|
2
|
+
require "spreadsheet/excel/row"
|
3
|
+
require "spreadsheet/worksheet"
|
4
4
|
|
5
5
|
module Spreadsheet
|
6
6
|
module Excel
|
7
|
-
##
|
8
|
-
# Excel-specific Worksheet methods. These are mostly pertinent to the Excel
|
9
|
-
# reader, and to recording changes to the Worksheet. You should have no reason
|
10
|
-
# to use any of these.
|
11
|
-
class Worksheet < Spreadsheet::Worksheet
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
ensure_rows_read
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
7
|
+
##
|
8
|
+
# Excel-specific Worksheet methods. These are mostly pertinent to the Excel
|
9
|
+
# reader, and to recording changes to the Worksheet. You should have no reason
|
10
|
+
# to use any of these.
|
11
|
+
class Worksheet < Spreadsheet::Worksheet
|
12
|
+
include Spreadsheet::Excel::Offset
|
13
|
+
offset :dimensions
|
14
|
+
attr_reader :offset, :ole, :links, :guts, :notes
|
15
|
+
def initialize opts = {}
|
16
|
+
@row_addresses = nil
|
17
|
+
super
|
18
|
+
@offset, @ole, @reader = opts[:offset], opts[:ole], opts[:reader]
|
19
|
+
@dimensions = nil
|
20
|
+
@links = {}
|
21
|
+
@guts = {}
|
22
|
+
@notes = {}
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_link row, column, link
|
26
|
+
@links.store [row, column], link
|
27
|
+
end
|
28
|
+
|
29
|
+
def add_note row, column, note
|
30
|
+
@notes.store [row, column], note
|
31
|
+
end
|
32
|
+
|
33
|
+
def column idx
|
34
|
+
ensure_rows_read
|
35
|
+
super
|
36
|
+
end
|
37
|
+
|
38
|
+
def date_base
|
39
|
+
@workbook.date_base
|
40
|
+
end
|
41
|
+
|
42
|
+
def margins
|
43
|
+
ensure_rows_read
|
44
|
+
super
|
45
|
+
end
|
46
|
+
|
47
|
+
def pagesetup
|
48
|
+
ensure_rows_read
|
49
|
+
super
|
50
|
+
end
|
51
|
+
|
52
|
+
def each *args
|
53
|
+
ensure_rows_read
|
54
|
+
super
|
55
|
+
end
|
56
|
+
|
57
|
+
def ensure_rows_read
|
58
|
+
return if @row_addresses
|
59
|
+
@dimensions = nil
|
60
|
+
@row_addresses = []
|
61
|
+
@reader&.read_worksheet self, @offset
|
62
|
+
end
|
63
|
+
|
64
|
+
def row idx
|
65
|
+
@rows[idx] or begin
|
66
|
+
ensure_rows_read
|
67
|
+
if (addr = @row_addresses[idx])
|
68
|
+
row = @reader.read_row self, addr
|
69
|
+
[:default_format, :height, :outline_level, :hidden].each do |key|
|
70
|
+
row.send :"unupdated_#{key}=", addr[key]
|
71
|
+
end
|
72
|
+
row.worksheet = self
|
73
|
+
row
|
74
|
+
else
|
75
|
+
Row.new self, idx
|
76
|
+
end
|
62
77
|
end
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
78
|
+
end
|
79
|
+
|
80
|
+
def rows
|
81
|
+
to_a
|
82
|
+
end
|
83
|
+
|
84
|
+
def row_updated idx, row
|
85
|
+
res = super
|
86
|
+
@workbook.changes.store self, true
|
87
|
+
@workbook.changes.store :boundsheets, true
|
88
|
+
@changes.store idx, true
|
89
|
+
@changes.store :dimensions, true
|
90
|
+
res
|
91
|
+
end
|
92
|
+
|
93
|
+
def set_row_address idx, opts
|
94
|
+
@offsets.store idx, opts[:row_block]
|
95
|
+
@row_addresses[idx] = opts
|
96
|
+
end
|
97
|
+
|
98
|
+
def shared_string idx
|
99
|
+
@workbook.shared_string idx
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
## premature optimization?
|
105
|
+
def have_set_dimensions value, pos, len
|
106
|
+
if @row_addresses.size < row_count
|
107
|
+
@row_addresses.concat Array.new(row_count - @row_addresses.size)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def recalculate_dimensions
|
112
|
+
ensure_rows_read
|
113
|
+
shorten @rows
|
114
|
+
@dimensions = []
|
115
|
+
@dimensions[0] = [index_of_first(@rows),
|
116
|
+
index_of_first(@row_addresses)].compact.min || 0
|
117
|
+
@dimensions[1] = [@rows.size, @row_addresses.size].compact.max || 0
|
118
|
+
compact = @rows.compact
|
119
|
+
first_rows = compact.collect { |row| row.first_used }.compact.min
|
120
|
+
first_addrs = @row_addresses.compact.collect do |addr|
|
121
|
+
addr[:first_used]
|
122
|
+
end.compact.min
|
123
|
+
@dimensions[2] = [first_rows, first_addrs].compact.min || 0
|
124
|
+
last_rows = compact.collect { |row| row.first_unused }.max
|
125
|
+
last_addrs = @row_addresses.compact.collect do |addr|
|
126
|
+
addr[:first_unused]
|
127
|
+
end.compact.max
|
128
|
+
@dimensions[3] = [last_rows, last_addrs].compact.max || 0
|
129
|
+
@dimensions
|
67
130
|
end
|
68
131
|
end
|
69
132
|
end
|
70
|
-
def rows
|
71
|
-
self.to_a
|
72
|
-
end
|
73
|
-
def row_updated idx, row
|
74
|
-
res = super
|
75
|
-
@workbook.changes.store self, true
|
76
|
-
@workbook.changes.store :boundsheets, true
|
77
|
-
@changes.store idx, true
|
78
|
-
@changes.store :dimensions, true
|
79
|
-
res
|
80
|
-
end
|
81
|
-
def set_row_address idx, opts
|
82
|
-
@offsets.store idx, opts[:row_block]
|
83
|
-
@row_addresses[idx] = opts
|
84
|
-
end
|
85
|
-
def shared_string idx
|
86
|
-
@workbook.shared_string idx
|
87
|
-
end
|
88
|
-
private
|
89
|
-
## premature optimization?
|
90
|
-
def have_set_dimensions value, pos, len
|
91
|
-
if @row_addresses.size < row_count
|
92
|
-
@row_addresses.concat Array.new(row_count - @row_addresses.size)
|
93
|
-
end
|
94
|
-
end
|
95
|
-
def recalculate_dimensions
|
96
|
-
ensure_rows_read
|
97
|
-
shorten @rows
|
98
|
-
@dimensions = []
|
99
|
-
@dimensions[0] = [ index_of_first(@rows),
|
100
|
-
index_of_first(@row_addresses) ].compact.min || 0
|
101
|
-
@dimensions[1] = [ @rows.size, @row_addresses.size ].compact.max || 0
|
102
|
-
compact = @rows.compact
|
103
|
-
first_rows = compact.collect do |row| row.first_used end.compact.min
|
104
|
-
first_addrs = @row_addresses.compact.collect do |addr|
|
105
|
-
addr[:first_used] end.compact.min
|
106
|
-
@dimensions[2] = [ first_rows, first_addrs ].compact.min || 0
|
107
|
-
last_rows = compact.collect do |row| row.first_unused end.max
|
108
|
-
last_addrs = @row_addresses.compact.collect do |addr|
|
109
|
-
addr[:first_unused] end.compact.max
|
110
|
-
@dimensions[3] = [last_rows, last_addrs].compact.max || 0
|
111
|
-
@dimensions
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
115
133
|
end
|
@@ -1,53 +1,54 @@
|
|
1
|
-
require
|
1
|
+
require "spreadsheet/encodings"
|
2
2
|
|
3
3
|
module Spreadsheet
|
4
4
|
module Excel
|
5
5
|
module Writer
|
6
|
-
##
|
7
|
-
# This Module collects writer methods such as unicode_string that are specific
|
8
|
-
# to Biff8. This Module is likely to be expanded as Support for older Versions
|
9
|
-
# of Excel grows and methods get moved here for disambiguation.
|
10
|
-
module Biff8
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
6
|
+
##
|
7
|
+
# This Module collects writer methods such as unicode_string that are specific
|
8
|
+
# to Biff8. This Module is likely to be expanded as Support for older Versions
|
9
|
+
# of Excel grows and methods get moved here for disambiguation.
|
10
|
+
module Biff8
|
11
|
+
include Spreadsheet::Encodings
|
12
|
+
##
|
13
|
+
# Check whether the string _data_ can be compressed (i.e. every second byte
|
14
|
+
# is a Null-byte) and perform compression.
|
15
|
+
# Returns the data and compression_status (0/1)
|
16
|
+
def compress_unicode_string data
|
17
|
+
compressed = internal("")
|
18
|
+
expect_null = false
|
19
|
+
data.each_byte do |byte|
|
20
|
+
if expect_null
|
21
|
+
if byte != 0
|
22
|
+
return [data, 1] # 1 => Data consists of wide Chars
|
23
|
+
end
|
24
|
+
expect_null = false
|
25
|
+
else
|
26
|
+
compressed << byte
|
27
|
+
expect_null = true
|
28
|
+
end
|
29
|
+
end
|
30
|
+
[compressed, 0] # 0 => Data consists of compressed Chars
|
23
31
|
end
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
size = data.send(@@bytesize) / 2
|
45
|
-
fmt = count_length == 1 ? 'C2' : 'vC'
|
46
|
-
data, wide = compress_unicode_string data
|
47
|
-
opts = wide
|
48
|
-
header = [
|
49
|
-
size, # Length of the string (character count, ln)
|
50
|
-
opts, # Option flags:
|
32
|
+
|
33
|
+
##
|
34
|
+
# Encode _string_ into a Biff8 Unicode String. Header and body are encoded
|
35
|
+
# separately by #_unicode_string. This method simply combines the two.
|
36
|
+
def unicode_string string, count_length = 1
|
37
|
+
header, data, _ = _unicode_string string, count_length
|
38
|
+
header << data
|
39
|
+
end
|
40
|
+
@@bytesize = (RUBY_VERSION >= "1.9") ? :bytesize : :size
|
41
|
+
##
|
42
|
+
# Encode _string_ into a Biff8 Unicode String Header and Body.
|
43
|
+
def _unicode_string string, count_length = 1
|
44
|
+
data = internal string
|
45
|
+
size = data.send(@@bytesize) / 2
|
46
|
+
fmt = (count_length == 1) ? "C2" : "vC"
|
47
|
+
data, wide = compress_unicode_string data
|
48
|
+
opts = wide
|
49
|
+
header = [
|
50
|
+
size, # Length of the string (character count, ln)
|
51
|
+
opts # Option flags:
|
51
52
|
# Bit Mask Contents
|
52
53
|
# 0 0x01 Character compression (ccompr):
|
53
54
|
# 0 = Compressed (8-bit characters)
|
@@ -58,18 +59,18 @@ module Biff8
|
|
58
59
|
# 3 0x08 Rich-Text settings (richtext):
|
59
60
|
# 0 = Does not contain Rich-Text settings
|
60
61
|
# 1 = Contains Rich-Text settings
|
61
|
-
|
62
|
+
# 0x00,# (optional, only if richtext=1) Number of Rich-Text
|
62
63
|
# formatting runs (rt)
|
63
|
-
|
64
|
+
# 0x00,# (optional, only if phonetic=1) Size of Asian phonetic
|
64
65
|
# settings block (in bytes, sz)
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
end
|
66
|
+
].pack fmt
|
67
|
+
data << "" # (optional, only if richtext=1)
|
68
|
+
# List of rt formatting runs (➜ 3.2)
|
69
|
+
data << "" # (optional, only if phonetic=1)
|
70
|
+
# Asian Phonetic Settings Block (➜ 3.4.2)
|
71
|
+
[header, data, wide]
|
72
|
+
end
|
73
|
+
end
|
73
74
|
end
|
74
75
|
end
|
75
76
|
end
|