lib/decisive/template_handler.rb in decisive-0.7.1 vs lib/decisive/template_handler.rb in decisive-0.8.0
- old
+ new
@@ -1,10 +1,11 @@
-require "csv"
require "action_view"
-require "active_support/core_ext/string/inflections"
-require "spreadsheet"
+require "decisive/stream_csv_context"
+require "decisive/render_csv_context"
+require "decisive/render_xls_context"
+
module Decisive
class TemplateHandler
def self.register
ActionView::Template.register_template_handler 'decisive', self
end
@@ -31,11 +32,11 @@
else
context.to_csv(force_quotes: true)
end
else
- response.headers["Content-Type"] = "application/vnd.ms-excel"
+ response.headers["Content-Type"] = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
context.to_xls
end
RUBY
end
end
@@ -55,223 +56,17 @@
module DSL
def csv records, filename:, stream: true, &block
if stream
raise StreamingNotEnabledByControllerError unless controller.is_a?(ActionController::Live)
raise StreamIncompatibleBlockArgumentError if block.arity != 0
- StreamContext.new([], records, filename, &block)
+ StreamCSVContext.new(records, filename, block)
else
- RenderContext.new(records, filename, block)
+ RenderCSVContext.new(records, filename, block)
end
end
def xls worksheets=nil, filename:, &block
- if worksheets
- XLSContext.new(worksheets, filename, block)
- else
- XLSWithWorksheetsContext.new(filename, [], &block)
- end
- end
- end
-
- class XLSWithWorksheetsContext < Struct.new(:filename, :worksheets)
- class Worksheet < Struct.new(:records, :name, :block); end
-
- def initialize *args, &block
- super
- instance_eval &block
- end
-
- def to_xls
- to_string(render(Spreadsheet::Workbook.new))
- end
-
- def csv?
- false
- end
-
- private
-
- def worksheet records, name:, &block
- worksheets.push Worksheet.new(records, name, block)
- end
-
- def render xls
- worksheets.each do |worksheet|
- sheet = xls.create_worksheet(name: sanitize_name(worksheet.name))
-
- rows = to_array(worksheet)
-
- rows.each.with_index do |row, index|
- sheet.row(index).concat row
- end
- end
- xls
- end
-
- def sanitize_name name
- name
- .gsub(/[\[\]\*\?:\/\\\t\n\r]/, " ")
- .gsub(/^'/, "")
- .gsub(/'$/, "")
- .strip
- .slice(0,31)
- end
-
- def to_array worksheet
- context = RenderContext.new(worksheet.records, nil, worksheet.block)
- context.send(:header) + context.send(:body)
- end
-
- def to_string xls
- io = StringIO.new
- xls.write(io)
- io.rewind
- string = io.read
- string.force_encoding(Encoding::ASCII_8BIT)
- string
- end
- end
-
-
- class XLSContext < Struct.new(:worksheets, :filename, :block)
- def to_xls
- to_string(render(Spreadsheet::Workbook.new))
- end
-
- def csv?
- false
- end
-
- private
-
- def render xls
- worksheets.each do |name, enumerable|
- sheet = xls.create_worksheet(name: sanitize_name(name))
-
- rows = to_array(enumerable)
-
- rows.each.with_index do |row, index|
- sheet.row(index).concat row
- end
- end
- xls
- end
-
- def sanitize_name name
- name
- .gsub(/[\[\]\*\?:\/\\\t\n\r]/, " ")
- .gsub(/^'/, "")
- .gsub(/'$/, "")
- .strip
- .slice(0,31)
- end
-
- def to_array records
- context = RenderContext.new(records, nil, block)
- context.send(:header) + context.send(:body)
- end
-
- def to_string xls
- io = StringIO.new
- xls.write(io)
- io.rewind
- string = io.read
- string.force_encoding(Encoding::ASCII_8BIT)
- string
- end
- end
-
- class StreamContext < Struct.new(:columns, :records, :filename)
- class Column < Struct.new(:label, :block); end
-
- def initialize *args, &block
- super
- instance_eval &block
- end
-
- def column label, value=nil, &block # field, label: field.to_s.humanize, &block
- value ||= label.parameterize.underscore.to_sym
- block ||= ->(record) { record.send(value) }
- columns << Column.new(label, block)
- end
-
- def each
- yield header
-
- records.map do |record|
- row = columns.map do |column|
- column.block.call(record).to_s
- end
- yield row
- end
- end
-
- def csv?
- true
- end
-
- private
-
- def header
- columns.map(&:label)
- end
- end
-
- class RenderContext < Struct.new(:records, :filename, :block)
- def to_csv(*args, **kwargs)
- (header + body).map do |row|
- row.to_csv(*args, **kwargs)
- end.join
- end
-
- def csv?
- true
- end
-
- private
-
- def header
- [keys]
- end
-
- def body
- hashes.map do |hash|
- hash.values_at(*keys)
- end
- end
-
- def keys
- @keys ||= hashes.flat_map(&:keys).uniq
- end
-
- def hashes
- @hashes ||= records.map do |record|
- Row.new(record, block).to_hash
- end
- end
-
- class Row < Struct.new(:record, :block)
- module Nothing; end
-
- def to_hash
- @hash = {}
- instance_exec record, &block
- @hash
- end
-
- private
-
- def column key, value=Nothing, &block
- @hash[key] = if block_given?
- block.call(record)
- elsif value.is_a?(Symbol)
- record.send(value)
- elsif value == Nothing
- record.send(key.parameterize.underscore.to_sym)
- else
- value
- end.to_s
- end
+ RenderXLSContext.new(worksheets, filename, block)
end
end
end