lib/exporters/excel_exporter.rb in datashift-0.16.0 vs lib/exporters/excel_exporter.rb in datashift-0.40.0

- old
+ new

@@ -1,130 +1,149 @@ -# Copyright:: (c) Autotelik Media Ltd 2011 +# Copyright:: (c) Autotelik Media Ltd 2016 # Author :: Tom Statter -# Date :: Aug 2011 +# Date :: Mar 2016 # License:: MIT # # Details:: Export a model to Excel '97(-2007) file format. # -# TOD : Can we switch between .xls and XSSF (POI implementation of Excel 2007 OOXML (.xlsx) file format.) +# TODO: Can we switch between .xls and XSSF (POI implementation of Excel 2007 OOXML (.xlsx) file format.) # # module DataShift - require 'exporter_base' - - require 'excel' - class ExcelExporter < ExporterBase include DataShift::Logging include DataShift::ColumnPacker - def initialize(filename) - @filename = filename + include DataShift::ExcelBase + + # Optional, otherwise uses the standard collection of Model Methods for supplied klass + attr_accessor :data_flow_schema + + def initialize + super + + @data_flow_schema = nil end # Create an Excel file from list of ActiveRecord objects - def export(export_records, options = {}) + def export(file_name, export_records, options = {}) + @file_name = file_name + records = [*export_records] - unless(records && records.size > 0) - logger.warn("No objects supplied for export") + if(records.nil? || records.empty?) + logger.warn('Excel Export - No objects supplied for export - no file written') return end first = records[0] - logger.info("Exporting #{records.size} #{first.class} to Excel") + raise(ArgumentError, 'Please supply set of ActiveRecord objects to export') unless first.is_a?(ActiveRecord::Base) - raise ArgumentError.new('Please supply set of ActiveRecord objects to export') unless(first.is_a?(ActiveRecord::Base)) + klass = first.class + excel = start_excel(klass, options) - raise ArgumentError.new('Please supply array of records to export') unless records.is_a? Array + prepare_data_flow_schema(klass) - excel = Excel.new + export_headers(klass) - if(options[:sheet_name] ) - excel.create_worksheet( :name => options[:sheet_name] ) - else - excel.create_worksheet( :name => records.first.class.name ) - end + logger.info("Exporting #{records.size} #{klass} to Excel") - excel.ar_to_headers(records) - excel.ar_to_xls(records) - excel.write( filename() ) + logger.info("Writing Excel to file [#{file_name}]") + + excel.write( file_name ) end + def export_headers(klass) + + headers = if(data_flow_schema) + data_flow_schema.sources + else + Headers.klass_to_headers(klass) + end + + excel.set_headers( headers ) + + logger.info("Wrote headers for #{klass} to Excel") + headers + end + + def prepare_data_flow_schema(klass) + @data_flow_schema = DataShift::DataFlowSchema.new + @data_flow_schema.prepare_from_klass( klass ) + + data_flow_schema + end + # Create an Excel file from list of ActiveRecord objects, includes relationships # - # Options + # The Associations/relationships to include are driven by Configuration Options # - # only Specify (as symbols) columns (assignments) to export from klass - # with: Specify which association types to export :with - # Possible values are : [:assignment, :belongs_to, :has_one, :has_many] - # with_only Specify (as symbols) columns for association types to export - # sheet_name Else uses Class name - # json: Export association data in single column in JSON format + # See - lib/exporters/configuration.rb # - def export_with_associations(klass, records, options = {}) + def export_with_associations(file_name, klass, records, options = {}) - records = [*records] + state = DataShift::Configuration.call.with - only = options[:only] ? [*options[:only]] : nil + DataShift::Configuration.call.with = :all - excel = Excel.new + @file_name = file_name - if(options[:sheet_name] ) - excel.create_worksheet( :name => options[:sheet_name] ) - else - excel.create_worksheet( :name => records.first.class.name ) - end + excel = start_excel(klass, options) - MethodDictionary.find_operators( klass ) + logger.info("Processing [#{records.size}] #{klass} records to Excel") - MethodDictionary.build_method_details( klass ) + prepare_data_flow_schema(klass) - # For each type belongs has_one, has_many etc find the operators - # and create headers, then for each record call those operators - operators = options[:with] || MethodDetail::supported_types_enum + export_headers(klass) - excel.ar_to_headers( records, operators, options) + nodes = data_flow_schema.nodes - details_mgr = MethodDictionary.method_details_mgrs[klass] - row = 1 records.each do |obj| - column = 0 - [*operators].each do |op_type| # belongs_to, has_one, has_many etc + nodes.each do |node| - operators_for_type = details_mgr.get_list(op_type) + logger.info("Send to Excel: #{node.inspect}") - next if(operators_for_type.nil? || operators_for_type.empty?) + model_method = node.model_method - operators_for_type.each do |md| # actual associations on obj + logger.info("Send to Excel: #{model_method.pp}") - next if(only && !only.include?( md.name.to_sym ) ) - - if(MethodDetail.is_association_type?(op_type)) - excel[row, column] = record_to_column( obj.send( md.operator ), options ) # pack association into single column + begin + # pack association instances into single column + if model_method.association_type? + logger.info("Processing #{model_method.inspect} associations") + excel[row, column] = record_to_column( obj.send( model_method.operator ), configuration.json ) else - excel[row, column] = obj.send( md.operator ) + excel[row, column] = obj.send( model_method.operator ) end - column += 1 + rescue => x + logger.error("Failed to write #{model_method.inspect} to Excel") + logger.error(x.inspect) end + + column += 1 end row += 1 end - excel.write( filename() ) + logger.info("Writing Excel to file [#{file_name}]") + excel.write( file_name ) + ensure + DataShift::Configuration.call.with = state + end + end # ExcelGenerator -end # DataShift \ No newline at end of file +end # DataShift