datashift 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. data/.document +5 -5
  2. data/Gemfile +28 -25
  3. data/LICENSE.txt +26 -26
  4. data/README.markdown +302 -285
  5. data/README.rdoc +19 -19
  6. data/Rakefile +93 -95
  7. data/VERSION +5 -5
  8. data/datashift.gemspec +162 -178
  9. data/lib/applications/jruby/jexcel_file.rb +396 -396
  10. data/lib/applications/jruby/word.rb +79 -79
  11. data/lib/datashift.rb +152 -113
  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 +236 -236
  16. data/lib/datashift/method_mapper.rb +256 -256
  17. data/lib/generators/csv_generator.rb +36 -36
  18. data/lib/generators/excel_generator.rb +121 -121
  19. data/lib/generators/generator_base.rb +13 -13
  20. data/lib/helpers/core_ext/to_b.rb +24 -24
  21. data/lib/helpers/spree_helper.rb +131 -131
  22. data/lib/java/poi-3.7/LICENSE +507 -507
  23. data/lib/java/poi-3.7/NOTICE +21 -21
  24. data/lib/java/poi-3.7/RELEASE_NOTES.txt +115 -115
  25. data/lib/loaders/csv_loader.rb +98 -98
  26. data/lib/loaders/excel_loader.rb +154 -149
  27. data/lib/loaders/loader_base.rb +403 -331
  28. data/lib/loaders/spreadsheet_loader.rb +136 -136
  29. data/lib/loaders/spree/image_loader.rb +45 -45
  30. data/lib/loaders/spree/product_loader.rb +224 -224
  31. data/spec/csv_loader_spec.rb +30 -30
  32. data/spec/datashift_spec.rb +26 -26
  33. data/spec/db/migrate/20110803201325_create_test_bed.rb +85 -85
  34. data/spec/excel_generator_spec.rb +78 -78
  35. data/spec/excel_loader_spec.rb +204 -176
  36. data/spec/file_definitions.rb +141 -141
  37. data/spec/fixtures/.~lock.ProjectsSingleCategories.xls# +1 -0
  38. data/spec/fixtures/ProjectsDefaults.yml +29 -0
  39. data/spec/fixtures/config/database.yml +24 -24
  40. data/spec/fixtures/interact_models_db.sqlite +0 -0
  41. data/spec/fixtures/interact_spree_db.sqlite +0 -0
  42. data/spec/fixtures/negative/SpreeProdMiss1Mandatory.csv +4 -4
  43. data/spec/fixtures/negative/SpreeProdMissManyMandatory.csv +4 -4
  44. data/spec/fixtures/spree/SpreeProducts.csv +4 -4
  45. data/spec/fixtures/spree/SpreeProductsMultiColumn.csv +4 -4
  46. data/spec/fixtures/spree/SpreeProductsSimple.csv +4 -4
  47. data/spec/fixtures/spree/SpreeZoneExample.csv +5 -5
  48. data/spec/fixtures/test_model_defs.rb +57 -57
  49. data/spec/loader_spec.rb +120 -120
  50. data/spec/method_mapper_spec.rb +237 -237
  51. data/spec/spec_helper.rb +115 -115
  52. data/spec/spree_generator_spec.rb +64 -64
  53. data/spec/spree_loader_spec.rb +310 -310
  54. data/spec/spree_method_mapping_spec.rb +214 -214
  55. data/tasks/config/seed_fu_product_template.erb +15 -15
  56. data/tasks/config/tidy_config.txt +12 -12
  57. data/tasks/db_tasks.rake +65 -64
  58. data/tasks/excel_generator.rake +78 -78
  59. data/tasks/file_tasks.rake +36 -36
  60. data/tasks/import/csv.rake +49 -49
  61. data/tasks/import/excel.rake +71 -66
  62. data/tasks/spree/image_load.rake +108 -108
  63. data/tasks/spree/product_loader.rake +43 -43
  64. data/tasks/word_to_seedfu.rake +166 -166
  65. data/test/helper.rb +18 -18
  66. data/test/test_interact.rb +7 -7
  67. metadata +7 -38
  68. data/Gemfile.lock +0 -211
  69. data/bin/autospec +0 -16
  70. data/bin/convert_to_should_syntax +0 -16
  71. data/bin/erubis +0 -16
  72. data/bin/htmldiff +0 -16
  73. data/bin/jeweler +0 -16
  74. data/bin/ldiff +0 -16
  75. data/bin/nokogiri +0 -16
  76. data/bin/rackup +0 -16
  77. data/bin/rails +0 -16
  78. data/bin/rake +0 -16
  79. data/bin/rake2thor +0 -16
  80. data/bin/ri +0 -16
  81. data/bin/rspec +0 -16
  82. data/bin/spree +0 -16
  83. data/bin/thor +0 -16
  84. data/bin/tilt +0 -16
  85. data/bin/tt +0 -16
@@ -1,397 +1,397 @@
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
-
216
- def ar_to_xls_row(start_column, record)
217
- return unless( record.is_a?(ActiveRecord::Base))
218
-
219
- record.class.columns.each do |connection_column|
220
- ar_to_xls_cell(start_column, record, connection_column)
221
- start_column += 1
222
- end
223
- end
224
-
225
- def ar_to_xls_cell(column, record, connection_column)
226
- datum = record.send(connection_column.name)
227
-
228
- if(connection_column.sql_type =~ /date/) then
229
- @row.createCell(column - 1, HSSFCell::CELL_TYPE_STRING).setCellValue(datum.to_s)
230
- elsif connection_column.sql_type =~ /int/ then
231
- @row.createCell(column - 1, HSSFCell::CELL_TYPE_NUMERIC).setCellValue(datum.to_i)
232
- else
233
- @row.createCell(column - 1, HSSFCell::CELL_TYPE_STRING).setCellValue( datum.to_s )
234
- end
235
- end
236
-
237
- ##############################
238
- # RETRIEVING DATA FROM EXCEL #
239
- ##############################
240
-
241
- # Return the raw data of the requested cell by row/column
242
- def get_cell_value(row, column)
243
- raise TypeError, "Expect row argument of type HSSFRow" unless row.is_a?(Java::OrgApachePoiHssfUsermodel::HSSFRow)
244
- cell_value( row.getCell(column) )
245
- end
246
-
247
- # Return the raw data of an HSSFCell
248
- def cell_value(cell)
249
- return unless cell
250
- #puts "DEBUG CELL TYPE : #{cell} => #{cell.getCellType().inspect}"
251
- case (cell.getCellType())
252
- when HSSFCell::CELL_TYPE_FORMULA then return cell.getCellFormula()
253
- when HSSFCell::CELL_TYPE_NUMERIC then return cell.getNumericCellValue()
254
- when HSSFCell::CELL_TYPE_STRING then return cell.getStringCellValue()
255
- when HSSFCell::CELL_TYPE_BOOLEAN then return cell.getBooleanCellValue()
256
- when HSSFCell::CELL_TYPE_BLANK then return ""
257
- end
258
- end
259
-
260
- def save( filename = nil )
261
- filename.nil? ? file = @filepath : file = filename
262
- out = FileOutputStream.new(file)
263
- @book.write(out) unless @book.nil?
264
- out.close
265
- end
266
-
267
- def save_to_text( filename )
268
- File.open( filename, 'w') {|f| f.write(to_s) }
269
- end
270
-
271
-
272
- def add_comment( cell, text )
273
- raise "Please supply valid HSSFCell" unless cell.respond_to?('setCellComment')
274
- return if @sheet.nil?
275
-
276
- patriarch = @patriarchs[@sheet.getSheetName()]
277
-
278
- anchor = HSSFClientAnchor.new(100, 50, 100, 50, cell.getColumnIndex(), cell.getRowIndex(), cell.getColumnIndex()+3, cell.getRowIndex()+4)
279
- comment = patriarch.createCellComment(anchor)
280
-
281
- comment_text = HSSFRichTextString.new(text)
282
- comment.setString(comment_text)
283
- comment.setAuthor("Mapping")
284
-
285
- cell.setCellComment(comment)
286
- end
287
-
288
- # The internal representation of a Excel File
289
-
290
- # Get a percentage style
291
- def getPercentStyle()
292
- if (@percentCellStyle.nil? && @book)
293
- @percentCellStyle = @book.createCellStyle();
294
- @percentCellStyle.setDataFormat(HSSFDataFormat.getBuiltinFormat("0.00%"));
295
- end
296
- return @percentCellStyle
297
- end
298
-
299
- # Auto size either the given column index or all columns
300
- def autosize(column = nil)
301
- return if @sheet.nil?
302
- if (column.kind_of? Integer)
303
- @sheet.autoSizeColumn(column)
304
- else
305
- @sheet.getRow(0).cellIterator.each{|c| @sheet.autoSizeColumn(c.getColumnIndex)}
306
- end
307
- end
308
-
309
- def to_s
310
- return "" unless @book
311
-
312
- outs = ByteArrayOutputStream.new
313
- @book.write(outs);
314
- outs.close();
315
- String.from_java_bytes(outs.toByteArray)
316
- end
317
-
318
- def createFreezePane(row=1, column=0)
319
- return if @sheet.nil?
320
- @sheet.createFreezePane(row, column)
321
- end
322
-
323
- # Use execute to run sql query provided
324
- # and write to a csv file (path required)
325
- # header row is optional but default is on
326
- # Auto mapping of specified columns is optional
327
- # @mappings is a hash{column => map} of columns to a map{old_value => new_value}
328
- def results_to_sheet( results, sheet, mappings=nil, header=true)
329
- numrows = results.length
330
- sheet_name = sheet
331
-
332
- if (numrows == 0)
333
- log :info, "WARNING - results are empty nothing written to sheet: #{sheet}"
334
- return
335
- end
336
-
337
- #Check if we need to split the results into seperate sheets
338
- if (numrows > @@maxrows )
339
- startrow = 0
340
- while (numrows > 0)
341
- # Split the results and write to a new sheet
342
- next_results = results.slice(startrow, @@maxrows > numrows ? numrows : @@maxrows)
343
- self.results_to_sheet(next_results, "#{sheet_name}", mappings, header) if next_results
344
-
345
- # Increase counters
346
- numrows -= next_results.length
347
- startrow += next_results.length
348
- sheet_name += 'I'
349
- end
350
- else
351
- # Create required sheet
352
- self.create(sheet)
353
-
354
- row_index = self.num_rows
355
- # write header line
356
- if (header && row_index==0 )
357
- header_row = @sheet.createRow(row_index)
358
- cell_index = 0
359
- results[0].keys.each{ |h|
360
- header_row.createCell(cell_index).setCellValue("#{h}")
361
- @sheet.setDefaultColumnStyle(cell_index, self.getPercentStyle) if "#{h}".include? '%'
362
- cell_index += 1
363
- }
364
- # Freeze the header row
365
- @sheet.createFreezePane( 0, 1, 0, 1 )
366
- row_index += 1
367
- end
368
-
369
- # write_results
370
- results.each{ |row|
371
- sheet_row = @sheet.createRow(row_index)
372
- cell_index = 0
373
- row.each{|k,v|
374
- celltype = v.kind_of?(Numeric) ? HSSFCell::CELL_TYPE_NUMERIC : HSSFCell::CELL_TYPE_STRING
375
- cell = sheet_row.createCell(cell_index, celltype)
376
-
377
- v.nil? ? value = "<NIL>" : value = v
378
-
379
- cell.setCellValue(value)
380
-
381
- cell_index +=1
382
- }
383
- #puts "#{sheet}: written row #{row_index}"
384
- row_index +=1
385
- }
386
- end
387
-
388
- end
389
-
390
- end # END JExcelFile
391
- else
392
- class JExcelFile
393
- def initialize
394
- raise DataShift::BadRuby, "Please install and use JRuby for working with .xls files"
395
- end
396
- 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
+
216
+ def ar_to_xls_row(start_column, record)
217
+ return unless( record.is_a?(ActiveRecord::Base))
218
+
219
+ record.class.columns.each do |connection_column|
220
+ ar_to_xls_cell(start_column, record, connection_column)
221
+ start_column += 1
222
+ end
223
+ end
224
+
225
+ def ar_to_xls_cell(column, record, connection_column)
226
+ datum = record.send(connection_column.name)
227
+
228
+ if(connection_column.sql_type =~ /date/) then
229
+ @row.createCell(column - 1, HSSFCell::CELL_TYPE_STRING).setCellValue(datum.to_s)
230
+ elsif connection_column.sql_type =~ /int/ then
231
+ @row.createCell(column - 1, HSSFCell::CELL_TYPE_NUMERIC).setCellValue(datum.to_i)
232
+ else
233
+ @row.createCell(column - 1, HSSFCell::CELL_TYPE_STRING).setCellValue( datum.to_s )
234
+ end
235
+ end
236
+
237
+ ##############################
238
+ # RETRIEVING DATA FROM EXCEL #
239
+ ##############################
240
+
241
+ # Return the raw data of the requested cell by row/column
242
+ def get_cell_value(row, column)
243
+ raise TypeError, "Expect row argument of type HSSFRow" unless row.is_a?(Java::OrgApachePoiHssfUsermodel::HSSFRow)
244
+ cell_value( row.getCell(column) )
245
+ end
246
+
247
+ # Return the raw data of an HSSFCell
248
+ def cell_value(cell)
249
+ return unless cell
250
+ #puts "DEBUG CELL TYPE : #{cell} => #{cell.getCellType().inspect}"
251
+ case (cell.getCellType())
252
+ when HSSFCell::CELL_TYPE_FORMULA then return cell.getCellFormula()
253
+ when HSSFCell::CELL_TYPE_NUMERIC then return cell.getNumericCellValue()
254
+ when HSSFCell::CELL_TYPE_STRING then return cell.getStringCellValue()
255
+ when HSSFCell::CELL_TYPE_BOOLEAN then return cell.getBooleanCellValue()
256
+ when HSSFCell::CELL_TYPE_BLANK then return ""
257
+ end
258
+ end
259
+
260
+ def save( filename = nil )
261
+ filename.nil? ? file = @filepath : file = filename
262
+ out = FileOutputStream.new(file)
263
+ @book.write(out) unless @book.nil?
264
+ out.close
265
+ end
266
+
267
+ def save_to_text( filename )
268
+ File.open( filename, 'w') {|f| f.write(to_s) }
269
+ end
270
+
271
+
272
+ def add_comment( cell, text )
273
+ raise "Please supply valid HSSFCell" unless cell.respond_to?('setCellComment')
274
+ return if @sheet.nil?
275
+
276
+ patriarch = @patriarchs[@sheet.getSheetName()]
277
+
278
+ anchor = HSSFClientAnchor.new(100, 50, 100, 50, cell.getColumnIndex(), cell.getRowIndex(), cell.getColumnIndex()+3, cell.getRowIndex()+4)
279
+ comment = patriarch.createCellComment(anchor)
280
+
281
+ comment_text = HSSFRichTextString.new(text)
282
+ comment.setString(comment_text)
283
+ comment.setAuthor("Mapping")
284
+
285
+ cell.setCellComment(comment)
286
+ end
287
+
288
+ # The internal representation of a Excel File
289
+
290
+ # Get a percentage style
291
+ def getPercentStyle()
292
+ if (@percentCellStyle.nil? && @book)
293
+ @percentCellStyle = @book.createCellStyle();
294
+ @percentCellStyle.setDataFormat(HSSFDataFormat.getBuiltinFormat("0.00%"));
295
+ end
296
+ return @percentCellStyle
297
+ end
298
+
299
+ # Auto size either the given column index or all columns
300
+ def autosize(column = nil)
301
+ return if @sheet.nil?
302
+ if (column.kind_of? Integer)
303
+ @sheet.autoSizeColumn(column)
304
+ else
305
+ @sheet.getRow(0).cellIterator.each{|c| @sheet.autoSizeColumn(c.getColumnIndex)}
306
+ end
307
+ end
308
+
309
+ def to_s
310
+ return "" unless @book
311
+
312
+ outs = ByteArrayOutputStream.new
313
+ @book.write(outs);
314
+ outs.close();
315
+ String.from_java_bytes(outs.toByteArray)
316
+ end
317
+
318
+ def createFreezePane(row=1, column=0)
319
+ return if @sheet.nil?
320
+ @sheet.createFreezePane(row, column)
321
+ end
322
+
323
+ # Use execute to run sql query provided
324
+ # and write to a csv file (path required)
325
+ # header row is optional but default is on
326
+ # Auto mapping of specified columns is optional
327
+ # @mappings is a hash{column => map} of columns to a map{old_value => new_value}
328
+ def results_to_sheet( results, sheet, mappings=nil, header=true)
329
+ numrows = results.length
330
+ sheet_name = sheet
331
+
332
+ if (numrows == 0)
333
+ log :info, "WARNING - results are empty nothing written to sheet: #{sheet}"
334
+ return
335
+ end
336
+
337
+ #Check if we need to split the results into seperate sheets
338
+ if (numrows > @@maxrows )
339
+ startrow = 0
340
+ while (numrows > 0)
341
+ # Split the results and write to a new sheet
342
+ next_results = results.slice(startrow, @@maxrows > numrows ? numrows : @@maxrows)
343
+ self.results_to_sheet(next_results, "#{sheet_name}", mappings, header) if next_results
344
+
345
+ # Increase counters
346
+ numrows -= next_results.length
347
+ startrow += next_results.length
348
+ sheet_name += 'I'
349
+ end
350
+ else
351
+ # Create required sheet
352
+ self.create(sheet)
353
+
354
+ row_index = self.num_rows
355
+ # write header line
356
+ if (header && row_index==0 )
357
+ header_row = @sheet.createRow(row_index)
358
+ cell_index = 0
359
+ results[0].keys.each{ |h|
360
+ header_row.createCell(cell_index).setCellValue("#{h}")
361
+ @sheet.setDefaultColumnStyle(cell_index, self.getPercentStyle) if "#{h}".include? '%'
362
+ cell_index += 1
363
+ }
364
+ # Freeze the header row
365
+ @sheet.createFreezePane( 0, 1, 0, 1 )
366
+ row_index += 1
367
+ end
368
+
369
+ # write_results
370
+ results.each{ |row|
371
+ sheet_row = @sheet.createRow(row_index)
372
+ cell_index = 0
373
+ row.each{|k,v|
374
+ celltype = v.kind_of?(Numeric) ? HSSFCell::CELL_TYPE_NUMERIC : HSSFCell::CELL_TYPE_STRING
375
+ cell = sheet_row.createCell(cell_index, celltype)
376
+
377
+ v.nil? ? value = "<NIL>" : value = v
378
+
379
+ cell.setCellValue(value)
380
+
381
+ cell_index +=1
382
+ }
383
+ #puts "#{sheet}: written row #{row_index}"
384
+ row_index +=1
385
+ }
386
+ end
387
+
388
+ end
389
+
390
+ end # END JExcelFile
391
+ else
392
+ class JExcelFile
393
+ def initialize
394
+ raise DataShift::BadRuby, "Please install and use JRuby for working with .xls files"
395
+ end
396
+ end
397
397
  end