datashift 0.9.0 → 0.10.0

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