datashift 0.1.0 → 0.2.1

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.
Files changed (86) hide show
  1. data/.document +5 -5
  2. data/LICENSE.txt +26 -26
  3. data/README.markdown +305 -303
  4. data/README.rdoc +19 -19
  5. data/Rakefile +93 -93
  6. data/VERSION +1 -1
  7. data/datashift-0.1.0.gem +0 -0
  8. data/datashift.gemspec +152 -136
  9. data/lib/applications/jruby/jexcel_file.rb +408 -408
  10. data/lib/applications/jruby/word.rb +79 -79
  11. data/lib/datashift.rb +152 -152
  12. data/lib/datashift/exceptions.rb +11 -11
  13. data/lib/datashift/file_definitions.rb +353 -353
  14. data/lib/datashift/mapping_file_definitions.rb +87 -87
  15. data/lib/datashift/method_detail.rb +275 -275
  16. data/lib/datashift/method_dictionary.rb +209 -209
  17. data/lib/datashift/method_mapper.rb +90 -90
  18. data/lib/generators/csv_generator.rb +36 -36
  19. data/lib/generators/excel_generator.rb +122 -122
  20. data/lib/generators/generator_base.rb +13 -13
  21. data/lib/helpers/core_ext/to_b.rb +24 -24
  22. data/lib/helpers/spree_helper.rb +153 -155
  23. data/lib/java/poi-3.7/LICENSE +507 -507
  24. data/lib/java/poi-3.7/NOTICE +21 -21
  25. data/lib/java/poi-3.7/RELEASE_NOTES.txt +115 -115
  26. data/lib/loaders/csv_loader.rb +98 -98
  27. data/lib/loaders/excel_loader.rb +155 -155
  28. data/lib/loaders/loader_base.rb +420 -420
  29. data/lib/loaders/spreadsheet_loader.rb +136 -136
  30. data/lib/loaders/spree/image_loader.rb +63 -64
  31. data/lib/loaders/spree/product_loader.rb +248 -250
  32. data/public/spree/products/large/DEMO_001_ror_bag.jpeg +0 -0
  33. data/public/spree/products/large/DEMO_002_Powerstation.jpg +0 -0
  34. data/public/spree/products/large/DEMO_003_ror_mug.jpeg +0 -0
  35. data/public/spree/products/mini/DEMO_001_ror_bag.jpeg +0 -0
  36. data/public/spree/products/mini/DEMO_002_Powerstation.jpg +0 -0
  37. data/public/spree/products/mini/DEMO_003_ror_mug.jpeg +0 -0
  38. data/public/spree/products/original/DEMO_001_ror_bag.jpeg +0 -0
  39. data/public/spree/products/original/DEMO_002_Powerstation.jpg +0 -0
  40. data/public/spree/products/original/DEMO_003_ror_mug.jpeg +0 -0
  41. data/public/spree/products/product/DEMO_001_ror_bag.jpeg +0 -0
  42. data/public/spree/products/product/DEMO_002_Powerstation.jpg +0 -0
  43. data/public/spree/products/product/DEMO_003_ror_mug.jpeg +0 -0
  44. data/public/spree/products/small/DEMO_001_ror_bag.jpeg +0 -0
  45. data/public/spree/products/small/DEMO_002_Powerstation.jpg +0 -0
  46. data/public/spree/products/small/DEMO_003_ror_mug.jpeg +0 -0
  47. data/spec/csv_loader_spec.rb +30 -30
  48. data/spec/datashift_spec.rb +26 -26
  49. data/spec/db/migrate/20110803201325_create_test_bed.rb +85 -85
  50. data/spec/excel_exporter_spec.rb +78 -78
  51. data/spec/excel_generator_spec.rb +78 -78
  52. data/spec/excel_loader_spec.rb +223 -223
  53. data/spec/file_definitions.rb +141 -141
  54. data/spec/fixtures/ProjectsDefaults.yml +29 -29
  55. data/spec/fixtures/config/database.yml +27 -24
  56. data/spec/fixtures/datashift_Spree_db.sqlite +0 -0
  57. data/spec/fixtures/interact_models_db.sqlite +0 -0
  58. data/spec/fixtures/negative/SpreeProdMiss1Mandatory.csv +4 -4
  59. data/spec/fixtures/negative/SpreeProdMissManyMandatory.csv +4 -4
  60. data/spec/fixtures/spree/SpreeProducts.csv +4 -4
  61. data/spec/fixtures/spree/SpreeProductsMultiColumn.csv +4 -4
  62. data/spec/fixtures/spree/SpreeProductsSimple.csv +4 -4
  63. data/spec/fixtures/spree/SpreeProductsWithImages.csv +4 -0
  64. data/spec/fixtures/spree/SpreeZoneExample.csv +5 -5
  65. data/spec/fixtures/test_model_defs.rb +57 -57
  66. data/spec/loader_spec.rb +120 -120
  67. data/spec/method_dictionary_spec.rb +242 -242
  68. data/spec/method_mapper_spec.rb +41 -41
  69. data/spec/spec_helper.rb +116 -116
  70. data/spec/spree_generator_spec.rb +64 -64
  71. data/spec/spree_loader_spec.rb +324 -327
  72. data/spec/spree_method_mapping_spec.rb +214 -214
  73. data/tasks/config/seed_fu_product_template.erb +15 -15
  74. data/tasks/config/tidy_config.txt +12 -12
  75. data/tasks/db_tasks.rake +65 -65
  76. data/tasks/excel_generator.rake +78 -78
  77. data/tasks/file_tasks.rake +36 -36
  78. data/tasks/import/csv.rake +49 -49
  79. data/tasks/import/excel.rake +71 -71
  80. data/tasks/spree/image_load.rake +108 -108
  81. data/tasks/spree/product_loader.rake +43 -43
  82. data/tasks/word_to_seedfu.rake +166 -166
  83. data/test/helper.rb +18 -18
  84. data/test/test_interact.rb +7 -7
  85. metadata +22 -3
  86. data/spec/fixtures/interact_spree_db.sqlite +0 -0
@@ -1,409 +1,409 @@
1
- # Copyright:: (c) Autotelik Media Ltd 2011
2
- # Author :: Tom Statter
3
- # Date :: Aug 2010
4
- # License:: MIT
5
- #
6
- # An Excel file helper. Create and populate XSL files
7
- #
8
- # The maximum number of columns and rows in an Excel file is fixed at 256 Columns and 65536 Rows
9
- #
10
- # POI jar location needs to be added to class path.
11
- #
12
- # TODO - Check out http://poi.apache.org/poi-ruby.html
13
- #
14
- if(DataShift::Guards::jruby?)
15
-
16
- require "poi-3.7-20101029.jar"
17
-
18
- class JExcelFile
19
-
20
- java_import org.apache.poi.poifs.filesystem.POIFSFileSystem
21
-
22
- include_class 'org.apache.poi.hssf.usermodel.HSSFCell'
23
- include_class 'org.apache.poi.hssf.usermodel.HSSFWorkbook'
24
- include_class 'org.apache.poi.hssf.usermodel.HSSFCellStyle'
25
- include_class 'org.apache.poi.hssf.usermodel.HSSFDataFormat'
26
- include_class 'org.apache.poi.hssf.usermodel.HSSFClientAnchor'
27
- include_class 'org.apache.poi.hssf.usermodel.HSSFRichTextString'
28
-
29
- include_class 'java.io.ByteArrayOutputStream'
30
- include_class 'java.util.Date'
31
- include_class 'java.io.FileInputStream'
32
- include_class 'java.io.FileOutputStream'
33
-
34
- attr_accessor :book, :row, :date_style
35
- attr_reader :sheet
36
-
37
- MAX_COLUMNS = 256.freeze
38
-
39
- def self.date_format
40
- HSSFDataFormat.getBuiltinFormat("m/d/yy h:mm")
41
- end
42
-
43
- # NOTE: this is the POI 3.7 HSSF maximum rows
44
- def self.maxrows
45
- return 65535
46
- end
47
-
48
- # The HSSFWorkbook uses 0 based indexes, whilst our companion jexcel_win32 class
49
- # uses 1 based indexes. So they can be used interchangeably we bring indexes
50
- # inline with JExcel usage in this class, as 1 based maps more intuitively for the user
51
- #
52
- # i.e Row 1 passed to this class, internally means Row 0
53
-
54
- def initialize()
55
- @book = nil
56
- # The @patriarchs hash is a workaround because HSSFSheet.getDrawingPatriarch()
57
- # causes a lot of issues (if it doesn't throw an exception!)
58
- @patriarchs = Hash.new
59
-
60
- @date_style = nil
61
- end
62
-
63
- def open(filename)
64
- inp = FileInputStream.new(filename)
65
-
66
- @book = HSSFWorkbook.new(inp)
67
-
68
- @date_style = @book.createCellStyle
69
- @date_style.setDataFormat( JExcelFile::date_format )
70
-
71
- @current_sheet = 0
72
- sheet(@current_sheet)
73
- end
74
-
75
- # EXCEL ITEMS
76
-
77
- def create(sheet_name)
78
- @book = HSSFWorkbook.new() if @book.nil?
79
-
80
- # Double check sheet doesn't already exist
81
- if(@book.getSheetIndex(sheet_name) < 0)
82
- sheet = @book.createSheet(sheet_name.gsub(" ", ''))
83
-
84
- @patriarchs.store(sheet_name, sheet.createDrawingPatriarch())
85
- end
86
- @current_sheet = @book.getSheetIndex(sheet_name)
87
-
88
- @date_style = @book.createCellStyle
89
- @date_style.setDataFormat( JExcelFile::date_format )
90
-
91
- self.sheet()
92
- end
93
-
94
- alias_method(:create_sheet, :create)
95
-
96
- # Return the current or specified HSSFSheet
97
- def sheet(i = nil)
98
- @current_sheet = i if i
99
- @sheet = @book.getSheetAt(@current_sheet)
100
- end
101
-
102
- def activate_sheet(sheet)
103
- active_sheet = @current_sheet
104
- if(@book)
105
- i = sheet if sheet.kind_of?(Integer)
106
- i = @book.getSheetIndex(sheet) if sheet.kind_of?(String)
107
-
108
- if( i >= 0 )
109
- @book.setActiveSheet(i) unless @book.nil?
110
- active_sheet = @book.getSheetAt(i)
111
- active_sheet.setActive(true)
112
- end unless i.nil?
113
- end
114
- return active_sheet
115
- end
116
-
117
- def num_rows
118
- @sheet.getPhysicalNumberOfRows
119
- end
120
-
121
- # Process each row. (type is org.apache.poi.hssf.usermodel.HSSFRow)
122
-
123
- def each_row
124
- @sheet.rowIterator.each { |row| yield row }
125
- end
126
-
127
- # Create new row, bring index in line with POI usage (our 1 is their 0)
128
- def create_row(index)
129
- return if @sheet.nil?
130
- raise "BAD INDEX: Row indexing starts at 1" if(index == 0)
131
- @row = @sheet.createRow(index - 1)
132
- @row
133
- end
134
-
135
- #############################
136
- # INSERTING DATA INTO EXCEL #
137
- #############################
138
-
139
- # Populate a single cell with data
140
- #
141
- def set_cell(row, column, datum)
142
- @row = @sheet.getRow(row - 1) || create_row(row)
143
- @row.createCell(column - 1, excel_cell_type(datum)).setCellValue(datum)
144
- end
145
-
146
- # Convert array into a header row
147
- def set_headers(headers)
148
- create_row(1)
149
- return if headers.empty?
150
-
151
- set_row(1, 1, headers)
152
- end
153
-
154
- # Populate a row of cells with data in an array
155
- # where the co-ordinates relate to row/column start position
156
- #
157
- def set_row( row, col, data, sheet_num = nil)
158
-
159
- sheet(sheet_num)
160
-
161
- create_row(row)
162
-
163
- column = col
164
- data.each do |datum|
165
- set_cell(row, column, datum)
166
- column += 1
167
- end
168
- end
169
-
170
- # Return a mapping from Ruby type to type for HSSFCell
171
- def excel_cell_type(data)
172
-
173
- if(data.kind_of?(Numeric))
174
- HSSFCell::CELL_TYPE_NUMERIC
175
- elsif(data.nil?)
176
- HSSFCell::CELL_TYPE_BLANK
177
- elsif(data.is_a?(TrueClass) || data.is_a?(FalseClass))
178
- HSSFCell::CELL_TYPE_BOOLEAN
179
- else
180
- HSSFCell::CELL_TYPE_STRING
181
- end
182
- # HSSFCell::CELL_TYPE_FORMULA
183
- end
184
-
185
- # TODO - Move into an ActiveRecord helper module of it's own
186
- def ar_to_headers( records )
187
- return if( !records.first.is_a?(ActiveRecord::Base) || records.empty?)
188
-
189
- headers = records.first.class.columns.collect( &:name )
190
- set_headers( headers )
191
- end
192
-
193
- # Pass a set of AR records
194
- def ar_to_xls(records, options = {})
195
- return if( ! records.first.is_a?(ActiveRecord::Base) || records.empty?)
196
-
197
- row_index =
198
- if(options[:no_headers])
199
- 1
200
- else
201
- ar_to_headers( records )
202
- 2
203
- end
204
-
205
- records.each do |record|
206
- create_row(row_index)
207
-
208
- ar_to_xls_row(1, record)
209
-
210
- row_index += 1
211
- end
212
- end
213
-
214
- # Save data from an AR record to the current row, based on the record's columns [c1,c2,c3]
215
- # Returns the number of the final column written to
216
- def ar_to_xls_row(start_column, record)
217
- return unless( record.is_a?(ActiveRecord::Base))
218
-
219
- column = start_column
220
- record.class.columns.each do |connection_column|
221
- ar_to_xls_cell(column, record, connection_column)
222
- column += 1
223
- end
224
- column
225
- end
226
-
227
- def ar_to_xls_cell(column, record, connection_column)
228
- begin
229
- datum = record.send(connection_column.name)
230
-
231
- if(connection_column.sql_type =~ /date/)
232
- @row.createCell(column - 1, HSSFCell::CELL_TYPE_STRING).setCellValue(datum.to_s)
233
-
234
- elsif(connection_column.type == :boolean || connection_column.sql_type =~ /tinyint/)
235
- @row.createCell(column - 1, HSSFCell::CELL_TYPE_BOOLEAN).setCellValue(datum)
236
-
237
- elsif(connection_column.sql_type =~ /int/)
238
- @row.createCell(column - 1, HSSFCell::CELL_TYPE_NUMERIC).setCellValue(datum.to_i)
239
- else
240
- @row.createCell(column - 1, HSSFCell::CELL_TYPE_STRING).setCellValue( datum.to_s )
241
- end
242
-
243
- rescue => e
244
- puts "Failed to export #{datum} from #{connection_column.inspect} to column #{column}"
245
- puts e
246
- end
247
- end
248
-
249
- ##############################
250
- # RETRIEVING DATA FROM EXCEL #
251
- ##############################
252
-
253
- # Return the raw data of the requested cell by row/column
254
- def get_cell_value(row, column)
255
- raise TypeError, "Expect row argument of type HSSFRow" unless row.is_a?(Java::OrgApachePoiHssfUsermodel::HSSFRow)
256
- cell_value( row.getCell(column) )
257
- end
258
-
259
- # Return the raw data of an HSSFCell
260
- def cell_value(cell)
261
- return unless cell
262
- #puts "DEBUG CELL TYPE : #{cell} => #{cell.getCellType().inspect}"
263
- case (cell.getCellType())
264
- when HSSFCell::CELL_TYPE_FORMULA then return cell.getCellFormula()
265
- when HSSFCell::CELL_TYPE_NUMERIC then return cell.getNumericCellValue()
266
- when HSSFCell::CELL_TYPE_STRING then return cell.getStringCellValue()
267
- when HSSFCell::CELL_TYPE_BOOLEAN then return cell.getBooleanCellValue()
268
- when HSSFCell::CELL_TYPE_BLANK then return ""
269
- end
270
- end
271
-
272
- def save( filename = nil )
273
- filename.nil? ? file = @filepath : file = filename
274
- out = FileOutputStream.new(file)
275
- @book.write(out) unless @book.nil?
276
- out.close
277
- end
278
-
279
- def save_to_text( filename )
280
- File.open( filename, 'w') {|f| f.write(to_s) }
281
- end
282
-
283
-
284
- def add_comment( cell, text )
285
- raise "Please supply valid HSSFCell" unless cell.respond_to?('setCellComment')
286
- return if @sheet.nil?
287
-
288
- patriarch = @patriarchs[@sheet.getSheetName()]
289
-
290
- anchor = HSSFClientAnchor.new(100, 50, 100, 50, cell.getColumnIndex(), cell.getRowIndex(), cell.getColumnIndex()+3, cell.getRowIndex()+4)
291
- comment = patriarch.createCellComment(anchor)
292
-
293
- comment_text = HSSFRichTextString.new(text)
294
- comment.setString(comment_text)
295
- comment.setAuthor("Mapping")
296
-
297
- cell.setCellComment(comment)
298
- end
299
-
300
- # The internal representation of a Excel File
301
-
302
- # Get a percentage style
303
- def getPercentStyle()
304
- if (@percentCellStyle.nil? && @book)
305
- @percentCellStyle = @book.createCellStyle();
306
- @percentCellStyle.setDataFormat(HSSFDataFormat.getBuiltinFormat("0.00%"));
307
- end
308
- return @percentCellStyle
309
- end
310
-
311
- # Auto size either the given column index or all columns
312
- def autosize(column = nil)
313
- return if @sheet.nil?
314
- if (column.kind_of? Integer)
315
- @sheet.autoSizeColumn(column)
316
- else
317
- @sheet.getRow(0).cellIterator.each{|c| @sheet.autoSizeColumn(c.getColumnIndex)}
318
- end
319
- end
320
-
321
- def to_s
322
- return "" unless @book
323
-
324
- outs = ByteArrayOutputStream.new
325
- @book.write(outs);
326
- outs.close();
327
- String.from_java_bytes(outs.toByteArray)
328
- end
329
-
330
- def createFreezePane(row=1, column=0)
331
- return if @sheet.nil?
332
- @sheet.createFreezePane(row, column)
333
- end
334
-
335
- # Use execute to run sql query provided
336
- # and write to a csv file (path required)
337
- # header row is optional but default is on
338
- # Auto mapping of specified columns is optional
339
- # @mappings is a hash{column => map} of columns to a map{old_value => new_value}
340
- def results_to_sheet( results, sheet, mappings=nil, header=true)
341
- numrows = results.length
342
- sheet_name = sheet
343
-
344
- if (numrows == 0)
345
- log :info, "WARNING - results are empty nothing written to sheet: #{sheet}"
346
- return
347
- end
348
-
349
- #Check if we need to split the results into seperate sheets
350
- if (numrows > @@maxrows )
351
- startrow = 0
352
- while (numrows > 0)
353
- # Split the results and write to a new sheet
354
- next_results = results.slice(startrow, @@maxrows > numrows ? numrows : @@maxrows)
355
- self.results_to_sheet(next_results, "#{sheet_name}", mappings, header) if next_results
356
-
357
- # Increase counters
358
- numrows -= next_results.length
359
- startrow += next_results.length
360
- sheet_name += 'I'
361
- end
362
- else
363
- # Create required sheet
364
- self.create(sheet)
365
-
366
- row_index = self.num_rows
367
- # write header line
368
- if (header && row_index==0 )
369
- header_row = @sheet.createRow(row_index)
370
- cell_index = 0
371
- results[0].keys.each{ |h|
372
- header_row.createCell(cell_index).setCellValue("#{h}")
373
- @sheet.setDefaultColumnStyle(cell_index, self.getPercentStyle) if "#{h}".include? '%'
374
- cell_index += 1
375
- }
376
- # Freeze the header row
377
- @sheet.createFreezePane( 0, 1, 0, 1 )
378
- row_index += 1
379
- end
380
-
381
- # write_results
382
- results.each{ |row|
383
- sheet_row = @sheet.createRow(row_index)
384
- cell_index = 0
385
- row.each{|k,v|
386
- celltype = v.kind_of?(Numeric) ? HSSFCell::CELL_TYPE_NUMERIC : HSSFCell::CELL_TYPE_STRING
387
- cell = sheet_row.createCell(cell_index, celltype)
388
-
389
- v.nil? ? value = "<NIL>" : value = v
390
-
391
- cell.setCellValue(value)
392
-
393
- cell_index +=1
394
- }
395
- #puts "#{sheet}: written row #{row_index}"
396
- row_index +=1
397
- }
398
- end
399
-
400
- end
401
-
402
- end # END JExcelFile
403
- else
404
- class JExcelFile
405
- def initialize
406
- raise DataShift::BadRuby, "Please install and use JRuby for working with .xls files"
407
- end
408
- end
1
+ # Copyright:: (c) Autotelik Media Ltd 2011
2
+ # Author :: Tom Statter
3
+ # Date :: Aug 2010
4
+ # License:: MIT
5
+ #
6
+ # An Excel file helper. Create and populate XSL files
7
+ #
8
+ # The maximum number of columns and rows in an Excel file is fixed at 256 Columns and 65536 Rows
9
+ #
10
+ # POI jar location needs to be added to class path.
11
+ #
12
+ # TODO - Check out http://poi.apache.org/poi-ruby.html
13
+ #
14
+ if(DataShift::Guards::jruby?)
15
+
16
+ require "poi-3.7-20101029.jar"
17
+
18
+ class JExcelFile
19
+
20
+ java_import org.apache.poi.poifs.filesystem.POIFSFileSystem
21
+
22
+ include_class 'org.apache.poi.hssf.usermodel.HSSFCell'
23
+ include_class 'org.apache.poi.hssf.usermodel.HSSFWorkbook'
24
+ include_class 'org.apache.poi.hssf.usermodel.HSSFCellStyle'
25
+ include_class 'org.apache.poi.hssf.usermodel.HSSFDataFormat'
26
+ include_class 'org.apache.poi.hssf.usermodel.HSSFClientAnchor'
27
+ include_class 'org.apache.poi.hssf.usermodel.HSSFRichTextString'
28
+
29
+ include_class 'java.io.ByteArrayOutputStream'
30
+ include_class 'java.util.Date'
31
+ include_class 'java.io.FileInputStream'
32
+ include_class 'java.io.FileOutputStream'
33
+
34
+ attr_accessor :book, :row, :date_style
35
+ attr_reader :sheet
36
+
37
+ MAX_COLUMNS = 256.freeze
38
+
39
+ def self.date_format
40
+ HSSFDataFormat.getBuiltinFormat("m/d/yy h:mm")
41
+ end
42
+
43
+ # NOTE: this is the POI 3.7 HSSF maximum rows
44
+ def self.maxrows
45
+ return 65535
46
+ end
47
+
48
+ # The HSSFWorkbook uses 0 based indexes, whilst our companion jexcel_win32 class
49
+ # uses 1 based indexes. So they can be used interchangeably we bring indexes
50
+ # inline with JExcel usage in this class, as 1 based maps more intuitively for the user
51
+ #
52
+ # i.e Row 1 passed to this class, internally means Row 0
53
+
54
+ def initialize()
55
+ @book = nil
56
+ # The @patriarchs hash is a workaround because HSSFSheet.getDrawingPatriarch()
57
+ # causes a lot of issues (if it doesn't throw an exception!)
58
+ @patriarchs = Hash.new
59
+
60
+ @date_style = nil
61
+ end
62
+
63
+ def open(filename)
64
+ inp = FileInputStream.new(filename)
65
+
66
+ @book = HSSFWorkbook.new(inp)
67
+
68
+ @date_style = @book.createCellStyle
69
+ @date_style.setDataFormat( JExcelFile::date_format )
70
+
71
+ @current_sheet = 0
72
+ sheet(@current_sheet)
73
+ end
74
+
75
+ # EXCEL ITEMS
76
+
77
+ def create(sheet_name)
78
+ @book = HSSFWorkbook.new() if @book.nil?
79
+
80
+ # Double check sheet doesn't already exist
81
+ if(@book.getSheetIndex(sheet_name) < 0)
82
+ sheet = @book.createSheet(sheet_name.gsub(" ", ''))
83
+
84
+ @patriarchs.store(sheet_name, sheet.createDrawingPatriarch())
85
+ end
86
+ @current_sheet = @book.getSheetIndex(sheet_name)
87
+
88
+ @date_style = @book.createCellStyle
89
+ @date_style.setDataFormat( JExcelFile::date_format )
90
+
91
+ self.sheet()
92
+ end
93
+
94
+ alias_method(:create_sheet, :create)
95
+
96
+ # Return the current or specified HSSFSheet
97
+ def sheet(i = nil)
98
+ @current_sheet = i if i
99
+ @sheet = @book.getSheetAt(@current_sheet)
100
+ end
101
+
102
+ def activate_sheet(sheet)
103
+ active_sheet = @current_sheet
104
+ if(@book)
105
+ i = sheet if sheet.kind_of?(Integer)
106
+ i = @book.getSheetIndex(sheet) if sheet.kind_of?(String)
107
+
108
+ if( i >= 0 )
109
+ @book.setActiveSheet(i) unless @book.nil?
110
+ active_sheet = @book.getSheetAt(i)
111
+ active_sheet.setActive(true)
112
+ end unless i.nil?
113
+ end
114
+ return active_sheet
115
+ end
116
+
117
+ def num_rows
118
+ @sheet.getPhysicalNumberOfRows
119
+ end
120
+
121
+ # Process each row. (type is org.apache.poi.hssf.usermodel.HSSFRow)
122
+
123
+ def each_row
124
+ @sheet.rowIterator.each { |row| yield row }
125
+ end
126
+
127
+ # Create new row, bring index in line with POI usage (our 1 is their 0)
128
+ def create_row(index)
129
+ return if @sheet.nil?
130
+ raise "BAD INDEX: Row indexing starts at 1" if(index == 0)
131
+ @row = @sheet.createRow(index - 1)
132
+ @row
133
+ end
134
+
135
+ #############################
136
+ # INSERTING DATA INTO EXCEL #
137
+ #############################
138
+
139
+ # Populate a single cell with data
140
+ #
141
+ def set_cell(row, column, datum)
142
+ @row = @sheet.getRow(row - 1) || create_row(row)
143
+ @row.createCell(column - 1, excel_cell_type(datum)).setCellValue(datum)
144
+ end
145
+
146
+ # Convert array into a header row
147
+ def set_headers(headers)
148
+ create_row(1)
149
+ return if headers.empty?
150
+
151
+ set_row(1, 1, headers)
152
+ end
153
+
154
+ # Populate a row of cells with data in an array
155
+ # where the co-ordinates relate to row/column start position
156
+ #
157
+ def set_row( row, col, data, sheet_num = nil)
158
+
159
+ sheet(sheet_num)
160
+
161
+ create_row(row)
162
+
163
+ column = col
164
+ data.each do |datum|
165
+ set_cell(row, column, datum)
166
+ column += 1
167
+ end
168
+ end
169
+
170
+ # Return a mapping from Ruby type to type for HSSFCell
171
+ def excel_cell_type(data)
172
+
173
+ if(data.kind_of?(Numeric))
174
+ HSSFCell::CELL_TYPE_NUMERIC
175
+ elsif(data.nil?)
176
+ HSSFCell::CELL_TYPE_BLANK
177
+ elsif(data.is_a?(TrueClass) || data.is_a?(FalseClass))
178
+ HSSFCell::CELL_TYPE_BOOLEAN
179
+ else
180
+ HSSFCell::CELL_TYPE_STRING
181
+ end
182
+ # HSSFCell::CELL_TYPE_FORMULA
183
+ end
184
+
185
+ # TODO - Move into an ActiveRecord helper module of it's own
186
+ def ar_to_headers( records )
187
+ return if( !records.first.is_a?(ActiveRecord::Base) || records.empty?)
188
+
189
+ headers = records.first.class.columns.collect( &:name )
190
+ set_headers( headers )
191
+ end
192
+
193
+ # Pass a set of AR records
194
+ def ar_to_xls(records, options = {})
195
+ return if( ! records.first.is_a?(ActiveRecord::Base) || records.empty?)
196
+
197
+ row_index =
198
+ if(options[:no_headers])
199
+ 1
200
+ else
201
+ ar_to_headers( records )
202
+ 2
203
+ end
204
+
205
+ records.each do |record|
206
+ create_row(row_index)
207
+
208
+ ar_to_xls_row(1, record)
209
+
210
+ row_index += 1
211
+ end
212
+ end
213
+
214
+ # Save data from an AR record to the current row, based on the record's columns [c1,c2,c3]
215
+ # Returns the number of the final column written to
216
+ def ar_to_xls_row(start_column, record)
217
+ return unless( record.is_a?(ActiveRecord::Base))
218
+
219
+ column = start_column
220
+ record.class.columns.each do |connection_column|
221
+ ar_to_xls_cell(column, record, connection_column)
222
+ column += 1
223
+ end
224
+ column
225
+ end
226
+
227
+ def ar_to_xls_cell(column, record, connection_column)
228
+ begin
229
+ datum = record.send(connection_column.name)
230
+
231
+ if(connection_column.sql_type =~ /date/)
232
+ @row.createCell(column - 1, HSSFCell::CELL_TYPE_STRING).setCellValue(datum.to_s)
233
+
234
+ elsif(connection_column.type == :boolean || connection_column.sql_type =~ /tinyint/)
235
+ @row.createCell(column - 1, HSSFCell::CELL_TYPE_BOOLEAN).setCellValue(datum)
236
+
237
+ elsif(connection_column.sql_type =~ /int/)
238
+ @row.createCell(column - 1, HSSFCell::CELL_TYPE_NUMERIC).setCellValue(datum.to_i)
239
+ else
240
+ @row.createCell(column - 1, HSSFCell::CELL_TYPE_STRING).setCellValue( datum.to_s )
241
+ end
242
+
243
+ rescue => e
244
+ puts "Failed to export #{datum} from #{connection_column.inspect} to column #{column}"
245
+ puts e
246
+ end
247
+ end
248
+
249
+ ##############################
250
+ # RETRIEVING DATA FROM EXCEL #
251
+ ##############################
252
+
253
+ # Return the raw data of the requested cell by row/column
254
+ def get_cell_value(row, column)
255
+ raise TypeError, "Expect row argument of type HSSFRow" unless row.is_a?(Java::OrgApachePoiHssfUsermodel::HSSFRow)
256
+ cell_value( row.getCell(column) )
257
+ end
258
+
259
+ # Return the raw data of an HSSFCell
260
+ def cell_value(cell)
261
+ return unless cell
262
+ #puts "DEBUG CELL TYPE : #{cell} => #{cell.getCellType().inspect}"
263
+ case (cell.getCellType())
264
+ when HSSFCell::CELL_TYPE_FORMULA then return cell.getCellFormula()
265
+ when HSSFCell::CELL_TYPE_NUMERIC then return cell.getNumericCellValue()
266
+ when HSSFCell::CELL_TYPE_STRING then return cell.getStringCellValue()
267
+ when HSSFCell::CELL_TYPE_BOOLEAN then return cell.getBooleanCellValue()
268
+ when HSSFCell::CELL_TYPE_BLANK then return ""
269
+ end
270
+ end
271
+
272
+ def save( filename = nil )
273
+ filename.nil? ? file = @filepath : file = filename
274
+ out = FileOutputStream.new(file)
275
+ @book.write(out) unless @book.nil?
276
+ out.close
277
+ end
278
+
279
+ def save_to_text( filename )
280
+ File.open( filename, 'w') {|f| f.write(to_s) }
281
+ end
282
+
283
+
284
+ def add_comment( cell, text )
285
+ raise "Please supply valid HSSFCell" unless cell.respond_to?('setCellComment')
286
+ return if @sheet.nil?
287
+
288
+ patriarch = @patriarchs[@sheet.getSheetName()]
289
+
290
+ anchor = HSSFClientAnchor.new(100, 50, 100, 50, cell.getColumnIndex(), cell.getRowIndex(), cell.getColumnIndex()+3, cell.getRowIndex()+4)
291
+ comment = patriarch.createCellComment(anchor)
292
+
293
+ comment_text = HSSFRichTextString.new(text)
294
+ comment.setString(comment_text)
295
+ comment.setAuthor("Mapping")
296
+
297
+ cell.setCellComment(comment)
298
+ end
299
+
300
+ # The internal representation of a Excel File
301
+
302
+ # Get a percentage style
303
+ def getPercentStyle()
304
+ if (@percentCellStyle.nil? && @book)
305
+ @percentCellStyle = @book.createCellStyle();
306
+ @percentCellStyle.setDataFormat(HSSFDataFormat.getBuiltinFormat("0.00%"));
307
+ end
308
+ return @percentCellStyle
309
+ end
310
+
311
+ # Auto size either the given column index or all columns
312
+ def autosize(column = nil)
313
+ return if @sheet.nil?
314
+ if (column.kind_of? Integer)
315
+ @sheet.autoSizeColumn(column)
316
+ else
317
+ @sheet.getRow(0).cellIterator.each{|c| @sheet.autoSizeColumn(c.getColumnIndex)}
318
+ end
319
+ end
320
+
321
+ def to_s
322
+ return "" unless @book
323
+
324
+ outs = ByteArrayOutputStream.new
325
+ @book.write(outs);
326
+ outs.close();
327
+ String.from_java_bytes(outs.toByteArray)
328
+ end
329
+
330
+ def createFreezePane(row=1, column=0)
331
+ return if @sheet.nil?
332
+ @sheet.createFreezePane(row, column)
333
+ end
334
+
335
+ # Use execute to run sql query provided
336
+ # and write to a csv file (path required)
337
+ # header row is optional but default is on
338
+ # Auto mapping of specified columns is optional
339
+ # @mappings is a hash{column => map} of columns to a map{old_value => new_value}
340
+ def results_to_sheet( results, sheet, mappings=nil, header=true)
341
+ numrows = results.length
342
+ sheet_name = sheet
343
+
344
+ if (numrows == 0)
345
+ log :info, "WARNING - results are empty nothing written to sheet: #{sheet}"
346
+ return
347
+ end
348
+
349
+ #Check if we need to split the results into seperate sheets
350
+ if (numrows > @@maxrows )
351
+ startrow = 0
352
+ while (numrows > 0)
353
+ # Split the results and write to a new sheet
354
+ next_results = results.slice(startrow, @@maxrows > numrows ? numrows : @@maxrows)
355
+ self.results_to_sheet(next_results, "#{sheet_name}", mappings, header) if next_results
356
+
357
+ # Increase counters
358
+ numrows -= next_results.length
359
+ startrow += next_results.length
360
+ sheet_name += 'I'
361
+ end
362
+ else
363
+ # Create required sheet
364
+ self.create(sheet)
365
+
366
+ row_index = self.num_rows
367
+ # write header line
368
+ if (header && row_index==0 )
369
+ header_row = @sheet.createRow(row_index)
370
+ cell_index = 0
371
+ results[0].keys.each{ |h|
372
+ header_row.createCell(cell_index).setCellValue("#{h}")
373
+ @sheet.setDefaultColumnStyle(cell_index, self.getPercentStyle) if "#{h}".include? '%'
374
+ cell_index += 1
375
+ }
376
+ # Freeze the header row
377
+ @sheet.createFreezePane( 0, 1, 0, 1 )
378
+ row_index += 1
379
+ end
380
+
381
+ # write_results
382
+ results.each{ |row|
383
+ sheet_row = @sheet.createRow(row_index)
384
+ cell_index = 0
385
+ row.each{|k,v|
386
+ celltype = v.kind_of?(Numeric) ? HSSFCell::CELL_TYPE_NUMERIC : HSSFCell::CELL_TYPE_STRING
387
+ cell = sheet_row.createCell(cell_index, celltype)
388
+
389
+ v.nil? ? value = "<NIL>" : value = v
390
+
391
+ cell.setCellValue(value)
392
+
393
+ cell_index +=1
394
+ }
395
+ #puts "#{sheet}: written row #{row_index}"
396
+ row_index +=1
397
+ }
398
+ end
399
+
400
+ end
401
+
402
+ end # END JExcelFile
403
+ else
404
+ class JExcelFile
405
+ def initialize
406
+ raise DataShift::BadRuby, "Please install and use JRuby for working with .xls files"
407
+ end
408
+ end
409
409
  end