require "datagrid/utils"
module Datagrid
class OrderUnsupported < StandardError
end
module Columns
require "datagrid/columns/column"
def self.included(base)
base.extend ClassMethods
base.class_eval do
include Datagrid::Core
datagrid_attribute :order do |value|
unless value.blank?
value = value.to_sym
column = column_by_name(value)
unless column
order_unsupported(value, "no column #{value} in #{self.class}")
end
unless column.order
order_unsupported(
name, "#{self.class}##{name} don't support order"
)
end
value
else
nil
end
end
datagrid_attribute :descending do |value|
Datagrid::Utils.booleanize(value)
end
end
base.send :include, InstanceMethods
end # self.included
module ClassMethods
def columns
@columns ||= []
end
def column(name, options = {}, &block)
check_scope_defined!("Scope should be defined before columns")
block ||= lambda do |model|
model.send(name)
end
self.columns << Datagrid::Columns::Column.new(self, name, options, &block)
end
def order_unsupported(name, reason)
raise Datagrid::OrderUnsupported, "Can not sort #{self.inspect} by ##{name}: #{reason}"
end
def column_by_name(name)
self.columns.find do |col|
col.name.to_sym == name.to_sym
end
end
end # ClassMethods
module InstanceMethods
# Returns Array of human readable column names. See also "Localization" section
def header
self.class.columns.map(&:header)
end
# Returns Array column values for given asset
def row_for(asset)
self.class.columns.map do |column|
column.value(asset, self)
end
end
# Returns Hash where keys are column names and values are column values for the given asset
def hash_for(asset)
result = {}
self.class.columns.each do |column|
result[column.name] = column.value(asset, self)
end
result
end
def rows
self.assets.map do |asset|
self.row_for(asset)
end
end
def data
self.rows.unshift(self.header)
end
def data_hash
self.assets.map do |asset|
hash_for(asset)
end
end
def assets
result = super
if self.order
column = column_by_name(self.order)
result = result.order(self.descending ? column.desc_order : column.order)
end
result
end
def to_csv(options = {})
klass = if RUBY_VERSION >= "1.9"
require 'csv'
CSV
else
require "fastercsv"
FasterCSV
end
klass.generate(
{:headers => self.header, :write_headers => true}.merge(options)
) do |csv|
self.rows.each do |row|
csv << row
end
end
end
def columns
self.class.columns
end
def column_by_name(name)
self.class.column_by_name(name)
end
end # InstanceMethods
end
end