spreadsheet 0.6.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 (47) hide show
  1. data/GUIDE.txt +209 -0
  2. data/History.txt +8 -0
  3. data/LICENSE.txt +619 -0
  4. data/Manifest.txt +46 -0
  5. data/README.txt +54 -0
  6. data/Rakefile +15 -0
  7. data/lib/parseexcel.rb +27 -0
  8. data/lib/parseexcel/parseexcel.rb +75 -0
  9. data/lib/parseexcel/parser.rb +11 -0
  10. data/lib/spreadsheet.rb +79 -0
  11. data/lib/spreadsheet/datatypes.rb +99 -0
  12. data/lib/spreadsheet/encodings.rb +49 -0
  13. data/lib/spreadsheet/excel.rb +75 -0
  14. data/lib/spreadsheet/excel/error.rb +26 -0
  15. data/lib/spreadsheet/excel/internals.rb +322 -0
  16. data/lib/spreadsheet/excel/internals/biff5.rb +17 -0
  17. data/lib/spreadsheet/excel/internals/biff8.rb +19 -0
  18. data/lib/spreadsheet/excel/offset.rb +37 -0
  19. data/lib/spreadsheet/excel/reader.rb +798 -0
  20. data/lib/spreadsheet/excel/reader/biff5.rb +22 -0
  21. data/lib/spreadsheet/excel/reader/biff8.rb +168 -0
  22. data/lib/spreadsheet/excel/row.rb +67 -0
  23. data/lib/spreadsheet/excel/sst_entry.rb +45 -0
  24. data/lib/spreadsheet/excel/workbook.rb +76 -0
  25. data/lib/spreadsheet/excel/worksheet.rb +85 -0
  26. data/lib/spreadsheet/excel/writer.rb +1 -0
  27. data/lib/spreadsheet/excel/writer/biff8.rb +66 -0
  28. data/lib/spreadsheet/excel/writer/format.rb +270 -0
  29. data/lib/spreadsheet/excel/writer/workbook.rb +586 -0
  30. data/lib/spreadsheet/excel/writer/worksheet.rb +556 -0
  31. data/lib/spreadsheet/font.rb +86 -0
  32. data/lib/spreadsheet/format.rb +172 -0
  33. data/lib/spreadsheet/formula.rb +9 -0
  34. data/lib/spreadsheet/row.rb +87 -0
  35. data/lib/spreadsheet/workbook.rb +120 -0
  36. data/lib/spreadsheet/worksheet.rb +215 -0
  37. data/lib/spreadsheet/writer.rb +29 -0
  38. data/test/data/test_copy.xls +0 -0
  39. data/test/data/test_version_excel5.xls +0 -0
  40. data/test/data/test_version_excel95.xls +0 -0
  41. data/test/data/test_version_excel97.xls +0 -0
  42. data/test/excel/row.rb +29 -0
  43. data/test/font.rb +163 -0
  44. data/test/integration.rb +1021 -0
  45. data/test/workbook.rb +21 -0
  46. data/test/worksheet.rb +62 -0
  47. metadata +113 -0
@@ -0,0 +1,215 @@
1
+ require 'date'
2
+ require 'spreadsheet/encodings'
3
+ require 'spreadsheet/row'
4
+
5
+ module Spreadsheet
6
+ ##
7
+ # The Worksheet class. Contains most of the Spreadsheet data in Rows.
8
+ #
9
+ # Interesting Attributes
10
+ # #name :: The Name of this Worksheet.
11
+ # #default_format:: The default format used for all cells in this Workhseet
12
+ # that have no format set explicitly or in
13
+ # Row#default_format.
14
+ # #rows :: The Rows in this Worksheet. It is not recommended to
15
+ # Manipulate this Array directly. If you do, call
16
+ # #updated_from with the smallest modified index.
17
+ class Worksheet
18
+ include Encodings
19
+ attr_accessor :name, :workbook
20
+ attr_reader :rows
21
+ include Enumerable
22
+ def initialize opts={}
23
+ @dimensions = [0,0,0,0]
24
+ @name = opts[:name] || 'Worksheet'
25
+ @workbook = opts[:workbook]
26
+ @rows = []
27
+ end
28
+ ##
29
+ # Add a Format to the Workbook. If you use Row#set_format, you should not
30
+ # need to use this Method.
31
+ def add_format fmt
32
+ @workbook.add_format fmt
33
+ end
34
+ ##
35
+ # Get the enriched value of the Cell at _row_, _column_.
36
+ # See also Worksheet#[], Row#[].
37
+ def cell row, column
38
+ row(row)[column]
39
+ end
40
+ ##
41
+ # The number of columns in this Worksheet which contain data.
42
+ def column_count
43
+ dimensions[3] - dimensions[2]
44
+ end
45
+ ##
46
+ # Delete the Row at _idx_ (0-based) from this Worksheet.
47
+ def delete_row idx
48
+ res = @rows.delete_at idx
49
+ updated_from idx
50
+ res
51
+ end
52
+ ##
53
+ # The default Format of this Worksheet, if you have set one.
54
+ # Returns the Workbook's default Format otherwise.
55
+ def default_format
56
+ @default_format || @workbook.default_format
57
+ end
58
+ ##
59
+ # Set the default Format of this Worksheet.
60
+ def default_format= format
61
+ @default_format = format
62
+ add_format format if format
63
+ format
64
+ end
65
+ ##
66
+ # Dimensions:: [ first used row, first unused row,
67
+ # first used column, first unused column ]
68
+ # ( First used means that all rows or columns before that are
69
+ # empty. First unused means that this and all following rows
70
+ # or columns are empty. )
71
+ def dimensions
72
+ @dimensions || recalculate_dimensions
73
+ end
74
+ ##
75
+ # If no argument is given, #each iterates over all used Rows (from the first
76
+ # used Row until but omitting the first unused Row, see also #dimensions).
77
+ #
78
+ # If the argument skip is given, #each iterates from that row until but
79
+ # omitting the first unused Row, effectively skipping the first _skip_ Rows
80
+ # from the top of the Worksheet.
81
+ def each skip=dimensions[0], &block
82
+ skip.upto(dimensions[1] - 1) do |idx|
83
+ block.call row(idx)
84
+ end
85
+ end
86
+ def encoding # :nodoc:
87
+ @workbook.encoding
88
+ end
89
+ ##
90
+ # Insert a Row at _idx_ (0-based) containing _cells_
91
+ def insert_row idx, cells=[]
92
+ res = @rows.insert idx, Row.new(self, idx, cells)
93
+ updated_from idx
94
+ res
95
+ end
96
+ def inspect
97
+ "#<#{self.class}:#{object_id} "
98
+ names = instance_variables
99
+ names.delete '@rows'
100
+ variables = names.collect do |name|
101
+ "%s=%s" % [name, instance_variable_get(name)]
102
+ end.join(' ')
103
+ sprintf "#<%s:0x%014x %s @rows[%i]>", self.class, object_id,
104
+ variables, row_count
105
+ end
106
+ ##
107
+ # Replace the Row at _idx_ with the following arguments. Like #update_row,
108
+ # but truncates the Row if there are fewer arguments than Cells in the Row.
109
+ def replace_row idx, *cells
110
+ if(row = @rows[idx]) && cells.size < row.size
111
+ cells.concat Array.new(row.size - cells.size)
112
+ end
113
+ update_row idx, *cells
114
+ end
115
+ ##
116
+ # The Row at _idx_ or a new Row.
117
+ def row idx
118
+ @rows[idx] || Row.new(self, idx)
119
+ end
120
+ ##
121
+ # The number of Rows in this Worksheet which contain data.
122
+ def row_count
123
+ dimensions[1] - dimensions[0]
124
+ end
125
+ ##
126
+ # Tell Worksheet that the Row at _idx_ has been updated and the #dimensions
127
+ # need to be recalculated. You should not need to call this directly.
128
+ def row_updated idx, row
129
+ @dimensions = nil
130
+ row = @rows[idx] = shorten(row)
131
+ format_dates row
132
+ row
133
+ end
134
+ ##
135
+ # Updates the Row at _idx_ with the following arguments.
136
+ def update_row idx, *cells
137
+ res = if row = @rows[idx]
138
+ row[0, cells.size] = cells
139
+ row
140
+ elsif cells = shorten(cells)
141
+ Row.new self, idx, cells
142
+ end
143
+ row_updated idx, res
144
+ res
145
+ end
146
+ ##
147
+ # Renumbers all Rows starting at _idx_ and calls #row_updated for each of
148
+ # them.
149
+ def updated_from idx
150
+ idx.upto(@rows.size - 1) do |idx|
151
+ row = row(idx)
152
+ row.idx = idx
153
+ row_updated idx, row
154
+ end
155
+ end
156
+ ##
157
+ # Get the enriched value of the Cell at _row_, _column_.
158
+ # See also Worksheet#cell, Row#[].
159
+ def [] row, column
160
+ row(row)[column]
161
+ end
162
+ ##
163
+ # Set the value of the Cell at _row_, _column_ to _value_.
164
+ # See also Row#[]=.
165
+ def []= row, column, value
166
+ row(row)[column] = value
167
+ end
168
+ private
169
+ def format_dates row # :nodoc:
170
+ ## If no format is set in a cell which contains a Date or Time, we will
171
+ # add a format. At the moment, the number formats correspond to builtin
172
+ # Excel number-formats. We may need to add a level of abstraction if
173
+ # additional writers are added to the library.
174
+ return unless row
175
+ row.each_with_index do |value, idx|
176
+ unless row.formats[idx]
177
+ format = nil
178
+ case value
179
+ when Date
180
+ format = @workbook.formats.find do |fmt| fmt.date? end
181
+ format ||= Format.new :number_format => client('M/D/YY', 'UTF8')
182
+ when DateTime, Time
183
+ format = @workbook.formats.find do |fmt| fmt.datetime? end
184
+ format ||= Format.new :number_format => client('M/D/YY h:mm', 'UTF8')
185
+ end
186
+ if format
187
+ row.formats[idx] = format
188
+ @workbook.add_format format
189
+ end
190
+ end
191
+ end
192
+ end
193
+ def index_of_first ary # :nodoc:
194
+ return unless ary
195
+ ary.index(ary.find do |elm| elm end)
196
+ end
197
+ def recalculate_dimensions # :nodoc:
198
+ shorten @rows
199
+ @dimensions = []
200
+ @dimensions[0] = index_of_first @rows
201
+ @dimensions[1] = @rows.size
202
+ compact = @rows.compact
203
+ @dimensions[2] = compact.collect do |row| index_of_first row end.compact.min
204
+ @dimensions[3] = compact.collect do |row| row.size end.max
205
+ @dimensions
206
+ end
207
+ def shorten ary # :nodoc:
208
+ return unless ary
209
+ while !ary.empty? && !ary.last
210
+ ary.pop
211
+ end
212
+ ary unless ary.empty?
213
+ end
214
+ end
215
+ end
@@ -0,0 +1,29 @@
1
+ module Spreadsheet
2
+ ##
3
+ # Parent Class for all Writers. Implements the copying of unmodified
4
+ # Spreadsheet documents.
5
+ class Writer
6
+ def initialize io_or_path
7
+ @io_or_path = io_or_path
8
+ end
9
+ def write workbook
10
+ if @io_or_path.is_a? IO
11
+ write_workbook workbook, @io_or_path
12
+ else
13
+ File.open(@io_or_path, "wb+") do |fh|
14
+ write_workbook workbook, fh
15
+ end
16
+ end
17
+ end
18
+ private
19
+ def write_workbook workbook, io
20
+ reader = workbook.io
21
+ unless io == reader
22
+ reader.rewind
23
+ data = reader.read
24
+ io.rewind
25
+ io.write data
26
+ end
27
+ end
28
+ end
29
+ end
Binary file
Binary file
Binary file
Binary file
data/test/excel/row.rb ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # Excel::TestRow -- Spreadsheet -- 12.10.2008 -- hwyss@ywesee.com
3
+
4
+ $: << File.expand_path('../../lib', File.dirname(__FILE__))
5
+
6
+ require 'test/unit'
7
+ require 'spreadsheet'
8
+
9
+ module Spreadsheet
10
+ module Excel
11
+ class TestRow < Test::Unit::TestCase
12
+ def setup
13
+ @workbook = Excel::Workbook.new
14
+ @worksheet = Excel::Worksheet.new
15
+ @workbook.add_worksheet @worksheet
16
+ end
17
+ def test_date
18
+ row = Row.new @worksheet, 0, [nil, 27627.6789]
19
+ assert_equal Date.new(1975,8,21), row.date(1)
20
+ end
21
+ def test_datetime
22
+ row = Row.new @worksheet, 0, [nil, 27627.6789]
23
+ d1 = DateTime.new(1975,8,21) + 0.6789
24
+ d2 = row.datetime 1
25
+ assert_equal d1, d2
26
+ end
27
+ end
28
+ end
29
+ end
data/test/font.rb ADDED
@@ -0,0 +1,163 @@
1
+ #!/usr/bin/env ruby
2
+ # TestFont -- Spreadsheet -- 09.10.2008 -- hwyss@ywesee.com
3
+
4
+ $: << File.expand_path('../lib', File.dirname(__FILE__))
5
+
6
+ require 'test/unit'
7
+ require 'spreadsheet/font'
8
+
9
+ module Spreadsheet
10
+ class TestFont < Test::Unit::TestCase
11
+ def setup
12
+ @font = Font.new 'Arial'
13
+ end
14
+ def test_italic
15
+ assert_equal false, @font.italic
16
+ @font.italic!
17
+ assert_equal true, @font.italic
18
+ @font.italic = nil
19
+ assert_equal false, @font.italic
20
+ @font.italic = 1
21
+ assert_equal true, @font.italic
22
+ end
23
+ def test_encoding
24
+ assert_equal :default, @font.encoding
25
+ @font.encoding = :apple_roman
26
+ assert_equal :apple_roman, @font.encoding
27
+ @font.encoding = 'Chinese Simplified'
28
+ assert_equal :chinese_simplified, @font.encoding
29
+ assert_raises ArgumentError do @font.size = 'ascii' end
30
+ assert_equal :chinese_simplified, @font.encoding
31
+ @font.encoding = nil
32
+ assert_equal :default, @font.encoding
33
+ end
34
+ def test_family
35
+ assert_equal :none, @font.family
36
+ @font.family = :roman
37
+ assert_equal :roman, @font.family
38
+ @font.family = 'Swiss'
39
+ assert_equal :swiss, @font.family
40
+ assert_raises ArgumentError do @font.size = :greek end
41
+ assert_equal :swiss, @font.family
42
+ @font.family = nil
43
+ assert_equal :none, @font.family
44
+ end
45
+ def test_name
46
+ assert_equal 'Arial', @font.name
47
+ @font.name = 'Helvetica'
48
+ assert_equal 'Helvetica', @font.name
49
+ end
50
+ def test_outline
51
+ assert_equal false, @font.outline
52
+ @font.outline!
53
+ assert_equal true, @font.outline
54
+ @font.outline = nil
55
+ assert_equal false, @font.outline
56
+ @font.outline = 1
57
+ assert_equal true, @font.outline
58
+ end
59
+ def test_escapement
60
+ assert_equal :normal, @font.escapement
61
+ @font.escapement = :superscript
62
+ assert_equal :superscript, @font.escapement
63
+ @font.escapement = 'sub'
64
+ assert_equal :subscript, @font.escapement
65
+ assert_raises ArgumentError do @font.size = "upwards" end
66
+ assert_equal :subscript, @font.escapement
67
+ @font.escapement = nil
68
+ assert_equal :normal, @font.escapement
69
+ end
70
+ def test_shadow
71
+ assert_equal false, @font.shadow
72
+ @font.shadow!
73
+ assert_equal true, @font.shadow
74
+ @font.shadow = nil
75
+ assert_equal false, @font.shadow
76
+ @font.shadow = 1
77
+ assert_equal true, @font.shadow
78
+ end
79
+ def test_size
80
+ assert_equal 10, @font.size
81
+ @font.size = 12
82
+ assert_equal 12, @font.size
83
+ @font.size = 11.2
84
+ assert_equal 11.2, @font.size
85
+ assert_raises ArgumentError do @font.size = "123" end
86
+ end
87
+ def test_strikeout
88
+ assert_equal false, @font.strikeout
89
+ @font.strikeout!
90
+ assert_equal true, @font.strikeout
91
+ @font.strikeout = nil
92
+ assert_equal false, @font.strikeout
93
+ @font.strikeout = 1
94
+ assert_equal true, @font.strikeout
95
+ end
96
+ def test_underline
97
+ assert_equal :none, @font.underline
98
+ @font.underline = :single
99
+ assert_equal :single, @font.underline
100
+ @font.underline = 'double accounting'
101
+ assert_equal :double_accounting, @font.underline
102
+ assert_raises ArgumentError do @font.size = :triple end
103
+ assert_equal :double_accounting, @font.underline
104
+ @font.underline = nil
105
+ assert_equal :none, @font.underline
106
+ @font.underline = true
107
+ assert_equal :single, @font.underline
108
+ end
109
+ def test_weight
110
+ assert_equal :normal, @font.weight
111
+ @font.weight = :bold
112
+ assert_equal :bold, @font.weight
113
+ @font.weight = 100
114
+ assert_equal 100, @font.weight
115
+ assert_raises ArgumentError do @font.weight = Object.new end
116
+ assert_equal 100, @font.weight
117
+ @font.weight = 'bold'
118
+ assert_equal :bold, @font.weight
119
+ @font.weight = nil
120
+ assert_equal :normal, @font.weight
121
+ end
122
+ def test_key
123
+ expected = 'Arial_10_normal_normal_none_text_none_default'
124
+ assert_equal expected, @font.key
125
+ @font.name = 'Helvetica'
126
+ expected = 'Helvetica_10_normal_normal_none_text_none_default'
127
+ assert_equal expected, @font.key
128
+ @font.size = 12
129
+ expected = 'Helvetica_12_normal_normal_none_text_none_default'
130
+ assert_equal expected, @font.key
131
+ @font.weight = :bold
132
+ expected = 'Helvetica_12_bold_normal_none_text_none_default'
133
+ assert_equal expected, @font.key
134
+ @font.italic!
135
+ expected = 'Helvetica_12_bold_italic_normal_none_text_none_default'
136
+ assert_equal expected, @font.key
137
+ @font.strikeout!
138
+ expected = 'Helvetica_12_bold_italic_strikeout_normal_none_text_none_default'
139
+ assert_equal expected, @font.key
140
+ @font.outline!
141
+ expected = 'Helvetica_12_bold_italic_strikeout_outline_normal_none_text_none_default'
142
+ assert_equal expected, @font.key
143
+ @font.shadow!
144
+ expected = 'Helvetica_12_bold_italic_strikeout_outline_shadow_normal_none_text_none_default'
145
+ assert_equal expected, @font.key
146
+ @font.escapement = :super
147
+ expected = 'Helvetica_12_bold_italic_strikeout_outline_shadow_superscript_none_text_none_default'
148
+ assert_equal expected, @font.key
149
+ @font.underline = :double
150
+ expected = 'Helvetica_12_bold_italic_strikeout_outline_shadow_superscript_double_text_none_default'
151
+ assert_equal expected, @font.key
152
+ @font.color = :blue
153
+ expected = 'Helvetica_12_bold_italic_strikeout_outline_shadow_superscript_double_blue_none_default'
154
+ assert_equal expected, @font.key
155
+ @font.family = :swiss
156
+ expected = 'Helvetica_12_bold_italic_strikeout_outline_shadow_superscript_double_blue_swiss_default'
157
+ assert_equal expected, @font.key
158
+ @font.encoding = :iso_latin1
159
+ expected = 'Helvetica_12_bold_italic_strikeout_outline_shadow_superscript_double_blue_swiss_iso_latin1'
160
+ assert_equal expected, @font.key
161
+ end
162
+ end
163
+ end