{"id":16820278,"url":"https://github.com/dvandersluis/compendium","last_synced_at":"2025-09-12T05:41:57.768Z","repository":{"id":41003625,"uuid":"12467750","full_name":"dvandersluis/compendium","owner":"dvandersluis","description":"Ruby on Rails reporting framework","archived":false,"fork":false,"pushed_at":"2019-08-27T21:59:55.000Z","size":281,"stargazers_count":83,"open_issues_count":4,"forks_count":19,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-08-11T02:35:36.727Z","etag":null,"topics":["reporting","reporting-engine"],"latest_commit_sha":null,"homepage":null,"language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dvandersluis.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-08-29T18:21:21.000Z","updated_at":"2024-09-09T02:15:16.000Z","dependencies_parsed_at":"2022-09-05T15:31:35.828Z","dependency_job_id":null,"html_url":"https://github.com/dvandersluis/compendium","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/dvandersluis/compendium","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dvandersluis%2Fcompendium","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dvandersluis%2Fcompendium/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dvandersluis%2Fcompendium/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dvandersluis%2Fcompendium/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dvandersluis","download_url":"https://codeload.github.com/dvandersluis/compendium/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dvandersluis%2Fcompendium/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274759115,"owners_count":25343872,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-12T02:00:09.324Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["reporting","reporting-engine"],"created_at":"2024-10-13T10:56:07.112Z","updated_at":"2025-09-12T05:41:57.721Z","avatar_url":"https://github.com/dvandersluis.png","language":"Ruby","readme":"# Compendium [![Gem Version](https://badge.fury.io/rb/compendium.svg)](http://badge.fury.io/rb/compendium) [![Build Status](https://travis-ci.org/dvandersluis/compendium.svg?branch=master)](https://travis-ci.org/dvandersluis/compendium)\n\nRuby on Rails framework for making reporting easy.\n\n## Usage\n\nCompendium is a reporting framework for Rails which makes it easy to create and render reports (with charts and tables). Compendium requires at least Ruby version 2.2.\n\nA Compendium report is a subclass of `Compendium::Report`. Reports can be defined using the simple DSL:\n\n```ruby\nclass MyReport \u003c Compendium::Report\n  # Options define which parameters your report will accept when being set up.\n  # An option is defined with a name, a type, and some settings (ie. default value, choices for radio buttons and\n  # dropdowns, etc.)\n  option :starting_on, :date, default: -\u003e { Date.today - 1.month }\n  option :ending_on, :date, default: -\u003e { Date.today }\n  option :currency, :radio, choices: [:USD, :CAD, :GBP]\n\n  # By default, queries are converted to SQL and executed instead of returning AR models\n  # The query definition block gets the report's current parameters\n  # totals: true means that the last row returned should be interpretted as a row of totals\n  query :deliveries, totals: true do |params|\n    Items.where(delivered: true, purchased_at: (params[:starting_on]..params[:ending_on]))\n  end\n\n  # Define a filter to modify the results from specified query (in this case :deliveries)\n  # For example, this can be useful to translate columns prior to rendering, as it will apply\n  # for all render types (table, chart, JSON)\n  # Note: A filter can be applied to multiple queries at once\n  filter :deliveries do |results, params|\n    results.each do |row|\n      row['price'] = sprintf('$%.2f', row['price'])\n    end\n  end\n\n  # Define a query which collects data by using AR directly\n  query :on_hand_inventory, collect: :active_record do |params|\n    Items.where(in_stock: true)\n  end\n\n  # Define a query that works on another query's result set\n  # Note: chart and data are aliases for query\n  chart :deliveries_over_time, through: :deliveries do |results|\n    results.group_by(\u0026:purchased_at)\n  end\n\n  # Queries can also be used to drive metrics\n  metric :shipping_time, -\u003e results { results.last['shipping_time'] }, through: :deliveries\nend\n```\n\nReports can then also be simply instantiated (which is done automatically if using the supplied\n`Compendium::ReportsController`):\n\n```ruby\nreport = MyReport.new(starting_on: '2013-06-01')\nreport.run(self) # The parameter is the context to run the report in; usually this should be\n                 # a controller context so that methods like current_user can be used\n```\n\nCompendium also comes with a variety of different presenters, for rendering the setup page, and displaying charts\n(`report.render_chart`), tables (`report.render_table`) and metrics for your report. Charting is delegated through a\n`ChartProvider` to a charting gem (amcharts.rb is currently supported).\n\n### Report Options\nReport options are defined by the keyword `option` in your report class. Options must have a name and a type (scalar, boolean, date, dropdown or radio). Additionally, an option can have a default value (given by a proc passed in with the `default:` key), and validations (via the `validates:` key).\n\nIn order to specify parameters for the options, pass a hash to `MyReport.new`. Parameters are available via `params`:\n\n```ruby\nr = MyReport.new(starting_on: Date.today - 3.months, ending_on: Date.today)\nr.params\n\n# {\n#   \"starting_on\"=\u003eSun, 30 Aug 2015,\n#   \"ending_on\"=\u003eMon, 30 Nov 2015,\n# }\n```\n\n#### Validation\n\nIf validation is set up on any options, calling `valid?` on the report will validate any given parameters against the validations set up, and will populate an errors object. All validations provided by `ActiveModel::Validations` are available.\n\n```ruby\nclass MyReport \u003c Compendium::Report\n  options :starting_on, :date, validates: { presence: true }\nend\n\nr = MyReport.new\nr.valid?\n# =\u003e false\n\nr.errors\n# =\u003e #\u003cActiveModel::Errors:0x007fe8359cc6b8\n#  @base={\"starting_on\"=\u003enil},\n#  @messages={:starting_on=\u003e[\"This field is required.\"]}\u003e\n```\n\n### Query types\n\nCompendium provides a few types of queries in order to make report writing more streamlined.\n\n#### Through Queries\n\nA **through query** lets you use the results of a previous query (or multiple queries) as the basis of your query. This lets you build on another query or combine multiple query's results into a single query. It it specified by passing the `through:` key to `query`, with a query name or array or query names (as symbols).\n\n```ruby\nquery :dog_sales { |params| Order.where(pet_type: 'dog', created_at: params[:starting_on]..params[:ending_on]) }\nquery :cat_sales { |params| Order.where(pet_type: 'cat', created_at: params[:starting_on]..params[:ending_on]) }\nquery :bird_sales { |params| Order.where(pet_type: 'bird', created_at: params[:starting_on]..params[:ending_on]) }\n\nquery :total_sales, through: [:dog_sales, :cat_sales, :bird_sales] do |results, params|\n  # results is a hash with keys :dog_sales, :cat_sales, :bird_sales\nend\n```\n\n#### Count Queries\n\nA **count query** simplifies creating a query where you want a count (especially per group of something). A count query is specified by adding `count: true` to the `query` call.\n\n```ruby\nquery :sales_per_day, count: true do\n  Order.group(\"DATE(created_at)\")\nend\n\n# results will look something like\n# { 2015-10-01 =\u003e 4, 2015-10-02 =\u003e 20, ... }\n```\n\n#### Sum Queries\n\nLike a count query, a **sum query** is useful for performing an aggregate function on a grouped query, in this case summing the results. A sum query is specified by adding \u003ccode\u003esum: \u003ci\u003e:column_name\u003c/i\u003e\u003c/code\u003e to the `query` call.\n\n```ruby\nquery :commission_per_salesperson, sum: 'commission' do\n  # assume commission is a numeric column\n  Order.group(:employee_id)\nend\n\n# results will be something like\n# { 1 =\u003e 840.34, 2 =\u003e 1065.02, ... }\n```\n\n#### Collection Queries\n\nSometimes you'll want to run a collection over a collection of data; for this, you can use a **collection query**. A collection query will perform the same query for each element of a hash or array, or for each result of a query. A collection is specified via `collection: [...]`, `collection: { ... }` or `collection: query` (note not a symbol but an actual query object).\n\n### Tying into your Rails application\n\nCompendium has a `Rails::Engine`, which adds a default controller and some views. If desired, the controller can be\nsubclassed so that filters and the like can be added. The controller (which extends `ApplicationController`\nautomatically) has two actions: `setup` (collect options for the report) and `run` (execute and render the report),\nwith accompanying views. The `setup` view can be included inside your own view using the `render_report_setup`\nmethod (*NOTE:* you have to pass `local_assigns` into it if you want locals to be passed along).\n\nRoutes are not automatically added to your application. In order to do so, you can use the `mount_compendium` helper\nwithin your `config/routes.rb` file\n\n```ruby\nmount_compendium at: '/report', controller: 'reports' # controller defaults to compendium/reports\n```\n\n### Rendering report results in other formats\n\n#### JSON\n\nWhile the default action when running a report is to render a view with the results, Compendium reports can be rendered\nas JSON. If using the default routes provided by `mount_compendium` (assuming compendium was mounted at `/report`),\n`GET`ing or `POST`ing to \u003ccode\u003ereport/\u003ci\u003ereport_name\u003c/i\u003e.json\u003c/code\u003e will return the report results as JSON. You can also collect\nthe results of a single query (instead of the entire report) by `GET`ing or `POST`ing to\n\u003ccode\u003ereport/\u003ci\u003ereport_name\u003c/i\u003e/\u003ci\u003equery_name\u003c/i\u003e.json\u003c/code\u003e.\n\n#### CSV\n\nA report can be exported as CSV. In order to enable CSV exports, a query needs to be defined as the exporter\nfor the report. Note that only one query can be exported, because otherwise there's no way to ensure that the\nheadings are consistent.\n\n```ruby\nclass MyReport \u003c Compendium::Report\n  exports :csv, :deliveries # Defines `deliveries` to be the query that is exported to CSV\nend\n```\n\nNote that if your report class subclasses another, and you want to disable a previously defined exporter, you can with `exports :csv, false`.\n\nWhen a report has a CSV exporter defined, an `Export CSV` button will appear on the default setup page. You can also directly export\nusing the path `/report/:report_name/export.csv` (using `GET` or `POST`).\n\nCustomization of the query can be done by setting table options for the query. See the [Rendering a table](#rendering-a-table) section below for more details.\n\n## Displaying Report Results\n\n### Chart Providers\n\nAs of 1.1.0, chart providers have been extracted out of the main repository and are available as their own gems. If you want to render queries as a chart, a chart provider gem is needed.\n\nIf multiple chart providers are installed, you can select the one you wish you use with the following initializer:\n\n```ruby\nCompendium.configure do |config|\n  config.chart_provider = :AmCharts # or any other provider name\nend\n```\n\nThe following providers are available (If you would like to contribute a chart provider, please let me know and I'll add it to the list):\n* [compendium-amcharts](https://github.com/dvandersluis/compendium-amcharts) - makes use of [AmCharts.rb](https://github.com/dvandersluis/amcharts.rb)\n* [compendium-highcharts](https://github.com/cimtico/compendium-highcharts) - makes use of [lazy_high_charts](https://github.com/michelson/lazy_high_charts) [thanks to [cimtico](https://github.com/cimtico)]\n\n### Rendering a table\n\n\u003e *Note: When table settings are defined for a query, they are applied both to rendering HTML tables, as well as CSV file exports.\nSee [Rendering report results in other formats](#rendering-report-results-in-other-formats) above for more details.* \n\nIn addition to charts, you can output a query as a table. When a query is rendered as a table, each row is output with columns in the\nquery order (so you may want to use an explicit `select` in your query to order the columns as required). If the query is set up with\n`totals: true`, a totals row will be added to the bottom of the table.\n\nIn order to customize the table, you can add a `table` declaration to your report. Each query can have different table settings.\n\n```ruby\nclass MyReport \u003c Compendium::Report\n  table :deliveries do\n    # The i18n scope to use for any translations can be specified:\n    i18n_scope 'reports.my_report'\n    \n    # Column headings by default are the column name passed through I18n,\n    # but can be overridden:\n  \n    # ... with a block...\n    override_heading do |heading|\n      # ...\n    end\n  \n    # ... or one at a time...\n    override_heading :col, 'My Column'\n  \n    # Records where a cell is 0 or nil can have the value overridden to something else:\n    display_zero_as 'N/A'\n    display_nil_as 'NULL'\n  \n    # You can specify how to format numbers:\n    number_format \"%0.1f\"\n  \n    # You can also specify formatting on a per-column basis:\n    format(:col) do |value|\n      \"#{(value / 50) * 100}%\"\n    end\n  end\nend\n```\n\nA query is rendered from a view, and is passed in the view context as the first parameter. Optionally, a block can be passed to\noverride previously defined settings:\n\n```ruby\nmy_query.render_table(self) do\n  display_zero_as 'nil' # Override the previous version just for this render\nend\n```\n\n#### CSS Classes\n\nBy default, Compendium uses the following four CSS classes when rendering a table:\n\n| Element               | Element Type | Class Name |\n|-----------------------|--------------|------------|\n| Table                 | `table`      | `results`  |\n| Table header          | `tr`         | `headings` |\n| Table data            | `tr`         | `data`     |\n| Table footer (totals) | `tr`         | `totals`   |\n\nEach class can be overridden when setting up the table:\n\n```ruby\nmy_query.render_table(self) do |t|\n  t.table_class   'my_table_class'\n  t.header_class  'my_header_class'\n  t.row_class     'my_row_class'\n  t.totals_class  'my_totals_class'\nend\n```\n\n### Interaction with other gems\n* If [accessible_tooltip](https://github.com/dvandersluis/accessible_tooltip) is present, option notes will be rendered\nin a tooltip rather than as straight text.\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n    gem 'compendium'\n\nAnd then execute:\n\n    $ bundle\n\nOr install it yourself as:\n\n    $ gem install compendium\n\n## Contributing\n\n1. Fork it\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Commit your changes (`git commit -am 'Add some feature'`)\n4. Push to the branch (`git push origin my-new-feature`)\n5. Create new Pull Request\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdvandersluis%2Fcompendium","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdvandersluis%2Fcompendium","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdvandersluis%2Fcompendium/lists"}