rubyexcel 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,10 +1,21 @@
1
1
  require 'win32ole' #Interface with Excel
2
2
  require 'win32/registry' #Find Documents / My Documents for default directory
3
3
 
4
+ # Holder for WIN32OLE Excel Constants
4
5
  module ExcelConstants; end
5
6
 
6
7
  module RubyExcel
7
8
 
9
+ #
10
+ # Add borders to an Excel Range
11
+ #
12
+ # @param [WIN32OLE::Range] range the Excel Range to add borders to
13
+ # @param [Fixnum] weight the weight of the borders
14
+ # @param [Boolean] inner add inner borders
15
+ # @raise [ArgumentError] 'First Argument must be WIN32OLE Range'
16
+ # @return [WIN32OLE::Range] the range initially given
17
+ #
18
+
8
19
  def self.borders( range, weight=1, inner=false )
9
20
  range.ole_respond_to?( :borders ) or fail ArgumentError, 'First Argument must be WIN32OLE Range'
10
21
  [0,1,2,3].include?( weight ) or fail ArgumentError, "Invalid line weight #{ weight }. Must be from 0 to 3"
@@ -18,12 +29,27 @@ module RubyExcel
18
29
 
19
30
  class Workbook
20
31
 
32
+ #
33
+ # Drop a multidimensional Array into an Excel Sheet
34
+ #
35
+ # @param [Array<Array>] data the data to place in the Sheet
36
+ # @param [WIN32OLE::Worksheet, nil] sheet optional WIN32OLE Worksheet to use
37
+ # @return [WIN32OLE::Worksheet] the Worksheet containing the data
38
+ #
39
+
21
40
  def dump_to_sheet( data, sheet=nil )
22
41
  data.is_a?( Array ) or fail ArgumentError, "Invalid data type: #{ data.class }"
23
42
  sheet ||= get_workbook.sheets(1)
24
43
  sheet.range( sheet.cells( 1, 1 ), sheet.cells( data.length, data[0].length ) ).value = data
25
44
  sheet
26
45
  end
46
+
47
+ #
48
+ # Open or connect to an Excel instance
49
+ #
50
+ # @param [Boolean] invisible leave Excel invisible if creating a new instance
51
+ # @return [WIN32OLE::Excel] the first available Excel application
52
+ #
27
53
 
28
54
  def get_excel( invisible = false )
29
55
  excel = WIN32OLE::connect( 'excel.application' ) rescue WIN32OLE::new( 'excel.application' )
@@ -31,6 +57,14 @@ module RubyExcel
31
57
  excel
32
58
  end
33
59
 
60
+ #
61
+ # Create a new Excel Workbook
62
+ #
63
+ # @param [WIN32OLE::Excel, nil] excel an Excel object to use
64
+ # @param [Boolean] invisible leave Excel invisible if creating a new instance
65
+ # @return [WIN32OLE::Workbook] the new Excel Workbook
66
+ #
67
+
34
68
  def get_workbook( excel=nil, invisible = false )
35
69
  excel ||= get_excel( invisible )
36
70
  wb = excel.workbooks.add
@@ -38,15 +72,32 @@ module RubyExcel
38
72
  wb
39
73
  end
40
74
 
75
+ #
76
+ # Take an Excel Sheet and standardise some of the formatting
77
+ #
78
+ # @param [WIN32OLE::Worksheet] sheet the Sheet to add formatting to
79
+ # @return [WIN32OLE::Worksheet] the sheet with formatting added
80
+ #
81
+
41
82
  def make_sheet_pretty( sheet )
42
83
  c = sheet.cells
43
84
  c.rowheight = 15
44
85
  c.entireColumn.autoFit
45
86
  c.horizontalAlignment = -4108
46
87
  c.verticalAlignment = -4108
88
+ sheet.UsedRange.Columns.each { |col| col.ColumnWidth = 30 if col.ColumnWidth > 50 }
89
+ RubyExcel.borders( sheet.usedrange, 1, true )
47
90
  sheet
48
91
  end
49
92
 
93
+ #
94
+ # Save the RubyExcel::Workbook as an Excel Workbook
95
+ #
96
+ # @param [String] filename the filename to save as
97
+ # @param [Boolean] invisible leave Excel invisible if creating a new instance
98
+ # @return [WIN32OLE::Workbook] the Workbook, saved as filename.
99
+ #
100
+
50
101
  def save_excel( filename = 'Output', invisible = false )
51
102
  filename = filename.gsub('/','\\')
52
103
  unless filename.include?('\\')
@@ -59,9 +110,16 @@ module RubyExcel
59
110
  wb
60
111
  end
61
112
 
113
+ #
114
+ # Output the RubyExcel::Workbook to Excel
115
+ #
116
+ # @param [Boolean] invisible leave Excel invisible if creating a new instance
117
+ # @return [WIN32OLE::Workbook] the Workbook in Excel
118
+ #
119
+
62
120
  def to_excel( invisible = false )
63
121
  self.sheets.count == self.sheets.map(&:name).uniq.length or fail NoMethodError, 'Duplicate sheet name'
64
- wb = get_workbook( nil, invisible )
122
+ wb = get_workbook( nil, true )
65
123
  wb.parent.displayAlerts = false
66
124
  first_time = true
67
125
  self.each do |s|
@@ -70,9 +128,10 @@ module RubyExcel
70
128
  make_sheet_pretty( dump_to_sheet( s.data.all, sht ) )
71
129
  end
72
130
  wb.sheets(1).select
131
+ wb.application.visible = true unless invisible
73
132
  wb
74
133
  end
75
134
 
76
- end
135
+ end # Workbook
77
136
 
78
- end
137
+ end # RubyExcel
@@ -5,6 +5,10 @@ require_relative 'section.rb'
5
5
 
6
6
  module RubyExcel
7
7
 
8
+ #
9
+ # Example data to use in tests / demos
10
+ #
11
+
8
12
  def self.sample_data
9
13
  [
10
14
  [ 'Part', 'Ref1', 'Ref2', 'Qty', 'Cost' ],
@@ -18,6 +22,10 @@ module RubyExcel
18
22
  ]
19
23
  end
20
24
 
25
+ #
26
+ # Shortcut to create a Sheet with example data
27
+ #
28
+
21
29
  def self.sample_sheet
22
30
  Workbook.new.load RubyExcel.sample_data
23
31
  end
@@ -1,91 +1,177 @@
1
1
  module RubyExcel
2
2
 
3
+ #
4
+ # Superclass for Row and Column
5
+ #
6
+
3
7
  class Section
4
-
5
8
  include Address
9
+ include Enumerable
6
10
 
7
- attr_reader :sheet, :idx, :data
11
+ # The Sheet parent of the Section
12
+ attr_reader :sheet
8
13
  alias parent sheet
9
14
 
15
+ # The Data underlying the Sheet
16
+ attr_reader :data
17
+
18
+ #
19
+ # Creates a RubyExcel::Section instance
20
+ #
21
+ # @param [RubyExcel::Sheet] sheet the parent Sheet
22
+ #
23
+
10
24
  def initialize( sheet )
11
25
  @sheet = sheet
12
26
  @data = sheet.data
13
27
  end
28
+
29
+ #
30
+ # Append a value to the Section.
31
+ # This only adds an extra cell if it is the first Row / Column.
32
+ # This prevents a loop through Rows or Columns from extending diagonally away from the main data.
33
+ #
34
+ # @param [Object] value the object to append
35
+ #
14
36
 
15
37
  def <<( value )
16
- if self.is_a? Row
17
- lastone = ( col_index( idx ) == 1 ? data.cols + 1 : data.cols )
18
- else
19
- lastone = ( col_index( idx ) == 1 ? data.rows + 1 : data.rows )
38
+ case self
39
+ when Row ; lastone = ( col_index( idx ) == 1 ? data.cols + 1 : data.cols )
40
+ else ; lastone = ( col_index( idx ) == 1 ? data.rows + 1 : data.rows )
20
41
  end
21
42
  data[ translate_address( lastone ) ] = value
22
43
  end
23
44
 
45
+ #
46
+ # Access a cell by its index within the Section
47
+ #
48
+
24
49
  def cell( ref )
25
50
  Element.new( sheet, translate_address( ref ) )
26
51
  end
27
52
 
53
+ #
54
+ # Delete the data referenced by self
55
+ #
56
+
28
57
  def delete
29
58
  data.delete( self )
30
59
  end
31
60
 
61
+ #
62
+ # Check whether the data in self is empty
63
+ #
64
+
32
65
  def empty?
33
66
  all? { |val| val.to_s.empty? }
34
67
  end
68
+
69
+ #
70
+ # Return the address of a given value
71
+ #
72
+ # @yield [Object] yields each cell value to the block
73
+ # @return [String, nil] the address of the value or nil
74
+ #
35
75
 
36
76
  def find
77
+ return to_enum( :find ) unless block_given?
37
78
  each_cell { |ce| return ce.address if yield ce.value }; nil
38
79
  end
39
80
 
81
+ #
82
+ # View the object for debugging
83
+ #
84
+
40
85
  def inspect
41
86
  "#{ self.class }:0x#{ '%x' % (object_id << 1) }: #{ idx }"
42
87
  end
43
88
 
89
+ #
90
+ # Read a value by address
91
+ #
92
+ # @param [String, Fixnum] id the index or reference of the required value
93
+ #
94
+
44
95
  def read( id )
45
96
  data[ translate_address( id ) ]
46
97
  end
47
98
  alias [] read
48
99
 
100
+ #
101
+ # Summarise the values of a Section into a Hash
102
+ #
103
+ # @return [Hash]
104
+ #
105
+
49
106
  def summarise
50
107
  each_wh.inject( Hash.new(0) ) { |h, v| h[v]+=1; h }
51
108
  end
52
109
  alias summarize summarise
53
110
 
111
+ #
112
+ # The Section as a seperated value String
113
+ #
114
+
54
115
  def to_s
55
116
  to_a.join ( self.is_a?( Row ) ? "\t" : "\n" )
56
117
  end
57
118
 
119
+ #
120
+ # Write a value by address
121
+ #
122
+ # @param [String, Fixnum] id the index or reference to write to
123
+ # @param [Object] val the object to place at the address
124
+ #
125
+
58
126
  def write( id, val )
59
127
  data[ translate_address( id ) ] = val
60
128
  end
61
129
  alias []= write
62
130
 
63
- include Enumerable
131
+ #
132
+ # Yields each value
133
+ #
64
134
 
65
135
  def each
66
136
  return to_enum(:each) unless block_given?
67
137
  each_address { |addr| yield data[ addr ] }
68
138
  end
69
139
 
140
+ #
141
+ # Yields each value, skipping headers
142
+ #
143
+
70
144
  def each_without_headers
71
- return to_enum(:each_without_headers) unless block_given?
145
+ return to_enum( :each_without_headers ) unless block_given?
72
146
  each_address_without_headers { |addr| yield data[ addr ] }
73
147
  end
74
148
  alias each_wh each_without_headers
75
149
 
150
+ #
151
+ # Yields each cell
152
+ #
153
+
76
154
  def each_cell
77
- return to_enum(:each_cell) unless block_given?
155
+ return to_enum( :each_cell ) unless block_given?
78
156
  each_address { |addr| yield Element.new( sheet, addr ) }
79
157
  end
80
158
 
159
+ #
160
+ # Yields each cell, skipping headers
161
+ #
162
+
81
163
  def each_cell_without_headers
82
- return to_enum(:each_cell) unless block_given?
164
+ return to_enum( :each_cell_without_headers ) unless block_given?
83
165
  each_address { |addr| yield Element.new( sheet, addr ) }
84
166
  end
85
167
  alias each_cell_wh each_cell_without_headers
86
168
 
169
+ #
170
+ # Replaces each value with the result of the block
171
+ #
172
+
87
173
  def map!
88
- return to_enum(:map!) unless block_given?
174
+ return to_enum( :map! ) unless block_given?
89
175
  each_address { |addr| data[addr] = ( yield data[addr] ) }
90
176
  end
91
177
 
@@ -93,7 +179,8 @@ module RubyExcel
93
179
 
94
180
  def translate_address( addr )
95
181
  case self
96
- when Row ; col_letter( addr ) + idx.to_s
182
+ when Row
183
+ col_letter( addr ) + idx.to_s
97
184
  when Column
98
185
  addr = addr.to_s unless addr.is_a?( String )
99
186
  fail ArgumentError, "Invalid address : #{ addr }" if addr =~ /[^\d]/
@@ -103,24 +190,61 @@ module RubyExcel
103
190
 
104
191
  end
105
192
 
193
+ #
194
+ # A Row in the Sheet
195
+ #
196
+
106
197
  class Row < Section
107
198
 
199
+ # The Row index
108
200
  attr_reader :idx
201
+
202
+ #
203
+ # Creates a RubyExcel::Row instance
204
+ #
205
+ # @param [RubyExcel::Sheet] sheet the Sheet which holds this Row
206
+ # @param [Fixnum] idx the index of this Row
207
+ #
109
208
 
110
209
  def initialize( sheet, idx )
111
210
  @idx = idx.to_i
112
211
  super( sheet )
113
212
  end
213
+
214
+ #
215
+ # Access a cell by its header
216
+ #
217
+ # @param [String] header the header to search for
218
+ # @return [RubyExcel::Element] the cell
219
+ #
114
220
 
115
221
  def cell_by_header( header )
116
222
  cell( getref( header ) )
117
223
  end
118
224
  alias cell_h cell_by_header
119
225
 
226
+ #
227
+ # Find the Address of a header
228
+ #
229
+ # @param [String] header the header to search for
230
+ # @return [String] the address of the header
231
+ #
232
+
120
233
  def getref( header )
121
- column_id( sheet.row(1).find &/#{header}/ )
234
+ sheet.header_rows.times do |t|
235
+ res = sheet.row( t + 1 ).find &/^#{header}$/
236
+ return column_id( res ) if res
237
+ end
238
+ fail ArgumentError, 'Invalid header: ' + header.to_s
122
239
  end
123
240
 
241
+ #
242
+ # Find a value in this Row by its header
243
+ #
244
+ # @param [String]header the header to search for
245
+ # @return [Object] the value at the address
246
+ #
247
+
124
248
  def value_by_header( header )
125
249
  self[ getref( header ) ]
126
250
  end
@@ -133,15 +257,27 @@ module RubyExcel
133
257
  end
134
258
 
135
259
  def each_address_without_headers
136
- ( col_letter( sheet.header_cols+1 )..col_letter( data.cols ) ).each { |col_id| yield "#{col_id}#{idx}" }
260
+ ( 'A'..col_letter( data.cols ) ).each { |col_id| yield "#{col_id}#{idx}" }
137
261
  end
138
262
 
139
263
  end
140
264
 
265
+ #
266
+ # A Column in the Sheet
267
+ #
268
+
141
269
  class Column < Section
142
270
 
271
+ # The Row index
143
272
  attr_reader :idx
144
273
 
274
+ #
275
+ # Creates a RubyExcel::Column instance
276
+ #
277
+ # @param [RubyExcel::Sheet] sheet the Sheet which holds this Column
278
+ # @param [String, Fixnum] idx the index of this Column
279
+ #
280
+
145
281
  def initialize( sheet, idx )
146
282
  @idx = idx
147
283
  super( sheet )