spreadsheet 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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