datashift 0.0.1 → 0.0.2

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 (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