rexcel 0.1.0
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.
- 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
|