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.
Files changed (44) hide show
  1. checksums.yaml +5 -13
  2. data/.travis.yml +12 -0
  3. data/CHANGELOG.md +18 -0
  4. data/Gemfile +4 -0
  5. data/README.md +185 -4
  6. data/app/assets/stylesheets/compendium/options.css.scss +2 -3
  7. data/app/classes/compendium/presenters/chart.rb +1 -1
  8. data/app/classes/compendium/presenters/csv.rb +32 -0
  9. data/app/classes/compendium/presenters/query.rb +4 -2
  10. data/app/classes/compendium/presenters/settings/query.rb +10 -2
  11. data/app/classes/compendium/presenters/settings/table.rb +24 -4
  12. data/app/classes/compendium/presenters/table.rb +33 -18
  13. data/app/controllers/compendium/reports_controller.rb +28 -7
  14. data/app/views/compendium/reports/setup.haml +16 -2
  15. data/compendium.gemspec +4 -3
  16. data/config/locales/en.yml +6 -1
  17. data/config/locales/es.yml +11 -0
  18. data/config/locales/fr.yml +11 -0
  19. data/lib/compendium.rb +1 -0
  20. data/lib/compendium/collection_query.rb +1 -1
  21. data/lib/compendium/count_query.rb +7 -1
  22. data/lib/compendium/dsl.rb +45 -4
  23. data/lib/compendium/engine/mount.rb +13 -5
  24. data/lib/compendium/errors.rb +6 -0
  25. data/lib/compendium/metric.rb +1 -1
  26. data/lib/compendium/open_hash.rb +1 -1
  27. data/lib/compendium/param_types.rb +2 -2
  28. data/lib/compendium/params.rb +1 -1
  29. data/lib/compendium/query.rb +23 -4
  30. data/lib/compendium/report.rb +14 -10
  31. data/lib/compendium/sum_query.rb +3 -1
  32. data/lib/compendium/through_query.rb +7 -2
  33. data/lib/compendium/version.rb +1 -1
  34. data/spec/count_query_spec.rb +41 -5
  35. data/spec/dsl_spec.rb +77 -2
  36. data/spec/presenters/csv_spec.rb +30 -0
  37. data/spec/presenters/settings/query_spec.rb +26 -0
  38. data/spec/presenters/settings/table_spec.rb +64 -0
  39. data/spec/presenters/table_spec.rb +83 -0
  40. data/spec/query_spec.rb +55 -8
  41. data/spec/report_spec.rb +24 -1
  42. data/spec/sum_query_spec.rb +40 -5
  43. metadata +73 -30
  44. data/config/initializers/ruby/hash.rb +0 -6
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- ZTRmMzFjMzFhMTA3YjVjNDMwYjM0NzQwYjFhMWMxMDNlZjdlZGQ0ZQ==
5
- data.tar.gz: !binary |-
6
- MWEzM2NiMjk2ZjhiNGE5YmIwNjkzNjY0MTRkMDI1YWU3OGE1NWE3Ng==
2
+ SHA1:
3
+ metadata.gz: a4bf2931ee1fe86a8844273e9219577c865fa9e7
4
+ data.tar.gz: 5f75cd47f1a38914d32850ce28b37341a536c36e
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- MWRlMjMxNTlkNDg4ZTUxMmRhZjBhZjJlZjVmNDJlZTRkMmVkY2Y1Nzg3YzM0
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
@@ -0,0 +1,12 @@
1
+ sudo: false
2
+ language: ruby
3
+ cache:
4
+ - bundler
5
+ rvm:
6
+ - 1.9.3
7
+ - 2.0
8
+ - 2.1.9
9
+ - 2.2.6
10
+ - 2.3.3
11
+ - 2.4.0
12
+ before_install: gem install bundler -v 1.13.7
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
@@ -2,3 +2,7 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in compendium.gemspec
4
4
  gemspec
5
+
6
+ if RUBY_VERSION >= '2.4'
7
+ gem 'json', github: 'flori/json', branch: 'v1.8'
8
+ end
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 as JSON
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
@@ -2,7 +2,6 @@
2
2
  {
3
3
  @mixin label-font
4
4
  {
5
- font-family: "Arial";
6
5
  font-size: 14px;
7
6
  font-weight: bold;
8
7
  color: #575757;
@@ -44,8 +43,8 @@
44
43
  }
45
44
  }
46
45
 
47
- & + &, & + input[type=submit]
46
+ & + &
48
47
  {
49
48
  margin-top: 15px;
50
49
  }
51
- }
50
+ }
@@ -48,7 +48,7 @@ module Compendium::Presenters
48
48
  params = {}
49
49
  params[:report] = options[:params] if options[:params]
50
50
 
51
- if remote? and protected_against_csrf?
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(headings)
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(results.keys)
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: 'results') do
22
+ content_tag(:table, class: @settings.table_class) do
17
23
  table = ActiveSupport::SafeBuffer.new
18
- table << content_tag(:thead, build_heading_row)
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 << build_data_row(row) }
27
+ records.each { |row| tbody << build_row(row, settings.row_class, &data_proc) }
22
28
  tbody
23
29
  end
24
- table << content_tag(:tfoot, build_totals_row) if has_totals_row?
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 build_data_row(row)
40
- build_row(row, 'data') { |key, val| formatted_value(key, val) }
45
+ def data_proc
46
+ proc { |key, val| formatted_value(key, val) }
41
47
  end
42
48
 
43
- def build_heading_row
44
- build_row(headings, 'headings', :th) { |key, val| t(val) }
49
+ def heading_proc
50
+ proc { |_, val| formatted_heading(val) }
45
51
  end
46
52
 
47
- def build_totals_row
48
- totals[totals.keys.first] = t(:total)
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('tr', class: row_class) do
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? and @settings.display_zero_as?
79
+ if v.zero? && @settings.display_zero_as?
71
80
  @settings.display_zero_as
72
81
  else
73
- sprintf(@settings.number_format || '%0.2f', v)
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