datashift 0.9.0 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +63 -64
- data/Rakefile +4 -7
- data/VERSION +1 -1
- data/datashift.gemspec +92 -62
- data/lib/applications/apache_poi_extensions.rb +62 -0
- data/lib/applications/excel.rb +78 -0
- data/lib/applications/excel_base.rb +65 -0
- data/lib/applications/jexcel_file.rb +222 -0
- data/lib/applications/jexcel_file_extensions.rb +244 -0
- data/lib/applications/jruby/{jexcel_file.rb → old_pre_proxy_jexcel_file.rb} +0 -0
- data/lib/applications/ruby_poi_translations.rb +64 -0
- data/lib/applications/spreadsheet_extensions.rb +31 -0
- data/lib/datashift/method_details_manager.rb +4 -0
- data/lib/exporters/csv_exporter.rb +3 -1
- data/lib/exporters/excel_exporter.rb +59 -74
- data/lib/generators/excel_generator.rb +70 -74
- data/lib/guards.rb +57 -0
- data/lib/loaders/excel_loader.rb +105 -105
- data/lib/loaders/loader_base.rb +43 -21
- data/lib/loaders/paperclip/attachment_loader.rb +104 -0
- data/lib/loaders/paperclip/datashift_paperclip.rb +78 -0
- data/lib/loaders/paperclip/{image_loader.rb → image_loading.rb} +2 -18
- data/lib/thor/{generate_excel.thor → generate.thor} +48 -0
- data/lib/thor/paperclip.thor +85 -0
- data/lib/thor/tools.thor +23 -2
- data/spec/Gemfile +1 -7
- data/spec/csv_exporter_spec.rb +4 -4
- data/spec/csv_loader_spec.rb +1 -1
- data/spec/excel_exporter_spec.rb +43 -45
- data/spec/excel_generator_spec.rb +132 -60
- data/spec/excel_loader_spec.rb +134 -140
- data/spec/excel_spec.rb +179 -0
- data/spec/fixtures/ProjectsMultiCategoriesHeaderLookup.xls +0 -0
- data/spec/fixtures/config/database.yml +2 -2
- data/spec/fixtures/db/datashift_test_models_db.sqlite +0 -0
- data/spec/{db → fixtures/db}/migrate/20110803201325_create_test_bed.rb +0 -0
- data/spec/fixtures/load_datashift.thor +3 -0
- data/spec/fixtures/models/category.rb +7 -0
- data/spec/fixtures/models/empty.rb +2 -0
- data/spec/fixtures/models/loader_release.rb +10 -0
- data/spec/fixtures/models/long_and_complex_table_linked_to_version.rb +6 -0
- data/spec/fixtures/models/milestone.rb +8 -0
- data/spec/fixtures/models/owner.rb +5 -0
- data/spec/fixtures/models/project.rb +26 -0
- data/spec/fixtures/models/test_model_defs.rb +67 -0
- data/spec/fixtures/models/version.rb +7 -0
- data/spec/loader_spec.rb +4 -3
- data/spec/method_dictionary_spec.rb +7 -6
- data/spec/method_mapper_spec.rb +3 -2
- data/spec/rails_sandbox/.gitignore +15 -0
- data/spec/rails_sandbox/Gemfile +40 -0
- data/spec/rails_sandbox/README.rdoc +261 -0
- data/spec/rails_sandbox/Rakefile +7 -0
- data/spec/rails_sandbox/app/assets/images/rails.png +0 -0
- data/spec/rails_sandbox/app/assets/javascripts/application.js +15 -0
- data/spec/rails_sandbox/app/assets/stylesheets/application.css +13 -0
- data/spec/rails_sandbox/app/controllers/application_controller.rb +3 -0
- data/spec/rails_sandbox/app/helpers/application_helper.rb +2 -0
- data/spec/rails_sandbox/app/mailers/.gitkeep +0 -0
- data/spec/rails_sandbox/app/models/.gitkeep +0 -0
- data/spec/rails_sandbox/app/models/category.rb +7 -0
- data/spec/rails_sandbox/app/models/empty.rb +2 -0
- data/spec/rails_sandbox/app/models/loader_release.rb +10 -0
- data/spec/rails_sandbox/app/models/long_and_complex_table_linked_to_version.rb +6 -0
- data/spec/rails_sandbox/app/models/milestone.rb +8 -0
- data/spec/rails_sandbox/app/models/owner.rb +5 -0
- data/spec/rails_sandbox/app/models/project.rb +26 -0
- data/spec/rails_sandbox/app/models/test_model_defs.rb +67 -0
- data/spec/rails_sandbox/app/models/version.rb +7 -0
- data/spec/rails_sandbox/app/views/layouts/application.html.erb +14 -0
- data/spec/rails_sandbox/config.ru +4 -0
- data/spec/rails_sandbox/config/application.rb +62 -0
- data/spec/rails_sandbox/config/boot.rb +6 -0
- data/spec/rails_sandbox/config/database.yml +20 -0
- data/spec/rails_sandbox/config/environment.rb +5 -0
- data/spec/rails_sandbox/config/environments/development.rb +37 -0
- data/spec/rails_sandbox/config/environments/production.rb +67 -0
- data/spec/rails_sandbox/config/environments/test.rb +37 -0
- data/spec/rails_sandbox/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/rails_sandbox/config/initializers/inflections.rb +15 -0
- data/spec/rails_sandbox/config/initializers/mime_types.rb +5 -0
- data/spec/rails_sandbox/config/initializers/secret_token.rb +7 -0
- data/spec/rails_sandbox/config/initializers/session_store.rb +8 -0
- data/spec/rails_sandbox/config/initializers/wrap_parameters.rb +14 -0
- data/spec/rails_sandbox/config/locales/en.yml +5 -0
- data/spec/rails_sandbox/config/routes.rb +58 -0
- data/spec/rails_sandbox/db/migrate/20110803201325_create_test_bed.rb +96 -0
- data/spec/rails_sandbox/db/schema.rb +81 -0
- data/spec/rails_sandbox/db/seeds.rb +7 -0
- data/spec/rails_sandbox/lib/assets/.gitkeep +0 -0
- data/spec/rails_sandbox/lib/tasks/.gitkeep +0 -0
- data/spec/rails_sandbox/log/.gitkeep +0 -0
- data/spec/rails_sandbox/public/404.html +26 -0
- data/spec/rails_sandbox/public/422.html +26 -0
- data/spec/rails_sandbox/public/500.html +25 -0
- data/spec/rails_sandbox/public/favicon.ico +0 -0
- data/spec/rails_sandbox/public/index.html +241 -0
- data/spec/rails_sandbox/public/robots.txt +5 -0
- data/spec/rails_sandbox/script/rails +6 -0
- data/spec/rails_sandbox/test/fixtures/.gitkeep +0 -0
- data/spec/rails_sandbox/test/functional/.gitkeep +0 -0
- data/spec/rails_sandbox/test/integration/.gitkeep +0 -0
- data/spec/rails_sandbox/test/performance/browsing_test.rb +12 -0
- data/spec/rails_sandbox/test/test_helper.rb +13 -0
- data/spec/rails_sandbox/test/unit/.gitkeep +0 -0
- data/spec/rails_sandbox/vendor/assets/javascripts/.gitkeep +0 -0
- data/spec/rails_sandbox/vendor/assets/stylesheets/.gitkeep +0 -0
- data/spec/rails_sandbox/vendor/plugins/.gitkeep +0 -0
- data/spec/spec_helper.rb +144 -121
- data/spec/thor_spec.rb +34 -14
- metadata +207 -194
- data/lib/helpers/spree_helper.rb +0 -213
- data/lib/loaders/spreadsheet_loader.rb +0 -144
- data/lib/loaders/spree/image_loader.rb +0 -90
- data/lib/loaders/spree/product_loader.rb +0 -354
- data/lib/thor/spree/bootstrap_cleanup.thor +0 -61
- data/lib/thor/spree/products_images.thor +0 -252
- data/lib/thor/spree/reports.thor +0 -56
- data/public/spree/products/large/DEMO_001_ror_bag.jpeg +0 -0
- data/public/spree/products/large/DEMO_002_Powerstation.jpg +0 -0
- data/public/spree/products/large/DEMO_003_ror_mug.jpeg +0 -0
- data/public/spree/products/mini/DEMO_001_ror_bag.jpeg +0 -0
- data/public/spree/products/mini/DEMO_002_Powerstation.jpg +0 -0
- data/public/spree/products/mini/DEMO_003_ror_mug.jpeg +0 -0
- data/public/spree/products/original/DEMO_001_ror_bag.jpeg +0 -0
- data/public/spree/products/original/DEMO_002_Powerstation.jpg +0 -0
- data/public/spree/products/original/DEMO_003_ror_mug.jpeg +0 -0
- data/public/spree/products/product/DEMO_001_ror_bag.jpeg +0 -0
- data/public/spree/products/product/DEMO_002_Powerstation.jpg +0 -0
- data/public/spree/products/product/DEMO_003_ror_mug.jpeg +0 -0
- data/public/spree/products/small/DEMO_001_ror_bag.jpeg +0 -0
- data/public/spree/products/small/DEMO_002_Powerstation.jpg +0 -0
- data/public/spree/products/small/DEMO_003_ror_mug.jpeg +0 -0
- data/spec/fixtures/datashift_Spree_db.sqlite +0 -0
- data/spec/fixtures/datashift_test_models_db.sqlite +0 -0
- data/spec/fixtures/negative/SpreeProdMiss1Mandatory.csv +0 -4
- data/spec/fixtures/negative/SpreeProdMiss1Mandatory.xls +0 -0
- data/spec/fixtures/negative/SpreeProdMissManyMandatory.csv +0 -4
- data/spec/fixtures/negative/SpreeProdMissManyMandatory.xls +0 -0
- data/spec/fixtures/spree/SpreeImages.xls +0 -0
- data/spec/fixtures/spree/SpreeMultiVariant.csv +0 -4
- data/spec/fixtures/spree/SpreeProducts.csv +0 -4
- data/spec/fixtures/spree/SpreeProducts.xls +0 -0
- data/spec/fixtures/spree/SpreeProductsDefaults.yml +0 -15
- data/spec/fixtures/spree/SpreeProductsMandatoryOnly.xls +0 -0
- data/spec/fixtures/spree/SpreeProductsMultiColumn.csv +0 -4
- data/spec/fixtures/spree/SpreeProductsMultiColumn.xls +0 -0
- data/spec/fixtures/spree/SpreeProductsSimple.csv +0 -4
- data/spec/fixtures/spree/SpreeProductsSimple.xls +0 -0
- data/spec/fixtures/spree/SpreeProductsWithImages.csv +0 -4
- data/spec/fixtures/spree/SpreeProductsWithImages.xls +0 -0
- data/spec/fixtures/spree/SpreeZoneExample.csv +0 -5
- data/spec/fixtures/spree/SpreeZoneExample.xls +0 -0
- data/spec/spree_exporter_spec.rb +0 -72
- data/spec/spree_generator_spec.rb +0 -96
- data/spec/spree_images_loader_spec.rb +0 -107
- data/spec/spree_loader_spec.rb +0 -375
- data/spec/spree_method_mapping_spec.rb +0 -226
- data/spec/spree_variants_loader_spec.rb +0 -189
- data/tasks/export/excel_generator.rake +0 -102
- data/tasks/import/excel.rake +0 -75
- data/test/helper.rb +0 -18
- 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
|