nulogy-spreadsheet 0.6.5.7.2

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 (66) hide show
  1. data/.gitignore +3 -0
  2. data/GUIDE.txt +267 -0
  3. data/Gemfile +4 -0
  4. data/Gemfile.lock +18 -0
  5. data/History.txt +365 -0
  6. data/LICENSE.txt +619 -0
  7. data/Manifest.txt +62 -0
  8. data/README.txt +107 -0
  9. data/Rakefile +1 -0
  10. data/bin/xlsopcodes +18 -0
  11. data/lib/parseexcel.rb +27 -0
  12. data/lib/parseexcel/parseexcel.rb +75 -0
  13. data/lib/parseexcel/parser.rb +11 -0
  14. data/lib/spreadsheet.rb +79 -0
  15. data/lib/spreadsheet/column.rb +71 -0
  16. data/lib/spreadsheet/compatibility.rb +23 -0
  17. data/lib/spreadsheet/datatypes.rb +105 -0
  18. data/lib/spreadsheet/encodings.rb +57 -0
  19. data/lib/spreadsheet/excel.rb +88 -0
  20. data/lib/spreadsheet/excel/error.rb +26 -0
  21. data/lib/spreadsheet/excel/internals.rb +361 -0
  22. data/lib/spreadsheet/excel/internals/biff5.rb +17 -0
  23. data/lib/spreadsheet/excel/internals/biff8.rb +19 -0
  24. data/lib/spreadsheet/excel/offset.rb +41 -0
  25. data/lib/spreadsheet/excel/reader.rb +1173 -0
  26. data/lib/spreadsheet/excel/reader/biff5.rb +22 -0
  27. data/lib/spreadsheet/excel/reader/biff8.rb +199 -0
  28. data/lib/spreadsheet/excel/row.rb +92 -0
  29. data/lib/spreadsheet/excel/sst_entry.rb +46 -0
  30. data/lib/spreadsheet/excel/workbook.rb +80 -0
  31. data/lib/spreadsheet/excel/worksheet.rb +100 -0
  32. data/lib/spreadsheet/excel/writer.rb +1 -0
  33. data/lib/spreadsheet/excel/writer/biff8.rb +75 -0
  34. data/lib/spreadsheet/excel/writer/format.rb +253 -0
  35. data/lib/spreadsheet/excel/writer/workbook.rb +653 -0
  36. data/lib/spreadsheet/excel/writer/worksheet.rb +886 -0
  37. data/lib/spreadsheet/font.rb +92 -0
  38. data/lib/spreadsheet/format.rb +177 -0
  39. data/lib/spreadsheet/formula.rb +9 -0
  40. data/lib/spreadsheet/helpers.rb +11 -0
  41. data/lib/spreadsheet/link.rb +43 -0
  42. data/lib/spreadsheet/row.rb +132 -0
  43. data/lib/spreadsheet/workbook.rb +126 -0
  44. data/lib/spreadsheet/worksheet.rb +277 -0
  45. data/lib/spreadsheet/writer.rb +30 -0
  46. data/nulogy-spreadsheet.gemspec +21 -0
  47. data/test/data/test_changes.xls +0 -0
  48. data/test/data/test_copy.xls +0 -0
  49. data/test/data/test_datetime.xls +0 -0
  50. data/test/data/test_empty.xls +0 -0
  51. data/test/data/test_formula.xls +0 -0
  52. data/test/data/test_long_sst_record.xls +0 -0
  53. data/test/data/test_missing_row.xls +0 -0
  54. data/test/data/test_version_excel5.xls +0 -0
  55. data/test/data/test_version_excel95.xls +0 -0
  56. data/test/data/test_version_excel97.xls +0 -0
  57. data/test/excel/row.rb +35 -0
  58. data/test/excel/writer/workbook.rb +23 -0
  59. data/test/excel/writer/worksheet.rb +55 -0
  60. data/test/font.rb +163 -0
  61. data/test/integration.rb +1311 -0
  62. data/test/row.rb +33 -0
  63. data/test/suite.rb +17 -0
  64. data/test/workbook.rb +29 -0
  65. data/test/worksheet.rb +80 -0
  66. metadata +162 -0
@@ -0,0 +1,126 @@
1
+ require 'spreadsheet/format'
2
+ require 'spreadsheet/encodings'
3
+
4
+ module Spreadsheet
5
+ ##
6
+ # The Workbook class represents a Spreadsheet-Document and is the entry point
7
+ # for all Spreadsheet manipulation.
8
+ #
9
+ # Interesting Attributes:
10
+ # #default_format:: The default format used for all cells in this Workbook.
11
+ # that have no format set explicitly or in
12
+ # Row#default_format or Worksheet#default_format.
13
+ class Workbook
14
+ include Spreadsheet::Encodings
15
+ attr_reader :io, :worksheets, :formats, :fonts
16
+ attr_accessor :active_worksheet, :encoding, :default_format, :version
17
+ def initialize io = nil, opts={:default_format => Format.new}
18
+ @worksheets = []
19
+ @io = io
20
+ @fonts = []
21
+ @formats = []
22
+ if @default_format = opts[:default_format]
23
+ @formats.push @default_format
24
+ end
25
+ end
26
+ ##
27
+ # Add a Font to the Workbook. Used by the parser. You should not need to
28
+ # use this Method.
29
+ def add_font font
30
+ @fonts.push(font).uniq! if font
31
+ font
32
+ end
33
+ ##
34
+ # Add a Format to the Workbook. If you use Row#set_format, you should not
35
+ # need to use this Method.
36
+ def add_format format
37
+ @formats.push(format) if format && !@formats.include?(format)
38
+ format
39
+ end
40
+ ##
41
+ # Add a Worksheet to the Workbook.
42
+ def add_worksheet worksheet
43
+ worksheet.workbook = self
44
+ @worksheets.push worksheet
45
+ worksheet
46
+ end
47
+ ##
48
+ # Create a new Worksheet in this Workbook.
49
+ # Used without options this creates a Worksheet with the name 'WorksheetN'
50
+ # where the new Worksheet is the Nth Worksheet in this Workbook.
51
+ #
52
+ # Use the option <em>:name => 'My pretty Name'</em> to override this
53
+ # behavior.
54
+ def create_worksheet opts = {}
55
+ opts[:name] ||= client("Worksheet#{@worksheets.size.next}", 'UTF-8')
56
+ add_worksheet Worksheet.new(opts)
57
+ end
58
+ ##
59
+ # Returns the count of total worksheets present.
60
+ # Takes no arguments. Just returns the length of @worksheets array.
61
+ def sheet_count
62
+ @worksheets.length
63
+ end
64
+ ##
65
+ # The Font at _idx_
66
+ def font idx
67
+ @fonts[idx]
68
+ end
69
+ ##
70
+ # The Format at _idx_, or - if _idx_ is a String -
71
+ # the Format with name == _idx_
72
+ def format idx
73
+ case idx
74
+ when Integer
75
+ @formats[idx] || @default_format
76
+ when String
77
+ @formats.find do |fmt| fmt.name == idx end
78
+ end
79
+ end
80
+ def inspect
81
+ variables = (instance_variables - uninspect_variables).collect do |name|
82
+ "%s=%s" % [name, instance_variable_get(name)]
83
+ end.join(' ')
84
+ uninspect = uninspect_variables.collect do |name|
85
+ var = instance_variable_get name
86
+ "%s=%s[%i]" % [name, var.class, var.size]
87
+ end.join(' ')
88
+ sprintf "#<%s:0x%014x %s %s>", self.class, object_id,
89
+ variables, uninspect
90
+ end
91
+ def uninspect_variables # :nodoc:
92
+ %w{@formats @fonts @worksheets}
93
+ end
94
+ ##
95
+ # The Worksheet at _idx_, or - if _idx_ is a String -
96
+ # the Worksheet with name == _idx_
97
+ def worksheet idx
98
+ case idx
99
+ when Integer
100
+ @worksheets[idx]
101
+ when String
102
+ @worksheets.find do |sheet| sheet.name == idx end
103
+ end
104
+ end
105
+ ##
106
+ # Write this Workbook to a File, IO Stream or Writer Object. The latter will
107
+ # make more sense once there are more than just an Excel-Writer available.
108
+ def write io_path_or_writer
109
+ if io_path_or_writer.is_a? Writer
110
+ io_path_or_writer.write self
111
+ else
112
+ writer(io_path_or_writer).write(self)
113
+ end
114
+ end
115
+ ##
116
+ # Returns a new instance of the default Writer class for this Workbook (can
117
+ # only be an Excel::Writer::Workbook at this time)
118
+ def writer io_or_path, type=Excel, version=self.version
119
+ if type == Excel
120
+ Excel::Writer::Workbook.new io_or_path
121
+ else
122
+ raise NotImplementedError, "No Writer defined for #{type}"
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,277 @@
1
+ require 'date'
2
+ require 'spreadsheet/column'
3
+ require 'spreadsheet/encodings'
4
+ require 'spreadsheet/row'
5
+
6
+ module Spreadsheet
7
+ ##
8
+ # The Worksheet class. Contains most of the Spreadsheet data in Rows.
9
+ #
10
+ # Interesting Attributes
11
+ # #name :: The Name of this Worksheet.
12
+ # #default_format:: The default format used for all cells in this Workhseet
13
+ # that have no format set explicitly or in
14
+ # Row#default_format.
15
+ # #rows :: The Rows in this Worksheet. It is not recommended to
16
+ # Manipulate this Array directly. If you do, call
17
+ # #updated_from with the smallest modified index.
18
+ # #columns :: The Column formatting in this Worksheet. Column
19
+ # instances may appear at more than one position in #columns.
20
+ # If you modify a Column directly, your changes will be
21
+ # reflected in all those positions.
22
+ # #selected :: When a user chooses to print a Workbook, Excel will include
23
+ # all selected Worksheets. If no Worksheet is selected at
24
+ # Workbook#write, then the first Worksheet is selected by
25
+ # default.
26
+ class Worksheet
27
+ include Spreadsheet::Encodings
28
+ include Enumerable
29
+ attr_accessor :name, :selected, :workbook
30
+ attr_reader :rows, :columns
31
+ def initialize opts={}
32
+ @default_format = nil
33
+ @selected = opts[:selected]
34
+ @dimensions = [0,0,0,0]
35
+ @name = opts[:name] || 'Worksheet'
36
+ @workbook = opts[:workbook]
37
+ @rows = []
38
+ @columns = []
39
+ @links = {}
40
+ end
41
+ def active # :nodoc:
42
+ warn "Worksheet#active is deprecated. Please use Worksheet#selected instead."
43
+ selected
44
+ end
45
+ def active= selected # :nodoc:
46
+ warn "Worksheet#active= is deprecated. Please use Worksheet#selected= instead."
47
+ self.selected = selected
48
+ end
49
+ ##
50
+ # Add a Format to the Workbook. If you use Row#set_format, you should not
51
+ # need to use this Method.
52
+ def add_format fmt
53
+ @workbook.add_format fmt if fmt
54
+ end
55
+ ##
56
+ # Get the enriched value of the Cell at _row_, _column_.
57
+ # See also Worksheet#[], Row#[].
58
+ def cell row, column
59
+ row(row)[column]
60
+ end
61
+ ##
62
+ # Returns the Column at _idx_.
63
+ def column idx
64
+ @columns[idx] || Column.new(idx, default_format, :worksheet => self)
65
+ end
66
+ ##
67
+ # The number of columns in this Worksheet which contain data.
68
+ def column_count
69
+ dimensions[3] - dimensions[2]
70
+ end
71
+ def column_updated idx, column
72
+ @columns[idx] = column
73
+ end
74
+ ##
75
+ # Delete the Row at _idx_ (0-based) from this Worksheet.
76
+ def delete_row idx
77
+ res = @rows.delete_at idx
78
+ updated_from idx
79
+ res
80
+ end
81
+ ##
82
+ # The default Format of this Worksheet, if you have set one.
83
+ # Returns the Workbook's default Format otherwise.
84
+ def default_format
85
+ @default_format || @workbook.default_format
86
+ end
87
+ ##
88
+ # Set the default Format of this Worksheet.
89
+ def default_format= format
90
+ @default_format = format
91
+ add_format format
92
+ format
93
+ end
94
+ ##
95
+ # Dimensions:: [ first used row, first unused row,
96
+ # first used column, first unused column ]
97
+ # ( First used means that all rows or columns before that are
98
+ # empty. First unused means that this and all following rows
99
+ # or columns are empty. )
100
+ def dimensions
101
+ @dimensions || recalculate_dimensions
102
+ end
103
+ ##
104
+ # If no argument is given, #each iterates over all used Rows (from the first
105
+ # used Row until but omitting the first unused Row, see also #dimensions).
106
+ #
107
+ # If the argument skip is given, #each iterates from that row until but
108
+ # omitting the first unused Row, effectively skipping the first _skip_ Rows
109
+ # from the top of the Worksheet.
110
+ def each skip=dimensions[0], &block
111
+ skip.upto(dimensions[1] - 1) do |idx|
112
+ block.call row(idx)
113
+ end
114
+ end
115
+ def encoding # :nodoc:
116
+ @workbook.encoding
117
+ end
118
+ ##
119
+ # Sets the default Format of the column at _idx_.
120
+ #
121
+ # _idx_ may be an Integer, or an Enumerable that iterates over a number of
122
+ # Integers.
123
+ #
124
+ # _format_ is a Format, or nil if you want to remove the Formatting at _idx_
125
+ #
126
+ # Returns an instance of Column if _idx_ is an Integer, an Array of Columns
127
+ # otherwise.
128
+ def format_column idx, format=nil, opts={}
129
+ opts[:worksheet] = self
130
+ res = case idx
131
+ when Integer
132
+ column = nil
133
+ if format
134
+ column = Column.new(idx, format, opts)
135
+ end
136
+ @columns[idx] = column
137
+ else
138
+ idx.collect do |col| format_column col, format, opts end
139
+ end
140
+ shorten @columns
141
+ res
142
+ end
143
+ ##
144
+ # Formats all Date, DateTime and Time cells with _format_ or the default
145
+ # formats:
146
+ # - 'DD.MM.YYYY' for Date
147
+ # - 'DD.MM.YYYY hh:mm:ss' for DateTime and Time
148
+ def format_dates! format=nil
149
+ each do |row|
150
+ row.each_with_index do |value, idx|
151
+ unless row.formats[idx] || row.format(idx).date_or_time?
152
+ numfmt = case value
153
+ when DateTime, Time
154
+ format || client('DD.MM.YYYY hh:mm:ss', 'UTF-8')
155
+ when Date
156
+ format || client('DD.MM.YYYY', 'UTF-8')
157
+ end
158
+ case numfmt
159
+ when Format
160
+ row.set_format idx, numfmt
161
+ when String
162
+ fmt = row.format(idx).dup
163
+ fmt.number_format = numfmt
164
+ row.set_format idx, fmt
165
+ end
166
+ end
167
+ end
168
+ end
169
+ end
170
+ ##
171
+ # Insert a Row at _idx_ (0-based) containing _cells_
172
+ def insert_row idx, cells=[]
173
+ res = @rows.insert idx, Row.new(self, idx, cells)
174
+ updated_from idx
175
+ res
176
+ end
177
+ def inspect
178
+ names = instance_variables
179
+ names.delete '@rows'
180
+ variables = names.collect do |name|
181
+ "%s=%s" % [name, instance_variable_get(name)]
182
+ end.join(' ')
183
+ sprintf "#<%s:0x%014x %s @rows[%i]>", self.class, object_id,
184
+ variables, row_count
185
+ end
186
+ ## The last Row containing any data
187
+ def last_row
188
+ row(last_row_index)
189
+ end
190
+ ## The index of the last Row containing any data
191
+ def last_row_index
192
+ [dimensions[1] - 1, 0].max
193
+ end
194
+ ##
195
+ # Replace the Row at _idx_ with the following arguments. Like #update_row,
196
+ # but truncates the Row if there are fewer arguments than Cells in the Row.
197
+ def replace_row idx, *cells
198
+ if(row = @rows[idx]) && cells.size < row.size
199
+ cells.concat Array.new(row.size - cells.size)
200
+ end
201
+ update_row idx, *cells
202
+ end
203
+ ##
204
+ # The Row at _idx_ or a new Row.
205
+ def row idx
206
+ @rows[idx] || Row.new(self, idx)
207
+ end
208
+ ##
209
+ # The number of Rows in this Worksheet which contain data.
210
+ def row_count
211
+ dimensions[1] - dimensions[0]
212
+ end
213
+ ##
214
+ # Tell Worksheet that the Row at _idx_ has been updated and the #dimensions
215
+ # need to be recalculated. You should not need to call this directly.
216
+ def row_updated idx, row
217
+ @dimensions = nil
218
+ @rows[idx] = row
219
+ end
220
+ ##
221
+ # Updates the Row at _idx_ with the following arguments.
222
+ def update_row idx, *cells
223
+ res = if row = @rows[idx]
224
+ row[0, cells.size] = cells
225
+ row
226
+ else
227
+ Row.new self, idx, cells
228
+ end
229
+ row_updated idx, res
230
+ res
231
+ end
232
+ ##
233
+ # Renumbers all Rows starting at _idx_ and calls #row_updated for each of
234
+ # them.
235
+ def updated_from index
236
+ index.upto(@rows.size - 1) do |idx|
237
+ row = row(idx)
238
+ row.idx = idx
239
+ row_updated idx, row
240
+ end
241
+ end
242
+ ##
243
+ # Get the enriched value of the Cell at _row_, _column_.
244
+ # See also Worksheet#cell, Row#[].
245
+ def [] row, column
246
+ row(row)[column]
247
+ end
248
+ ##
249
+ # Set the value of the Cell at _row_, _column_ to _value_.
250
+ # See also Row#[]=.
251
+ def []= row, column, value
252
+ row(row)[column] = value
253
+ end
254
+ private
255
+ def index_of_first ary # :nodoc:
256
+ return unless ary
257
+ ary.index(ary.find do |elm| elm end)
258
+ end
259
+ def recalculate_dimensions # :nodoc:
260
+ shorten @rows
261
+ @dimensions = []
262
+ @dimensions[0] = index_of_first(@rows) || 0
263
+ @dimensions[1] = @rows.size
264
+ compact = @rows.compact
265
+ @dimensions[2] = compact.collect do |row| row.first_used end.compact.min || 0
266
+ @dimensions[3] = compact.collect do |row| row.first_unused end.max || 0
267
+ @dimensions
268
+ end
269
+ def shorten ary # :nodoc:
270
+ return unless ary
271
+ while !ary.empty? && !ary.last
272
+ ary.pop
273
+ end
274
+ ary unless ary.empty?
275
+ end
276
+ end
277
+ end
@@ -0,0 +1,30 @@
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.respond_to? :seek
11
+ @io_or_path.binmode
12
+ write_workbook workbook, @io_or_path
13
+ else
14
+ File.open(@io_or_path, "wb+") do |fh|
15
+ write_workbook workbook, fh
16
+ end
17
+ end
18
+ end
19
+ private
20
+ def write_workbook workbook, io
21
+ reader = workbook.io
22
+ unless io == reader
23
+ reader.rewind
24
+ data = reader.read
25
+ io.rewind
26
+ io.write data
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "nulogy-spreadsheet"
6
+ s.version = "0.6.5.7.2"
7
+ s.summary = "The Spreadsheet Library is designed to read and write Spreadsheet Documents"
8
+ s.description = "As of version 0.6.0, only Microsoft Excel compatible spreadsheets are supported"
9
+ s.authors = ["Masaomi Hatakeyama", "Zeno R.R. Davatz", "Clemens Park"]
10
+ s.email = "sskirby@gmail.com"
11
+ s.homepage = "https://github.com/nulogy/spreadsheet"
12
+ s.rubyforge_project = "nulogy-spreadsheet"
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = ["lib"]
18
+
19
+ s.add_dependency('ruby-ole')
20
+ s.add_development_dependency('rake')
21
+ end