spreet 0.0.1

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.
@@ -0,0 +1,3 @@
1
+ Gemfile.lock
2
+ *~
3
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source :gemcutter
2
+
3
+ gemspec
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Brice Texier
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,3 @@
1
+ = Spreet
2
+
3
+ Universal handler for spr[eadsh]eets.
@@ -0,0 +1,15 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rake/testtask'
4
+ Rake::TestTask.new(:test) do |test|
5
+ test.libs << 'lib' << 'test'
6
+ test.pattern = 'test/**/test_*.rb'
7
+ test.verbose = true
8
+ end
9
+
10
+ task :default => :test
11
+
12
+ # Import all rake files
13
+ for rakefile in Dir.glob('lib/tasks/*.rake')
14
+ import(rakefile)
15
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,368 @@
1
+ # encoding: utf-8
2
+
3
+ module Spreet
4
+
5
+ module VERSION
6
+ version = nil
7
+ File.open("VERSION") {|f| version = f.read.split('.')}
8
+ MAJOR = version[0].to_i.freeze
9
+ MINOR = version[1].to_i.freeze
10
+ TINY = version[2].to_i.freeze
11
+ PATCH = TINY.freeze
12
+ PRE = version[3].freeze
13
+ STRING = version.freeze
14
+ end
15
+
16
+
17
+ class Coordinates
18
+ # Limit coordinates x and y in 0..65535 but coordinates are in one integer of 32 bits
19
+ CPU_SEMI_WIDTH = 16 # ((RUBY_PLATFORM.match(/^[^\-]*[^\-0-9]64/) ? 64 : 32) / 2).freeze
20
+ Y_FILTER = ((1 << CPU_SEMI_WIDTH) - 1).freeze
21
+
22
+ BASE_26_BEF = "0123456789abcdefghijklmnop"
23
+ BASE_26_AFT = "abcdefghijklmnopqrstuvwxyz"
24
+
25
+ attr_accessor :x, :y
26
+ def initialize(*args)
27
+ value = (args.size == 1 ? args[0] : args)
28
+ @x, @y = 0, 0
29
+ if value.is_a? String
30
+ if value.downcase.match(/^[a-z]+[0-9]+$/)
31
+ value = value.downcase.split(/([A-Z]+|[0-9]+)/).delete_if{|x| x.size.zero?}
32
+ @x, @y = value[0].tr(BASE_26_AFT, BASE_26_BEF).to_i(26), value[1].to_i(10)-1
33
+ elsif value.downcase.match(/^[0-9]+[^0-9]+[0-9]+$/)
34
+ value = value.downcase.split(/[^0-9]+/)
35
+ @x, @y = value[0].to_i(10), value[1].to_i(10)
36
+ end
37
+ elsif value.is_a? Integer
38
+ @x, @y = (value >> CPU_SEMI_WIDTH), value & Y_FILTER
39
+ elsif value.is_a? Coordinates
40
+ @x, @y = value.x, value.y
41
+ elsif value.is_a? Array
42
+ @x, @y = value[0].to_i, value[1].to_i
43
+ elsif value.is_a? Hash
44
+ @x, @y = value[:x] || value[:column] || 0, value[:y] || value[:row] || 0
45
+ end
46
+ end
47
+
48
+ def to_s
49
+ @x.to_s(26).tr(BASE_26_BEF, BASE_26_AFT).upcase+(@y+1).to_s(10)
50
+ end
51
+
52
+ def to_a
53
+ [@x, @y]
54
+ end
55
+
56
+ def to_hash
57
+ {:x=>@x, :y=>@y}
58
+ end
59
+
60
+ def to_i
61
+ (@x << CPU_SEMI_WIDTH) + @y
62
+ end
63
+
64
+ def ==(other_coordinate)
65
+ other_coordinate.x == self.x and other_coordinate.y == self.y
66
+ end
67
+
68
+ def <=>(other_coordinate)
69
+ self.to_i <=> other_coordinate.to_i
70
+ end
71
+ end
72
+
73
+ # Represents a cell in a sheet
74
+ class Cell
75
+ attr_reader :text, :value, :type, :sheet, :coordinates
76
+
77
+ def initialize(sheet, *args)
78
+ @sheet = sheet
79
+ @coordinates = Coordinates.new(*args)
80
+ self.value = nil
81
+ @empty = true
82
+ end
83
+
84
+ def value=(val)
85
+ @value = val
86
+ @type = determine_type
87
+ @text = val.to_s
88
+ @empty = false
89
+ end
90
+
91
+ def empty?
92
+ @empty
93
+ end
94
+
95
+ def clear!
96
+ self.value = nil
97
+ @empty = true
98
+ end
99
+
100
+ def remove!
101
+ @sheet.remove(self.coordinates)
102
+ end
103
+
104
+ def <=>(other_cell)
105
+ self.coordinates <=> other_cell.coordinates
106
+ end
107
+
108
+ private
109
+
110
+ def determine_type
111
+ if value.is_a? Date
112
+ :date
113
+ elsif value.is_a? Integer
114
+ :integer
115
+ elsif value.is_a? Numeric
116
+ :decimal
117
+ elsif value.is_a? DateTime
118
+ :datetime
119
+ elsif value.is_a?(TrueClass) or value.is_a?(FalseClass)
120
+ :boolean
121
+ elsif value.nil?
122
+ :null
123
+ else
124
+ :string
125
+ end
126
+ end
127
+
128
+ end
129
+
130
+
131
+ class Sheet
132
+ attr_reader :document, :name, :columns
133
+ attr_accessor :current_row
134
+
135
+ def initialize(document, name=nil)
136
+ @document = document
137
+ self.name = name
138
+ raise ArgumentError.new("Must be a Document") unless document.is_a? Document
139
+ @current_row = 0
140
+ @cells = {}
141
+ end
142
+
143
+ def name=(value)
144
+ unless value
145
+ value = (@document.sheets.count > 0 ? @document.sheets[-1].name.succ : "Sheet 1")
146
+ end
147
+ raise ArgumentError.new("Name of sheet must be given") if value.to_s.strip.size.zero?
148
+ if @document.sheets[value]
149
+ raise ArgumentError.new("Name of sheet must be unique")
150
+ end
151
+ @name = value
152
+ end
153
+
154
+ def cells
155
+ @cells.delete_if{|k,v| v.empty?}
156
+ @cells.values
157
+ end
158
+
159
+ def next_row(increment = 1)
160
+ @current_row += increment
161
+ end
162
+
163
+ def previous_row(increment = 1)
164
+ @current_row -= increment
165
+ end
166
+
167
+ def [](*args)
168
+ coord = Coordinates.new(*args)
169
+ @cells[coord.to_i] ||= Cell.new(self, coord)
170
+ return @cells[coord.to_i]
171
+ end
172
+
173
+ def []=(*args)
174
+ value = args.delete_at(-1)
175
+ cell = self[*args]
176
+ cell.value = value
177
+ @bound = compute_bound
178
+ end
179
+
180
+ def row(*args)
181
+ options = {}
182
+ options = args.delete_at(-1) if args[-1].is_a? Hash
183
+ row = options[:row] || @current_row
184
+ args.each_index do |index|
185
+ self[index, row] = args[index]
186
+ end
187
+ next_row
188
+ end
189
+
190
+ def each_row(&block)
191
+ for j in 0..bound.y
192
+ row = []
193
+ for i in 0..bound.x
194
+ row[i] = self[i, j]
195
+ end
196
+ yield row
197
+ end
198
+ end
199
+
200
+ # Find or build cell
201
+ def cell(*args)
202
+ return c
203
+ end
204
+
205
+ def bound
206
+ @bound
207
+ end
208
+
209
+ def remove!(coordinates)
210
+ raise ArgumentError.new("Must be a Coordinates") unless document.is_a?(Coordinates)
211
+ @cells.delete(coordinates.to_i)
212
+ @bound = compute_bound
213
+ end
214
+
215
+ # Moves the sheet to an other position in the list of sheets
216
+ def move_to(position)
217
+ @document.sheets.move_at(self, position)
218
+ end
219
+
220
+ # Moves the sheet higher in the list of sheets
221
+ def move_higher(increment=1)
222
+ @document.sheets.move(self, increment)
223
+ end
224
+
225
+ # Moves the sheet lower in the list of sheets
226
+ def move_lower(increment=1)
227
+ @document.sheets.move(self, -increment)
228
+ end
229
+
230
+ private
231
+
232
+ def compute_bound
233
+ bound = Coordinates.new
234
+ for id, cell in @cells
235
+ unless cell.empty?
236
+ bound.x = cell.coordinates.x if cell.coordinates.x > bound.x
237
+ bound.y = cell.coordinates.y if cell.coordinates.x > bound.y
238
+ end
239
+ end
240
+ return bound
241
+ end
242
+
243
+ end
244
+
245
+
246
+ class Sheets
247
+
248
+ def initialize(document)
249
+ raise ArgumentError.new("Must be a Document") unless document.is_a?(Document)
250
+ @document = document
251
+ @array = []
252
+ end
253
+
254
+ def count
255
+ @array.size
256
+ end
257
+
258
+ def index(name_or_sheet)
259
+ if name_or_sheet.is_a? String
260
+ @array.each_index do |i|
261
+ return i if @array[i].name == name_or_sheet
262
+ end
263
+ elsif name_or_sheet.is_a? Integer
264
+ return (@array[name_or_sheet].nil? ? nil : name_or_sheet)
265
+ else
266
+ return @array.index(name_or_sheet)
267
+ end
268
+ end
269
+
270
+ def add(name=nil, position=-1)
271
+ sheet = Sheet.new(@document, name)
272
+ @array.insert(position, sheet)
273
+ return sheet
274
+ end
275
+
276
+ def [](sheet)
277
+ sheet = index(sheet)
278
+ return (sheet.is_a?(Integer) ? @array[sheet] : nil)
279
+ end
280
+
281
+ def remove(sheet)
282
+ @array.delete(sheet)
283
+ end
284
+
285
+ def move(sheet, shift=0)
286
+ move_at(sheet, index(sheet) + shift)
287
+ end
288
+
289
+ def move_at(sheet, position=-1)
290
+ if i = index(sheet)
291
+ @array.insert(position, @array.delete_at(i))
292
+ end
293
+ end
294
+
295
+ def each(&block)
296
+ for item in @array
297
+ yield item
298
+ end
299
+ end
300
+
301
+ end
302
+
303
+
304
+ class Document
305
+ attr_reader :sheets
306
+ @@handlers = {}
307
+ @@associations = {}
308
+
309
+ def initialize(option={})
310
+ @sheets = Sheets.new(self)
311
+ end
312
+
313
+ def to_term
314
+ text = "Spreet (#{@sheets.count}):\n"
315
+ for sheet in @sheets
316
+ text << " - #{sheet.name}:\n"
317
+ for cell in sheet.cells.sort
318
+ text << " - #{cell.coordinates.to_s}: #{cell.text.inspect}\n"
319
+ end
320
+ end
321
+ return text
322
+ end
323
+
324
+ def write(file, options={})
325
+ handler = self.class.extract_handler(file, options.delete(:format))
326
+ handler.write(self, file, options)
327
+ end
328
+
329
+ class << self
330
+
331
+ def register_handler(klass, name, options={})
332
+ if klass.respond_to?(:read) or klass.respond_to?(:write)
333
+ if name.is_a?(Symbol)
334
+ @@handlers[name] = klass # options.merge(:class=>klass)
335
+ elsif
336
+ raise ArgumentError.new("Name is invalid. Symbol expected, #{name.class.name} got.")
337
+ end
338
+ else
339
+ raise ArgumentError.new("Handler do not support :read or :write method.")
340
+ end
341
+ end
342
+
343
+ def read(file, options={})
344
+ handler = extract_handler(file, options.delete(:format))
345
+ return handler.read(file, options)
346
+ end
347
+
348
+ def extract_handler(file, handler_name=nil)
349
+ file_path = Pathname.new(file)
350
+ extension = file_path.extname.to_s[1..-1]
351
+ if !handler_name and extension.size > 0
352
+ handler_name = extension.to_sym
353
+ end
354
+ if @@handlers[handler_name]
355
+ return @@handlers[handler_name]
356
+ else
357
+ raise ArgumentError.new("No corresponding handler (#{handler_name.inspect}). Available: #{@@handlers.keys.collect{|k| k.inspect}.join(', ')}.")
358
+ end
359
+ end
360
+
361
+ end
362
+
363
+
364
+ end
365
+
366
+ end
367
+
368
+ require 'spreet/handlers'
@@ -0,0 +1,25 @@
1
+ module Spreet
2
+
3
+ # Default handler
4
+ class Handler
5
+
6
+ def self.read(file, options={})
7
+ raise NotImplementedError.new
8
+ end
9
+
10
+ def self.write(spreet, file, options={})
11
+ raise NotImplementedError.new
12
+ end
13
+
14
+ end
15
+
16
+ end
17
+
18
+ require 'spreet/handlers/csv'
19
+ require 'spreet/handlers/open_document'
20
+
21
+ Spreet::Document.register_handler Spreet::Handlers::CSV, :csv
22
+ Spreet::Document.register_handler Spreet::Handlers::ExcelCSV, :xcsv
23
+ # Spreet::Document.register_handler Spreet::Handlers::HTML, :html
24
+ Spreet::Document.register_handler Spreet::Handlers::OpenDocument, :ods
25
+ # Spreet::Document.register_handler Spreet::Handlers::PDF, :pdf
@@ -0,0 +1,68 @@
1
+ # encoding: utf-8
2
+ require 'csv'
3
+ require 'iconv'
4
+
5
+ module Spreet
6
+ # Universal CSV support
7
+ CSV = (::CSV.const_defined?(:Reader) ? ::FasterCSV : ::CSV).freeze
8
+
9
+ module Handlers
10
+
11
+ class CSV < Spreet::Handler
12
+
13
+ # Read a CSV file and create its Spreet document
14
+ def self.read(file, options={})
15
+ spreet = Spreet::Document.new
16
+ sheet = spreet.sheets.add
17
+ Spreet::CSV.foreach(file) do |row|
18
+ sheet.row *row
19
+ end
20
+ return spreet
21
+ end
22
+
23
+
24
+ # Write a Spreet to a CSV file
25
+ def self.write(spreet, file, options={})
26
+ sheet = spreet.sheets[options[:sheet]||0]
27
+ Spreet::CSV.open(file, "wb") do |csv|
28
+ sheet.each_row do |row|
29
+ csv << row.collect{|c| c.text}
30
+ end
31
+ end
32
+ end
33
+
34
+ end
35
+
36
+ class ExcelCSV < Spreet::Handler
37
+
38
+ # Read a CSV file and create its Spreet document
39
+ def self.read(file, options={})
40
+ spreet = Spreet::Document.new
41
+ sheet = spreet.sheets.add
42
+ options = {:col_sep=>';'}.merge(options)
43
+ ic = Iconv.new('utf-8', 'cp1252')
44
+ Spreet::CSV.foreach(file, options) do |row|
45
+ sheet.row *(row.collect{|v| ic.iconv(v.to_s)})
46
+ end
47
+ return spreet
48
+ end
49
+
50
+
51
+ # Write a Spreet to a CSV file
52
+ def self.write(spreet, file, options={})
53
+ sheet = spreet.sheets[options[:sheet]||0]
54
+ options = {:col_sep=>';'}.merge(options)
55
+ ic = Iconv.new('cp1252', 'utf-8')
56
+ Spreet::CSV.open(file, "wb", options) do |csv|
57
+ sheet.each_row do |row|
58
+ csv << row.collect{|c| ic.iconv(c.text)}
59
+ end
60
+ end
61
+ end
62
+
63
+ end
64
+
65
+ end
66
+ end
67
+
68
+
@@ -0,0 +1,76 @@
1
+ # encoding: utf-8
2
+ require 'zip/zip'
3
+
4
+ module Spreet
5
+ module Handlers
6
+ class OpenDocument < Spreet::Handler
7
+ DATE_REGEXP = /\%./
8
+ DATE_ELEMENTS = {
9
+ "m" => "<number:month number:style=\"long\"/>",
10
+ "d" => "<number:day number:style=\"long\"/>",
11
+ "Y" => "<number:year/>"
12
+ }
13
+
14
+
15
+ def self.mimetype
16
+ end
17
+
18
+ def self.xmlec(string)
19
+ zs = string.to_s.gsub('&', '&amp;').gsub('\'', '&apos;').gsub('<', '&lt;').gsub('>', '&gt;')
20
+ zs.force_encoding('US-ASCII') if zs.respond_to?(:force_encoding)
21
+ return zs
22
+ end
23
+
24
+
25
+ def self.write(spreet, file, options={})
26
+ xml_escape = "to_s.gsub('&', '&amp;').gsub('\\'', '&apos;').gsub('<', '&lt;').gsub('>', '&gt;')"
27
+ xml_escape << ".force_encoding('US-ASCII')" if xml_escape.respond_to?(:force_encoding)
28
+ mimetype = "application/vnd.oasis.opendocument.spreadsheet"
29
+ # name = #{table.model.name}.model_name.human.gsub(/[^a-z0-9]/i,'_')
30
+ Zip::ZipOutputStream.open(file) do |zile|
31
+ # MimeType in first place
32
+ zile.put_next_entry('mimetype', nil, nil, Zip::ZipEntry::STORED)
33
+ zile << mimetype
34
+
35
+ # Manifest
36
+ zile.put_next_entry('META-INF/manifest.xml')
37
+ zile << ("<?xml version=\"1.0\" encoding=\"UTF-8\"?><manifest:manifest xmlns:manifest=\"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0\"><manifest:file-entry manifest:media-type=\"#{mimetype}\" manifest:full-path=\"/\"/><manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"content.xml\"/></manifest:manifest>")
38
+ zile.put_next_entry('content.xml')
39
+
40
+ zile << ("<?xml version=\"1.0\" encoding=\"UTF-8\"?><office:document-content xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\" xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\" xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\" xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\" xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\" xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\" xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\" xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\" xmlns:chart=\"urn:oasis:names:tc:opendocument:xmlns:chart:1.0\" xmlns:dr3d=\"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0\" xmlns:math=\"http://www.w3.org/1998/Math/MathML\" xmlns:form=\"urn:oasis:names:tc:opendocument:xmlns:form:1.0\" xmlns:script=\"urn:oasis:names:tc:opendocument:xmlns:script:1.0\" xmlns:ooo=\"http://openoffice.org/2004/office\" xmlns:ooow=\"http://openoffice.org/2004/writer\" xmlns:oooc=\"http://openoffice.org/2004/calc\" xmlns:dom=\"http://www.w3.org/2001/xml-events\" xmlns:xforms=\"http://www.w3.org/2002/xforms\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:field=\"urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:field:1.0\" office:version=\"1.1\"><office:scripts/>")
41
+ # Styles
42
+ default_date_format = '%d/%m%Y' # ::I18n.translate("date.formats.default")
43
+ zile << ("<office:automatic-styles><style:style style:name=\"co1\" style:family=\"table-column\"><style:table-column-properties fo:break-before=\"auto\" style:use-optimal-column-width=\"true\"/></style:style><style:style style:name=\"header\" style:family=\"table-cell\"><style:text-properties fo:font-weight=\"bold\" style:font-weight-asian=\"bold\" style:font-weight-complex=\"bold\"/></style:style><number:date-style style:name=\"K4D\" number:automatic-order=\"true\"><number:text>"+default_date_format.gsub(DATE_REGEXP){|x| "</number:text>"+DATE_ELEMENTS[x[1..1]]+"<number:text>"} +"</number:text></number:date-style><style:style style:name=\"ce1\" style:family=\"table-cell\" style:data-style-name=\"K4D\"/></office:automatic-styles>")
44
+
45
+ zile << ("<office:body><office:spreadsheet>")
46
+ # Tables
47
+ for sheet in spreet.sheets
48
+ zile << ("<table:table table:name=\"#{xmlec(sheet.name)}\">")
49
+ zile << ("<table:table-column table:number-columns-repeated=\"#{sheet.bound.x+1}\"/>")
50
+ # zile << ("<table:table-header-rows><table:table-row>"+columns_headers(table).collect{|h| "<table:table-cell table:style-name=\"header\" office:value-type=\"string\"><text:p>'+(#{h}).#{xml_escape}+'</text:p></table:table-cell>"}.join+"</table:table-row></table:table-header-rows>")
51
+ sheet.each_row do |row| # #{record} in #{table.records_variable_name}\n"
52
+ zile << "<table:table-row>"
53
+ for cell in row
54
+ zile << "<table:table-cell"+(if cell.type == :decimal
55
+ " office:value-type=\"float\" office:value=\"#{xmlec(cell.value)}\""
56
+ elsif cell.type == :boolean
57
+ " office:value-type=\"boolean\" office:boolean-value=\"#{xmlec(cell.value ? 'true' : 'false')}\""
58
+ elsif cell.type == :date
59
+ " office:value-type=\"date\" table:style-name=\"ce1\" office:date-value=\"#{xmlec(cell.value)}\""
60
+ else
61
+ " office:value-type=\"string\""
62
+ end)+"><text:p>"+xmlec(cell.text)+"</text:p></table:table-cell>"
63
+ end
64
+ zile << "</table:table-row>"
65
+ end
66
+ zile << ("</table:table>")
67
+ end
68
+ zile << ("</office:spreadsheet></office:body></office:document-content>")
69
+ end
70
+ # Zile is finished
71
+ end
72
+
73
+
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,40 @@
1
+ # encoding: utf-8
2
+ Gem::Specification.new do |s|
3
+ s.name = "spreet"
4
+ File.open("VERSION", "rb") do |f|
5
+ s.version = f.read
6
+ end
7
+
8
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
9
+ s.authors = ["Brice Texier"]
10
+ s.date = "2011-09-19"
11
+ s.summary = "Spr[eadsh]eet handler"
12
+ s.description = "Spr[eadsh]eet handler for CSV(RW), Excel CSV(RW) and ODS(W). The goal is to read and write in many open formats."
13
+ s.email = "brice.texier@ekylibre.org"
14
+ s.extra_rdoc_files = [
15
+ "LICENSE.txt",
16
+ "README.rdoc"
17
+ ]
18
+ s.files = `git ls-files`.split("\n")
19
+ s.homepage = "http://github.com/burisu/spreet"
20
+ s.licenses = ["MIT"]
21
+ s.require_paths = ["lib"]
22
+
23
+ if s.respond_to? :specification_version then
24
+ s.specification_version = 3
25
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
26
+ s.add_runtime_dependency("fastercsv", [">= 0"])
27
+ s.add_runtime_dependency("libxml-ruby", [">= 0"])
28
+ s.add_runtime_dependency("rubyzip", [">= 0.9.4"])
29
+ else
30
+ s.add_dependency("fastercsv", [">= 0"])
31
+ s.add_dependency("libxml-ruby", [">= 0"])
32
+ s.add_dependency("rubyzip", [">= 0.9.4"])
33
+ end
34
+ else
35
+ s.add_dependency("fastercsv", [">= 0"])
36
+ s.add_dependency("libxml-ruby", [">= 0"])
37
+ s.add_dependency("rubyzip", [">= 0.9.4"])
38
+ end
39
+ end
40
+
@@ -0,0 +1,17 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+
12
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
+ require 'spreet'
15
+
16
+ class Test::Unit::TestCase
17
+ end
@@ -0,0 +1,17 @@
1
+ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
2
+ 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
3
+ 1,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0
4
+ 1,3,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0
5
+ 1,4,6,4,1,0,0,0,0,0,0,0,0,0,0,0,0
6
+ 1,5,10,10,5,1,0,0,0,0,0,0,0,0,0,0,0
7
+ 1,6,15,20,15,6,1,0,0,0,0,0,0,0,0,0,0
8
+ 1,7,21,35,35,21,7,1,0,0,0,0,0,0,0,0,0
9
+ 1,8,28,56,70,56,28,8,1,0,0,0,0,0,0,0,0
10
+ 1,9,36,84,126,126,84,36,9,1,0,0,0,0,0,0,0
11
+ 1,10,45,120,210,252,210,120,45,10,1,0,0,0,0,0,0
12
+ 1,11,55,165,330,462,462,330,165,55,11,1,0,0,0,0,0
13
+ 1,12,66,220,495,792,924,792,495,220,66,12,1,0,0,0,0
14
+ 1,13,78,286,715,1287,1716,1716,1287,715,286,78,13,1,0,0,0
15
+ 1,14,91,364,1001,2002,3003,3432,3003,2002,1001,364,91,14,1,0,0
16
+ 1,15,105,455,1365,3003,5005,6435,6435,5005,3003,1365,455,105,15,1,0
17
+ 1,16,120,560,1820,4368,8008,11440,12870,11440,8008,4368,1820,560,120,16,1
@@ -0,0 +1,91 @@
1
+ # encoding: utf-8
2
+ require 'helper'
3
+
4
+ class TestSpreet < Test::Unit::TestCase
5
+
6
+ def test_coordinates
7
+ assert_equal Spreet::Coordinates.new(0,0), Spreet::Coordinates.new("A1")
8
+ assert_equal Spreet::Coordinates.new(0,0), Spreet::Coordinates.new("0-0")
9
+ assert_equal Spreet::Coordinates.new(1,1), Spreet::Coordinates.new("B2")
10
+ assert_equal Spreet::Coordinates.new(2,2), Spreet::Coordinates.new(:x=>2, :y=>2)
11
+ assert_equal Spreet::Coordinates.new(3,3), Spreet::Coordinates.new(3,3)
12
+ assert_equal Spreet::Coordinates.new(3,3), Spreet::Coordinates.new([3,3])
13
+ assert_equal Spreet::Coordinates.new(4,4), Spreet::Coordinates.new(Spreet::Coordinates.new(4,4).to_i)
14
+ assert_equal Spreet::Coordinates.new(5,5), Spreet::Coordinates.new(Spreet::Coordinates.new(5,5))
15
+ assert_equal("D25", Spreet::Coordinates.new(3,24).to_s)
16
+ assert_equal([3, 24], Spreet::Coordinates.new(3,24).to_a)
17
+ assert_equal({:x=>3, :y=>24}, Spreet::Coordinates.new(3,24).to_hash)
18
+ assert Spreet::Coordinates.new(0,0) <=> Spreet::Coordinates.new(0,1)
19
+ assert Spreet::Coordinates.new(0,1) <=> Spreet::Coordinates.new(1,0)
20
+ end
21
+
22
+ def test_spreet_version
23
+ assert_not_nil Spreet::VERSION
24
+ assert_not_nil Spreet::VERSION::MAJOR
25
+ assert_not_nil Spreet::VERSION::MINOR
26
+ assert_not_nil Spreet::VERSION::TINY
27
+ assert_not_nil Spreet::VERSION::PATCH
28
+ assert_equal(Spreet::VERSION::TINY, Spreet::VERSION::PATCH, "PATCH code must have the same value as TINY")
29
+ assert((Spreet::VERSION::MAJOR > 0 or Spreet::VERSION::MINOR > 0 or Spreet::VERSION::TINY > 0), "Version cannot be 0.0.0")
30
+ end
31
+
32
+ def test_spreet
33
+ assert_not_nil Spreet
34
+
35
+ spreet = Spreet::Document.new
36
+ assert_not_nil spreet
37
+ sheet = spreet.sheets.add
38
+ assert_not_nil sheet
39
+ assert_not_nil spreet.sheets.add("Feuille 2")
40
+ assert_not_nil spreet.sheets.add("ソフト 3")
41
+
42
+ assert_equal Spreet::Sheet, spreet.sheets[1].class
43
+ assert_equal "Feuille 2", spreet.sheets[1].name
44
+
45
+ assert_equal Spreet::Sheet, spreet.sheets["ソフト 3"].class
46
+ assert_equal "ソフト 3", spreet.sheets["ソフト 3"].name
47
+
48
+ assert_not_nil sheet[0,0]
49
+ sheet[0,0] = "Cell A1"
50
+ spreet.sheets[1][0] = "Cellule A1"
51
+ spreet.sheets["ソフト 3"]["A1"] = "セル A1"
52
+
53
+ assert_not_nil sheet["C30"]
54
+
55
+ sheet["F20"] = Date.today
56
+
57
+ spreet.write("test/samples/cleaned-nothing.ods")
58
+ end
59
+
60
+
61
+ def test_handlers
62
+ doc = nil
63
+ assert_nothing_raised do
64
+ doc = Spreet::Document.read("test/samples/pascal.csv")
65
+ end
66
+
67
+ sheet = doc.sheets[0]
68
+ sheet.each_row do |row|
69
+ for cell in row
70
+ if cell.text.to_i == 0
71
+ cell.clear!
72
+ end
73
+ end
74
+ end
75
+
76
+ doc.write("test/samples/cleaned-pascal.csv", :format=>:xcsv)
77
+ doc.write("test/samples/cleaned-pascal.ods")
78
+
79
+ assert_nothing_raised do
80
+ doc = Spreet::Document.read("test/samples/cleaned-pascal.csv", :format=>:xcsv)
81
+ end
82
+
83
+ FileUtils.rm_f("test/samples/cleaned-pascal.csv")
84
+ end
85
+
86
+
87
+
88
+
89
+ end
90
+
91
+
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: spreet
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Brice Texier
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-09-19 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: fastercsv
16
+ requirement: &11182000 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *11182000
25
+ - !ruby/object:Gem::Dependency
26
+ name: libxml-ruby
27
+ requirement: &11180960 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *11180960
36
+ - !ruby/object:Gem::Dependency
37
+ name: rubyzip
38
+ requirement: &11180240 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: 0.9.4
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *11180240
47
+ description: Spr[eadsh]eet handler for CSV(RW), Excel CSV(RW) and ODS(W). The goal
48
+ is to read and write in many open formats.
49
+ email: brice.texier@ekylibre.org
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files:
53
+ - LICENSE.txt
54
+ - README.rdoc
55
+ files:
56
+ - .gitignore
57
+ - Gemfile
58
+ - LICENSE.txt
59
+ - README.rdoc
60
+ - Rakefile
61
+ - VERSION
62
+ - lib/spreet.rb
63
+ - lib/spreet/handlers.rb
64
+ - lib/spreet/handlers/csv.rb
65
+ - lib/spreet/handlers/open_document.rb
66
+ - spreet.gemspec
67
+ - test/helper.rb
68
+ - test/samples/pascal.csv
69
+ - test/test_spreet.rb
70
+ homepage: http://github.com/burisu/spreet
71
+ licenses:
72
+ - MIT
73
+ post_install_message:
74
+ rdoc_options: []
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ none: false
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ! '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ requirements: []
90
+ rubyforge_project:
91
+ rubygems_version: 1.8.11
92
+ signing_key:
93
+ specification_version: 3
94
+ summary: Spr[eadsh]eet handler
95
+ test_files: []