Ruby Report

A simple report generator

Installation

Add this line to your application’s Gemfile:

gem "ruby_report"
gem "caxlsx" # optional: for generate xlsx

And then execute:

bundle install

Usage

Create class

class UserReport < RubyReport::Report
  columns :name, :age, :role, :created_at
end

Initialize object with data

# data is ActiveRecords or array of objects
report = UserReport.new(data: User.all)

Generate report

# Hash
report.to_h # {header: ["Name", "Age", "Role"], rows: [["Sasha", 18, "Student"]]}

# CSV
report.to_csv # IOString

# XLSX
report.to_xlsx(worksheet_name: "Worksheet") # IOString

Details

Get header

report.header # ["Name", "Age", "Role"]

Default translates for header get from i18n

I18n.t("ruby_reports.#{report.class.name.underscore}.headers.#{key}")

Determine custom header

UserReport.new(data: data, header_builder: ->(key, _report) { "Custom #{key}" })

Get rows

report.rows # [["Sasha", 18, "Student"], ["Jack", 30, "Worker"]]

Select columns

report = UserReport.new(data: data, columns: [:name, :age])
report.headers #["Name", "Age"]
report.rows #[["Sasha", 18], ["Jack", 30]]

Custom row

UserReport.new(data: data, row_resolver: ->(row) { row.user })

Custom row builder

UserReport.new(data: data, row_builder: ->(_row, _key, _report) { "" })

Decorators

class UserDecorator < RubyReport::Decorator
  def role
    I18n.t("roles.#{object.role}")
  end
end

class UserReport < RubyReport::Report
  columns :name, :age, :role, decorators: [UserDecorator]
end

Formatters

class TimeFormatter < RubyReport::Formatter
  def format(value)
    return value unless [::Time, ActiveSupport::TimeWithZone].include?(value.class)
    value.utc.to_formatted_s(:report)
  end
end

class UserReport < RubyReport::Report
  columns :name, :age, :role, :created_at, formatters: [TimeFormatter]
end

Decorator and Formatter with scope

class UserDecorator < RubyReport::Decorator
  def role
    I18n.t("roles.#{object.role}", account_name: scope[:account].name)
  end
end

report = UserReport.new(data: users, scope: {account: account})

Append/prepend other reports

class AccountReport < RubyReport::Report
  columns :name
end

class AddressReport < RubyReport::Report
  columns :street
end

user_report.prepend_report(account_report)
user_report.add_report(address_report)

XLSX with any worksheets

require "ruby_report/generator/xlsx"

generator = RubyReport::Generator::Xlsx.new
generator.add_report(report, worksheet_name: "Worksheet 1")
generator.add_report(other_report, worksheet_name: "Worksheet 2")
generator.generate # IOString