module Reporting
class Base
include ActionController::Pagination
cattr_accessor :template_root
@@template_root = "app/views/reports/"
cattr_accessor :template_name
@@template_name = nil
cattr_accessor :logger
@@logger = nil
cattr_accessor :sql_tables
@@sql_tables = []
cattr_accessor :sql_group_by
@@sql_group_by = ''
cattr_accessor :sql_order_by
@@sql_order_by = ''
cattr_accessor :sql_conditions
@@sql_conditions = ''
cattr_accessor :sql_limit
@@sql_limit = nil
cattr_accessor :sql_offset
@@sql_offset = 0
cattr_accessor :columns_attr
@@columns_attr = {}
attr_accessor :results
attr_accessor :pages
attr_accessor :report_name
attr_accessor :controller
class << self
def generate(controller_name, report_name = 'report', options = {})
report = self.new(controller_name, report_name, options)
report.render_view
end
private
def columns(*args)
@@columns_attr = HashArray.new(args)
end
def conditions(condition)
@@sql_conditions = condition
end
def group_by(group)
@@sql_group_by = group
end
def order_by(order)
@@sql_order_by= order
end
def tables(*args)
@@sql_tables = args.collect {|a| a.to_s }
end
def limit(max)
@@sql_limit = max
end
def offset(off)
@@sql_offset = off
end
def layout(name)
@@template_name = name
end
def template_name
@@template_name || (self == Reporting::Base ? 'default' : self.to_s.underscore)
end
end
def override_sql_options!(options)
default_keys = [:group_by, :order_by, :conditions, :tables, :limit, :offset]
options.symbolize_keys.delete_if {|key, value| !default_keys.include? key }
class_options = {
:conditions => sql_conditions,
:tables => sql_tables,
:group_by => sql_group_by,
:order_by => sql_order_by,
:limit => sql_limit,
:offset => sql_offset
}
class_options.update(options)
end
def initialize(controller_name, report_name, options)
@results, @pages, @report_name, @controller = [], nil, report_name, controller_name
sql = override_sql_options!(options)
main_sql = "FROM #{sql[:tables].join(", ")} " +
(sql[:conditions].blank? ? "" : "WHERE #{sql[:conditions]} ") +
(sql[:order_by].blank? ? "" : "ORDER BY #{sql[:order_by]} ") +
(sql[:group_by].blank? ? "" : "GROUP BY #{sql[:group_by]} ")
if options[:pagination]
# sql[:limit] ||= 10
# options[:page] ||= 1
count = ActiveRecord::Base.count_by_sql "SELECT COUNT(*) #{main_sql}"
@pages = ActionController::Pagination::Paginator.new controller, count, sql[:limit], options[:pagination][:page]
sql[:offset] = @pages.current.offset
end
limit = sql[:limit].blank? ? "" : "LIMIT #{sql[:offset]},#{sql[:limit]}"
ActiveRecord::Base.connection.execute("SELECT #{columns_attr.keys.join(", ")} #{main_sql} #{limit}").each do |row|
hash = HashArray.new
row.each_with_index {|col,i| hash[self.class.columns_attr.keys[i]] = col }
@results << hash
end
# Perform formatting on each column
@results.each_with_index do |row,i|
row.each do |key, value|
next unless respond_to? "format_#{key.to_s.underscore_dots}"
@results[i][key] = send("format_#{key.to_s.underscore_dots}", row)
end
end
end
def render_view
assigns = {
:columns => columns_attr,
:results => results,
:name => report_name,
:pages => pages
}
view = ActionView::Base.new(template_root, assigns, controller)
view.class.class_eval "include Reporting::ReportHelper"
view.render_file template_name
end
end
module ReportHelper
def report_pagination_links
if @pages
html, name = '', @name.underscore
html << report_link_to("<", name => @pages.current.previous) if @pages.current.previous
html << " "
html << pagination_links(@pages, :name => name, :params => report_url_to)
html << " "
html << report_link_to(">", name => @pages.current.next) if @pages.current.next
html
end
end
def report_descending_link(key, name = "v", html_options = {})
report_link_to name, { report_order => key, report_dir => 0 }, html_options
end
def report_ascending_link(key, name = "^", html_options = {})
report_link_to name, { report_order => key, report_dir => 1 }, html_options
end
def report_order
"#{@name.underscore}_order"
end
def report_dir
"#{@name.underscore}_dir"
end
def report_link_to(name, options = {}, html_options = {})
link_to name, report_url_to.update(options), html_options
end
def report_url_to
{
report_order => controller.params[report_order],
report_dir => controller.params[report_dir],
@name.underscore => controller.params[@name.underscore],
:anchor => @name.underscore
}
end
end
end
class String
def underscore_dots
gsub('.','_')
end
end
class HashArray
def initialize(*args)
@hash = Hash[*args.flatten]
if args.empty?
@data = []
else
@data = *args
end
end
def [](key)
if key.is_a?(Fixnum) and hash.has_key?(key)
@data[key].last
else
@hash[key]
end
end
def []=(key, value)
if @hash.has_key? key
@data.each_with_index do |e,i|
if e.first == key
@data[i][1] = value
end
end
else
@data << [ key, value ]
end
@hash[key] = value
end
def each(&block)
@data.each {|e| yield(e.first, e.last) }
end
def each_with_index(&block)
@data.each_with_index {|e,i| yield(e.last, i) }
end
def keys
@data.collect {|e| e.first }
end
def values
@data.collect {|e| e.last }
end
end Powered by
GeSHi Syntax Highlighting software.
Author of all (other) material unless otherwise specified:
Loren Segal. Copyright 2005.