rubyexcel 0.0.5 → 0.0.6

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.
@@ -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 )