ActiveExcel 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ === 0.0.1 / 2009-06-04
2
+
3
+ * 1 major enhancement
4
+
5
+ * Initial creation of package
6
+
7
+
@@ -0,0 +1,7 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ bin/active_excel
6
+ lib/active_excel.rb
7
+ test/test_active_excel.rb
@@ -0,0 +1,48 @@
1
+ = active_excel
2
+
3
+ * FIX (url)
4
+
5
+ == DESCRIPTION:
6
+
7
+ FIX (describe your package)
8
+
9
+ == FEATURES/PROBLEMS:
10
+
11
+ * FIX (list of features or problems)
12
+
13
+ == SYNOPSIS:
14
+
15
+ FIX (code sample of usage)
16
+
17
+ == REQUIREMENTS:
18
+
19
+ * FIX (list of requirements)
20
+
21
+ == INSTALL:
22
+
23
+ * FIX (sudo gem install, anything else)
24
+
25
+ == LICENSE:
26
+
27
+ (The MIT License)
28
+
29
+ Copyright (c) 2009 FIX
30
+
31
+ Permission is hereby granted, free of charge, to any person obtaining
32
+ a copy of this software and associated documentation files (the
33
+ 'Software'), to deal in the Software without restriction, including
34
+ without limitation the rights to use, copy, modify, merge, publish,
35
+ distribute, sublicense, and/or sell copies of the Software, and to
36
+ permit persons to whom the Software is furnished to do so, subject to
37
+ the following conditions:
38
+
39
+ The above copyright notice and this permission notice shall be
40
+ included in all copies or substantial portions of the Software.
41
+
42
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
43
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
44
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
45
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
46
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
47
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
48
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,30 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+ $:.unshift(File.dirname(__FILE__) + "/lib")
6
+ require 'active_excel'
7
+
8
+ Hoe.spec 'active_excel' do |p|
9
+ #self.rubyforge_name = 'active_excelx' # if different than 'active_excel'
10
+ #p.developer('FIX', 'FIX@example.com')
11
+ #Hoe.new('ActiveExcel', ActiveExcel::VERSION) do |p|
12
+ p.name = "ActiveExcel"
13
+ p.author = "Rob Whitener"
14
+ p.description = "Excel as the container of model objects"
15
+ p.email = 'robwhitener@gmail.com'
16
+ p.summary = <<EXCEL
17
+ Use Excel to contain model objects. Each row in a sheet represents an object, each sheet in a workbook
18
+ represents a class. Make sure that you rename your sheets - this gem uses ActiveSupport to take advantage
19
+ of the pluralization familiar to Rails developers. Modeled liberally on ActiveRecord, not quite as cool but
20
+ hopefully useful enough. Cheers.
21
+ EXCEL
22
+ p.url = "http://robsexocortex.blogspot.com/2009/06/activeexcel.html"
23
+ p.clean_globs = ['test/actual'] # Remove this directory on "rake clean"
24
+ p.remote_rdoc_dir = '' # Release to root
25
+ #p.changes = p.paragraphs_of('CHANGELOG', 0..1).join("\n\n")
26
+ # * extra_deps - An array of rubygem dependencies.
27
+ #end
28
+ end
29
+
30
+ # vim: syntax=ruby
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ abort "you need to write me"
@@ -0,0 +1,432 @@
1
+ require 'win32ole'
2
+ require 'activesupport'
3
+
4
+ class ExcelConstants
5
+ XLBLACK = 1
6
+ XLRED = 3
7
+ XLGREEN = 4
8
+ XLBLUE = 5
9
+ XLYELLOW = 6
10
+ XLMAGENTA = 7
11
+ XLCYAN = 8
12
+ XLBROWN = 9
13
+ XLOLIVE = 10
14
+ XLROYAL = 11
15
+ XLVOMIT = 12
16
+ XLPURPLE = 13
17
+ XLNOCOLOR = -4142
18
+ end
19
+
20
+ module ActiveExcel
21
+ VERSION = '0.0.1'
22
+ #This class conatins the main Excel functionality that will be inherited
23
+ #by objects which intend to wrap data in the spreadsheet
24
+ class Root
25
+ attr_accessor :workbook, :workbook_name, :id, :fields, :dirty, :is_new, :this_workbook
26
+ @@excel = nil
27
+ @@sheets = nil
28
+ @@workbook = nil
29
+ @@sheet_name = nil
30
+
31
+ def initialize()
32
+ #this will be called by the new method and will be called for
33
+ #each instance of any subclass that is created.
34
+ #The initialize routine will handel adding attributes to the
35
+ #new instance based on the fieldnames from the spreadsheet.
36
+ #If Find was used to get an object out of the sheet, then the
37
+ #attributes will be populated. Each instance will also have
38
+ #an id field that corresponds to its row number in the spreadsheet
39
+ @fields = nil
40
+ @this_workbook = @@workbook
41
+ add_attributes
42
+ @id = -1 #the id can have a default value of -1, since there is no -1 row in a sheet
43
+ @dirty = false
44
+ @is_new = true
45
+
46
+ end
47
+
48
+ class << self ###Class methods
49
+
50
+ #Config is a hash that expects the following parameters
51
+ # :wkbook -> The name of the workbook to open
52
+ # :path -> pathe where the workbook can be found if the workbook isn't in the my docs folder
53
+ def workbook_connect(config=nil)
54
+ @workbook_name = config[:wkbook]
55
+ if config[:path]
56
+ #there was a path specified, prepend that to the workbook name
57
+ @workbook_name = config[:path] + "/" + @workbook_name
58
+ puts "Fully Qualified Workbook Path:>> #{@workbook_name}"
59
+ else
60
+ #otherwise, figure out where MyDocuments is
61
+ @workbook_name = ENV['USERPROFILE'] + "\\" + "My Documents" + "\\" + @workbook_name
62
+ end
63
+ #create the Excel application
64
+
65
+ begin
66
+ @@excel = WIN32OLE::connect('Excel.Application') if !@@excel
67
+ rescue
68
+ @@excel = WIN32OLE::new('Excel.Application')
69
+ end
70
+
71
+ #we now have a connection to a workbook.
72
+ #first, check to see if the desired workbook is open, if it is put that in @@workbook
73
+ if @@excel.Workbooks.Count > 0 then
74
+ #there are workbooks open, grab the one we want by name
75
+ @@workbook = nil
76
+ for wkbk in @@excel.Workbooks
77
+ if wkbk.Name == config[:wkbook] then
78
+ @@workbook = wkbk
79
+ end
80
+ end
81
+
82
+ end
83
+
84
+ #at this point if @@workbook is nil, then go ahead and open it.
85
+ if @@workbook == nil then
86
+ @@workbook = @@excel.Workbooks.Open(@workbook_name)
87
+ end
88
+ @@excel.Visible = 1
89
+ #get all the sheet names
90
+ @@sheets ||= {}
91
+ i = 1
92
+ for worksheet in @@workbook.Worksheets
93
+ @@sheets[i] = worksheet.Name
94
+ i += 1
95
+ end
96
+ @@workbook
97
+ end
98
+
99
+ def sheet_names
100
+ @@sheets
101
+ end
102
+
103
+ def load_constants
104
+ begin
105
+ ExcelConstants::XLDown #try to access a constant,
106
+ rescue
107
+ #if an error is thrown, load them.
108
+ WIN32OLE.const_load(@@excel, ExcelConstants) #load Excel constants into the module.
109
+ end
110
+ end
111
+
112
+ def connected?
113
+ return @@excel ? true : false
114
+ end
115
+
116
+ def workbook_disconnect
117
+ #this method will save any changes to the workbook and then close it down.
118
+ @@workbook.Save if @@workbook
119
+ @@workbook.Close if @@workbook
120
+ @@workbook = nil
121
+ end
122
+
123
+ def excel_disconnect
124
+ @@excel.Quit if @@excel
125
+ @@excel = nil
126
+ end
127
+
128
+ #Define a sheet name to use, in case the naming convention doesn't work for
129
+ #particular situations
130
+ def set_sheet_name(sht)
131
+ #Add the sheetname as a class variable
132
+ class_eval{ class_variable_set(:"@@sheet_name",sht.to_s)}
133
+ end
134
+
135
+ #This method will find one or more records in the spreadsheet and
136
+ #return them as ActiveExcel objects.
137
+ def find(rec_no)
138
+
139
+ if rec_no.is_a? Integer
140
+ #if its just an integer, then look up by id
141
+ return find_by_id(rec_no)
142
+ elsif rec_no.is_a? Hash
143
+ return nil
144
+ elsif rec_no.is_a? Symbol
145
+ case rec_no
146
+ when :all then return find_all
147
+ when :first then find_first
148
+ when :last then find_last
149
+ end
150
+ end
151
+ set_sheet_name(self.class.to_s.tableize)
152
+
153
+ end
154
+
155
+ def find_by_id(i)
156
+ return nil if i < 2 #The rowid has to be 2 or greater
157
+ o = new #create a new object, this will also set the workseet
158
+ o.this_workbook = @@workbook.clone
159
+ @wksheet = get_the_worksheet
160
+
161
+ #iterate over the list of field names
162
+ @columns.each_pair do |k,v|
163
+ #Access the Cell by passing in the Letter cooresponding to the field name and the
164
+ #Row index (1 based)
165
+ value = @wksheet.Range("#{v}#{i}").Value
166
+ o.send(:"#{k.to_s}=",value)
167
+
168
+ end
169
+ o.dirty = false
170
+ o.is_new = false
171
+ o.id=i
172
+ o #return the new object
173
+ end
174
+
175
+ def find_all
176
+ #basically, grab all the records except the header, roll them into ActiveExcel objects
177
+ obj_array = Array.new #make a new array to hold the objects
178
+ #figure out the current region size
179
+ current_region = get_the_current_region
180
+ 2.upto(current_region.Rows.Count) do |i|
181
+ o = new
182
+ o.this_workbook = @@workbook.clone
183
+ 1.upto(current_region.Columns.Count) do |j|
184
+ field = get_the_field_name_for_index(j-1) #the letters array is 0 based, but excel is 1 based.
185
+ o.send(:"#{field}=",@wksheet.Cells(i,j).Value.to_s)
186
+ o.is_new = false
187
+ o.dirty = false
188
+ o.id = i
189
+ end
190
+ obj_array << o
191
+ end
192
+ obj_array
193
+ end
194
+
195
+ #Returns a list of column names. If the columns hash hasn't been created, it will create the
196
+ #columns hash by scanning the first row of the CurrentRegion (Which is defined as a region on the
197
+ #active worksheet bounded by blank cells).
198
+ def column_names(sheet = nil)
199
+ if !@columns
200
+ if sheet
201
+ #if a sheet name was passed in we can just use that to get the column names
202
+ @wksheet = @@workbook.Worksheets(sheet)
203
+ else
204
+ #Test to see if a sheet_name class variable has been set
205
+ #if it has, then use that value other wise use the class name
206
+ classvar = self.class_eval{class_variable_get(:"@@sheet_name")}
207
+ classname = classvar ? classvar : self.class.to_s.tableize
208
+ puts "Tableized: #{classname}"
209
+ @wksheet = @@workbook.Worksheets(classname)
210
+ end
211
+ #now, grab the collumn names and put them into a hash name=>col_letter
212
+ row = @wksheet.Cells.CurrentRegion.Rows(1)
213
+ @columns = {}
214
+ @letters = []
215
+ col_name = "A"
216
+ row.Cells.each do |c|
217
+ #c represents a Cell in the worksheet
218
+ @columns[c.Value.to_sym] = col_name.clone
219
+ @letters << col_name.clone
220
+ col_name.succ! #advance the col_name one letter
221
+ end
222
+ end
223
+ #return a list of the keys
224
+ keys = []
225
+ @columns.each_key {|k| keys << k}
226
+ keys
227
+ end
228
+
229
+ def columns
230
+ return @columns
231
+ end
232
+
233
+ def wksheet
234
+ return @wksheet
235
+ end
236
+
237
+ #This implementation of method_missing will provide methods that will allow records
238
+ #to be looked up using find_by_<field_name>(value). For simplicity sake, this first
239
+ #iteration will only allow the search of individual fields.
240
+ def method_missing(methodid,*args,&blk)
241
+ #make sure the columns hash has been built
242
+ puts("METHOD ID --> #{methodid.to_s}")
243
+ column_names if !@columns
244
+
245
+ #if the words 'find_ and 'by' are not part of method id, then get out.
246
+ return if methodid.to_s !~ /find_.*by/
247
+
248
+ field = methodid.to_s.split("by_").last
249
+ letter = @columns[field.to_sym] #grab the column letter
250
+ col_index = @letters.index(letter) + 1 #get the column index, add 1 because Excel is one based.
251
+
252
+ if methodid.to_s.index("find_all_by")
253
+ return find_all_by_attribute(field,col_index,args[0])
254
+ else
255
+ return find_by_attribute(field,col_index,args[0])
256
+ end
257
+ end
258
+
259
+ #this method is caled from within method missing to return all objects
260
+ #that can be found which contain a particular value for a particular field
261
+ def find_all_by_attribute(field,col_index,args)
262
+ lookup_records(field,col_index,args,false)
263
+ end
264
+
265
+ #This method is called by method_missing to return the first object in the sheet which
266
+ #contains a particular value for a particular field.
267
+ def find_by_attribute(field,col_index,args)
268
+ lookup_records(field,col_index,args)
269
+ end
270
+
271
+ def lookup_records(field,col_index,args,first=true)
272
+ i = 1 #keep track of the row number with this variable
273
+ @wksheet = get_the_worksheet
274
+ current_region = get_the_current_region
275
+ records = Array.new
276
+ current_region.each do |range|
277
+ if @wksheet.Cells(i,col_index).Value == args then
278
+ #the value of the cell in the range matches the value passed into the
279
+ #missing method. Create a new object and return it
280
+ o = new
281
+ o.this_workbook = @@workbook.clone
282
+ 1.upto(current_region.Columns.Count) do |j|
283
+ #get the column letter
284
+ l = @letters[j-1]
285
+ #from the hash, go backward from the column letter to the field name
286
+ field = @columns.index(l)
287
+ o.send(:"#{field.to_s}=",@wksheet.Cells(i,j).Value.to_s)
288
+ end
289
+ o.id = i
290
+ o.dirty = false
291
+ o.is_new = false
292
+ return o if first
293
+ records << o
294
+ break if i == current_region.Rows.Count
295
+ end
296
+ i+=1
297
+ end
298
+ records
299
+ end
300
+
301
+ #Get the CurrentRegion of the spreadsheet as a standard range
302
+ def get_the_current_region
303
+ @wksheet = get_the_worksheet
304
+ curr_reg_addr = @wksheet.Cells.CurrentRegion.address.to_s.gsub(/\$/,'') #remove $ from address
305
+ current_region = @wksheet.Range(curr_reg_addr)
306
+ end
307
+
308
+ #returns the field name for a given column letter
309
+ def get_the_field_name_for_index(index)
310
+ l = @letters[index]
311
+ @columns.index(l)
312
+ end
313
+
314
+ def get_the_worksheet
315
+ puts("-----------------------------")
316
+ puts("\tself.name.tableize: #{self.name.tableize}")
317
+ puts("\tsheet_name: #{@@sheet_name}")
318
+ @@sheet_name = self.name.tableize if !@@sheet_name
319
+ puts("\tThe SheetName being used is: #{@@sheet_name}\n")
320
+ puts("-----------------------------")
321
+ @@workbook.Worksheets(@@sheet_name)
322
+
323
+ end
324
+
325
+ end ###End class methods####
326
+
327
+ #allows the workbook that an individual object comes from to be stored in the object.
328
+ #def this_workbook=(wkbk)
329
+ # @this_workbook = wkbk
330
+ #end
331
+ #
332
+ #def this_workbook
333
+ # @this_workbook
334
+ #end
335
+
336
+ #Define the attributes of the instance based on what is in the
337
+ #spreadheet
338
+ def add_attributes
339
+ #we should be able to use the column_names here
340
+ if !@@sheet_name then
341
+ @fields = self.class.column_names(self.class.to_s.tableize)
342
+ else
343
+ @fields = self.class.column_names()
344
+ end
345
+ #add a getter/setter pair for each column name
346
+ @fields.each do |c|
347
+ #add the setter method
348
+ self.class_eval do
349
+ define_method(:"#{c.to_s}=") do |v|
350
+ instance_variable_set(:"@#{c.to_s}",v)
351
+ instance_variable_set(:"@dirty",true)
352
+ end
353
+ end
354
+
355
+ #add the getter method
356
+ self.class_eval do
357
+ define_method(c) do
358
+ instance_variable_get(:"@#{c.to_s}")
359
+ end
360
+ end
361
+ end
362
+
363
+ end
364
+
365
+ #This method will save the object back into the spreadsheet. THIS DOES NOT SAVE
366
+ #CHANGES TO THE ACTUAL SPREADSHEET THAT IS IN MEMORY.
367
+ #
368
+ def save
369
+ update_or_create
370
+ end
371
+
372
+ #Returns whether or not this is a dirty object or not
373
+ def dirty?
374
+ dirty
375
+ end
376
+
377
+ def color_cell(name,const)
378
+ #first, get the cell name
379
+ letter = self.class.columns[name.to_sym]
380
+ #get the sheet name, if we don't already have it
381
+ @wksheet = @@workbook.worksheets(self.class.to_s.tableize) if !@wksheet
382
+ #color the cell
383
+ @wksheet.Range("#{letter}#{self.id}").Interior.ColorIndex = const
384
+ end
385
+
386
+ def get_cell_color(name)
387
+ #get the cell name
388
+ letter = self.class.columns[name.to_sym]
389
+ @wksheet = @@workbook.worksheets(self.class.to_s.tableize) if !@wksheet
390
+ #get the cell color
391
+ @wksheet.Range("#{letter}#{self.id}").Interior.ColorIndex
392
+ end
393
+
394
+ private
395
+ #This method will determine whether to update an existing record
396
+ #or create a brand new one
397
+ def update_or_create
398
+ res = (is_new == true) ? create : update
399
+ res != false
400
+ end
401
+
402
+ #This method will create a brand new row in the sheet
403
+ def create
404
+ #determine the last row in the table
405
+ row = self.class.wksheet.Cells.CurrentRegion.Rows.Count
406
+ row += 1 #add 1 to the row to point to the next empty row
407
+ self.class.columns.each_pair do |k,v|
408
+ #k: will be the field name
409
+ #v: will be the column letter
410
+ self.class.wksheet.Range("#{v}#{row}").Value = self.send(k)
411
+
412
+ end
413
+ self.dirty = false
414
+ self.is_new = false
415
+ self.id = row
416
+ end
417
+
418
+ #this method will save the existing record
419
+ def update
420
+ self.class.columns.each_pair do |k,v|
421
+ #k: will be the field name
422
+ #v: will be the column letter
423
+ self.class.wksheet.Range("#{v}#{self.id}").Value = self.send(k)
424
+ end
425
+ self.dirty = false
426
+ end
427
+
428
+
429
+
430
+ end #End of Root class
431
+
432
+ end #End of Module
@@ -0,0 +1,180 @@
1
+ require "test/unit"
2
+ require File.dirname(__FILE__)+ "/../lib/active_excel"
3
+
4
+ #this is a subclass of ActiveExcel::Root, it will be used
5
+ #to help verify inherited behaviors and connections
6
+ class OtherRecord < ActiveExcel::Root
7
+
8
+ end
9
+
10
+ class NoSheet < ActiveExcel::Root
11
+ set_sheet_name :other_records
12
+ end
13
+
14
+ class X12CarbonCopyTest < ActiveExcel::Root
15
+
16
+ end
17
+
18
+ class TestActiveExcel < Test::Unit::TestCase
19
+
20
+ def setup
21
+ @wkbk = ActiveExcel::Root.workbook_connect({:wkbook=>"gxstestsubs_billing.xls"})
22
+ #ActiveExcel::Root.load_constants if !@const_loaded
23
+ #@const_loaded = true
24
+ end
25
+
26
+ def teardown
27
+ puts "Closing down excel....."
28
+ ActiveExcel::Root.workbook_disconnect
29
+ ActiveExcel::Root.excel_disconnect
30
+ @wkbk = nil
31
+ GC.start
32
+ sleep(2)
33
+ end
34
+
35
+ def test_connect_to_workbook
36
+ #this test verifies that a workbook can be connected to by passing in a hash
37
+ #config = {:wkbook=>"gxstestsubs_billing.xls"}
38
+ #ActiveExcel::Root.workbook_connect(config)
39
+ assert_not_nil @wkbk
40
+ assert_equal 3,@wkbk.Worksheets.Count
41
+
42
+
43
+ end
44
+
45
+ #def test_connect_to_two_different_workbooks
46
+ # #this test verifies that ActiveExcel won't crash if two Excel workbooks are open.
47
+ # #the first one will be opened by the set up method, and the second will be a connection
48
+ # #to SmallCCTests_FEReq_FEPart_FERecip.xls
49
+ #
50
+ # #first, grab an OtherRecord object, this will store the first workbook in the object:
51
+ # orec = OtherRecord.find(3)
52
+ # #now, open up the second one.
53
+ # ActiveExcel::Root.workbook_connect({:wkbook=>"SmallCCTests_FEReq_FEPart_FERecip.xls"})
54
+ # ActiveExcel::Root.set_sheet_name :x12_carbon_copy_tests
55
+ # x12 = X12CarbonCopyTest.find(2)
56
+ # assert_not_equal(orec.this_workbook, x12.this_workbook )
57
+ # ActiveExcel::Root.set_sheet_name = nil
58
+ #end
59
+
60
+ def test_column_names
61
+ #ae = ActiveExcel::Root.new
62
+ h = ActiveExcel::Root.column_names("other_records")
63
+ 0.upto(3) do |i|
64
+ assert_equal true,h.include?(:"Field#{i+1}")
65
+ end
66
+ assert_equal "A",ActiveExcel::Root.columns[:Field1]
67
+ assert_equal "B",ActiveExcel::Root.columns[:Field2]
68
+ assert_equal "C",ActiveExcel::Root.columns[:Field3]
69
+ assert_equal "D",ActiveExcel::Root.columns[:Field4]
70
+ end
71
+
72
+ def test_using_a_subclass
73
+ oe = OtherRecord.new
74
+ h = oe.class.column_names
75
+ 0.upto(3) do |i|
76
+ assert_equal true,h.include?(:"Field#{i+1}")
77
+ end
78
+ end
79
+
80
+ def test_specifying_a_sheet_name
81
+
82
+ ns = NoSheet.new
83
+ #assert_equal "other_records",NoSheet.sheet_name
84
+ h = ns.class.column_names
85
+ 0.upto(3) do |i|
86
+ assert_equal true,h.include?(:"Field#{i+1}")
87
+ end
88
+ end
89
+
90
+ def test_verify_that_attr_added_dynamically
91
+ orec = OtherRecord.new
92
+ orec.Field1 = "A new value"
93
+ orec.Field4 = "BLAH BLAH"
94
+ assert_equal "A new value",orec.Field1
95
+ assert_equal -1,orec.id
96
+ assert_equal nil,orec.Field2
97
+ assert_equal nil,orec.Field3
98
+ assert_equal "BLAH BLAH",orec.Field4
99
+ end
100
+
101
+ def test_find_a_record_with_a_specific_id
102
+
103
+ #simply passing in an integer will cause it to find by id
104
+ orec = OtherRecord.find(3)
105
+ assert_equal "Value2",orec.Field1
106
+ assert_equal "Value10",orec.Field2
107
+ assert_equal "Value18",orec.Field3
108
+ assert_equal "Value26",orec.Field4
109
+ end
110
+
111
+ def test_find_by_attr_name
112
+ orec = OtherRecord.find_by_Field2("Value11")
113
+ assert_equal 4,orec.id
114
+ assert_equal "Value3",orec.Field1
115
+ assert_equal "Value11",orec.Field2
116
+ assert_equal "Value19",orec.Field3
117
+ assert_equal "Value27",orec.Field4
118
+ end
119
+
120
+ def test_find_all_by_attr_name
121
+ orecs = OtherRecord.find_all_by_Field1("Value8")
122
+ assert_equal 2,orecs.size
123
+ orec1 = orecs[0]
124
+ orec2 = orecs[1]
125
+ assert_equal "Value8",orec1.Field1
126
+ assert_equal "Value16",orec1.Field2
127
+ assert_equal "Value8", orec2.Field1
128
+ assert_equal "Value160",orec2.Field2
129
+ end
130
+
131
+ def test_find_by_attr_name_with_underscore
132
+ orec = OtherRecord.find_by_Field_Five("Value35")
133
+ assert_equal "Value3",orec.Field1
134
+ assert_equal "Value11",orec.Field2
135
+ assert_equal "Value19",orec.Field3
136
+ assert_equal "Value27",orec.Field4
137
+ assert_equal "Value35",orec.Field_Five
138
+ end
139
+
140
+ def test_save_an_edited_record
141
+ orec = OtherRecord.find_by_Field3("Value23")
142
+ orec.Field1="UPDATED"
143
+ orec.Field2="RECORD"
144
+ orec.save
145
+
146
+ teardown()
147
+ #sleep(5) #go to sleep for 5 seconds so I can watch the taskmanager
148
+
149
+ #open it back up now
150
+ ActiveExcel::Root.workbook_connect({:wkbook=>"gxstestsubs_billing.xls"})
151
+
152
+ uprec = OtherRecord.find_by_Field3("Value23")
153
+ assert_equal "UPDATED",uprec.Field1
154
+ assert_equal "RECORD",uprec.Field2
155
+
156
+ #change them again and ensure that the object has been marked dirty.
157
+ uprec.Field1 = "Value7"
158
+ uprec.Field2 = "Value15"
159
+
160
+ assert_equal true,uprec.dirty?
161
+ uprec.save
162
+ end
163
+
164
+ def test_find_all_records_in_sheet
165
+ recs = OtherRecord.find(:all)
166
+ assert_equal 9,recs.size
167
+ 0.upto(7) do |i|
168
+ assert_equal "OtherRecord",recs[i].class.to_s
169
+ assert_equal "Value#{i+1}",recs[i].send(:"Field1")
170
+ end
171
+ end
172
+
173
+ def test_colorize_cell
174
+ #this verifies that we can color a cell using an excel constant
175
+ oe = OtherRecord.find(4)
176
+ oe.color_cell("Field1",ExcelConstants::XLGREEN)
177
+ oe.color_cell("Field3",ExcelConstants::XLRED)
178
+ oe.save
179
+ end
180
+ end
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ActiveExcel
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Rob Whitener
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-02 00:00:00 -04:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: hoe
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 2.0.0
24
+ version:
25
+ description: Excel as the container of model objects
26
+ email: robwhitener@gmail.com
27
+ executables:
28
+ - active_excel
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - History.txt
33
+ - Manifest.txt
34
+ - README.txt
35
+ files:
36
+ - History.txt
37
+ - Manifest.txt
38
+ - README.txt
39
+ - Rakefile
40
+ - bin/active_excel
41
+ - lib/active_excel.rb
42
+ - test/test_active_excel.rb
43
+ has_rdoc: true
44
+ homepage: http://robsexocortex.blogspot.com/2009/06/activeexcel.html
45
+ licenses: []
46
+
47
+ post_install_message:
48
+ rdoc_options:
49
+ - --main
50
+ - README.txt
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ version:
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "0"
64
+ version:
65
+ requirements: []
66
+
67
+ rubyforge_project: active_excel
68
+ rubygems_version: 1.3.5
69
+ signing_key:
70
+ specification_version: 3
71
+ summary: Use Excel to contain model objects. Each row in a sheet represents an object, each sheet in a workbook represents a class. Make sure that you rename your sheets - this gem uses ActiveSupport to take advantage of the pluralization familiar to Rails developers. Modeled liberally on ActiveRecord, not quite as cool but hopefully useful enough. Cheers.
72
+ test_files:
73
+ - test/test_active_excel.rb