rexcel 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/benchmark/rexcel_benchmark.rb +70 -0
- data/examples/example.rb +29 -0
- data/examples/example_color.rb +43 -0
- data/examples/example_format.rb +23 -0
- data/lib/rexcel.rb +166 -0
- data/lib/rexcel/cell.rb +130 -0
- data/lib/rexcel/row.rb +73 -0
- data/lib/rexcel/style.rb +224 -0
- data/lib/rexcel/workbook.rb +229 -0
- data/lib/rexcel/worksheet.rb +92 -0
- data/unittest/expected/Test_Style_xlm-test_backgroundcolor-gray.xml +34 -0
- data/unittest/expected/Test_Style_xlm-test_bold-bold.xml +34 -0
- data/unittest/expected/Test_Style_xlm-test_color-gray.xml +34 -0
- data/unittest/expected/Test_Style_xlm-test_italic-italic.xml +34 -0
- data/unittest/expected/Test_workbook-test_save_xml.xml +29 -0
- data/unittest/test_rexcel.rb +725 -0
- metadata +139 -0
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'benchmark'
|
2
|
+
$:.unshift("../lib")
|
3
|
+
require 'rexcel'
|
4
|
+
Excel::LOGGER.level = Log4r::OFF #no messages
|
5
|
+
|
6
|
+
def delete_testfiles()
|
7
|
+
%w{test.xml test.xls test.xlsx}.each{|fn|
|
8
|
+
File.delete(fn) if File.exist?(fn)
|
9
|
+
}
|
10
|
+
end #delete_testfiles
|
11
|
+
delete_testfiles
|
12
|
+
|
13
|
+
def test(rownumber)
|
14
|
+
puts "======Test with #{rownumber} rows"
|
15
|
+
wb = Excel::Workbook.new()
|
16
|
+
rownumber.times{
|
17
|
+
wb << [1,2,3,4,5,6,7]
|
18
|
+
wb << [:a, :b, :c, :d, :e, :f]
|
19
|
+
}
|
20
|
+
|
21
|
+
Benchmark.bm do |x|
|
22
|
+
x.report('xml ') { wb.save('test.xml') }
|
23
|
+
x.report('xml2xls ') { wb.save('test.xls', 'test.xml')}
|
24
|
+
x.report('xml2xlsx') { wb.save('test.xlsx', 'test.xml')}
|
25
|
+
|
26
|
+
delete_testfiles
|
27
|
+
x.report('xls ') { wb.save('test.xls') }
|
28
|
+
delete_testfiles
|
29
|
+
x.report('xlsx ') { wb.save('test.xlsx') }
|
30
|
+
delete_testfiles
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
test( 10)
|
35
|
+
test( 500)
|
36
|
+
test(1000)
|
37
|
+
test(5000)
|
38
|
+
|
39
|
+
|
40
|
+
__END__
|
41
|
+
My Testresult:
|
42
|
+
|
43
|
+
======Test with 10 rows
|
44
|
+
user system total real
|
45
|
+
xml 0.031000 0.078000 0.109000 ( 0.124771)
|
46
|
+
xml2xls 0.000000 0.015000 0.015000 ( 2.760563)
|
47
|
+
xml2xlsx 0.000000 0.016000 0.016000 ( 0.452296)
|
48
|
+
xls 0.016000 0.000000 0.016000 ( 0.701838)
|
49
|
+
xlsx 0.031000 0.015000 0.046000 ( 0.717435)
|
50
|
+
======Test with 500 rows
|
51
|
+
user system total real
|
52
|
+
xml 0.875000 0.016000 0.891000 ( 0.951380)
|
53
|
+
xml2xls 0.000000 0.016000 0.016000 ( 0.483488)
|
54
|
+
xml2xlsx 0.000000 0.000000 0.000000 ( 0.452296)
|
55
|
+
xls 1.000000 0.265000 1.265000 ( 6.316542)
|
56
|
+
xlsx 1.062000 0.375000 1.437000 ( 6.456910)
|
57
|
+
======Test with 1000 rows
|
58
|
+
user system total real
|
59
|
+
xml 1.813000 0.015000 1.828000 ( 1.840375)
|
60
|
+
xml2xls 0.000000 0.000000 0.000000 ( 0.530278)
|
61
|
+
xml2xlsx 0.000000 0.000000 0.000000 ( 0.561470)
|
62
|
+
xls 2.015000 0.766000 2.781000 ( 13.366115)
|
63
|
+
xlsx 2.688000 0.906000 3.594000 ( 14.676212)
|
64
|
+
======Test with 5000 rows
|
65
|
+
user system total real
|
66
|
+
xml 9.594000 0.062000 9.656000 ( 9.841328)
|
67
|
+
xml2xls 0.000000 0.000000 0.000000 ( 1.575237)
|
68
|
+
xml2xlsx 0.000000 0.000000 0.000000 ( 1.138537)
|
69
|
+
xls 24.234000 4.500000 28.734000 (145.873129)
|
70
|
+
xlsx 31.938000 4.453000 36.391000 (161.625493)
|
data/examples/example.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
$:.unshift('../lib') if $0 == __FILE__
|
2
|
+
require 'rexcel'
|
3
|
+
Excel::LOGGER.level = Log4r::DEBUG
|
4
|
+
|
5
|
+
wb = Excel::Workbook.new('data')
|
6
|
+
|
7
|
+
wb << [1,2,3,4,5,6,7]
|
8
|
+
wb << [:a, :b, :c, :d, :e, :f]
|
9
|
+
|
10
|
+
|
11
|
+
wb << ws = Excel::Worksheet.new('Formats')
|
12
|
+
ws << row = Excel::Row.new
|
13
|
+
row << cell = Excel::Cell.new(1)
|
14
|
+
|
15
|
+
wb << style = Excel::Style.new('bold', :bold=> true, :backgroundcolor => 15)
|
16
|
+
row << cell = Excel::Cell.new('Bold', :style => style)
|
17
|
+
#~ puts wb.build_excel_xml('ss')
|
18
|
+
|
19
|
+
wb << style = Excel::Style.new('boldit', :bold=> true, :bold => true, :italic => true)
|
20
|
+
row << cell = Excel::Cell.new('Bold and italic', :style => style)
|
21
|
+
|
22
|
+
wb << style = Excel::Style.new('gray', :color => 18, :backgroundcolor => 27)
|
23
|
+
row << cell = Excel::Cell.new('grau text', :style => style)
|
24
|
+
|
25
|
+
|
26
|
+
wb.save('test.xml')
|
27
|
+
wb.save('test_xml.xls', 'test.xml')
|
28
|
+
wb.save('test.xls')
|
29
|
+
wb.save('test.xlsx')
|
@@ -0,0 +1,43 @@
|
|
1
|
+
$:.unshift('../lib') if $0 == __FILE__
|
2
|
+
require 'rexcel'
|
3
|
+
|
4
|
+
wb = Excel::Workbook.new()
|
5
|
+
wb << ws = Excel::Worksheet.new('Colors')
|
6
|
+
|
7
|
+
# For each color in color index
|
8
|
+
1.upto(56) do |i|
|
9
|
+
wb << style = Excel::Style.new("color%02i" % i, :color => i)
|
10
|
+
wb << styleback = Excel::Style.new("backgroundcolor%02i" % i, :backgroundcolor => i)
|
11
|
+
|
12
|
+
ws << row = Excel::Row.new
|
13
|
+
row << cell = Excel::Cell.new("Font color %02i" % i, :style => style)
|
14
|
+
row << cell = Excel::Cell.new("Background %02i" % i, :style => styleback)
|
15
|
+
end
|
16
|
+
|
17
|
+
#
|
18
|
+
#Color matrix
|
19
|
+
#
|
20
|
+
wb << ws = Excel::Worksheet.new('Color matrix')
|
21
|
+
ws << firstrow = Excel::Row.new
|
22
|
+
firstrow << cell = Excel::Cell.new
|
23
|
+
1.upto(56) do |i2|
|
24
|
+
firstrow << Excel::Cell.new("Background %02i" % i2)
|
25
|
+
end
|
26
|
+
|
27
|
+
1.upto(56) do |i1|
|
28
|
+
ws << row = Excel::Row.new
|
29
|
+
row << Excel::Cell.new("Font color %02i" % i1)
|
30
|
+
1.upto(56) do |i2|
|
31
|
+
wb << style = Excel::Style.new("color%02i-%02i" % [i1, i2], :color => i1, :backgroundcolor => i2)
|
32
|
+
row << Excel::Cell.new("Color %02i/%02i" % [i1, i2], :style => style, :string => true)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
wb.save('colors.xml')
|
38
|
+
wb.save('colors_xml.xlsx', 'colors.xml')
|
39
|
+
wb.save('colors.xls')
|
40
|
+
wb.save('colors.xlsx')
|
41
|
+
|
42
|
+
Excel::Excel.instance.close
|
43
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
$:.unshift('../lib') if $0 == __FILE__
|
2
|
+
require 'rexcel'
|
3
|
+
Excel::LOGGER.level = Log4r::DEBUG
|
4
|
+
|
5
|
+
wb << ws = Excel::Worksheet.new('Formats')
|
6
|
+
ws << row = Excel::Row.new
|
7
|
+
row << cell = Excel::Cell.new(1)
|
8
|
+
|
9
|
+
wb << style = Excel::Style.new('bold', :bold=> true, :backgroundcolor => 15)
|
10
|
+
row << cell = Excel::Cell.new('Bold', :style => style)
|
11
|
+
#~ puts wb.build_excel_xml('ss')
|
12
|
+
|
13
|
+
wb << style = Excel::Style.new('boldit', :bold=> true, :bold => true, :italic => true)
|
14
|
+
row << cell = Excel::Cell.new('Bold and italic', :style => style)
|
15
|
+
|
16
|
+
wb << style = Excel::Style.new('gray', :color => 18, :backgroundcolor => 27)
|
17
|
+
row << cell = Excel::Cell.new('grau text', :style => style)
|
18
|
+
|
19
|
+
|
20
|
+
wb.save('test_format.xml')
|
21
|
+
wb.save('test_xml.xls', 'test_format.xml')
|
22
|
+
wb.save('test_format.xls')
|
23
|
+
wb.save('test_format.xlsx')
|
data/lib/rexcel.rb
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
=begin rdoc
|
3
|
+
:title:Create Excel-documents with ruby
|
4
|
+
Build Excel documents via win32ole.
|
5
|
+
|
6
|
+
==Example 1 (Simple Spreadsheet):
|
7
|
+
require 'excel'
|
8
|
+
|
9
|
+
wb = Excel::Workbook.new()
|
10
|
+
|
11
|
+
wb << [1,2,3,4,5,6,7]
|
12
|
+
wb << [:a, :b, :c, :d, :e, :f]
|
13
|
+
|
14
|
+
#Save as excel spreadsheets
|
15
|
+
wb.save('test.xls') #excel97_2003_format
|
16
|
+
wb.save('test.xlsx') #Excel 2007
|
17
|
+
|
18
|
+
wb.save('test.xml') #Microsoft Office Word 2003 XML Format
|
19
|
+
wb.save('test.xls', 'test.xml')#Build xls from xlm
|
20
|
+
|
21
|
+
==Example 2 (Access to Worksheets, Rows and Cells):
|
22
|
+
require 'excel'
|
23
|
+
|
24
|
+
wb = Excel::Workbook.new()
|
25
|
+
|
26
|
+
wb << ws = Excel::Worksheet.new('My Spreadsheet')
|
27
|
+
ws << row = Excel::Row.new()
|
28
|
+
row << Excel::Cell.new(1)
|
29
|
+
row << Excel::Cell.new(2)
|
30
|
+
row << Excel::Cell.new(4)
|
31
|
+
|
32
|
+
#Save as excel spreadsheets
|
33
|
+
wb.save('test.xls') #excel97_2003_format
|
34
|
+
wb.save('test.xlsx') #Excel 2007
|
35
|
+
|
36
|
+
wb.save('test.xml') #Microsoft Office Word 2003 XML Format
|
37
|
+
wb.save('test.xls', 'test.xml')#Build xls from xlm
|
38
|
+
|
39
|
+
==Example 3 (With Format options):
|
40
|
+
require 'excel'
|
41
|
+
|
42
|
+
wb = Excel::Workbook.new()
|
43
|
+
wb << style = Excel::Style.new('fett', :bold => true)
|
44
|
+
|
45
|
+
wb << ws = Excel::Worksheet.new('My Spreadsheet')
|
46
|
+
ws << row = Excel::Row.new()
|
47
|
+
row << Excel::Cell.new(1)
|
48
|
+
row << Excel::Cell.new(2)
|
49
|
+
row << Excel::Cell.new(999, :style => style)
|
50
|
+
|
51
|
+
#Save as excel spreadsheets
|
52
|
+
wb.save('test.xls') #excel97_2003_format
|
53
|
+
wb.save('test.xlsx') #Excel 2007
|
54
|
+
|
55
|
+
wb.save('test.xml') #Microsoft Office Word 2003 XML Format
|
56
|
+
wb.save('test.xls', 'test.xml')#Build xls from xlm
|
57
|
+
|
58
|
+
|
59
|
+
'Big' spreadsheets needs a long time to be build.
|
60
|
+
(20000 lines need 2 hours)
|
61
|
+
|
62
|
+
When you build the xml, and then the xls from xlm, the wor is done in seconds.
|
63
|
+
|
64
|
+
|
65
|
+
=end
|
66
|
+
require 'win32ole'
|
67
|
+
require 'log4r'
|
68
|
+
require 'singleton'
|
69
|
+
|
70
|
+
=begin rdoc
|
71
|
+
Frame for Excel-tools.
|
72
|
+
=end
|
73
|
+
module Excel
|
74
|
+
VERSION = '0.1.0'
|
75
|
+
|
76
|
+
LOGGER = Log4r::Logger.new( name )#, Log4r::DEBUG, :trunc => true )
|
77
|
+
LOGGER.outputters << Log4r::StdoutOutputter.new('std', :level => Log4r::WARN )
|
78
|
+
|
79
|
+
=begin rdoc
|
80
|
+
Singleton for Excel.
|
81
|
+
|
82
|
+
Will be closed at END.
|
83
|
+
=end
|
84
|
+
class Excel
|
85
|
+
include Singleton
|
86
|
+
def initialize()
|
87
|
+
reconnect()
|
88
|
+
end
|
89
|
+
=begin rdoc
|
90
|
+
Create OLE-object.
|
91
|
+
=end
|
92
|
+
def reconnect()
|
93
|
+
return @xl if @xl
|
94
|
+
# Create an instance of the Excel application object
|
95
|
+
@xl = WIN32OLE.new('Excel.Application')
|
96
|
+
# Make Excel visible 1=visible 0=not visible
|
97
|
+
@xl.Visible = 0
|
98
|
+
#~ xl.Interactive = false #visible, but no input allowed
|
99
|
+
#~ xl.ScreenUpdating = false #make it faster
|
100
|
+
@xl.DisplayAlerts = false #No alerts like "don't overwrite
|
101
|
+
|
102
|
+
end
|
103
|
+
#OLE-object
|
104
|
+
attr_reader :xl
|
105
|
+
=begin rdoc
|
106
|
+
Make sure Excel is closed.
|
107
|
+
|
108
|
+
Called at END to be sure it's really closed.
|
109
|
+
|
110
|
+
See http://forum.ruby-portal.de/viewtopic.php?f=22&t=11667
|
111
|
+
|
112
|
+
When closed once: Don't create it again. There may be errors.
|
113
|
+
=end
|
114
|
+
def close()
|
115
|
+
return unless @xl
|
116
|
+
@xl.Quit #Leider Kein effekt.
|
117
|
+
WIN32OLE.ole_free(@xl)
|
118
|
+
@xl = nil
|
119
|
+
end
|
120
|
+
end #class Excel
|
121
|
+
=begin rdoc
|
122
|
+
Exceptionclass for empty Workbook, Worksheet, Row
|
123
|
+
=end
|
124
|
+
class EmptyError < Exception; end
|
125
|
+
end #module Excel
|
126
|
+
|
127
|
+
=begin
|
128
|
+
makes problems in unit test
|
129
|
+
=end
|
130
|
+
#~ at_exit {
|
131
|
+
#~ Excel::Excel.instance.close
|
132
|
+
#~ }
|
133
|
+
|
134
|
+
|
135
|
+
require 'rexcel/workbook'
|
136
|
+
require 'rexcel/worksheet'
|
137
|
+
require 'rexcel/row'
|
138
|
+
require 'rexcel/cell'
|
139
|
+
require 'rexcel/style'
|
140
|
+
|
141
|
+
=begin
|
142
|
+
Open:
|
143
|
+
* Height (only Row)
|
144
|
+
* Width (Column)
|
145
|
+
|
146
|
+
Styles??
|
147
|
+
class Style
|
148
|
+
def initialize(name)
|
149
|
+
|
150
|
+
end
|
151
|
+
#Bold
|
152
|
+
attr_accessor :bold
|
153
|
+
#Italic
|
154
|
+
attr_accessor :italic
|
155
|
+
#Color
|
156
|
+
attr_accessor :color
|
157
|
+
#Background Color
|
158
|
+
attr_accessor :backgroundcolor
|
159
|
+
end
|
160
|
+
|
161
|
+
Columns
|
162
|
+
(actual only sequence.
|
163
|
+
missing:
|
164
|
+
* title
|
165
|
+
* width
|
166
|
+
=end
|
data/lib/rexcel/cell.rb
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
module Excel
|
2
|
+
=begin rdoc
|
3
|
+
Cell of a Worksheet.
|
4
|
+
|
5
|
+
A cell is part of a Row.
|
6
|
+
|
7
|
+
Cells define
|
8
|
+
* Type .
|
9
|
+
The type is defined by the type of the content.
|
10
|
+
* String
|
11
|
+
* Number
|
12
|
+
* DateTime (not supported/tested yet)
|
13
|
+
* Style (Reference to Excel::Style instance)
|
14
|
+
=end
|
15
|
+
class Cell
|
16
|
+
TYPES = [
|
17
|
+
nil, #
|
18
|
+
:string,
|
19
|
+
]
|
20
|
+
|
21
|
+
=begin rdoc
|
22
|
+
Define a cell and add the content.
|
23
|
+
|
24
|
+
Options:
|
25
|
+
* :string [true/false]
|
26
|
+
* :log: Replacement for the default Logger.
|
27
|
+
* :style see Excel::Style
|
28
|
+
=end
|
29
|
+
def initialize( content = nil, options = {})
|
30
|
+
@log = options[:log] || LOGGER
|
31
|
+
options.each{|key,value|
|
32
|
+
case key
|
33
|
+
when :log
|
34
|
+
when :string
|
35
|
+
@type = 'String' if value
|
36
|
+
when :style
|
37
|
+
@style = value
|
38
|
+
raise ArgumentError, "Style is no Excel::Style" unless @style.is_a?(Style)
|
39
|
+
else
|
40
|
+
@log.warn("Excel::Cell: undefined option #{options}")
|
41
|
+
end
|
42
|
+
}
|
43
|
+
@content = content
|
44
|
+
@type = get_excel_type() unless @type
|
45
|
+
end
|
46
|
+
#Content of the cell
|
47
|
+
attr_reader :content
|
48
|
+
#Target type for Excel
|
49
|
+
attr_reader :type
|
50
|
+
#Style
|
51
|
+
attr_reader :style
|
52
|
+
|
53
|
+
=begin rdoc
|
54
|
+
Supported Excel types:
|
55
|
+
* Number
|
56
|
+
* String
|
57
|
+
* DateTime
|
58
|
+
Example: 2010-02-01T00:00:00.000
|
59
|
+
=end
|
60
|
+
def get_excel_type()
|
61
|
+
case content
|
62
|
+
#~ when Rational #-> Formula?
|
63
|
+
when Numeric #Fixnum, Bignum, Float
|
64
|
+
@type = 'Number'
|
65
|
+
when Time #Date
|
66
|
+
@type = 'DateTime'
|
67
|
+
@log.warn("Cell type DateTime not tested")
|
68
|
+
else
|
69
|
+
@type = 'String'
|
70
|
+
end
|
71
|
+
end #def get_excel_type()
|
72
|
+
protected :get_excel_type
|
73
|
+
|
74
|
+
=begin rdoc
|
75
|
+
Build the xml a work sheet row,
|
76
|
+
|
77
|
+
ns must be a method-object to implement the namespace definitions.
|
78
|
+
=end
|
79
|
+
def to_xml(xmlbuilder, ns, row = nil)
|
80
|
+
#~ ns.call(:StyleID)=>"1"
|
81
|
+
|
82
|
+
cell_options = {}
|
83
|
+
if @style
|
84
|
+
cell_options[ns.call('StyleID')] = @style.style_id
|
85
|
+
#~ elsif row and row.style
|
86
|
+
#~ cell_options[ns.call('StyleID')] = row.style.style_id
|
87
|
+
end
|
88
|
+
xmlbuilder[ns.call].Cell(cell_options){
|
89
|
+
#~ options[ns.call('Type')] = @type
|
90
|
+
xmlbuilder[ns.call].Data(@content, ns.call('Type') => @type )
|
91
|
+
}
|
92
|
+
end #to_xml
|
93
|
+
|
94
|
+
=begin rdoc
|
95
|
+
Fill an Excel field.
|
96
|
+
Receives a OLE-cell and optional a row.
|
97
|
+
|
98
|
+
* value is added
|
99
|
+
* format is set (depending on cell and row format).
|
100
|
+
|
101
|
+
=end
|
102
|
+
def to_xls(cell, row = nil)
|
103
|
+
case @type
|
104
|
+
when 'String' #Suppress automatic conversion from Excel
|
105
|
+
cell.NumberFormat = "@" #as String
|
106
|
+
cell.Value = @content.to_s
|
107
|
+
when 'Number'
|
108
|
+
cell.Value = @content
|
109
|
+
when 'DateTime'
|
110
|
+
@log.warn("Cell type DateTime not tested")
|
111
|
+
cell.Value = @content
|
112
|
+
when nil #no conversion
|
113
|
+
cell.Value = @content
|
114
|
+
else
|
115
|
+
raise ArgumentError, "#{self.class}##{__method__}: Undefined Excel type #{@type}"
|
116
|
+
end
|
117
|
+
#Style must be defined in Workbook
|
118
|
+
#As long I don't know how to do it, I will use Style#to_xls_direct
|
119
|
+
if @style
|
120
|
+
#~ cell.Style = @style.style_id #
|
121
|
+
@style.to_xls_direct(cell)
|
122
|
+
elsif row and row.style
|
123
|
+
row.style.to_xls_direct(cell)
|
124
|
+
end
|
125
|
+
cell
|
126
|
+
end #to_xls
|
127
|
+
|
128
|
+
|
129
|
+
end #class Cell
|
130
|
+
end #module Excel
|