compendium 1.0.2 → 1.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/app/classes/compendium/presenters/chart.rb +10 -3
- data/app/classes/compendium/presenters/option.rb +5 -3
- data/app/classes/compendium/presenters/query.rb +2 -0
- data/app/controllers/compendium/reports_controller.rb +9 -3
- data/app/views/compendium/reports/setup.haml +1 -1
- data/compendium.gemspec +1 -1
- data/lib/compendium/collection_query.rb +44 -0
- data/lib/compendium/dsl.rb +33 -12
- data/lib/compendium/param_types.rb +1 -1
- data/lib/compendium/params.rb +10 -3
- data/lib/compendium/query.rb +19 -39
- data/lib/compendium/report.rb +38 -3
- data/lib/compendium/result_set.rb +4 -1
- data/lib/compendium/through_query.rb +43 -0
- data/lib/compendium/version.rb +1 -1
- data/lib/compendium.rb +2 -0
- data/spec/collection_query_spec.rb +46 -0
- data/spec/dsl_spec.rb +69 -1
- data/spec/params_spec.rb +22 -7
- data/spec/presenters/chart_spec.rb +37 -0
- data/spec/presenters/option_spec.rb +1 -1
- data/spec/query_spec.rb +32 -34
- data/spec/report_spec.rb +56 -0
- data/spec/result_set_spec.rb +23 -0
- data/spec/through_query_spec.rb +71 -0
- metadata +14 -4
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
ODBjOTg1ZGM3NjVhYTM3ZjcxZDM5YjMyYjI1M2I2MzJjYTkzZmFiNg==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
Yzg1ZDk0MmUxYTlkMDg2NTgzYTIxMzEyZjk3NjcxYjYwMzc2ZjhiZQ==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
ZTA4YTdjYjUwOWE5ZTU3ODVhZmRhMzU2NjViZjZiMGFjZjk3ZDhkYjY0MjIz
|
10
|
+
NjY3ZmVjODkzNGYyNWNiNDY2ODlmZWNiNTI4NGI2MGFhNGIzNThjMzgwZjZl
|
11
|
+
ZTM5MzIzNjVlNDdmY2FiN2U2MTAxZTQwN2Q0NWUxZmFmN2Q2MjM=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
N2QyNWI2OGU4ZGQ0OWJiODMxZDNhOTA4NDU1NTliOTViNzAxMzQ3MGRlZTAz
|
14
|
+
Y2UxODhjMjUyZTEzNjFhYmI5MzkwZGI3ZTYzNzEwMWM4NWVmNGVlZjJmYjdh
|
15
|
+
NTZkYWJkODVmYzk4OTUzZTVhNjkxNDVjODhjN2QyNmY2N2Q4ZTM=
|
@@ -1,11 +1,18 @@
|
|
1
|
+
require 'compendium/presenters/query'
|
2
|
+
require 'active_support/core_ext/array/extract_options'
|
3
|
+
|
1
4
|
module Compendium::Presenters
|
2
5
|
class Chart < Query
|
3
|
-
attr_reader :data, :chart_provider
|
6
|
+
attr_reader :data, :container, :chart_provider
|
7
|
+
|
8
|
+
def initialize(template, object, *args, &setup)
|
9
|
+
options = args.extract_options!
|
10
|
+
type, container = args
|
4
11
|
|
5
|
-
def initialize(template, object, type, container = nil, &setup)
|
6
12
|
super(template, object)
|
7
13
|
|
8
|
-
@data = results.records
|
14
|
+
@data = options[:index] ? results.records[options[:index]] : results
|
15
|
+
@data = @data.records if @data.is_a?(Compendium::ResultSet)
|
9
16
|
@data = @data[0...-1] if query.options[:totals]
|
10
17
|
|
11
18
|
@container = container || query.name
|
@@ -5,7 +5,7 @@ module Compendium::Presenters
|
|
5
5
|
presents :option
|
6
6
|
|
7
7
|
def name
|
8
|
-
t(option.name)
|
8
|
+
t("options.#{option.name}", cascade: { offset: 2 })
|
9
9
|
end
|
10
10
|
|
11
11
|
def label(form)
|
@@ -21,10 +21,12 @@ module Compendium::Presenters
|
|
21
21
|
out << content_tag(:span, label, class: 'option-label')
|
22
22
|
|
23
23
|
if option.note?
|
24
|
-
|
24
|
+
key = option.note == true ? :"#{option.name}_note" : option.note
|
25
|
+
note = t("options.#{key}", cascade: { offset: 2 })
|
26
|
+
title = t("options.#{option.name}_note_title", default: '', cascade: { offset: 2 })
|
25
27
|
|
26
28
|
if defined?(AccessibleTooltip)
|
27
|
-
return accessible_tooltip(:help, label: out, title:
|
29
|
+
return accessible_tooltip(:help, label: out, title: title) { note }
|
28
30
|
else
|
29
31
|
out << content_tag(:div, note, class: 'option-note')
|
30
32
|
end
|
@@ -4,6 +4,7 @@ module Compendium
|
|
4
4
|
include Compendium::ReportsHelper
|
5
5
|
|
6
6
|
before_filter :find_report
|
7
|
+
before_filter :validate_options, only: :run
|
7
8
|
before_filter :run_report, only: :run
|
8
9
|
|
9
10
|
def setup
|
@@ -24,6 +25,7 @@ module Compendium
|
|
24
25
|
begin
|
25
26
|
require(@report_name) unless Rails.env.development? or Module.const_defined?(@report_name.classify)
|
26
27
|
@report_class = @report_name.camelize.constantize
|
28
|
+
@report = setup_report
|
27
29
|
rescue LoadError
|
28
30
|
flash[:error] = t(:invalid_report)
|
29
31
|
redirect_to action: :index
|
@@ -31,16 +33,20 @@ module Compendium
|
|
31
33
|
end
|
32
34
|
|
33
35
|
def render_setup(opts = {})
|
34
|
-
locals = { report:
|
35
|
-
render_if_exists(opts.merge(locals: locals)) || render(locals: locals)
|
36
|
+
locals = { report: @report, prefix: @prefix }
|
37
|
+
opts.empty? ? render(action: :setup, locals: locals) : render_if_exists(opts.merge(locals: locals)) || render(action: :setup, locals: locals)
|
36
38
|
end
|
37
39
|
|
38
40
|
def setup_report
|
39
41
|
@report_class.new(params[:report] || {})
|
40
42
|
end
|
41
43
|
|
44
|
+
def validate_options
|
45
|
+
render_setup and return unless @report.valid?
|
46
|
+
end
|
47
|
+
|
42
48
|
def run_report
|
43
|
-
@report
|
49
|
+
@report.run(self)
|
44
50
|
end
|
45
51
|
|
46
52
|
def get_template_prefixes
|
data/compendium.gemspec
CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |gem|
|
|
21
21
|
gem.add_dependency 'rails', '>= 3.0.0'
|
22
22
|
gem.add_dependency 'sass-rails', '>= 3.0.0'
|
23
23
|
gem.add_dependency 'compass-rails', '>= 1.0.0'
|
24
|
-
gem.add_dependency 'collection_of', '1.0.
|
24
|
+
gem.add_dependency 'collection_of', '1.0.5'
|
25
25
|
gem.add_dependency 'inheritable_attr', '>= 1.0.0'
|
26
26
|
gem.add_development_dependency 'rspec', '~> 2.0'
|
27
27
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'compendium/query'
|
2
|
+
|
3
|
+
module Compendium
|
4
|
+
# A CollectionQuery is a Query which runs once for each in a given set of criteria
|
5
|
+
class CollectionQuery < Query
|
6
|
+
attr_accessor :collection
|
7
|
+
|
8
|
+
def initialize(*)
|
9
|
+
super
|
10
|
+
self.collection = prepare_collection(@options[:collection])
|
11
|
+
end
|
12
|
+
|
13
|
+
def run(params, context = self)
|
14
|
+
collection_values = get_collection_values(context, params)
|
15
|
+
|
16
|
+
results = collection_values.inject({}) do |r, (key, value)|
|
17
|
+
res = collect_results(context, params, key, value)
|
18
|
+
r[key] = res unless res.empty?
|
19
|
+
r
|
20
|
+
end
|
21
|
+
|
22
|
+
# A CollectionQuery's results will be a ResultSet of ResultSets
|
23
|
+
@results = ResultSet.new(results)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def get_collection_values(context, params)
|
29
|
+
self.collection = get_associated_query(collection) if collection.is_a?(Symbol)
|
30
|
+
|
31
|
+
if collection.is_a?(Query)
|
32
|
+
collection.run(params, context) unless collection.ran?
|
33
|
+
collection.results
|
34
|
+
else
|
35
|
+
collection
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def prepare_collection(collection)
|
40
|
+
return collection if collection.is_a?(Query) or collection.is_a?(Symbol)
|
41
|
+
collection.is_a?(Hash) ? collection : Hash[collection.zip(collection)]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/compendium/dsl.rb
CHANGED
@@ -7,7 +7,7 @@ module Compendium
|
|
7
7
|
module DSL
|
8
8
|
def self.extended(klass)
|
9
9
|
klass.inheritable_attr :queries, default: ::Collection[Query]
|
10
|
-
klass.inheritable_attr :options, default:
|
10
|
+
klass.inheritable_attr :options, default: ::Collection[Option]
|
11
11
|
end
|
12
12
|
|
13
13
|
def query(name, opts = {}, &block)
|
@@ -20,16 +20,20 @@ module Compendium
|
|
20
20
|
opts = args.extract_options!
|
21
21
|
type = args.shift
|
22
22
|
|
23
|
+
add_params_validations(name, opts.delete(:validates))
|
24
|
+
|
23
25
|
if options[name]
|
24
26
|
options[name].type = type if type
|
25
27
|
options[name].default = opts.delete(:default) if opts.key?(:default)
|
26
28
|
options[name].merge!(opts)
|
27
29
|
else
|
28
|
-
options
|
30
|
+
options << Compendium::Option.new(opts.merge(name: name, type: type))
|
29
31
|
end
|
30
32
|
end
|
31
33
|
|
32
|
-
def metric(name,
|
34
|
+
def metric(name, *args, &block)
|
35
|
+
proc = args.first.is_a?(Proc) ? args.first : block
|
36
|
+
opts = args.extract_options!
|
33
37
|
raise ArgumentError, 'through option must be specified for metric' unless opts.key?(:through)
|
34
38
|
|
35
39
|
[opts.delete(:through)].flatten.each do |query|
|
@@ -38,6 +42,15 @@ module Compendium
|
|
38
42
|
end
|
39
43
|
end
|
40
44
|
|
45
|
+
# Each Report will have its own descendant of Params in order to safely add validations
|
46
|
+
def params_class
|
47
|
+
@params_class ||= Class.new(Params)
|
48
|
+
end
|
49
|
+
|
50
|
+
def params_class=(klass)
|
51
|
+
@params_class = klass
|
52
|
+
end
|
53
|
+
|
41
54
|
# Allow defined queries to be redefined by name, eg:
|
42
55
|
# query :main_query
|
43
56
|
# main_query { collect_records_here }
|
@@ -59,22 +72,30 @@ module Compendium
|
|
59
72
|
|
60
73
|
private
|
61
74
|
|
62
|
-
def define_query(name, opts,
|
63
|
-
|
64
|
-
|
75
|
+
def define_query(name, opts, &block)
|
76
|
+
params = [name.to_sym, opts, block]
|
77
|
+
query_type = Query
|
65
78
|
|
66
|
-
if opts.key?(:
|
79
|
+
if opts.key?(:collection)
|
80
|
+
query_type = CollectionQuery
|
81
|
+
elsif opts.key?(:through)
|
82
|
+
# Ensure each through query is defined
|
67
83
|
through = [opts[:through]].flatten
|
84
|
+
through.each { |q| raise ArgumentError, "query #{q} is not defined" unless self.queries.include?(q.to_sym) }
|
68
85
|
|
69
|
-
|
70
|
-
|
71
|
-
end
|
72
|
-
|
73
|
-
query.through = through
|
86
|
+
query_type = ThroughQuery
|
87
|
+
params.insert(1, through)
|
74
88
|
end
|
75
89
|
|
90
|
+
query = query_type.new(*params)
|
91
|
+
|
76
92
|
metrics[name] = opts[:metric] if opts.key?(:metric)
|
77
93
|
queries << query
|
78
94
|
end
|
95
|
+
|
96
|
+
def add_params_validations(name, validations)
|
97
|
+
return if validations.blank?
|
98
|
+
self.params_class.validates name, validations
|
99
|
+
end
|
79
100
|
end
|
80
101
|
end
|
data/lib/compendium/params.rb
CHANGED
@@ -2,9 +2,12 @@ require 'compendium/open_hash'
|
|
2
2
|
require 'compendium/param_types'
|
3
3
|
require 'active_support/core_ext/string/inflections'
|
4
4
|
require 'active_support/core_ext/object/blank'
|
5
|
+
require 'active_model'
|
5
6
|
|
6
7
|
module Compendium
|
7
8
|
class Params < OpenHash
|
9
|
+
include ActiveModel::Validations
|
10
|
+
|
8
11
|
attr_reader :options
|
9
12
|
|
10
13
|
def initialize(hash = {}, options = {})
|
@@ -12,15 +15,19 @@ module Compendium
|
|
12
15
|
super(prepare_hash_from_options(hash))
|
13
16
|
end
|
14
17
|
|
18
|
+
def self.model_name
|
19
|
+
ActiveModel::Name.new(Compendium::Params, Compendium, 'compendium.params')
|
20
|
+
end
|
21
|
+
|
15
22
|
protected
|
16
23
|
|
17
24
|
def prepare_hash_from_options(params)
|
18
25
|
params = params.slice(*options.keys)
|
19
26
|
|
20
|
-
options.each do |
|
27
|
+
options.each do |option|
|
21
28
|
begin
|
22
|
-
klass = "Compendium::#{"#{
|
23
|
-
params[
|
29
|
+
klass = "Compendium::#{"#{option.type}Param".classify}".constantize
|
30
|
+
params[option.name] = klass.new(get_default_value(params[option.name], option.default), option.choices)
|
24
31
|
rescue IndexError
|
25
32
|
raise IndexError, "invalid index for #{option_name}"
|
26
33
|
end
|
data/lib/compendium/query.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
require 'compendium/result_set'
|
2
2
|
require 'compendium/params'
|
3
|
+
require 'compendium/presenters/chart'
|
4
|
+
require 'compendium/presenters/table'
|
3
5
|
require 'collection_of'
|
4
6
|
require_relative '../../config/initializers/ruby/hash'
|
5
7
|
|
6
8
|
module Compendium
|
7
9
|
class Query
|
8
10
|
attr_reader :name, :results, :metrics
|
9
|
-
attr_accessor :options, :proc, :
|
11
|
+
attr_accessor :options, :proc, :report
|
10
12
|
|
11
13
|
def initialize(*args)
|
12
14
|
@report = args.shift if arg_is_report?(args.first)
|
@@ -23,7 +25,7 @@ module Compendium
|
|
23
25
|
end
|
24
26
|
|
25
27
|
def run(params, context = self)
|
26
|
-
collect_results(
|
28
|
+
collect_results(context, params)
|
27
29
|
collect_metrics(context)
|
28
30
|
|
29
31
|
@results
|
@@ -34,11 +36,11 @@ module Compendium
|
|
34
36
|
end
|
35
37
|
|
36
38
|
def render_table(template, *options, &block)
|
37
|
-
Compendium::Presenters::Table.new(template, self, *options, &block).render
|
39
|
+
Compendium::Presenters::Table.new(template, self, *options, &block).render unless empty?
|
38
40
|
end
|
39
41
|
|
40
42
|
def render_chart(template, *options, &block)
|
41
|
-
Compendium::Presenters::Chart.new(template, self, *options, &block).render
|
43
|
+
Compendium::Presenters::Chart.new(template, self, *options, &block).render unless empty?
|
42
44
|
end
|
43
45
|
|
44
46
|
def ran?
|
@@ -46,24 +48,20 @@ module Compendium
|
|
46
48
|
end
|
47
49
|
alias_method :has_run?, :ran?
|
48
50
|
|
51
|
+
# A query is nil if it has no proc
|
49
52
|
def nil?
|
50
53
|
proc.nil?
|
51
54
|
end
|
52
55
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
args = params
|
58
|
-
else
|
59
|
-
args = collect_through_query_results(through, params, context)
|
56
|
+
# A query is empty if it has no results
|
57
|
+
def empty?
|
58
|
+
results.empty?
|
59
|
+
end
|
60
60
|
|
61
|
-
|
62
|
-
# depends on the results of its parents.
|
63
|
-
return @results = ResultSet.new([]) if args.compact.empty?
|
64
|
-
end
|
61
|
+
private
|
65
62
|
|
66
|
-
|
63
|
+
def collect_results(context, *params)
|
64
|
+
command = context.instance_exec(*params, &proc) if proc
|
67
65
|
command = fetch_results(command)
|
68
66
|
@results = ResultSet.new(command) if command
|
69
67
|
end
|
@@ -73,11 +71,7 @@ module Compendium
|
|
73
71
|
end
|
74
72
|
|
75
73
|
def fetch_results(command)
|
76
|
-
|
77
|
-
command
|
78
|
-
else
|
79
|
-
execute_command(command)
|
80
|
-
end
|
74
|
+
(options.fetch(:collect, nil) == :active_record) ? command : execute_command(command)
|
81
75
|
end
|
82
76
|
|
83
77
|
def execute_command(command)
|
@@ -90,26 +84,12 @@ module Compendium
|
|
90
84
|
::ActiveRecord::Base.connection.select_all(command)
|
91
85
|
end
|
92
86
|
|
93
|
-
def collect_through_query_results(through, params, context)
|
94
|
-
results = {}
|
95
|
-
|
96
|
-
through = [through].flatten.map(&method(:get_through_query))
|
97
|
-
|
98
|
-
through.each do |q|
|
99
|
-
q.run(params, context) unless q.ran?
|
100
|
-
results[q.name] = q.results.records
|
101
|
-
end
|
102
|
-
|
103
|
-
results = results[through.first.name] if through.size == 1
|
104
|
-
results
|
105
|
-
end
|
106
|
-
|
107
|
-
def get_through_query(name)
|
108
|
-
report.queries[name]
|
109
|
-
end
|
110
|
-
|
111
87
|
def arg_is_report?(arg)
|
112
88
|
arg.is_a?(Report) or (arg.is_a?(Class) and arg < Report)
|
113
89
|
end
|
90
|
+
|
91
|
+
def get_associated_query(query)
|
92
|
+
query.is_a?(Query) ? query : report.queries[query]
|
93
|
+
end
|
114
94
|
end
|
115
95
|
end
|
data/lib/compendium/report.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'active_support/core_ext/class/attribute_accessors'
|
2
2
|
require 'active_support/core_ext/hash/slice'
|
3
|
+
require 'active_support/core_ext/module/delegation'
|
4
|
+
require 'active_support/core_ext/string/inflections'
|
3
5
|
require 'compendium/dsl'
|
4
6
|
|
5
7
|
module Compendium
|
@@ -8,12 +10,45 @@ module Compendium
|
|
8
10
|
|
9
11
|
extend Compendium::DSL
|
10
12
|
|
11
|
-
|
12
|
-
|
13
|
+
delegate :valid?, :errors, to: :params
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def inherited(report)
|
17
|
+
Compendium.reports << report
|
18
|
+
|
19
|
+
# Each Report object has its own Params class so that validations can be added without affecting other
|
20
|
+
# reports. However, validations also need to be inherited, so when inheriting a report, subclass its
|
21
|
+
# params_class
|
22
|
+
report.params_class = Class.new(self.params_class)
|
23
|
+
report.params_class.class_eval %Q{
|
24
|
+
def self.model_name
|
25
|
+
ActiveModel::Name.new(Compendium::Params, Compendium, "compendium.params.#{report.name.underscore rescue 'report'}")
|
26
|
+
end
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
# Define predicate methods for getting the report type
|
31
|
+
# ie. r.spending? checks that r == SpendingReport
|
32
|
+
def method_missing(name, *args, &block)
|
33
|
+
prefix = name.to_s.gsub(/[?!]\z/, '')
|
34
|
+
report_class = "#{prefix}_report".classify.constantize rescue nil
|
35
|
+
|
36
|
+
return self == report_class if name.to_s.end_with?('?') and Compendium.reports.include?(report_class)
|
37
|
+
|
38
|
+
super
|
39
|
+
end
|
40
|
+
|
41
|
+
def respond_to_missing?(name, include_private = false)
|
42
|
+
prefix = name.to_s.gsub(/[?!]\z/, '')
|
43
|
+
report_class = "#{prefix}_report".classify.constantize rescue nil
|
44
|
+
|
45
|
+
return true if name.to_s.end_with?('?') and Compendium.reports.include?(report_class)
|
46
|
+
super
|
47
|
+
end
|
13
48
|
end
|
14
49
|
|
15
50
|
def initialize(params = {})
|
16
|
-
@params =
|
51
|
+
@params = self.class.params_class.new(params, options)
|
17
52
|
|
18
53
|
# When creating a new report, map each query back to the report
|
19
54
|
queries.each { |q| q.report = self }
|
@@ -1,8 +1,9 @@
|
|
1
1
|
require 'active_support/core_ext/module/delegation'
|
2
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
2
3
|
|
3
4
|
module Compendium
|
4
5
|
class ResultSet
|
5
|
-
delegate :first, :last, :to_a, :empty?, :each, :map, :[], :count, :length, :size, :==, to: :records
|
6
|
+
delegate :first, :last, :to_a, :empty?, :each, :map, :inject, :select, :detect, :[], :count, :length, :size, :==, to: :records
|
6
7
|
|
7
8
|
attr_reader :records
|
8
9
|
alias :all :records
|
@@ -11,6 +12,8 @@ module Compendium
|
|
11
12
|
@records = records.map do |r|
|
12
13
|
r.respond_to?(:with_indifferent_access) ? r.with_indifferent_access : r
|
13
14
|
end
|
15
|
+
|
16
|
+
@records = Hash[@records] if records.is_a?(Hash)
|
14
17
|
end
|
15
18
|
|
16
19
|
def keys
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'compendium/query'
|
2
|
+
|
3
|
+
module Compendium
|
4
|
+
class ThroughQuery < Query
|
5
|
+
attr_accessor :through
|
6
|
+
|
7
|
+
def initialize(*args)
|
8
|
+
@report = args.shift if arg_is_report?(args.first)
|
9
|
+
@through = args.slice!(1)
|
10
|
+
super(*args)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def collect_results(context, params)
|
16
|
+
args = collect_through_query_results(params, context)
|
17
|
+
|
18
|
+
# If none of the through queries have any results, we shouldn't try to execute the query, because it
|
19
|
+
# depends on the results of its parents.
|
20
|
+
return @results = ResultSet.new([]) if args.compact.empty?
|
21
|
+
|
22
|
+
super(context, args)
|
23
|
+
end
|
24
|
+
|
25
|
+
def fetch_results(command)
|
26
|
+
command
|
27
|
+
end
|
28
|
+
|
29
|
+
def collect_through_query_results(params, context)
|
30
|
+
results = {}
|
31
|
+
|
32
|
+
queries = [through].flatten.map(&method(:get_associated_query))
|
33
|
+
|
34
|
+
queries.each do |q|
|
35
|
+
q.run(params, context) unless q.ran?
|
36
|
+
results[q.name] = q.results.records
|
37
|
+
end
|
38
|
+
|
39
|
+
results = results[queries.first.name] if queries.size == 1
|
40
|
+
results
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/compendium/version.rb
CHANGED
data/lib/compendium.rb
CHANGED
@@ -5,6 +5,7 @@ require 'active_support/configurable'
|
|
5
5
|
module Compendium
|
6
6
|
autoload :AbstractChartProvider, 'compendium/abstract_chart_provider'
|
7
7
|
autoload :ChartProvider, 'compendium/abstract_chart_provider'
|
8
|
+
autoload :CollectionQuery, 'compendium/collection_query'
|
8
9
|
autoload :ContextWrapper, 'compendium/context_wrapper'
|
9
10
|
autoload :DSL, 'compendium/dsl'
|
10
11
|
autoload :Metric, 'compendium/metric'
|
@@ -13,6 +14,7 @@ module Compendium
|
|
13
14
|
autoload :Query, 'compendium/query'
|
14
15
|
autoload :ResultSet, 'compendium/result_set'
|
15
16
|
autoload :Report, 'compendium/report'
|
17
|
+
autoload :ThroughQuery, 'compendium/through_query'
|
16
18
|
|
17
19
|
autoload :Param, 'compendium/param_types'
|
18
20
|
autoload :BooleanParam, 'compendium/param_types'
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'compendium/collection_query'
|
3
|
+
|
4
|
+
describe Compendium::CollectionQuery do
|
5
|
+
let(:collection) { { one: 1, two: 2, three: 3 } }
|
6
|
+
subject { described_class.new(:collection_query, { collection: collection }, -> _, key, item { [item * 2] }) }
|
7
|
+
|
8
|
+
before { Compendium::Query.any_instance.stub(:execute_query) { |cmd| cmd } }
|
9
|
+
|
10
|
+
describe "#run" do
|
11
|
+
context do
|
12
|
+
before { subject.run(nil) }
|
13
|
+
|
14
|
+
its(:results) { should be_a Compendium::ResultSet }
|
15
|
+
its(:results) { should == { one: [2], two: [4], three: [6] } }
|
16
|
+
|
17
|
+
context "when given an array instead of a hash" do
|
18
|
+
let(:collection) { [1, 2, 3] }
|
19
|
+
|
20
|
+
its(:results) { should be_a Compendium::ResultSet }
|
21
|
+
its(:results) { should == { 1 => [2], 2 => [4], 3 => [6] } }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should not collect empty results" do
|
26
|
+
subject.proc = -> _, key, item { [item] if item > 2 }
|
27
|
+
subject.run(nil)
|
28
|
+
subject.results.should == { three: [3] }
|
29
|
+
end
|
30
|
+
|
31
|
+
context "when given another query" do
|
32
|
+
let(:q) { Compendium::Query.new(:q, {}, -> * { { one: 1, two: 2, three: 3 } }) }
|
33
|
+
subject { described_class.new(:collection, { collection: q }, -> _, key, item { [ item * 2 ] }) }
|
34
|
+
|
35
|
+
before { subject.run(nil) if example.metadata.fetch(:run_query, true) }
|
36
|
+
|
37
|
+
its(:results) { should == { one: [2], two: [4], three: [6] } }
|
38
|
+
|
39
|
+
it "should not re-run the query if it has already ran", run_query: false do
|
40
|
+
q.run(nil)
|
41
|
+
q.should_not_receive(:run)
|
42
|
+
subject.run(nil)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/spec/dsl_spec.rb
CHANGED
@@ -25,15 +25,34 @@ describe Compendium::DSL do
|
|
25
25
|
subject.option :starting_on, :date, default: proc
|
26
26
|
subject.options[:starting_on].default.should == proc
|
27
27
|
end
|
28
|
+
|
29
|
+
it "should add validations" do
|
30
|
+
subject.option :foo, validates: { presence: true }
|
31
|
+
subject.params_class.validators_on(:foo).should_not be_empty
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should not add validations if no validates option is given" do
|
35
|
+
subject.params_class.should_not_receive :validates
|
36
|
+
subject.option :foo
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should not bleed overridden options into the superclass" do
|
40
|
+
r = Class.new(subject)
|
41
|
+
r.option :starting_on, :boolean
|
42
|
+
r.option :new, :date
|
43
|
+
subject.options[:starting_on].should be_date
|
44
|
+
end
|
28
45
|
end
|
29
46
|
|
30
47
|
describe "#query" do
|
31
|
-
|
48
|
+
let(:report_class) do
|
32
49
|
Class.new(Compendium::Report) do
|
33
50
|
query :test
|
34
51
|
end
|
35
52
|
end
|
36
53
|
|
54
|
+
subject { report_class }
|
55
|
+
|
37
56
|
its(:queries) { should include :test }
|
38
57
|
|
39
58
|
it "should relate the new query back to the report instance" do
|
@@ -44,6 +63,42 @@ describe Compendium::DSL do
|
|
44
63
|
it "should not relate a query to the report class" do
|
45
64
|
subject.test.report.should be_nil
|
46
65
|
end
|
66
|
+
|
67
|
+
context "when given a through option" do
|
68
|
+
before { report_class.query :through, through: :test }
|
69
|
+
subject { report_class.queries[:through] }
|
70
|
+
|
71
|
+
it { should be_a Compendium::ThroughQuery }
|
72
|
+
its(:through) { should == [:test] }
|
73
|
+
end
|
74
|
+
|
75
|
+
context "when given a collection option" do
|
76
|
+
subject { report_class.queries[:collection] }
|
77
|
+
|
78
|
+
context "that is an enumerable" do
|
79
|
+
before { report_class.query :collection, collection: [] }
|
80
|
+
|
81
|
+
it { should be_a Compendium::CollectionQuery }
|
82
|
+
end
|
83
|
+
|
84
|
+
context "that is a symbol" do
|
85
|
+
let(:query) { double("Query") }
|
86
|
+
|
87
|
+
before do
|
88
|
+
Compendium::Query.any_instance.stub(:get_associated_query).with(:query).and_return(query)
|
89
|
+
report_class.query :collection, collection: :query
|
90
|
+
end
|
91
|
+
|
92
|
+
its(:collection) { should == :query }
|
93
|
+
end
|
94
|
+
|
95
|
+
context "that is a query" do
|
96
|
+
let(:query) { Compendium::Query.new(:query, {}, ->{}) }
|
97
|
+
before { report_class.query :collection, collection: query }
|
98
|
+
|
99
|
+
its(:collection) { should == query }
|
100
|
+
end
|
101
|
+
end
|
47
102
|
end
|
48
103
|
|
49
104
|
describe "#chart" do
|
@@ -81,6 +136,19 @@ describe Compendium::DSL do
|
|
81
136
|
it "should raise an error if specified for an invalid query" do
|
82
137
|
expect{ subject.metric :test_metric, metric_proc, through: :fake }.to raise_error ArgumentError, 'query fake is not defined'
|
83
138
|
end
|
139
|
+
|
140
|
+
it "should allow metrics to be defined with a block" do
|
141
|
+
subject.metric :block_metric, through: :test do
|
142
|
+
123
|
143
|
+
end
|
144
|
+
|
145
|
+
subject.queries[:test].metrics[:block_metric].run(self, nil).should == 123
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should allow metrics to be defined with a lambda" do
|
149
|
+
subject.metric :block_metric, -> * { 123 }, through: :test
|
150
|
+
subject.queries[:test].metrics[:block_metric].run(self, nil).should == 123
|
151
|
+
end
|
84
152
|
end
|
85
153
|
|
86
154
|
it "should allow previously defined queries to be redefined by name" do
|
data/spec/params_spec.rb
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
require 'compendium/params'
|
2
2
|
|
3
3
|
describe Compendium::Params do
|
4
|
-
let(:options) {
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
4
|
+
let(:options) {
|
5
|
+
opts = Collection[Compendium::Option]
|
6
|
+
opts << Compendium::Option.new(name: :starting_on, type: :date, default: ->{ Date.today })
|
7
|
+
opts << Compendium::Option.new(name: :ending_on, type: :date)
|
8
|
+
opts << Compendium::Option.new(name: :report_type, type: :radio, choices: [:big, :small])
|
9
|
+
opts << Compendium::Option.new(name: :boolean, type: :boolean)
|
10
|
+
opts << Compendium::Option.new(name: :another_boolean, type: :boolean)
|
11
|
+
opts
|
12
|
+
}
|
11
13
|
|
12
14
|
subject{ described_class.new(@params, options) }
|
13
15
|
|
@@ -25,4 +27,17 @@ describe Compendium::Params do
|
|
25
27
|
@params = {}
|
26
28
|
subject.ending_on.should be_nil
|
27
29
|
end
|
30
|
+
|
31
|
+
describe "#validations" do
|
32
|
+
let(:report_class) { Class.new(described_class) }
|
33
|
+
subject { report_class.new({}, options) }
|
34
|
+
|
35
|
+
before do
|
36
|
+
report_class.validates :ending_on, presence: true
|
37
|
+
subject.valid?
|
38
|
+
end
|
39
|
+
|
40
|
+
it { should_not be_valid }
|
41
|
+
its('errors.keys') { should include :ending_on }
|
42
|
+
end
|
28
43
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'compendium/presenters/chart'
|
3
|
+
|
4
|
+
describe Compendium::Presenters::Chart do
|
5
|
+
before do
|
6
|
+
described_class.any_instance.stub(:provider) { double('ChartProvider') }
|
7
|
+
described_class.any_instance.stub(:initialize_chart_provider)
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '#initialize' do
|
11
|
+
let(:template) { double('Template') }
|
12
|
+
let(:query) { double('Query', name: 'test_query', results: results, options: {}) }
|
13
|
+
let(:results) { Compendium::ResultSet.new([]) }
|
14
|
+
|
15
|
+
context 'when all params are given' do
|
16
|
+
subject{ described_class.new(template, query, :pie, :container) }
|
17
|
+
|
18
|
+
its(:data) { should == results.records }
|
19
|
+
its(:container) { should == :container }
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'when container is not given' do
|
23
|
+
subject{ described_class.new(template, query, :pie) }
|
24
|
+
|
25
|
+
its(:data) { should == results.records }
|
26
|
+
its(:container) { should == 'test_query' }
|
27
|
+
end
|
28
|
+
|
29
|
+
context "when options are given" do
|
30
|
+
before { results.stub(:records) { { one: [] } } }
|
31
|
+
subject{ described_class.new(template, query, :pie, index: :one) }
|
32
|
+
|
33
|
+
its(:data) { should == results.records[:one] }
|
34
|
+
its(:container) { should == 'test_query' }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -15,7 +15,7 @@ describe Compendium::Presenters::Option do
|
|
15
15
|
|
16
16
|
describe "#name" do
|
17
17
|
it "should pass the name through I18n" do
|
18
|
-
template.should_receive(:t).with(
|
18
|
+
template.should_receive(:t).with('options.test_option', anything)
|
19
19
|
subject.name
|
20
20
|
end
|
21
21
|
end
|
data/spec/query_spec.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'spec_helper'
|
1
2
|
require 'compendium/query'
|
2
3
|
|
3
4
|
describe Compendium::Query do
|
@@ -48,50 +49,47 @@ describe Compendium::Query do
|
|
48
49
|
query = described_class.new(:blank, {}, nil)
|
49
50
|
query.run(nil).should be_empty
|
50
51
|
end
|
52
|
+
end
|
51
53
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
subject { described_class.new(:sub, {}, -> records { records.first }) }
|
58
|
-
|
59
|
-
before do
|
60
|
-
subject.stub(:get_through_query).with(:parent1).and_return(parent_query1)
|
61
|
-
subject.stub(:get_through_query).with(:parent2).and_return(parent_query2)
|
62
|
-
subject.stub(:get_through_query).with(:parent3).and_return(parent_query3)
|
63
|
-
described_class.any_instance.stub(:execute_query) { |cmd| cmd }
|
64
|
-
end
|
65
|
-
|
66
|
-
it "should not try to run a through query if the parent query has no results" do
|
67
|
-
subject.through = :parent1
|
54
|
+
describe "#nil?" do
|
55
|
+
it "should return true if the query's proc is nil" do
|
56
|
+
Compendium::Query.new(:test, {}, nil).should be_nil
|
57
|
+
end
|
68
58
|
|
69
|
-
|
70
|
-
|
71
|
-
|
59
|
+
it "should return false if the query's proc is not nil" do
|
60
|
+
Compendium::Query.new(:test, {}, ->{}).should_not be_nil
|
61
|
+
end
|
62
|
+
end
|
72
63
|
|
73
|
-
|
74
|
-
|
64
|
+
describe "#render_chart" do
|
65
|
+
let(:template) { double("Template") }
|
66
|
+
subject { described_class.new(:test, {}, -> * {}) }
|
75
67
|
|
76
|
-
|
77
|
-
|
78
|
-
|
68
|
+
it "should return nil if the query has no results" do
|
69
|
+
subject.stub(empty?: true)
|
70
|
+
subject.render_chart(template).should be_nil
|
71
|
+
end
|
79
72
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
end
|
73
|
+
it "should initialize a new Chart presenter if the query has results" do
|
74
|
+
subject.stub(empty?: false)
|
75
|
+
Compendium::Presenters::Chart.should_receive(:new).with(template, subject).and_return(double("Presenter").as_null_object)
|
76
|
+
subject.render_chart(template)
|
85
77
|
end
|
86
78
|
end
|
87
79
|
|
88
|
-
describe "#
|
89
|
-
|
90
|
-
|
80
|
+
describe "#render_table" do
|
81
|
+
let(:template) { double("Template") }
|
82
|
+
subject { described_class.new(:test, {}, -> * {}) }
|
83
|
+
|
84
|
+
it "should return nil if the query has no results" do
|
85
|
+
subject.stub(empty?: true)
|
86
|
+
subject.render_table(template).should be_nil
|
91
87
|
end
|
92
88
|
|
93
|
-
it "should
|
94
|
-
|
89
|
+
it "should initialize a new Table presenter if the query has results" do
|
90
|
+
subject.stub(empty?: false)
|
91
|
+
Compendium::Presenters::Table.should_receive(:new).with(template, subject).and_return(double("Presenter").as_null_object)
|
92
|
+
subject.render_table(template)
|
95
93
|
end
|
96
94
|
end
|
97
95
|
end
|
data/spec/report_spec.rb
CHANGED
@@ -129,4 +129,60 @@ describe Compendium::Report do
|
|
129
129
|
end
|
130
130
|
end
|
131
131
|
end
|
132
|
+
|
133
|
+
describe "predicate methods" do
|
134
|
+
before do
|
135
|
+
OneReport = Class.new(Compendium::Report)
|
136
|
+
TwoReport = Class.new(Compendium::Report)
|
137
|
+
ThreeReport = Class.new
|
138
|
+
end
|
139
|
+
|
140
|
+
after do
|
141
|
+
Object.send(:remove_const, :OneReport)
|
142
|
+
Object.send(:remove_const, :TwoReport)
|
143
|
+
Object.send(:remove_const, :ThreeReport)
|
144
|
+
end
|
145
|
+
|
146
|
+
it { should respond_to(:one?) }
|
147
|
+
it { should respond_to(:two?) }
|
148
|
+
it { should_not respond_to(:three?) }
|
149
|
+
|
150
|
+
it { should_not be_one }
|
151
|
+
it { should_not be_two }
|
152
|
+
|
153
|
+
specify { OneReport.should be_one }
|
154
|
+
specify { TwoReport.should be_two }
|
155
|
+
end
|
156
|
+
|
157
|
+
describe "parameters" do
|
158
|
+
let(:report_class) { Class.new(subject) }
|
159
|
+
let(:report_class2) { Class.new(report_class) }
|
160
|
+
|
161
|
+
it "should include ancestors params" do
|
162
|
+
report_class.params_class.ancestors.should include subject.params_class
|
163
|
+
end
|
164
|
+
|
165
|
+
it "should inherit validations" do
|
166
|
+
report_class.params_class.validates :foo, presence: true
|
167
|
+
report_class2.params_class.validators_on(:foo).should_not be_nil
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
describe "#valid?" do
|
172
|
+
let(:report_class) do
|
173
|
+
Class.new(described_class) do
|
174
|
+
option :id, :dropdown, choices: (0..10).to_a, validates: { presence: true }
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
it "should return true if there are no validation failures" do
|
179
|
+
r = report_class.new(id: 5)
|
180
|
+
r.should be_valid
|
181
|
+
end
|
182
|
+
|
183
|
+
it "should return false if there are validation failures" do
|
184
|
+
r = report_class.new(id: nil)
|
185
|
+
r.should_not be_valid
|
186
|
+
end
|
187
|
+
end
|
132
188
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'compendium/result_set'
|
2
|
+
|
3
|
+
describe Compendium::ResultSet do
|
4
|
+
describe "#initialize" do
|
5
|
+
subject{ described_class.new(results).records }
|
6
|
+
|
7
|
+
context "when given an array" do
|
8
|
+
let(:results) { [1, 2, 3] }
|
9
|
+
it { should == [1, 2, 3] }
|
10
|
+
end
|
11
|
+
|
12
|
+
context "when given an array of hashes" do
|
13
|
+
let(:results) { [{one: 1}, {two: 2}] }
|
14
|
+
it { should == [{"one" => 1}, {"two" => 2}] }
|
15
|
+
its(:first) { should be_a ActiveSupport::HashWithIndifferentAccess }
|
16
|
+
end
|
17
|
+
|
18
|
+
context "when given a hash" do
|
19
|
+
let(:results) { { one: 1, two: 2 } }
|
20
|
+
it { should == { one: 1, two: 2 } }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'compendium/through_query'
|
2
|
+
|
3
|
+
describe Compendium::ThroughQuery do
|
4
|
+
describe "#initialize" do
|
5
|
+
let(:options) { double("Options") }
|
6
|
+
let(:proc) { double("Proc") }
|
7
|
+
let(:through) { double("Query") }
|
8
|
+
|
9
|
+
context "when supplying a report" do
|
10
|
+
let(:r) { Compendium::Report.new }
|
11
|
+
subject { described_class.new(r, :test, through, options, proc)}
|
12
|
+
|
13
|
+
its(:report) { should == r }
|
14
|
+
its(:name) { should == :test }
|
15
|
+
its(:through) { should == through }
|
16
|
+
its(:options) { should == options }
|
17
|
+
its(:proc) { should == proc }
|
18
|
+
end
|
19
|
+
|
20
|
+
context "when not supplying a report" do
|
21
|
+
subject { described_class.new(:test, through, options, proc)}
|
22
|
+
|
23
|
+
its(:report) { should be_nil }
|
24
|
+
its(:name) { should == :test }
|
25
|
+
its(:through) { should == through }
|
26
|
+
its(:options) { should == options }
|
27
|
+
its(:proc) { should == proc }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "#run" do
|
32
|
+
let(:parent1) { Compendium::Query.new(:parent1, {}, -> * { }) }
|
33
|
+
let(:parent2) { Compendium::Query.new(:parent2, {}, -> * { }) }
|
34
|
+
let(:parent3) { Compendium::Query.new(:parent3, {}, -> * { [[1, 2, 3]] }) }
|
35
|
+
|
36
|
+
before { parent3.stub(:execute_query) { |cmd| cmd } }
|
37
|
+
|
38
|
+
context "with a single parent" do
|
39
|
+
subject { described_class.new(:sub, parent1, {}, -> r { r.first }) }
|
40
|
+
|
41
|
+
it "should not try to run a through query if the parent query has no results" do
|
42
|
+
expect { subject.run(nil) }.to_not raise_error
|
43
|
+
subject.results.should be_empty
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "with multiple parents" do
|
48
|
+
subject { described_class.new(:sub, [parent1, parent2], {}, -> r { r.first }) }
|
49
|
+
|
50
|
+
it "should not try to run a through query with multiple parents all of which have no results" do
|
51
|
+
expect { subject.run(nil) }.to_not raise_error
|
52
|
+
subject.results.should be_empty
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should allow non blank queries" do
|
56
|
+
subject.through = parent3
|
57
|
+
subject.run(nil)
|
58
|
+
subject.results.should == [1, 2, 3]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context "when the through option is an actual query" do
|
63
|
+
subject { described_class.new(:sub, parent3, {}, -> r { r.first }) }
|
64
|
+
|
65
|
+
before { subject.run(nil) }
|
66
|
+
|
67
|
+
its(:through) { should == parent3 }
|
68
|
+
its(:results) { should == [1, 2, 3] }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: compendium
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Vandersluis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-11-
|
11
|
+
date: 2013-11-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
type: :runtime
|
@@ -60,12 +60,12 @@ dependencies:
|
|
60
60
|
requirements:
|
61
61
|
- - '='
|
62
62
|
- !ruby/object:Gem::Version
|
63
|
-
version: 1.0.
|
63
|
+
version: 1.0.5
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - '='
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: 1.0.
|
68
|
+
version: 1.0.5
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
type: :runtime
|
71
71
|
prerelease: false
|
@@ -129,6 +129,7 @@ files:
|
|
129
129
|
- lib/compendium.rb
|
130
130
|
- lib/compendium/abstract_chart_provider.rb
|
131
131
|
- lib/compendium/chart_provider/amcharts.rb
|
132
|
+
- lib/compendium/collection_query.rb
|
132
133
|
- lib/compendium/context_wrapper.rb
|
133
134
|
- lib/compendium/dsl.rb
|
134
135
|
- lib/compendium/engine.rb
|
@@ -141,7 +142,9 @@ files:
|
|
141
142
|
- lib/compendium/query.rb
|
142
143
|
- lib/compendium/report.rb
|
143
144
|
- lib/compendium/result_set.rb
|
145
|
+
- lib/compendium/through_query.rb
|
144
146
|
- lib/compendium/version.rb
|
147
|
+
- spec/collection_query_spec.rb
|
145
148
|
- spec/context_wrapper_spec.rb
|
146
149
|
- spec/dsl_spec.rb
|
147
150
|
- spec/metric_spec.rb
|
@@ -149,10 +152,13 @@ files:
|
|
149
152
|
- spec/param_types_spec.rb
|
150
153
|
- spec/params_spec.rb
|
151
154
|
- spec/presenters/base_spec.rb
|
155
|
+
- spec/presenters/chart_spec.rb
|
152
156
|
- spec/presenters/option_spec.rb
|
153
157
|
- spec/query_spec.rb
|
154
158
|
- spec/report_spec.rb
|
159
|
+
- spec/result_set_spec.rb
|
155
160
|
- spec/spec_helper.rb
|
161
|
+
- spec/through_query_spec.rb
|
156
162
|
homepage: https://github.com/dvandersluis/compendium
|
157
163
|
licenses:
|
158
164
|
- MIT
|
@@ -178,6 +184,7 @@ signing_key:
|
|
178
184
|
specification_version: 4
|
179
185
|
summary: Ruby on Rails reporting framework
|
180
186
|
test_files:
|
187
|
+
- spec/collection_query_spec.rb
|
181
188
|
- spec/context_wrapper_spec.rb
|
182
189
|
- spec/dsl_spec.rb
|
183
190
|
- spec/metric_spec.rb
|
@@ -185,8 +192,11 @@ test_files:
|
|
185
192
|
- spec/param_types_spec.rb
|
186
193
|
- spec/params_spec.rb
|
187
194
|
- spec/presenters/base_spec.rb
|
195
|
+
- spec/presenters/chart_spec.rb
|
188
196
|
- spec/presenters/option_spec.rb
|
189
197
|
- spec/query_spec.rb
|
190
198
|
- spec/report_spec.rb
|
199
|
+
- spec/result_set_spec.rb
|
191
200
|
- spec/spec_helper.rb
|
201
|
+
- spec/through_query_spec.rb
|
192
202
|
has_rdoc:
|