compendium 1.1.3.4 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -13
- data/.travis.yml +12 -0
- data/CHANGELOG.md +18 -0
- data/Gemfile +4 -0
- data/README.md +185 -4
- data/app/assets/stylesheets/compendium/options.css.scss +2 -3
- data/app/classes/compendium/presenters/chart.rb +1 -1
- data/app/classes/compendium/presenters/csv.rb +32 -0
- data/app/classes/compendium/presenters/query.rb +4 -2
- data/app/classes/compendium/presenters/settings/query.rb +10 -2
- data/app/classes/compendium/presenters/settings/table.rb +24 -4
- data/app/classes/compendium/presenters/table.rb +33 -18
- data/app/controllers/compendium/reports_controller.rb +28 -7
- data/app/views/compendium/reports/setup.haml +16 -2
- data/compendium.gemspec +4 -3
- data/config/locales/en.yml +6 -1
- data/config/locales/es.yml +11 -0
- data/config/locales/fr.yml +11 -0
- data/lib/compendium.rb +1 -0
- data/lib/compendium/collection_query.rb +1 -1
- data/lib/compendium/count_query.rb +7 -1
- data/lib/compendium/dsl.rb +45 -4
- data/lib/compendium/engine/mount.rb +13 -5
- data/lib/compendium/errors.rb +6 -0
- data/lib/compendium/metric.rb +1 -1
- data/lib/compendium/open_hash.rb +1 -1
- data/lib/compendium/param_types.rb +2 -2
- data/lib/compendium/params.rb +1 -1
- data/lib/compendium/query.rb +23 -4
- data/lib/compendium/report.rb +14 -10
- data/lib/compendium/sum_query.rb +3 -1
- data/lib/compendium/through_query.rb +7 -2
- data/lib/compendium/version.rb +1 -1
- data/spec/count_query_spec.rb +41 -5
- data/spec/dsl_spec.rb +77 -2
- data/spec/presenters/csv_spec.rb +30 -0
- data/spec/presenters/settings/query_spec.rb +26 -0
- data/spec/presenters/settings/table_spec.rb +64 -0
- data/spec/presenters/table_spec.rb +83 -0
- data/spec/query_spec.rb +55 -8
- data/spec/report_spec.rb +24 -1
- data/spec/sum_query_spec.rb +40 -5
- metadata +73 -30
- data/config/initializers/ruby/hash.rb +0 -6
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
MWEzM2NiMjk2ZjhiNGE5YmIwNjkzNjY0MTRkMDI1YWU3OGE1NWE3Ng==
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a4bf2931ee1fe86a8844273e9219577c865fa9e7
|
4
|
+
data.tar.gz: 5f75cd47f1a38914d32850ce28b37341a536c36e
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
YzI2YTY0NGYzODdmOGFkNmI1NTBmMDVmNzBjZTI3ODBiMDdlMzJiZDk3OWZk
|
11
|
-
NDhjMjk2NDlmZTdkOTJkMTc3NWJjZGE1ZTcxZGQ0N2RkODNiODE=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
ZGMzNzk4NGVhMDU0NjU1MDVjNGYyYzM2ZjIyMWZjOTc5MzgwMDEyNWEzYzcz
|
14
|
-
NTgwZGQ2OTA0YTMwNDZhYTAyYWNlMWQ1MGYzZDM0ZWQ3YTRmODE0MzAzMDUy
|
15
|
-
MzNlYjQ0NDNiZGJlMDViOTQ0NDRmNDcwMDc5MTJiNWMzYTk0NzY=
|
6
|
+
metadata.gz: '09afd485514be265abc5af4600fad2ef3054650160ea351658ea27aa325e3b90e9b81b88d138394568bb5abf652d79cb90e40907662f739503d3a4cf4a31be7a'
|
7
|
+
data.tar.gz: 8eb6644a34e973139131469c3c069fbd518f62ed7bd3ba0afebebeb8ea27a09f1d6f8a9da433ec62987d7c814ddb08d588b433ef888adfad98e5b3e2b86c1d8d
|
data/.travis.yml
ADDED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,23 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## 1.2.0
|
4
|
+
* Added the ability to render a query to CSV, and a controller action for downloading the CSV
|
5
|
+
* Added `exports` report setting
|
6
|
+
* Added `skip_totals_for` option to table settings to define columns to skip in the totals row
|
7
|
+
* Added `i18n_scope` option to table settings
|
8
|
+
* Added `Settings::Query#update` to update query settings with a block
|
9
|
+
* Allow table settings to be specified on the report object
|
10
|
+
* Add settings to `render_table` to specify the CSS classes to use for each element.
|
11
|
+
* Allow queries to be ordered and reversed via query options (:order and :reverse)
|
12
|
+
* Add default orders for count and sum queries
|
13
|
+
* Fix redefining a query so that it actually overrides the previous query instead of creating a new one with the same name
|
14
|
+
|
15
|
+
## 1.1.3
|
16
|
+
* Add `SumQuery` query type
|
17
|
+
* Fix option tooltip covering input elements in IE [rvracaric]
|
18
|
+
* Allow custom param validations to be specified
|
19
|
+
* Fix filters being overridden by subclassed queries
|
20
|
+
|
3
21
|
## 1.1.2
|
4
22
|
* Allow direct access to a chart object without having to render it (useful if the provider allows chart settings to be updated after initialization)
|
5
23
|
* Delegate missing methods from ChartProvider classes to the chart
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Compendium [![Gem Version](https://badge.fury.io/rb/compendium.svg)](http://badge.fury.io/rb/compendium)
|
1
|
+
# 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)
|
2
2
|
|
3
3
|
Ruby on Rails framework for making reporting easy.
|
4
4
|
|
@@ -63,6 +63,89 @@ Compendium also comes with a variety of different presenters, for rendering the
|
|
63
63
|
(`report.render_chart`), tables (`report.render_table`) and metrics for your report. Charting is delegated through a
|
64
64
|
`ChartProvider` to a charting gem (amcharts.rb is currently supported).
|
65
65
|
|
66
|
+
### Report Options
|
67
|
+
Report 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).
|
68
|
+
|
69
|
+
In order to specify parameters for the options, pass a hash to `MyReport.new`. Parameters are available via `params`:
|
70
|
+
|
71
|
+
```ruby
|
72
|
+
r = MyReport.new(starting_on: Date.today - 3.months, ending_on: Date.today)
|
73
|
+
r.params
|
74
|
+
|
75
|
+
# {
|
76
|
+
# "starting_on"=>Sun, 30 Aug 2015,
|
77
|
+
# "ending_on"=>Mon, 30 Nov 2015,
|
78
|
+
# }
|
79
|
+
```
|
80
|
+
|
81
|
+
#### Validation
|
82
|
+
|
83
|
+
If 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.
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
class MyReport < Compendium::Report
|
87
|
+
options :starting_on, :date, validates: { presence: true }
|
88
|
+
end
|
89
|
+
|
90
|
+
r = MyReport.new
|
91
|
+
r.valid?
|
92
|
+
# => false
|
93
|
+
|
94
|
+
r.errors
|
95
|
+
# => #<ActiveModel::Errors:0x007fe8359cc6b8
|
96
|
+
# @base={"starting_on"=>nil},
|
97
|
+
# @messages={:starting_on=>["This field is required."]}>
|
98
|
+
```
|
99
|
+
|
100
|
+
### Query types
|
101
|
+
|
102
|
+
Compendium provides a few types of queries in order to make report writing more streamlined.
|
103
|
+
|
104
|
+
#### Through Queries
|
105
|
+
|
106
|
+
A **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).
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
query :dog_sales { |params| Order.where(pet_type: 'dog', created_at: params[:starting_on]..params[:ending_on]) }
|
110
|
+
query :cat_sales { |params| Order.where(pet_type: 'cat', created_at: params[:starting_on]..params[:ending_on]) }
|
111
|
+
query :bird_sales { |params| Order.where(pet_type: 'bird', created_at: params[:starting_on]..params[:ending_on]) }
|
112
|
+
|
113
|
+
query :total_sales, through: [:dog_sales, :cat_sales, :bird_sales] do |results, params|
|
114
|
+
# results is a hash with keys :dog_sales, :cat_sales, :bird_sales
|
115
|
+
end
|
116
|
+
```
|
117
|
+
|
118
|
+
#### Count Queries
|
119
|
+
|
120
|
+
A **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.
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
query :sales_per_day, count: true do
|
124
|
+
Order.group("DATE(created_at)")
|
125
|
+
end
|
126
|
+
|
127
|
+
# results will look something like
|
128
|
+
# { 2015-10-01 => 4, 2015-10-02 => 20, ... }
|
129
|
+
```
|
130
|
+
|
131
|
+
#### Sum Queries
|
132
|
+
|
133
|
+
Like 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 <code>sum: <i>:column_name</i></code> to the `query` call.
|
134
|
+
|
135
|
+
```ruby
|
136
|
+
query :commission_per_salesperson, sum: 'commission' do
|
137
|
+
# assume commission is a numeric column
|
138
|
+
Order.group(:employee_id)
|
139
|
+
end
|
140
|
+
|
141
|
+
# results will be something like
|
142
|
+
# { 1 => 840.34, 2 => 1065.02, ... }
|
143
|
+
```
|
144
|
+
|
145
|
+
#### Collection Queries
|
146
|
+
|
147
|
+
Sometimes 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).
|
148
|
+
|
66
149
|
### Tying into your Rails application
|
67
150
|
|
68
151
|
Compendium has a `Rails::Engine`, which adds a default controller and some views. If desired, the controller can be
|
@@ -78,14 +161,37 @@ within your `config/routes.rb` file
|
|
78
161
|
mount_compendium at: '/report', controller: 'reports' # controller defaults to compendium/reports
|
79
162
|
```
|
80
163
|
|
81
|
-
### Rendering report results
|
164
|
+
### Rendering report results in other formats
|
165
|
+
|
166
|
+
#### JSON
|
82
167
|
|
83
168
|
While the default action when running a report is to render a view with the results, Compendium reports can be rendered
|
84
169
|
as JSON. If using the default routes provided by `mount_compendium` (assuming compendium was mounted at `/report`),
|
85
|
-
`POST`ing to <code>report/<i>report_name</i>.json</code> will return the report results as JSON. You can also collect
|
86
|
-
the results of a single query (instead of the entire report) by `POST`ing to
|
170
|
+
`GET`ing or `POST`ing to <code>report/<i>report_name</i>.json</code> will return the report results as JSON. You can also collect
|
171
|
+
the results of a single query (instead of the entire report) by `GET`ing or `POST`ing to
|
87
172
|
<code>report/<i>report_name</i>/<i>query_name</i>.json</code>.
|
88
173
|
|
174
|
+
#### CSV
|
175
|
+
|
176
|
+
A report can be exported as CSV. In order to enable CSV exports, a query needs to be defined as the exporter
|
177
|
+
for the report. Note that only one query can be exported, because otherwise there's no way to ensure that the
|
178
|
+
headings are consistent.
|
179
|
+
|
180
|
+
```ruby
|
181
|
+
class MyReport < Compendium::Report
|
182
|
+
exports :csv, :deliveries # Defines `deliveries` to be the query that is exported to CSV
|
183
|
+
end
|
184
|
+
```
|
185
|
+
|
186
|
+
Note that if your report class subclasses another, and you want to disable a previously defined exporter, you can with `exports :csv, false`.
|
187
|
+
|
188
|
+
When a report has a CSV exporter defined, an `Export CSV` button will appear on the default setup page. You can also directly export
|
189
|
+
using the path `/report/:report_name/export.csv` (using `GET` or `POST`).
|
190
|
+
|
191
|
+
Customization 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.
|
192
|
+
|
193
|
+
## Displaying Report Results
|
194
|
+
|
89
195
|
### Chart Providers
|
90
196
|
|
91
197
|
As 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.
|
@@ -100,6 +206,81 @@ end
|
|
100
206
|
|
101
207
|
The 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):
|
102
208
|
* [compendium-amcharts](https://github.com/dvandersluis/compendium-amcharts) - makes use of [AmCharts.rb](https://github.com/dvandersluis/amcharts.rb)
|
209
|
+
* [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)]
|
210
|
+
|
211
|
+
### Rendering a table
|
212
|
+
|
213
|
+
> *Note: When table settings are defined for a query, they are applied both to rendering HTML tables, as well as CSV file exports.
|
214
|
+
See [Rendering report results in other formats](#rendering-report-results-in-other-formats) above for more details.*
|
215
|
+
|
216
|
+
In 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
|
217
|
+
query 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
|
218
|
+
`totals: true`, a totals row will be added to the bottom of the table.
|
219
|
+
|
220
|
+
In order to customize the table, you can add a `table` declaration to your report. Each query can have different table settings.
|
221
|
+
|
222
|
+
```ruby
|
223
|
+
class MyReport < Compendium::Report
|
224
|
+
table :deliveries do
|
225
|
+
# The i18n scope to use for any translations can be specified:
|
226
|
+
i18n_scope 'reports.my_report'
|
227
|
+
|
228
|
+
# Column headings by default are the column name passed through I18n,
|
229
|
+
# but can be overridden:
|
230
|
+
|
231
|
+
# ... with a block...
|
232
|
+
override_heading do |heading|
|
233
|
+
# ...
|
234
|
+
end
|
235
|
+
|
236
|
+
# ... or one at a time...
|
237
|
+
override_heading :col, 'My Column'
|
238
|
+
|
239
|
+
# Records where a cell is 0 or nil can have the value overridden to something else:
|
240
|
+
display_zero_as 'N/A'
|
241
|
+
display_nil_as 'NULL'
|
242
|
+
|
243
|
+
# You can specify how to format numbers:
|
244
|
+
number_format "%0.1f"
|
245
|
+
|
246
|
+
# You can also specify formatting on a per-column basis:
|
247
|
+
format(:col) do |value|
|
248
|
+
"#{(value / 50) * 100}%"
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
```
|
253
|
+
|
254
|
+
A query is rendered from a view, and is passed in the view context as the first parameter. Optionally, a block can be passed to
|
255
|
+
override previously defined settings:
|
256
|
+
|
257
|
+
```ruby
|
258
|
+
my_query.render_table(self) do
|
259
|
+
display_zero_as 'nil' # Override the previous version just for this render
|
260
|
+
end
|
261
|
+
```
|
262
|
+
|
263
|
+
#### CSS Classes
|
264
|
+
|
265
|
+
By default, Compendium uses the following four CSS classes when rendering a table:
|
266
|
+
|
267
|
+
| Element | Element Type | Class Name |
|
268
|
+
|-----------------------|--------------|------------|
|
269
|
+
| Table | `table` | `results` |
|
270
|
+
| Table header | `tr` | `headings` |
|
271
|
+
| Table data | `tr` | `data` |
|
272
|
+
| Table footer (totals) | `tr` | `totals` |
|
273
|
+
|
274
|
+
Each class can be overridden when setting up the table:
|
275
|
+
|
276
|
+
```ruby
|
277
|
+
my_query.render_table(self) do |t|
|
278
|
+
t.table_class 'my_table_class'
|
279
|
+
t.header_class 'my_header_class'
|
280
|
+
t.row_class 'my_row_class'
|
281
|
+
t.totals_class 'my_totals_class'
|
282
|
+
end
|
283
|
+
```
|
103
284
|
|
104
285
|
### Interaction with other gems
|
105
286
|
* If [accessible_tooltip](https://github.com/dvandersluis/accessible_tooltip) is present, option notes will be rendered
|
@@ -48,7 +48,7 @@ module Compendium::Presenters
|
|
48
48
|
params = {}
|
49
49
|
params[:report] = options[:params] if options[:params]
|
50
50
|
|
51
|
-
if remote?
|
51
|
+
if remote? && protected_against_csrf?
|
52
52
|
# If we're loading remotely, and CSRF protection is enabled,
|
53
53
|
# automatically include the CSRF token in AJAX params
|
54
54
|
params.merge!(form_authenticity_param)
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'csv'
|
2
|
+
|
3
|
+
module Compendium::Presenters
|
4
|
+
class CSV < Table
|
5
|
+
def initialize(object, &block)
|
6
|
+
super(nil, object, &block)
|
7
|
+
end
|
8
|
+
|
9
|
+
def render
|
10
|
+
::CSV.generate do |csv|
|
11
|
+
csv << headings.map{ |_, val| formatted_heading(val) }
|
12
|
+
|
13
|
+
records.each do |row|
|
14
|
+
csv << row.map{ |key, val| formatted_value(key, val) }
|
15
|
+
end
|
16
|
+
|
17
|
+
if has_totals_row?
|
18
|
+
totals[totals.keys.first] = translate(:total)
|
19
|
+
csv << totals.map do |key, val|
|
20
|
+
formatted_value(key, val) unless settings.skipped_total_cols.include?(key.to_sym)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def settings_class
|
29
|
+
Compendium::Presenters::Settings::Table
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -1,4 +1,6 @@
|
|
1
1
|
require 'compendium/presenters/base'
|
2
|
+
require 'compendium/presenters/settings/query'
|
3
|
+
require 'compendium/presenters/settings/table'
|
2
4
|
|
3
5
|
module Compendium::Presenters
|
4
6
|
class Query < Base
|
@@ -19,7 +21,7 @@ module Compendium::Presenters
|
|
19
21
|
end
|
20
22
|
|
21
23
|
def settings_class
|
22
|
-
Settings.const_get(self.class.name.demodulize) rescue Settings::Query
|
24
|
+
Settings.const_get(self.class.name.demodulize, false) rescue Settings::Query
|
23
25
|
end
|
24
26
|
end
|
25
|
-
end
|
27
|
+
end
|
@@ -1,9 +1,17 @@
|
|
1
1
|
module Compendium::Presenters::Settings
|
2
2
|
class Query
|
3
|
+
attr_reader :query
|
4
|
+
|
3
5
|
delegate :[], :fetch, to: :@settings
|
6
|
+
delegate :report, to: :query, allow_nil: true
|
4
7
|
|
5
|
-
def initialize
|
8
|
+
def initialize(query = nil)
|
6
9
|
@settings = {}.with_indifferent_access
|
10
|
+
@query = query
|
11
|
+
end
|
12
|
+
|
13
|
+
def update(&block)
|
14
|
+
instance_exec(self, &block)
|
7
15
|
end
|
8
16
|
|
9
17
|
def method_missing(name, *args, &block)
|
@@ -19,4 +27,4 @@ module Compendium::Presenters::Settings
|
|
19
27
|
end
|
20
28
|
end
|
21
29
|
end
|
22
|
-
end
|
30
|
+
end
|
@@ -1,16 +1,32 @@
|
|
1
|
+
require 'compendium/presenters/settings/query'
|
2
|
+
|
1
3
|
module Compendium::Presenters::Settings
|
2
4
|
class Table < Query
|
3
5
|
attr_reader :headings
|
4
6
|
|
5
|
-
def initialize(
|
6
|
-
super
|
7
|
+
def initialize(*)
|
8
|
+
super
|
9
|
+
|
10
|
+
@headings = {}
|
11
|
+
|
12
|
+
# Set default values for settings
|
13
|
+
number_format '%0.2f'
|
14
|
+
table_class 'results'
|
15
|
+
header_class 'headings'
|
16
|
+
row_class 'data'
|
17
|
+
totals_class 'totals'
|
18
|
+
skipped_total_cols []
|
19
|
+
end
|
20
|
+
|
21
|
+
def set_headings(headings)
|
22
|
+
headings.map!(&:to_sym)
|
7
23
|
@headings = Hash[headings.zip(headings)].with_indifferent_access
|
8
24
|
end
|
9
25
|
|
10
26
|
def override_heading(*args, &block)
|
11
27
|
if block_given?
|
12
28
|
@headings.each do |key, val|
|
13
|
-
res = yield val
|
29
|
+
res = yield val.to_s
|
14
30
|
@headings[key] = res if res
|
15
31
|
end
|
16
32
|
else
|
@@ -27,5 +43,9 @@ module Compendium::Presenters::Settings
|
|
27
43
|
def formatters
|
28
44
|
(@settings[:formatters] || {})
|
29
45
|
end
|
46
|
+
|
47
|
+
def skip_total_for(*cols)
|
48
|
+
@settings[:skipped_total_cols].concat(cols.map(&:to_sym))
|
49
|
+
end
|
30
50
|
end
|
31
|
-
end
|
51
|
+
end
|
@@ -1,27 +1,33 @@
|
|
1
1
|
module Compendium::Presenters
|
2
2
|
class Table < Query
|
3
|
-
attr_reader :records, :totals
|
3
|
+
attr_reader :records, :totals, :settings
|
4
4
|
|
5
5
|
def initialize(*)
|
6
6
|
super
|
7
7
|
|
8
8
|
@records = results.records
|
9
|
-
@totals = @records.pop if has_totals_row?
|
10
9
|
|
11
|
-
@settings = settings_class.new(
|
10
|
+
@settings = settings_class.new(query)
|
11
|
+
@settings.set_headings(results.keys)
|
12
|
+
@settings.update(&query.table_settings) if query.table_settings
|
12
13
|
yield @settings if block_given?
|
14
|
+
|
15
|
+
if has_totals_row?
|
16
|
+
@totals = @records.pop
|
17
|
+
totals[totals.keys.first] = translate(:total)
|
18
|
+
end
|
13
19
|
end
|
14
20
|
|
15
21
|
def render
|
16
|
-
content_tag(:table, class:
|
22
|
+
content_tag(:table, class: @settings.table_class) do
|
17
23
|
table = ActiveSupport::SafeBuffer.new
|
18
|
-
table << content_tag(:thead,
|
24
|
+
table << content_tag(:thead, build_row(headings, settings.header_class, :th, &heading_proc))
|
19
25
|
table << content_tag(:tbody) do
|
20
26
|
tbody = ActiveSupport::SafeBuffer.new
|
21
|
-
records.each { |row| tbody <<
|
27
|
+
records.each { |row| tbody << build_row(row, settings.row_class, &data_proc) }
|
22
28
|
tbody
|
23
29
|
end
|
24
|
-
table << content_tag(:tfoot,
|
30
|
+
table << content_tag(:tfoot, build_row(totals, @settings.totals_class, :th, &totals_proc)) if has_totals_row?
|
25
31
|
table
|
26
32
|
end
|
27
33
|
end
|
@@ -36,21 +42,20 @@ module Compendium::Presenters
|
|
36
42
|
query.options.fetch(:totals, false)
|
37
43
|
end
|
38
44
|
|
39
|
-
def
|
40
|
-
|
45
|
+
def data_proc
|
46
|
+
proc { |key, val| formatted_value(key, val) }
|
41
47
|
end
|
42
48
|
|
43
|
-
def
|
44
|
-
|
49
|
+
def heading_proc
|
50
|
+
proc { |_, val| formatted_heading(val) }
|
45
51
|
end
|
46
52
|
|
47
|
-
def
|
48
|
-
|
49
|
-
build_row(totals, 'totals', :th) { |key, val| formatted_value(key, val) }
|
53
|
+
def totals_proc
|
54
|
+
proc { |key, val| formatted_value(key, val) unless settings.skipped_total_cols.include?(key.to_sym) }
|
50
55
|
end
|
51
56
|
|
52
57
|
def build_row(row, row_class, cell_type = :td)
|
53
|
-
content_tag(
|
58
|
+
content_tag(:tr, class: row_class) do
|
54
59
|
out = ActiveSupport::SafeBuffer.new
|
55
60
|
|
56
61
|
row.each.with_index do |(key, val), i|
|
@@ -62,20 +67,30 @@ module Compendium::Presenters
|
|
62
67
|
end
|
63
68
|
end
|
64
69
|
|
70
|
+
def formatted_heading(v)
|
71
|
+
v.is_a?(Symbol) ? translate(v) : v
|
72
|
+
end
|
73
|
+
|
65
74
|
def formatted_value(k, v)
|
66
75
|
if @settings.formatters[k]
|
67
76
|
@settings.formatters[k].call(v)
|
68
77
|
else
|
69
78
|
if v.numeric?
|
70
|
-
if v.zero?
|
79
|
+
if v.zero? && @settings.display_zero_as?
|
71
80
|
@settings.display_zero_as
|
72
81
|
else
|
73
|
-
sprintf(@settings.number_format
|
82
|
+
sprintf(@settings.number_format, v)
|
74
83
|
end
|
75
84
|
elsif v.nil?
|
76
85
|
@settings.display_nil_as
|
77
86
|
end
|
78
87
|
end || v
|
79
88
|
end
|
89
|
+
|
90
|
+
def translate(v, opts = {})
|
91
|
+
opts.reverse_merge!(scope: settings.i18n_scope) if settings.i18n_scope?
|
92
|
+
opts[:default] = -> * { I18n.t(v, scope: 'compendium') }
|
93
|
+
I18n.t(v, opts)
|
94
|
+
end
|
80
95
|
end
|
81
|
-
end
|
96
|
+
end
|