datashift 0.9.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (163) hide show
  1. data/README.markdown +63 -64
  2. data/Rakefile +4 -7
  3. data/VERSION +1 -1
  4. data/datashift.gemspec +92 -62
  5. data/lib/applications/apache_poi_extensions.rb +62 -0
  6. data/lib/applications/excel.rb +78 -0
  7. data/lib/applications/excel_base.rb +65 -0
  8. data/lib/applications/jexcel_file.rb +222 -0
  9. data/lib/applications/jexcel_file_extensions.rb +244 -0
  10. data/lib/applications/jruby/{jexcel_file.rb → old_pre_proxy_jexcel_file.rb} +0 -0
  11. data/lib/applications/ruby_poi_translations.rb +64 -0
  12. data/lib/applications/spreadsheet_extensions.rb +31 -0
  13. data/lib/datashift/method_details_manager.rb +4 -0
  14. data/lib/exporters/csv_exporter.rb +3 -1
  15. data/lib/exporters/excel_exporter.rb +59 -74
  16. data/lib/generators/excel_generator.rb +70 -74
  17. data/lib/guards.rb +57 -0
  18. data/lib/loaders/excel_loader.rb +105 -105
  19. data/lib/loaders/loader_base.rb +43 -21
  20. data/lib/loaders/paperclip/attachment_loader.rb +104 -0
  21. data/lib/loaders/paperclip/datashift_paperclip.rb +78 -0
  22. data/lib/loaders/paperclip/{image_loader.rb → image_loading.rb} +2 -18
  23. data/lib/thor/{generate_excel.thor → generate.thor} +48 -0
  24. data/lib/thor/paperclip.thor +85 -0
  25. data/lib/thor/tools.thor +23 -2
  26. data/spec/Gemfile +1 -7
  27. data/spec/csv_exporter_spec.rb +4 -4
  28. data/spec/csv_loader_spec.rb +1 -1
  29. data/spec/excel_exporter_spec.rb +43 -45
  30. data/spec/excel_generator_spec.rb +132 -60
  31. data/spec/excel_loader_spec.rb +134 -140
  32. data/spec/excel_spec.rb +179 -0
  33. data/spec/fixtures/ProjectsMultiCategoriesHeaderLookup.xls +0 -0
  34. data/spec/fixtures/config/database.yml +2 -2
  35. data/spec/fixtures/db/datashift_test_models_db.sqlite +0 -0
  36. data/spec/{db → fixtures/db}/migrate/20110803201325_create_test_bed.rb +0 -0
  37. data/spec/fixtures/load_datashift.thor +3 -0
  38. data/spec/fixtures/models/category.rb +7 -0
  39. data/spec/fixtures/models/empty.rb +2 -0
  40. data/spec/fixtures/models/loader_release.rb +10 -0
  41. data/spec/fixtures/models/long_and_complex_table_linked_to_version.rb +6 -0
  42. data/spec/fixtures/models/milestone.rb +8 -0
  43. data/spec/fixtures/models/owner.rb +5 -0
  44. data/spec/fixtures/models/project.rb +26 -0
  45. data/spec/fixtures/models/test_model_defs.rb +67 -0
  46. data/spec/fixtures/models/version.rb +7 -0
  47. data/spec/loader_spec.rb +4 -3
  48. data/spec/method_dictionary_spec.rb +7 -6
  49. data/spec/method_mapper_spec.rb +3 -2
  50. data/spec/rails_sandbox/.gitignore +15 -0
  51. data/spec/rails_sandbox/Gemfile +40 -0
  52. data/spec/rails_sandbox/README.rdoc +261 -0
  53. data/spec/rails_sandbox/Rakefile +7 -0
  54. data/spec/rails_sandbox/app/assets/images/rails.png +0 -0
  55. data/spec/rails_sandbox/app/assets/javascripts/application.js +15 -0
  56. data/spec/rails_sandbox/app/assets/stylesheets/application.css +13 -0
  57. data/spec/rails_sandbox/app/controllers/application_controller.rb +3 -0
  58. data/spec/rails_sandbox/app/helpers/application_helper.rb +2 -0
  59. data/spec/rails_sandbox/app/mailers/.gitkeep +0 -0
  60. data/spec/rails_sandbox/app/models/.gitkeep +0 -0
  61. data/spec/rails_sandbox/app/models/category.rb +7 -0
  62. data/spec/rails_sandbox/app/models/empty.rb +2 -0
  63. data/spec/rails_sandbox/app/models/loader_release.rb +10 -0
  64. data/spec/rails_sandbox/app/models/long_and_complex_table_linked_to_version.rb +6 -0
  65. data/spec/rails_sandbox/app/models/milestone.rb +8 -0
  66. data/spec/rails_sandbox/app/models/owner.rb +5 -0
  67. data/spec/rails_sandbox/app/models/project.rb +26 -0
  68. data/spec/rails_sandbox/app/models/test_model_defs.rb +67 -0
  69. data/spec/rails_sandbox/app/models/version.rb +7 -0
  70. data/spec/rails_sandbox/app/views/layouts/application.html.erb +14 -0
  71. data/spec/rails_sandbox/config.ru +4 -0
  72. data/spec/rails_sandbox/config/application.rb +62 -0
  73. data/spec/rails_sandbox/config/boot.rb +6 -0
  74. data/spec/rails_sandbox/config/database.yml +20 -0
  75. data/spec/rails_sandbox/config/environment.rb +5 -0
  76. data/spec/rails_sandbox/config/environments/development.rb +37 -0
  77. data/spec/rails_sandbox/config/environments/production.rb +67 -0
  78. data/spec/rails_sandbox/config/environments/test.rb +37 -0
  79. data/spec/rails_sandbox/config/initializers/backtrace_silencers.rb +7 -0
  80. data/spec/rails_sandbox/config/initializers/inflections.rb +15 -0
  81. data/spec/rails_sandbox/config/initializers/mime_types.rb +5 -0
  82. data/spec/rails_sandbox/config/initializers/secret_token.rb +7 -0
  83. data/spec/rails_sandbox/config/initializers/session_store.rb +8 -0
  84. data/spec/rails_sandbox/config/initializers/wrap_parameters.rb +14 -0
  85. data/spec/rails_sandbox/config/locales/en.yml +5 -0
  86. data/spec/rails_sandbox/config/routes.rb +58 -0
  87. data/spec/rails_sandbox/db/migrate/20110803201325_create_test_bed.rb +96 -0
  88. data/spec/rails_sandbox/db/schema.rb +81 -0
  89. data/spec/rails_sandbox/db/seeds.rb +7 -0
  90. data/spec/rails_sandbox/lib/assets/.gitkeep +0 -0
  91. data/spec/rails_sandbox/lib/tasks/.gitkeep +0 -0
  92. data/spec/rails_sandbox/log/.gitkeep +0 -0
  93. data/spec/rails_sandbox/public/404.html +26 -0
  94. data/spec/rails_sandbox/public/422.html +26 -0
  95. data/spec/rails_sandbox/public/500.html +25 -0
  96. data/spec/rails_sandbox/public/favicon.ico +0 -0
  97. data/spec/rails_sandbox/public/index.html +241 -0
  98. data/spec/rails_sandbox/public/robots.txt +5 -0
  99. data/spec/rails_sandbox/script/rails +6 -0
  100. data/spec/rails_sandbox/test/fixtures/.gitkeep +0 -0
  101. data/spec/rails_sandbox/test/functional/.gitkeep +0 -0
  102. data/spec/rails_sandbox/test/integration/.gitkeep +0 -0
  103. data/spec/rails_sandbox/test/performance/browsing_test.rb +12 -0
  104. data/spec/rails_sandbox/test/test_helper.rb +13 -0
  105. data/spec/rails_sandbox/test/unit/.gitkeep +0 -0
  106. data/spec/rails_sandbox/vendor/assets/javascripts/.gitkeep +0 -0
  107. data/spec/rails_sandbox/vendor/assets/stylesheets/.gitkeep +0 -0
  108. data/spec/rails_sandbox/vendor/plugins/.gitkeep +0 -0
  109. data/spec/spec_helper.rb +144 -121
  110. data/spec/thor_spec.rb +34 -14
  111. metadata +207 -194
  112. data/lib/helpers/spree_helper.rb +0 -213
  113. data/lib/loaders/spreadsheet_loader.rb +0 -144
  114. data/lib/loaders/spree/image_loader.rb +0 -90
  115. data/lib/loaders/spree/product_loader.rb +0 -354
  116. data/lib/thor/spree/bootstrap_cleanup.thor +0 -61
  117. data/lib/thor/spree/products_images.thor +0 -252
  118. data/lib/thor/spree/reports.thor +0 -56
  119. data/public/spree/products/large/DEMO_001_ror_bag.jpeg +0 -0
  120. data/public/spree/products/large/DEMO_002_Powerstation.jpg +0 -0
  121. data/public/spree/products/large/DEMO_003_ror_mug.jpeg +0 -0
  122. data/public/spree/products/mini/DEMO_001_ror_bag.jpeg +0 -0
  123. data/public/spree/products/mini/DEMO_002_Powerstation.jpg +0 -0
  124. data/public/spree/products/mini/DEMO_003_ror_mug.jpeg +0 -0
  125. data/public/spree/products/original/DEMO_001_ror_bag.jpeg +0 -0
  126. data/public/spree/products/original/DEMO_002_Powerstation.jpg +0 -0
  127. data/public/spree/products/original/DEMO_003_ror_mug.jpeg +0 -0
  128. data/public/spree/products/product/DEMO_001_ror_bag.jpeg +0 -0
  129. data/public/spree/products/product/DEMO_002_Powerstation.jpg +0 -0
  130. data/public/spree/products/product/DEMO_003_ror_mug.jpeg +0 -0
  131. data/public/spree/products/small/DEMO_001_ror_bag.jpeg +0 -0
  132. data/public/spree/products/small/DEMO_002_Powerstation.jpg +0 -0
  133. data/public/spree/products/small/DEMO_003_ror_mug.jpeg +0 -0
  134. data/spec/fixtures/datashift_Spree_db.sqlite +0 -0
  135. data/spec/fixtures/datashift_test_models_db.sqlite +0 -0
  136. data/spec/fixtures/negative/SpreeProdMiss1Mandatory.csv +0 -4
  137. data/spec/fixtures/negative/SpreeProdMiss1Mandatory.xls +0 -0
  138. data/spec/fixtures/negative/SpreeProdMissManyMandatory.csv +0 -4
  139. data/spec/fixtures/negative/SpreeProdMissManyMandatory.xls +0 -0
  140. data/spec/fixtures/spree/SpreeImages.xls +0 -0
  141. data/spec/fixtures/spree/SpreeMultiVariant.csv +0 -4
  142. data/spec/fixtures/spree/SpreeProducts.csv +0 -4
  143. data/spec/fixtures/spree/SpreeProducts.xls +0 -0
  144. data/spec/fixtures/spree/SpreeProductsDefaults.yml +0 -15
  145. data/spec/fixtures/spree/SpreeProductsMandatoryOnly.xls +0 -0
  146. data/spec/fixtures/spree/SpreeProductsMultiColumn.csv +0 -4
  147. data/spec/fixtures/spree/SpreeProductsMultiColumn.xls +0 -0
  148. data/spec/fixtures/spree/SpreeProductsSimple.csv +0 -4
  149. data/spec/fixtures/spree/SpreeProductsSimple.xls +0 -0
  150. data/spec/fixtures/spree/SpreeProductsWithImages.csv +0 -4
  151. data/spec/fixtures/spree/SpreeProductsWithImages.xls +0 -0
  152. data/spec/fixtures/spree/SpreeZoneExample.csv +0 -5
  153. data/spec/fixtures/spree/SpreeZoneExample.xls +0 -0
  154. data/spec/spree_exporter_spec.rb +0 -72
  155. data/spec/spree_generator_spec.rb +0 -96
  156. data/spec/spree_images_loader_spec.rb +0 -107
  157. data/spec/spree_loader_spec.rb +0 -375
  158. data/spec/spree_method_mapping_spec.rb +0 -226
  159. data/spec/spree_variants_loader_spec.rb +0 -189
  160. data/tasks/export/excel_generator.rake +0 -102
  161. data/tasks/import/excel.rake +0 -75
  162. data/test/helper.rb +0 -18
  163. data/test/test_interact.rb +0 -7
@@ -0,0 +1,62 @@
1
+ # Copyright:: Autotelik Media Ltd
2
+ # Author :: Tom Statter
3
+ # Date :: July 2010
4
+ # License::
5
+ #
6
+ #
7
+ if(DataShift::Guards::jruby?)
8
+
9
+ require 'java'
10
+ require "poi-3.7-20101029.jar"
11
+
12
+ # Extend the Poi classes with some syntactic sugar
13
+
14
+ class Java::OrgApachePoiHssfUsermodel::HSSFSheet
15
+ def name()
16
+ getSheetName
17
+ end
18
+
19
+ def num_rows
20
+ getPhysicalNumberOfRows
21
+ end
22
+
23
+ end
24
+
25
+ class Java::OrgApachePoiHssfUsermodel::HSSFRow
26
+
27
+ include RubyPoiTranslations
28
+
29
+ include Enumerable
30
+
31
+ def []( column)
32
+ cell_value( get_or_create_cell( column ) )
33
+ end
34
+
35
+ def []=( column, value )
36
+ get_or_create_cell(column, value).setCellValue((value.to_s || ""))
37
+ end
38
+
39
+ def get_or_create_cell( column, value = nil )
40
+ if(value)
41
+ java_send(:getCell, [Java::int], column) || createCell(column, poi_cell_type(value))
42
+ else
43
+ java_send(:getCell, [Java::int], column) || java_send(:createCell, [Java::int], column)
44
+ end
45
+ end
46
+
47
+ def idx
48
+ getRowNum()
49
+ end
50
+
51
+ # Iterate over each column in the row and yield on the cell
52
+ def each(&block)
53
+ cellIterator.each {|c| yield cell_value(c) }
54
+ end
55
+
56
+ # TODO
57
+ # for min, max and sort from enumerable need <=>
58
+ # def <=> end
59
+
60
+ end
61
+
62
+ end
@@ -0,0 +1,78 @@
1
+ # Copyright:: Autotelik Media Ltd
2
+ # Author :: Tom Statter
3
+ # Date :: July 2010
4
+ # License::
5
+ #
6
+ # Details:: A wrapper around creating and directly manipulating Excel files.
7
+ # Acts as proxy over main Ruby gem spreadsheet and our own JRuby only implementation using Apache POI
8
+ # Aim is to make it seamless to switch between any Excel implementation
9
+ #
10
+ # http://spreadsheet.rubyforge.org/GUIDE_txt.html
11
+ #
12
+ require 'guards'
13
+
14
+ module ExcelProxy
15
+ # Returns the current proxy class
16
+ def self.proxy_class
17
+ if(DataShift::Guards.jruby?)
18
+ require 'jexcel_file'
19
+ JExcelFile
20
+ else
21
+ require 'spreadsheet'
22
+ require 'spreadsheet_extensions'
23
+ Spreadsheet
24
+ end
25
+ end
26
+
27
+ def self.proxy_object
28
+ if(DataShift::Guards.jruby?)
29
+ ExcelProxy::proxy_class.new
30
+ else
31
+ ExcelProxy::proxy_class::Workbook.new
32
+ end
33
+ end
34
+ end
35
+
36
+ class Excel #< BasicObject
37
+
38
+ def initialize()
39
+ @excel_class = ExcelProxy::proxy_class
40
+ @excel = ExcelProxy::proxy_object
41
+ end
42
+
43
+ # Forward all undefined methods to the wrapped Excel object.
44
+ def method_missing(method, *args, &block)
45
+ #puts @excel.class, method, args.inspect
46
+
47
+ if(@excel.respond_to?(method))
48
+ @excel.send(method, *args, &block)
49
+ elsif(@excel.worksheets.last.respond_to?(method)) # active_worksheet doesn't work so use the latest
50
+ @excel.worksheets.last.send(method, *args, &block)
51
+ elsif(@excel_class.respond_to?(method))
52
+ if(method == :open || method == 'open')
53
+ @excel = @excel_class.send(method, *args, &block)
54
+ else
55
+ @excel_class.send(method, *args, &block)
56
+ end
57
+ else
58
+ super
59
+ end
60
+ end
61
+
62
+ def self.method_missing(method, *args, &block)
63
+ @excel_class.send(method, *args, &block)
64
+ end
65
+
66
+ # Returns +true+ if _obj_ responds to the given method. Private methods are included in the search
67
+ # only if the optional second parameter evaluates to +true+.
68
+ def respond_to?(method, include_private=false)
69
+ super || @excel.respond_to?(method, include_private)
70
+ end
71
+
72
+ # without this can't get at any defined modules etc
73
+ #
74
+ def self.const_missing(name)
75
+ ::Object.const_get(name)
76
+ end
77
+
78
+ end
@@ -0,0 +1,65 @@
1
+ # To change this template, choose Tools | Templates
2
+ # and open the template in the editor.
3
+
4
+ module ExcelBase
5
+
6
+ def sanitize_sheet_name( name )
7
+ name.gsub(/[\[\]:\*\/\\\?]/, '')
8
+ end
9
+
10
+ # Helpers for dealing with Active Record models and collections
11
+
12
+ def ar_to_headers( records )
13
+ return if( !records.first.is_a?(ActiveRecord::Base) || records.empty?)
14
+
15
+ headers = records.first.class.columns.collect( &:name )
16
+ set_headers( headers )
17
+ end
18
+
19
+
20
+ # Pass a set of AR records
21
+ def ar_to_xls(records, options = {})
22
+ return if( ! records.first.is_a?(ActiveRecord::Base) || records.empty?)
23
+
24
+ row_index =
25
+ if(options[:no_headers])
26
+ 0
27
+ else
28
+ ar_to_headers( records )
29
+ 1
30
+ end
31
+
32
+ records.each do |record|
33
+ create_row(row_index)
34
+
35
+ ar_to_xls_row(0, record)
36
+
37
+ row_index += 1
38
+ end
39
+ end
40
+
41
+
42
+ # Save data from an AR record to the current row, based on the record's columns [c1,c2,c3]
43
+ # Returns the number of the final column written to
44
+ def ar_to_xls_row(row, start_column, record)
45
+ return unless( record.is_a?(ActiveRecord::Base))
46
+
47
+ column = start_column
48
+ record.class.columns.each do |connection_column|
49
+ ar_to_xls_cell(row, column, record, connection_column)
50
+ column += 1
51
+ end
52
+ column
53
+ end
54
+
55
+ def ar_to_xls_cell(row, column, record, connection_column)
56
+ begin
57
+ datum = record.send(connection_column.name)
58
+
59
+ self[row, column] = datum
60
+ rescue => e
61
+ puts "Failed to export #{datum} from #{connection_column.inspect} to column #{column}"
62
+ puts e, e.backtrace
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,222 @@
1
+ # Copyright:: Autotelik Media Ltd
2
+ # Author :: Tom Statter
3
+ # Date :: July 2010
4
+ # License::
5
+ #
6
+ # A wrapper around creating and directly manipulating Excel files.
7
+ #
8
+ # i.e Create and populate XSL files
9
+ #
10
+ # jar added to class path in manifest - 'poi-3.5-beta4-20081128.jar'
11
+ #
12
+ if(DataShift::Guards::jruby?)
13
+
14
+ require 'java'
15
+
16
+ require 'excel_base'
17
+ require 'ruby_poi_translations'
18
+
19
+ class JExcelFile
20
+
21
+ include ExcelBase
22
+
23
+ include RubyPoiTranslations
24
+ extend RubyPoiTranslations
25
+
26
+ include Enumerable
27
+
28
+ include_class 'org.apache.poi.hssf.util.HSSFColor'
29
+ java_import 'org.apache.poi.poifs.filesystem.POIFSFileSystem'
30
+
31
+ java_import 'org.apache.poi.hssf.usermodel.HSSFCell'
32
+ java_import 'org.apache.poi.hssf.usermodel.HSSFWorkbook'
33
+ java_import 'org.apache.poi.hssf.usermodel.HSSFCellStyle'
34
+ java_import 'org.apache.poi.hssf.usermodel.HSSFDataFormat'
35
+ java_import 'org.apache.poi.hssf.usermodel.HSSFClientAnchor'
36
+ java_import 'org.apache.poi.hssf.usermodel.HSSFRichTextString'
37
+
38
+ attr_accessor :workbook, :row, :date_style
39
+ attr_reader :sheet, :current_sheet_index
40
+
41
+ # NOTE: this is the POI 3.7 HSSF maximum rows
42
+ @@maxrows = 65535
43
+
44
+ def self.maxrows
45
+ return @@maxrows
46
+ end
47
+
48
+ def self.date_format
49
+ HSSFDataFormat.getBuiltinFormat("m/d/yy h:mm")
50
+ end
51
+
52
+ def self.open(filename)
53
+ HSSFWorkbook.new(FileInputStream.new(filename))
54
+ end
55
+
56
+ # NOTES :
57
+ # The HSSFWorkbook uses 0 based indexes
58
+
59
+ def initialize()
60
+ @workbook = HSSFWorkbook.new
61
+
62
+ @sheet = nil
63
+ @current_sheet_index = 0
64
+
65
+ # The @patriarchs hash is a workaround because HSSFSheet.getDrawingPatriarch()
66
+ # causes a lot of issues (if it doesn't throw an exception!)
67
+ @patriarchs = Hash.new
68
+
69
+ @date_style = nil
70
+ end
71
+
72
+ def open(filename)
73
+ @workbook = JExcelFile.open(filename)
74
+
75
+ @date_style = @workbook.createCellStyle
76
+ @date_style.setDataFormat( JExcelFile::date_format )
77
+
78
+ activate_sheet(0)
79
+ @workbook
80
+ end
81
+
82
+ # Create and return a new worksheet.
83
+ # Not set to the active worksheet
84
+
85
+ def create_worksheet( options = {} )
86
+ sheet_name = options[:name]
87
+
88
+ @workbook = HSSFWorkbook.new() if @workbook.nil?
89
+
90
+ unless(sheet_name)
91
+ i = 0
92
+ begin
93
+ sheet_name = "Worksheet#{i += 1}"
94
+ end while(@workbook.getSheetIndex(sheet_name) >= 0) # there is no hard limit to no of sheets in Excel but at some point you will run out of memory!
95
+
96
+ return create_sheet_and_set_styles( sheet_name )
97
+ else
98
+ if (@workbook.getSheetIndex(sheet_name) < 0) #Check sheet doesn't already exist
99
+ return create_sheet_and_set_styles( sheet_name )
100
+ else
101
+ activate_sheet(sheet_name)
102
+ end
103
+ end
104
+ end
105
+
106
+ # Set the supplied sheet index or name, as the active sheet and return it.
107
+ # If no such sheet return current sheet
108
+ def activate_sheet(term)
109
+
110
+ if(@workbook)
111
+ x = term.is_a?(String) ? @workbook.getSheetIndex(term.to_java(java.lang.String)) : term
112
+ @sheet = worksheet(x)
113
+
114
+ if( @sheet )
115
+ @current_sheet_index = x
116
+ @workbook.setActiveSheet(@current_sheet_index)
117
+ @sheet = @workbook.getSheetAt(@current_sheet_index)
118
+ @sheet.setActive(true)
119
+ end
120
+ end
121
+ @sheet
122
+ end
123
+
124
+ # Return a sheet by index
125
+ def worksheet( index )
126
+ if(@workbook)
127
+ x = index.is_a?(String) ? @workbook.getSheetIndex(index.to_java(java.lang.String)) : index
128
+ return @workbook.getSheetAt(x)
129
+ end
130
+ nil
131
+ end
132
+
133
+ def worksheets
134
+ (0...@workbook.getNumberOfSheets).collect { |i| @workbook.getSheetAt(i) }
135
+ end
136
+
137
+ # Create new row (indexing in line with POI usage, start 0)
138
+ def create_row(index)
139
+ return nil if @sheet.nil?
140
+ raise "BAD INDEX: Row indexing starts at 0" if(index < 0)
141
+ @row = @sheet.createRow(index)
142
+ @row
143
+ end
144
+
145
+ def num_rows
146
+ @sheet.getPhysicalNumberOfRows
147
+ end
148
+
149
+ # Process each row. Row type is org.apache.poi.hssf.usermodel.HSSFRow
150
+
151
+ # Currently ignores skip argument - TODO - this is how spreadsheet gem works
152
+ # #each iterates over all used Rows (from the first used Row until but omitting the first unused Row, see also #dimensions)
153
+ # If the argument skip is given,
154
+ # #each iterates from that row until but omitting the first unused Row, effectively skipping the first skip Rows from the top of the Worksheet.
155
+
156
+ def each(skip = nil, &block)
157
+ @sheet.rowIterator.each(&block)
158
+ end
159
+
160
+ def row( index )
161
+ @sheet.getRow(index) || create_row(index)
162
+ end
163
+
164
+ # Get the enriched value of the Cell at row, column.
165
+ def cell(row, column)
166
+ row = row(row)
167
+ cell_value( row.get_or_create_cell( column ) )
168
+ end
169
+
170
+ # Get the enriched value of the Cell at row, column.
171
+ def [](row, column)
172
+ cell(row, column)
173
+ end
174
+
175
+ def []=(row, column, value)
176
+ set_cell(row, column, value)
177
+ end
178
+
179
+ def set_cell(row, column, value)
180
+ @row = row(row)
181
+
182
+ @row.get_or_create_cell(column, value).setCellValue((value || ""))
183
+ end
184
+
185
+ def write( filename = nil )
186
+ filename.nil? ? file = @filepath : file = filename
187
+ out = FileOutputStream.new(file)
188
+ @workbook.write(out) unless @workbook.nil?
189
+ out.close
190
+ end
191
+
192
+ alias_method :save, :write
193
+
194
+ def save_to_text( filename )
195
+ File.open( filename, 'w') {|f| f.write(to_s) }
196
+ end
197
+
198
+ def to_s
199
+ outs = ByteArrayOutputStream.new
200
+ @workbook.write(outs);
201
+ outs.close();
202
+ String.from_java_bytes(outs.toByteArray)
203
+ end
204
+
205
+ private
206
+
207
+ def create_sheet_and_set_styles( sheet_name )
208
+ @sheet = @workbook.createSheet( sanitize_sheet_name(sheet_name) )
209
+
210
+ @patriarchs.store(sheet_name, @sheet.createDrawingPatriarch())
211
+
212
+ @date_style = @workbook.createCellStyle
213
+ @date_style.setDataFormat( JExcelFile::date_format )
214
+ @sheet
215
+ end
216
+
217
+ end
218
+
219
+ require 'jexcel_file_extensions'
220
+ require 'apache_poi_extensions'
221
+
222
+ end
@@ -0,0 +1,244 @@
1
+ # Copyright:: Autotelik Media Ltd
2
+ # Author :: Tom Statter
3
+ # Date :: July 2010
4
+ # License::
5
+ #
6
+ # Details:: A helper module providing shortcuts for manipulating Excel files.
7
+ #
8
+
9
+ if(DataShift::Guards::jruby?)
10
+
11
+ JExcelFile.class_eval do
12
+
13
+ include_class 'org.apache.poi.hssf.util.HSSFColor'
14
+
15
+ # Return the current active sheet
16
+ # If term supplied find sheet and set active
17
+ #
18
+ def active_worksheet(term = nil)
19
+ if( term.nil? )
20
+ @sheet ||= @workbook.getSheetAt(@current_sheet_index)
21
+ else
22
+ activate_sheet(term)
23
+ end if(@workbook)
24
+ @sheet
25
+ end
26
+
27
+ # Populate a row of cells with data in an array
28
+ # where the co-ordinates relate to row/column start position
29
+ #
30
+ def set_row( row, col, data, sheet_num = nil)
31
+
32
+ sheet(sheet_num)
33
+
34
+ create_row(row)
35
+
36
+ column = col
37
+ data.each do |datum|
38
+ set_cell(row, column, datum)
39
+ column += 1
40
+ end
41
+ end
42
+
43
+ def headers=( headers )
44
+ headers.each_with_index do |header, column|
45
+ self[0, column] = (header || "")
46
+ end
47
+ end
48
+
49
+ # Convert array into a header row
50
+ def set_headers(headers, apply_style = nil)
51
+ create_row(0)
52
+ return if headers.empty?
53
+
54
+ style = apply_style || header_style()
55
+
56
+ headers.each_with_index do |datum, i|
57
+ c = @row.createCell(i, poi_cell_type(datum))
58
+ c.setCellValue(datum)
59
+ c.setCellStyle(style)
60
+ end
61
+ end
62
+
63
+ attr_writer :header_background_colour
64
+
65
+ def header_background_colour
66
+ @header_background_colour ||= org.apache.poi.hssf.util.HSSFColor::LIGHT_CORNFLOWER_BLUE.index
67
+ end
68
+
69
+ def header_style
70
+ return @header_style if @header_style
71
+ @header_style = @workbook.createCellStyle();
72
+ @header_style.setBorderTop(6) # double lines border
73
+ @header_style.setBorderBottom(1) # single line border
74
+ @header_style.setFillBackgroundColor(header_background_colour)
75
+
76
+ @header_style
77
+ end
78
+
79
+ def add_comment( cell, text )
80
+ raise "Please supply valid HSSFCell" unless cell.respond_to?('setCellComment')
81
+ return if @sheet.nil?
82
+
83
+ patriarch = @patriarchs[@sheet.getSheetName()]
84
+
85
+ anchor = HSSFClientAnchor.new(100, 50, 100, 50, cell.getColumnIndex(), cell.getRowIndex(), cell.getColumnIndex()+3, cell.getRowIndex()+4)
86
+ comment = patriarch.createCellComment(anchor)
87
+
88
+ comment_text = HSSFRichTextString.new(text)
89
+ comment.setString(comment_text)
90
+ comment.setAuthor("Mapping")
91
+
92
+ cell.setCellComment(comment)
93
+ end
94
+
95
+ # Get a percentage style
96
+ def getPercentStyle()
97
+ if (@percentCellStyle.nil? && @workbook)
98
+ @percentCellStyle = @workbook.createCellStyle();
99
+ @percentCellStyle.setDataFormat(HSSFDataFormat.getBuiltinFormat("0.00%"));
100
+ end
101
+ return @percentCellStyle
102
+ end
103
+
104
+ # Auto size either the given column index or all columns
105
+ def autosize(column = nil)
106
+ return if @sheet.nil?
107
+ if (column.kind_of? Integer)
108
+ @sheet.autoSizeColumn(column)
109
+ else
110
+ @sheet.getRow(0).cellIterator.each{|c| @sheet.autoSizeColumn(c.getColumnIndex)}
111
+ end
112
+ end
113
+
114
+ def create_freeze_pane(row=1, column=0)
115
+ return if @sheet.nil?
116
+ @sheet.createFreezePane(row, column)
117
+ end
118
+
119
+
120
+ # Use execute to run sql query provided
121
+ # and write to a csv file (path required)
122
+ # header row is optional but default is on
123
+ # Auto mapping of specified columns is optional
124
+ # @mappings is a hash{column => map} of columns to a map{old_value => new_value}
125
+ def results_to_sheet( results, sheet, mappings=nil, header=true)
126
+ numrows = results.length
127
+ sheet_name = sheet
128
+
129
+ if (numrows == 0)
130
+ log :info, "WARNING - results are empty nothing written to sheet: #{sheet}"
131
+ return
132
+ end
133
+
134
+ #Check if we need to split the results into seperate sheets
135
+ if (numrows > @@maxrows )
136
+ startrow = 0
137
+ while (numrows > 0)
138
+ # Split the results and write to a new sheet
139
+ next_results = results.slice(startrow, @@maxrows > numrows ? numrows : @@maxrows)
140
+ self.results_to_sheet(next_results, "#{sheet_name}", mappings, header) if next_results
141
+
142
+ # Increase counters
143
+ numrows -= next_results.length
144
+ startrow += next_results.length
145
+ sheet_name += 'I'
146
+ end
147
+ else
148
+ log :info, "Writting #{numrows} rows to : #{sheet_name}"
149
+ # Create required sheet
150
+ self.create(sheet)
151
+
152
+ row_index = self.num_rows
153
+ # write header line
154
+ if (header && row_index==0 )
155
+ header_row = @sheet.createRow(row_index)
156
+ cell_index = 0
157
+ results[0].keys.each{ |h|
158
+ header_row.createCell(cell_index).setCellValue("#{h}")
159
+ @sheet.setDefaultColumnStyle(cell_index, self.getPercentStyle) if "#{h}".include? '%'
160
+ cell_index += 1
161
+ }
162
+ # Freeze the header row
163
+ @sheet.createFreezePane( 0, 1, 0, 1 )
164
+ row_index += 1
165
+ end
166
+
167
+ # write_results
168
+ results.each{ |row|
169
+ sheet_row = @sheet.createRow(row_index)
170
+ cell_index = 0
171
+ row.each{|k,v|
172
+ celltype = v.kind_of?(Numeric) ? HSSFCell::CELL_TYPE_NUMERIC : HSSFCell::CELL_TYPE_STRING
173
+ cell = sheet_row.createCell(cell_index, celltype)
174
+
175
+ v.nil? ? value = "<NIL>" : value = v
176
+
177
+ cell.setCellValue(value)
178
+
179
+ cell_index +=1
180
+ }
181
+ #puts "#{sheet}: written row #{row_index}"
182
+ row_index +=1
183
+ }
184
+ end
185
+ end
186
+
187
+ module ExcelHelper
188
+ require 'java'
189
+
190
+ java_import 'org.apache.poi.poifs.filesystem.POIFSFileSystem'
191
+ java_import 'org.apache.poi.hssf.usermodel.HSSFCell'
192
+ java_import 'org.apache.poi.hssf.usermodel.HSSFWorkbook'
193
+ java_import 'org.apache.poi.hssf.usermodel.HSSFCellStyle'
194
+ java_import 'org.apache.poi.hssf.usermodel.HSSFDataFormat'
195
+ java_import 'java.io.ByteArrayOutputStream'
196
+ java_import 'java.util.Date'
197
+
198
+ # ActiveRecord Helper - Export model data to XLS file format
199
+ #
200
+ def to_xls(items=[])
201
+
202
+ @excel = ExcelFile.new(items[0].class.name)
203
+
204
+ @excel.create_row(0)
205
+
206
+ sheet = @excel.sheet
207
+
208
+ # header row
209
+ if !items.empty?
210
+ row = sheet.createRow(0)
211
+ cell_index = 0
212
+ items[0].class.columns.each do |column|
213
+ row.createCell(cell_index).setCellValue(column.name)
214
+ cell_index += 1
215
+ end
216
+ end
217
+
218
+ # value rows
219
+ row_index = 1
220
+ items.each do |item|
221
+ row = sheet.createRow(row_index);
222
+
223
+ cell_index = 0
224
+ item.class.columns.each do |column|
225
+ cell = row.createCell(cell_index)
226
+ if column.sql_type =~ /date/ then
227
+ millis = item.send(column.name).to_f * 1000
228
+ cell.setCellValue(Date.new(millis))
229
+ cell.setCellStyle(dateStyle);
230
+ elsif column.sql_type =~ /int/ then
231
+ cell.setCellValue(item.send(column.name).to_i)
232
+ else
233
+ value = item.send(column.name)
234
+ cell.setCellValue(item.send(column.name)) unless value.nil?
235
+ end
236
+ cell_index += 1
237
+ end
238
+ row_index += 1
239
+ end
240
+ @excel.to_s
241
+ end
242
+ end
243
+ end
244
+ end