spreet 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,54 @@
1
+ module Spreet
2
+
3
+ class Document
4
+ attr_reader :sheets
5
+ @@handlers = {}
6
+ @@associations = {}
7
+
8
+ def initialize(option={})
9
+ @sheets = Sheets.new(self)
10
+ end
11
+
12
+ def write(file, options={})
13
+ handler = self.class.extract_handler(file, options.delete(:format))
14
+ handler.write(self, file, options)
15
+ end
16
+
17
+ class << self
18
+
19
+ def register_handler(klass, name, options={})
20
+ if klass.respond_to?(:read) or klass.respond_to?(:write)
21
+ if name.is_a?(Symbol)
22
+ @@handlers[name] = klass # options.merge(:class=>klass)
23
+ elsif
24
+ raise ArgumentError.new("Name is invalid. Symbol expected, #{name.class.name} got.")
25
+ end
26
+ else
27
+ raise ArgumentError.new("Handler do not support :read or :write method.")
28
+ end
29
+ end
30
+
31
+ def read(file, options={})
32
+ handler = extract_handler(file, options.delete(:format))
33
+ return handler.read(file, options)
34
+ end
35
+
36
+ def extract_handler(file, handler_name=nil)
37
+ file_path = Pathname.new(file)
38
+ extension = file_path.extname.to_s[1..-1]
39
+ if !handler_name and extension.size > 0
40
+ handler_name = extension.to_sym
41
+ end
42
+ if @@handlers[handler_name]
43
+ return @@handlers[handler_name]
44
+ else
45
+ raise ArgumentError.new("No corresponding handler (#{handler_name.inspect}). Available: #{@@handlers.keys.collect{|k| k.inspect}.join(', ')}.")
46
+ end
47
+ end
48
+
49
+ end
50
+
51
+ end
52
+
53
+
54
+ end
@@ -1,25 +1,9 @@
1
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
-
2
+ module Handlers
3
+ autoload :Base, 'spreet/handlers/base'
4
+ autoload :CSV, 'spreet/handlers/csv'
5
+ autoload :ExcelCSV, 'spreet/handlers/excel_csv'
6
+ autoload :OpenDocument, 'spreet/handlers/open_document'
14
7
  end
15
-
16
8
  end
17
9
 
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,19 @@
1
+ module Spreet
2
+ module Handlers
3
+
4
+ # Default handler
5
+ class Base
6
+
7
+ def self.read(file, options={})
8
+ raise NotImplementedError.new
9
+ end
10
+
11
+ def self.write(spreet, file, options={})
12
+ raise NotImplementedError.new
13
+ end
14
+
15
+ end
16
+
17
+
18
+ end
19
+ end
@@ -1,21 +1,15 @@
1
- # encoding: utf-8
2
- require 'fastercsv'
3
1
  require 'csv'
4
- require 'iconv'
5
2
 
6
3
  module Spreet
7
- # Universal CSV support
8
- CSV = (::CSV.const_defined?(:Reader) ? ::FasterCSV : ::CSV).freeze
9
-
10
4
  module Handlers
11
5
 
12
- class CSV < Spreet::Handler
6
+ class CSV < Spreet::Handlers::Base
13
7
 
14
8
  # Read a CSV file and create its Spreet document
15
9
  def self.read(file, options={})
16
10
  spreet = Spreet::Document.new
17
11
  sheet = spreet.sheets.add
18
- Spreet::CSV.foreach(file) do |row|
12
+ ::CSV.foreach(file) do |row|
19
13
  sheet.row *row
20
14
  end
21
15
  return spreet
@@ -25,7 +19,7 @@ module Spreet
25
19
  # Write a Spreet to a CSV file
26
20
  def self.write(spreet, file, options={})
27
21
  sheet = spreet.sheets[options[:sheet]||0]
28
- Spreet::CSV.open(file, "wb") do |csv|
22
+ ::CSV.open(file, "wb") do |csv|
29
23
  sheet.each_row do |row|
30
24
  csv << row.collect{|c| c.text}
31
25
  end
@@ -34,35 +28,6 @@ module Spreet
34
28
 
35
29
  end
36
30
 
37
- class ExcelCSV < Spreet::Handler
38
-
39
- # Read a CSV file and create its Spreet document
40
- def self.read(file, options={})
41
- spreet = Spreet::Document.new
42
- sheet = spreet.sheets.add
43
- options = {:col_sep=>';'}.merge(options)
44
- ic = Iconv.new('utf-8', 'cp1252')
45
- Spreet::CSV.foreach(file, options) do |row|
46
- sheet.row *(row.collect{|v| ic.iconv(v.to_s)})
47
- end
48
- return spreet
49
- end
50
-
51
-
52
- # Write a Spreet to a CSV file
53
- def self.write(spreet, file, options={})
54
- sheet = spreet.sheets[options[:sheet]||0]
55
- options = {:col_sep=>';'}.merge(options)
56
- ic = Iconv.new('cp1252', 'utf-8')
57
- Spreet::CSV.open(file, "wb", options) do |csv|
58
- sheet.each_row do |row|
59
- csv << row.collect{|c| ic.iconv(c.text)}
60
- end
61
- end
62
- end
63
-
64
- end
65
-
66
31
  end
67
32
  end
68
33
 
@@ -0,0 +1,36 @@
1
+ require 'csv'
2
+
3
+ module Spreet
4
+ module Handlers
5
+
6
+ class ExcelCSV < Spreet::Handlers::Base
7
+
8
+ # Read a CSV file and create its Spreet document
9
+ def self.read(file, options={})
10
+ spreet = Spreet::Document.new
11
+ sheet = spreet.sheets.add
12
+ options = {:col_sep=>';', :encoding => "CP1252"}.merge(options)
13
+ ::CSV.foreach(file, options) do |row|
14
+ sheet.row *(row.map{|v| v.to_s.encode('utf-8')}) # collect{|v| v.to_s.encode('cp1252')}
15
+ end
16
+ return spreet
17
+ end
18
+
19
+
20
+ # Write a Spreet to a CSV file
21
+ def self.write(spreet, file, options={})
22
+ sheet = spreet.sheets[options[:sheet]||0]
23
+ options = {:col_sep=>';', :encoding => "CP1252"}.merge(options)
24
+ ::CSV.open(file, "wb", options) do |csv|
25
+ sheet.each_row do |row|
26
+ csv << row.map(&:text)
27
+ end
28
+ end
29
+ end
30
+
31
+ end
32
+
33
+ end
34
+ end
35
+
36
+
@@ -1,10 +1,13 @@
1
1
  # encoding: utf-8
2
- require 'zip/zip'
2
+ require 'zip'
3
3
  require 'libxml'
4
+ require 'money'
5
+ require 'time'
6
+ require 'duration'
4
7
 
5
8
  module Spreet
6
9
  module Handlers
7
- class OpenDocument < Spreet::Handler
10
+ class OpenDocument < Spreet::Handlers::Base
8
11
  DATE_REGEXP = /\%./
9
12
  DATE_ELEMENTS = {
10
13
  "m" => "<number:month number:style=\"long\"/>",
@@ -62,7 +65,7 @@ module Spreet
62
65
 
63
66
  def self.read(file, options={})
64
67
  spreet = nil
65
- Zip::ZipFile.open(file) do |zile|
68
+ Zip::File.open(file) do |zile|
66
69
  # Check mime_type
67
70
  entry = zile.find_entry "mimetype"
68
71
  if entry.nil?
@@ -135,7 +138,7 @@ module Spreet
135
138
  elsif value_type == :currency
136
139
  value = cell.attributes.get_attribute_ns(XMLNS_OFFICE, "value").value
137
140
  currency = cell.attributes.get_attribute_ns(XMLNS_OFFICE, "currency").value
138
- sheet[x,y] = Money.new(value, currency)
141
+ sheet[x,y] = Money.new(value.to_f, currency)
139
142
  elsif value_type == :date
140
143
  value = cell.attributes.get_attribute_ns(XMLNS_OFFICE, "date-value").value
141
144
  if value.match(/\d{1,8}-\d{1,2}-\d{1,2}/)
@@ -202,9 +205,9 @@ module Spreet
202
205
  xml_escape << ".force_encoding('US-ASCII')" if xml_escape.respond_to?(:force_encoding)
203
206
  mime_type = MIME_ODS
204
207
  # name = #{table.model.name}.model_name.human.gsub(/[^a-z0-9]/i,'_')
205
- Zip::ZipOutputStream.open(file) do |zile|
208
+ Zip::OutputStream.open(file) do |zile|
206
209
  # MimeType in first place
207
- zile.put_next_entry('mimetype', nil, nil, Zip::ZipEntry::STORED)
210
+ zile.put_next_entry('mimetype', nil, nil, Zip::Entry::STORED)
208
211
  zile << mime_type
209
212
 
210
213
  # Manifest
@@ -0,0 +1,125 @@
1
+ module Spreet
2
+
3
+ class Sheet
4
+ attr_reader :document, :name, :columns
5
+ attr_accessor :current_row
6
+
7
+ def initialize(document, name=nil)
8
+ @document = document
9
+ self.name = name
10
+ raise ArgumentError.new("Must be a Document") unless document.is_a? Document
11
+ @current_row = 0
12
+ @cells = {} # BigArray::Cells.new
13
+ @bound = compute_bound
14
+ end
15
+
16
+ def name=(value)
17
+ unless value
18
+ value = (@document.sheets.count > 0 ? @document.sheets[-1].name.succ : "Sheet 1")
19
+ end
20
+ raise ArgumentError.new("Name of sheet must be given") if value.to_s.strip.size.zero?
21
+ if @document.sheets[value]
22
+ raise ArgumentError.new("Name of sheet must be unique")
23
+ end
24
+ @name = value
25
+ end
26
+
27
+ def next_row(increment = 1)
28
+ @current_row += increment
29
+ end
30
+
31
+ def previous_row(increment = 1)
32
+ @current_row -= increment
33
+ end
34
+
35
+ def [](*args)
36
+ coord = Coordinates.new(*args)
37
+ @cells[coord.to_i] ||= Cell.new(self, coord)
38
+ return @cells[coord.to_i]
39
+ end
40
+
41
+ def []=(*args)
42
+ value = args.delete_at(-1)
43
+ cell = self[*args]
44
+ cell.value = value
45
+ @updated = true
46
+ end
47
+
48
+ def row(*args)
49
+ options = {}
50
+ options = args.delete_at(-1) if args[-1].is_a? Hash
51
+ row = options[:row] || @current_row
52
+ args.each_index do |index|
53
+ self[index, row] = args[index]
54
+ end
55
+ next_row
56
+ end
57
+
58
+ def rows(index)
59
+ row = []
60
+ for i in 0..bound.x
61
+ row[i] = self[i, index]
62
+ end
63
+ return row
64
+ end
65
+
66
+ def each_row(&block)
67
+ for j in 0..bound.y
68
+ yield rows(j)
69
+ end
70
+ end
71
+
72
+ # Find or build cell
73
+ def cell(*args)
74
+ return c
75
+ end
76
+
77
+ def bound
78
+ if @updated
79
+ compute_bound
80
+ else
81
+ @bound
82
+ end
83
+ end
84
+
85
+ def remove!(coordinates)
86
+ raise ArgumentError.new("Must be a Coordinates") unless document.is_a?(Coordinates)
87
+ @cells.delete(coordinates.to_i)
88
+ @updated = true
89
+ end
90
+
91
+ # Moves the sheet to an other position in the list of sheets
92
+ def move_to(position)
93
+ @document.sheets.move_at(self, position)
94
+ end
95
+
96
+ # Moves the sheet higher in the list of sheets
97
+ def move_higher(increment=1)
98
+ @document.sheets.move(self, increment)
99
+ end
100
+
101
+ # Moves the sheet lower in the list of sheets
102
+ def move_lower(increment=1)
103
+ @document.sheets.move(self, -increment)
104
+ end
105
+
106
+ private
107
+
108
+ def compute_bound
109
+ bound = Coordinates.new(0,0)
110
+ for index, cell in @cells
111
+ # for cell in @cells.compact
112
+ unless cell.empty?
113
+ bound.x = cell.coordinates.x if cell.coordinates.x > bound.x
114
+ bound.y = cell.coordinates.y if cell.coordinates.y > bound.y
115
+ end
116
+ end
117
+ @updated = false
118
+ @bound = bound
119
+ return @bound
120
+ end
121
+
122
+ end
123
+
124
+
125
+ end
@@ -0,0 +1,63 @@
1
+ module Spreet
2
+
3
+ class Sheets
4
+
5
+ def initialize(document)
6
+ raise ArgumentError.new("Must be a Document") unless document.is_a?(Document)
7
+ @document = document
8
+ @array = []
9
+ end
10
+
11
+ def count
12
+ @array.size
13
+ end
14
+
15
+ def index(name_or_sheet)
16
+ if name_or_sheet.is_a? String
17
+ @array.each_index do |i|
18
+ return i if @array[i].name == name_or_sheet
19
+ end
20
+ elsif name_or_sheet.is_a? Integer
21
+ return (@array[name_or_sheet].nil? ? nil : name_or_sheet)
22
+ else
23
+ return @array.index(name_or_sheet)
24
+ end
25
+ end
26
+
27
+ def add(name=nil, position=-1)
28
+ sheet = Sheet.new(@document, name)
29
+ @array.insert(position, sheet)
30
+ return sheet
31
+ end
32
+
33
+ def [](sheet)
34
+ sheet = index(sheet)
35
+ return (sheet.is_a?(Integer) ? @array[sheet] : nil)
36
+ end
37
+
38
+ def remove(sheet)
39
+ @array.delete_at(index(sheet))
40
+ end
41
+
42
+ def move(sheet, shift=0)
43
+ position = index(sheet) + shift
44
+ position = 0 if position < 0
45
+ position = self.count-1 if position >= self.count
46
+ move_at(sheet, position)
47
+ end
48
+
49
+ def move_at(sheet, position=-1)
50
+ if i = index(sheet)
51
+ @array.insert(position, @array.delete_at(i))
52
+ end
53
+ end
54
+
55
+ def each(&block)
56
+ for item in @array
57
+ yield item
58
+ end
59
+ end
60
+
61
+ end
62
+
63
+ end