datashift 0.1.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
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