compendium 0.0.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/README.md +70 -4
- data/Rakefile +4 -0
- data/app/assets/stylesheets/compendium/_metrics.css.scss +92 -0
- data/app/assets/stylesheets/compendium/options.css.scss +41 -0
- data/app/assets/stylesheets/compendium/report.css.scss +22 -0
- data/app/classes/compendium/presenters/base.rb +30 -0
- data/app/classes/compendium/presenters/chart.rb +31 -0
- data/app/classes/compendium/presenters/metric.rb +19 -0
- data/app/classes/compendium/presenters/option.rb +97 -0
- data/app/classes/compendium/presenters/query.rb +23 -0
- data/app/classes/compendium/presenters/settings/query.rb +22 -0
- data/app/classes/compendium/presenters/settings/table.rb +23 -0
- data/app/classes/compendium/presenters/table.rb +81 -0
- data/app/controllers/compendium/reports_controller.rb +52 -0
- data/app/helpers/compendium/reports_helper.rb +21 -0
- data/app/views/compendium/reports/run.haml +1 -0
- data/app/views/compendium/reports/setup.haml +14 -0
- data/compendium.gemspec +7 -1
- data/config/initializers/rails/active_record/connection_adapters/quoting.rb +14 -0
- data/config/initializers/ruby/numeric.rb +26 -0
- data/config/locales/en.yml +5 -0
- data/lib/compendium/abstract_chart_provider.rb +30 -0
- data/lib/compendium/chart_provider/amcharts.rb +20 -0
- data/lib/compendium/context_wrapper.rb +27 -0
- data/lib/compendium/dsl.rb +79 -0
- data/lib/compendium/engine/mount.rb +13 -0
- data/lib/compendium/engine.rb +8 -0
- data/lib/compendium/metric.rb +29 -0
- data/lib/compendium/open_hash.rb +68 -0
- data/lib/compendium/option.rb +37 -0
- data/lib/compendium/param_types.rb +91 -0
- data/lib/compendium/params.rb +40 -0
- data/lib/compendium/query.rb +94 -0
- data/lib/compendium/report.rb +56 -0
- data/lib/compendium/result_set.rb +24 -0
- data/lib/compendium/version.rb +1 -1
- data/lib/compendium.rb +46 -1
- data/spec/context_wrapper_spec.rb +71 -0
- data/spec/dsl_spec.rb +90 -0
- data/spec/metric_spec.rb +84 -0
- data/spec/option_spec.rb +12 -0
- data/spec/param_types_spec.rb +147 -0
- data/spec/params_spec.rb +28 -0
- data/spec/presenters/base_spec.rb +20 -0
- data/spec/presenters/option_spec.rb +49 -0
- data/spec/query_spec.rb +33 -0
- data/spec/report_spec.rb +93 -0
- data/spec/spec_helper.rb +1 -0
- metadata +135 -14
data/lib/compendium/version.rb
CHANGED
data/lib/compendium.rb
CHANGED
@@ -1,5 +1,50 @@
|
|
1
|
-
require
|
1
|
+
require 'compendium/engine'
|
2
|
+
require 'compendium/version'
|
3
|
+
require 'active_support/configurable'
|
2
4
|
|
3
5
|
module Compendium
|
6
|
+
autoload :AbstractChartProvider, 'compendium/abstract_chart_provider'
|
7
|
+
autoload :ChartProvider, 'compendium/abstract_chart_provider'
|
8
|
+
autoload :ContextWrapper, 'compendium/context_wrapper'
|
9
|
+
autoload :DSL, 'compendium/dsl'
|
10
|
+
autoload :Metric, 'compendium/metric'
|
11
|
+
autoload :Option, 'compendium/option'
|
12
|
+
autoload :Params, 'compendium/params'
|
13
|
+
autoload :Query, 'compendium/query'
|
14
|
+
autoload :ResultSet, 'compendium/result_set'
|
15
|
+
autoload :Report, 'compendium/report'
|
4
16
|
|
17
|
+
autoload :Param, 'compendium/param_types'
|
18
|
+
autoload :BooleanParam, 'compendium/param_types'
|
19
|
+
autoload :DateParam, 'compendium/param_types'
|
20
|
+
autoload :DropdownParam, 'compendium/param_types'
|
21
|
+
autoload :ParamWithChoices, 'compendium/param_types'
|
22
|
+
autoload :RadioParam, 'compendium/param_types'
|
23
|
+
|
24
|
+
def self.reports
|
25
|
+
@reports ||= []
|
26
|
+
end
|
27
|
+
|
28
|
+
# Configures global settings for Compendium
|
29
|
+
# Compendium.configure do |config|
|
30
|
+
# config.chart_provider = :AmCharts
|
31
|
+
# end
|
32
|
+
def self.configure(&block)
|
33
|
+
yield @config ||= Compendium::Configuration.new
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.config
|
37
|
+
@config
|
38
|
+
end
|
39
|
+
|
40
|
+
# need a Class for 3.0
|
41
|
+
class Configuration #:nodoc:
|
42
|
+
include ActiveSupport::Configurable
|
43
|
+
|
44
|
+
config_accessor :chart_provider
|
45
|
+
end
|
46
|
+
|
47
|
+
configure do |config|
|
48
|
+
config.chart_provider = Compendium::AbstractChartProvider.find_chart_provider
|
49
|
+
end
|
5
50
|
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'compendium/context_wrapper'
|
2
|
+
|
3
|
+
class Wrapper1
|
4
|
+
def test_val
|
5
|
+
123
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class Wrapper2
|
10
|
+
def wrapped
|
11
|
+
true
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class Wrapper3
|
16
|
+
def wrapper_num
|
17
|
+
3
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Wrapper4
|
22
|
+
def wrapper_num
|
23
|
+
4
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe Compendium::ContextWrapper do
|
28
|
+
describe ".wrap" do
|
29
|
+
let(:w1) { Wrapper1.new }
|
30
|
+
let(:w2) { Wrapper2.new }
|
31
|
+
let(:w3) { Wrapper3.new }
|
32
|
+
let(:w4) { Wrapper4.new }
|
33
|
+
|
34
|
+
subject { described_class.wrap(w2, w1) }
|
35
|
+
|
36
|
+
it { should respond_to :test_val }
|
37
|
+
it { should respond_to :wrapped }
|
38
|
+
|
39
|
+
its(:test_val) { should == 123 }
|
40
|
+
its(:wrapped) { should == true }
|
41
|
+
|
42
|
+
it "should not affect the original objects" do
|
43
|
+
subject
|
44
|
+
w1.should_not respond_to :wrapped
|
45
|
+
w2.should_not respond_to :test_val
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should yield a block if given" do
|
49
|
+
described_class.wrap(w2, w1) { test_val }.should == 123
|
50
|
+
end
|
51
|
+
|
52
|
+
context "overriding methods" do
|
53
|
+
subject { described_class.wrap(w4, w3) }
|
54
|
+
its(:wrapper_num) { should == 4 }
|
55
|
+
end
|
56
|
+
|
57
|
+
context "nested wrapping" do
|
58
|
+
let(:inner) { described_class.wrap(w2, w1) }
|
59
|
+
subject { described_class.wrap(inner, w3) }
|
60
|
+
|
61
|
+
it { should respond_to :test_val }
|
62
|
+
it { should respond_to :wrapped }
|
63
|
+
it { should respond_to :wrapper_num }
|
64
|
+
|
65
|
+
it "should not extend the inner wrap" do
|
66
|
+
subject
|
67
|
+
inner.should_not respond_to :wrapper_num
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/spec/dsl_spec.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'compendium'
|
2
|
+
require 'compendium/dsl'
|
3
|
+
|
4
|
+
describe Compendium::DSL do
|
5
|
+
subject do
|
6
|
+
Class.new do
|
7
|
+
extend Compendium::DSL
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "#option" do
|
12
|
+
before { subject.option :starting_on, :date }
|
13
|
+
|
14
|
+
its(:options) { should include :starting_on }
|
15
|
+
specify { subject.options[:starting_on].should be_date }
|
16
|
+
|
17
|
+
it "should allow previously defined options to be redefined" do
|
18
|
+
subject.option :starting_on, :boolean
|
19
|
+
subject.options[:starting_on].should be_boolean
|
20
|
+
subject.options[:starting_on].should_not be_date
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#query" do
|
25
|
+
subject do
|
26
|
+
Class.new(Compendium::Report) do
|
27
|
+
query :test
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
its(:queries) { should include :test }
|
32
|
+
|
33
|
+
it "should relate the new query back to the report instance" do
|
34
|
+
r = subject.new
|
35
|
+
r.test.report.should == r
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should not relate a query to the report class" do
|
39
|
+
subject.test.report.should be_nil
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "#chart" do
|
44
|
+
before { subject.chart(:chart) }
|
45
|
+
|
46
|
+
its(:queries) { should include :chart }
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "#data" do
|
50
|
+
before { subject.data(:data) }
|
51
|
+
|
52
|
+
its(:queries) { should include :data }
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "#metric" do
|
56
|
+
let(:metric_proc) { ->{ :metric } }
|
57
|
+
|
58
|
+
before do
|
59
|
+
subject.query :test
|
60
|
+
subject.metric :test_metric, metric_proc, through: :test
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should add a metric to the given query" do
|
64
|
+
subject.queries[:test].metrics.first.name.should == :test_metric
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should set the metric command" do
|
68
|
+
subject.queries[:test].metrics.first.command.should == metric_proc
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should raise an error if through is not specified" do
|
72
|
+
expect{ subject.metric :test_metric, metric_proc }.to raise_error ArgumentError, 'through option must be specified for metric'
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should raise an error if specified for an invalid query" do
|
76
|
+
expect{ subject.metric :test_metric, metric_proc, through: :fake }.to raise_error ArgumentError, 'query fake is not defined'
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should allow previously defined queries to be redefined by name" do
|
81
|
+
subject.query :test_query
|
82
|
+
subject.test_query foo: :bar
|
83
|
+
subject.queries[:test_query].options.should == { foo: :bar }
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should allow previously defined queries to be accessed by name" do
|
87
|
+
subject.query :test_query
|
88
|
+
subject.test_query.should == subject.queries[:test_query]
|
89
|
+
end
|
90
|
+
end
|
data/spec/metric_spec.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'compendium/metric'
|
2
|
+
|
3
|
+
class MetricContext
|
4
|
+
def calculate(data)
|
5
|
+
data.first.first
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
describe Compendium::Metric do
|
10
|
+
let(:ctx) { MetricContext.new }
|
11
|
+
let(:data) { [[1, 2, 3], [4, 5, 6]] }
|
12
|
+
|
13
|
+
subject { described_class.new(:test_metric, :query, nil) }
|
14
|
+
|
15
|
+
describe "#run" do
|
16
|
+
it "should delegate the command to the context when the command is a symbol" do
|
17
|
+
subject.command = :calculate
|
18
|
+
subject.run(ctx, data).should == 1
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should call the command when it is a proc" do
|
22
|
+
subject.command = -> d { d.flatten.inject(:+) }
|
23
|
+
subject.run(ctx, data).should == 21
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should allow procs that refer back to the context" do
|
27
|
+
subject.command = -> d { calculate(d) * 2 }
|
28
|
+
subject.run(ctx, data).should == 2
|
29
|
+
end
|
30
|
+
|
31
|
+
context "when an if proc is given" do
|
32
|
+
before { subject.command = -> * { 100 } }
|
33
|
+
|
34
|
+
it "should calculate the metric if the proc evaluates to true" do
|
35
|
+
subject.options[:if] = ->{ true }
|
36
|
+
subject.run(ctx, data).should == 100
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should not calculate the metric if the proc evaluates to false" do
|
40
|
+
subject.options[:if] = ->{ false }
|
41
|
+
subject.run(ctx, data).should be_nil
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should clear the result if the proc evaluates to false" do
|
45
|
+
subject.options[:if] = ->{ false }
|
46
|
+
subject.result = 123
|
47
|
+
subject.run(ctx, data)
|
48
|
+
subject.result.should be_nil
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context "when an unless proc is given" do
|
53
|
+
before { subject.command = -> * { 100 } }
|
54
|
+
|
55
|
+
it "should calculate the metric if the proc evaluates to false" do
|
56
|
+
subject.options[:unless] = ->{ false }
|
57
|
+
subject.run(ctx, data).should == 100
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should not calculate the metric if the proc evaluates to true" do
|
61
|
+
subject.options[:unless] = ->{ true }
|
62
|
+
subject.run(ctx, data).should be_nil
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should clear the result if the proc evaluates to false" do
|
66
|
+
subject.options[:unless] = ->{ true }
|
67
|
+
subject.result = 123
|
68
|
+
subject.run(ctx, data)
|
69
|
+
subject.result.should be_nil
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "#ran?" do
|
75
|
+
it "should return true if there are any results" do
|
76
|
+
subject.stub(result: 123)
|
77
|
+
subject.should have_ran
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should return false if there are no results" do
|
81
|
+
subject.should_not have_ran
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
data/spec/option_spec.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'compendium/option'
|
2
|
+
|
3
|
+
describe Compendium::Option do
|
4
|
+
it "should raise an ArgumentError if no name is given" do
|
5
|
+
expect { described_class.new }.to raise_error ArgumentError, "name must be provided"
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should set up type predicates from the type option" do
|
9
|
+
o = described_class.new(name: :option, type: :date)
|
10
|
+
o.should be_date
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
require 'compendium/param_types'
|
2
|
+
|
3
|
+
describe Compendium::Param do
|
4
|
+
subject{ described_class.new(:test) }
|
5
|
+
|
6
|
+
it { should_not be_boolean }
|
7
|
+
it { should_not be_date }
|
8
|
+
it { should_not be_dropdown }
|
9
|
+
it { should_not be_radio }
|
10
|
+
|
11
|
+
describe "#==" do
|
12
|
+
it "should compare to the param's value" do
|
13
|
+
subject.stub(value: :test_value)
|
14
|
+
subject.should == :test_value
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe Compendium::ParamWithChoices do
|
20
|
+
subject{ described_class.new(0, %w(a b c)) }
|
21
|
+
|
22
|
+
it { should_not be_boolean }
|
23
|
+
it { should_not be_date }
|
24
|
+
it { should_not be_dropdown }
|
25
|
+
it { should_not be_radio }
|
26
|
+
|
27
|
+
it "should return the index when given an index" do
|
28
|
+
p = described_class.new(1, [:foo, :bar, :baz])
|
29
|
+
p.should == 1
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should return the index when given a value" do
|
33
|
+
p = described_class.new(:foo, [:foo, :bar, :baz])
|
34
|
+
p.should == 0
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should return the index when given a string value" do
|
38
|
+
p = described_class.new("2", [:foo, :bar, :baz])
|
39
|
+
p.should == 2
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should raise an error if given an invalid index" do
|
43
|
+
expect { described_class.new(3, [:foo, :bar, :baz]) }.to raise_error IndexError
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should raise an error if given a value that is not included in the choices" do
|
47
|
+
expect { described_class.new(:quux, [:foo, :bar, :baz]) }.to raise_error IndexError
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "#value" do
|
51
|
+
it "should return the value of the given choice" do
|
52
|
+
p = described_class.new(2, [:foo, :bar, :baz])
|
53
|
+
p.value.should == :baz
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe Compendium::BooleanParam do
|
59
|
+
subject{ described_class.new(true) }
|
60
|
+
|
61
|
+
it { should be_boolean }
|
62
|
+
it { should_not be_date }
|
63
|
+
it { should_not be_dropdown }
|
64
|
+
it { should_not be_radio }
|
65
|
+
|
66
|
+
it "should pass along 0 and 1" do
|
67
|
+
described_class.new(0).should == 0
|
68
|
+
described_class.new(1).should == 1
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should convert a numeric string to a number" do
|
72
|
+
described_class.new('0').should == 0
|
73
|
+
described_class.new('1').should == 1
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should return 0 for a truthy value" do
|
77
|
+
described_class.new(true).should == 0
|
78
|
+
described_class.new(:abc).should == 0
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should return 1 for a falsey value" do
|
82
|
+
described_class.new(false).should == 1
|
83
|
+
described_class.new(nil).should == 1
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "#value" do
|
87
|
+
it "should return true for a truthy value" do
|
88
|
+
described_class.new(true).value.should == true
|
89
|
+
described_class.new(:abc).value.should == true
|
90
|
+
described_class.new(0).value.should == true
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should return false for a falsey value" do
|
94
|
+
described_class.new(false).value.should == false
|
95
|
+
described_class.new(nil).value.should == false
|
96
|
+
described_class.new(1).value.should == false
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "#!" do
|
101
|
+
it "should return false if the boolean is true" do
|
102
|
+
!described_class.new(true).should == false
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should return true if the boolean is false" do
|
106
|
+
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe Compendium::DateParam do
|
112
|
+
subject{ described_class.new(Date.today) }
|
113
|
+
|
114
|
+
it { should_not be_boolean }
|
115
|
+
it { should be_date }
|
116
|
+
it { should_not be_dropdown }
|
117
|
+
it { should_not be_radio }
|
118
|
+
|
119
|
+
it "should convert date strings to date objects" do
|
120
|
+
p = described_class.new("2010-05-20")
|
121
|
+
p.should == Date.new(2010, 5, 20)
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should convert other date/time formats to date objects" do
|
125
|
+
described_class.new(DateTime.new(2010, 5, 20, 10, 30, 59)) == Date.new(2010, 5, 20)
|
126
|
+
described_class.new(Time.new(2010, 5, 20, 10, 30, 59)) == Date.new(2010, 5, 20)
|
127
|
+
described_class.new(Date.new(2010, 5, 20)) == Date.new(2010, 5, 20)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe Compendium::DropdownParam do
|
132
|
+
subject{ described_class.new(0, %w(a b c)) }
|
133
|
+
|
134
|
+
it { should_not be_boolean }
|
135
|
+
it { should_not be_date }
|
136
|
+
it { should be_dropdown }
|
137
|
+
it { should_not be_radio }
|
138
|
+
end
|
139
|
+
|
140
|
+
describe Compendium::RadioParam do
|
141
|
+
subject{ described_class.new(0, %w(a b c)) }
|
142
|
+
|
143
|
+
it { should_not be_boolean }
|
144
|
+
it { should_not be_date }
|
145
|
+
it { should_not be_dropdown }
|
146
|
+
it { should be_radio }
|
147
|
+
end
|
data/spec/params_spec.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'compendium/params'
|
2
|
+
|
3
|
+
describe Compendium::Params do
|
4
|
+
let(:options) { {
|
5
|
+
starting_on: Compendium::Option.new(name: :starting_on, type: :date, default: ->{ Date.today }),
|
6
|
+
ending_on: Compendium::Option.new(name: :ending_on, type: :date),
|
7
|
+
report_type: Compendium::Option.new(name: :report_type, type: :radio, choices: [:big, :small]),
|
8
|
+
boolean: Compendium::Option.new(name: :boolean, type: :boolean),
|
9
|
+
another_boolean: Compendium::Option.new(name: :another_boolean, type: :boolean)
|
10
|
+
} }
|
11
|
+
|
12
|
+
subject{ described_class.new(@params, options) }
|
13
|
+
|
14
|
+
it "should only allow keys that are given as options" do
|
15
|
+
@params = { starting_on: '2013-10-15', foo: :bar }
|
16
|
+
subject.keys.should_not include :foo
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should set missing options to their default value" do
|
20
|
+
@params = {}
|
21
|
+
subject.starting_on.should == Date.today
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should set missing options to nil if there is no default value" do
|
25
|
+
@params = {}
|
26
|
+
subject.ending_on.should be_nil
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'compendium/presenters/base'
|
3
|
+
|
4
|
+
TestPresenter = Class.new(Compendium::Presenters::Base) do
|
5
|
+
presents :test_obj
|
6
|
+
end
|
7
|
+
|
8
|
+
describe Compendium::Presenters::Base do
|
9
|
+
let(:template) { double("Template", delegated?: true) }
|
10
|
+
subject { TestPresenter.new(template, :test) }
|
11
|
+
|
12
|
+
it "should allow the object name to be overridden" do
|
13
|
+
subject.test_obj.should == :test
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should delegate missing methods to the template object" do
|
17
|
+
template.should_receive(:delegated?)
|
18
|
+
subject.should be_delegated
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'compendium/presenters/option'
|
3
|
+
require 'compendium/option'
|
4
|
+
|
5
|
+
describe Compendium::Presenters::Option do
|
6
|
+
let(:template) do
|
7
|
+
t = double('Template')
|
8
|
+
t.stub(:t) { |key| key } # Stub I18n.t to just return the given value
|
9
|
+
t
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:option) { Compendium::Option.new(name: :test_option) }
|
13
|
+
|
14
|
+
subject { described_class.new(template, option) }
|
15
|
+
|
16
|
+
describe "#name" do
|
17
|
+
it "should pass the name through I18n" do
|
18
|
+
template.should_receive(:t).with(:test_option)
|
19
|
+
subject.name
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "#note" do
|
24
|
+
before { template.stub(:content_tag) }
|
25
|
+
|
26
|
+
it "should return nil if no note is specified" do
|
27
|
+
subject.note.should be_nil
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should pass to I18n if the note option is set to true" do
|
31
|
+
option.merge!(note: true)
|
32
|
+
template.should_receive(:t).with(:test_option_note)
|
33
|
+
subject.note
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should pass to I18n if the note option is set" do
|
37
|
+
option.merge!(note: :the_note)
|
38
|
+
template.should_receive(:t).with(:the_note)
|
39
|
+
subject.note
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should create the note within a div with class option-note" do
|
43
|
+
option.merge!(note: true)
|
44
|
+
template.should_receive(:content_tag).with(:div, anything, class: 'option-note')
|
45
|
+
subject.note
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
data/spec/query_spec.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'compendium/query'
|
2
|
+
|
3
|
+
describe Compendium::Query do
|
4
|
+
describe "#run" do
|
5
|
+
let(:query) { described_class.new(:test, {}, -> * { [1, 2, 3] }) }
|
6
|
+
before { query.stub(:fetch_results) { |c| c } }
|
7
|
+
|
8
|
+
it "should return the result of the query" do
|
9
|
+
query.run(nil).should == [1, 2, 3]
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should mark the query as having ran" do
|
13
|
+
query.run(nil)
|
14
|
+
query.should have_run
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should not affect any cloned queries" do
|
18
|
+
q2 = query.clone
|
19
|
+
query.run(nil)
|
20
|
+
q2.should_not have_run
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#nil?" do
|
25
|
+
it "should return true if the query's proc is nil" do
|
26
|
+
Compendium::Query.new(:test, {}, nil).should be_nil
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should return false if the query's proc is not nil" do
|
30
|
+
Compendium::Query.new(:test, {}, ->{}).should_not be_nil
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/spec/report_spec.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'compendium/report'
|
2
|
+
|
3
|
+
describe Compendium::Report do
|
4
|
+
subject { described_class }
|
5
|
+
|
6
|
+
its(:queries) { should be_empty }
|
7
|
+
its(:options) { should be_empty }
|
8
|
+
|
9
|
+
it "should not do anything when run" do
|
10
|
+
report = subject.new
|
11
|
+
report.run
|
12
|
+
report.results.should be_empty
|
13
|
+
end
|
14
|
+
|
15
|
+
context "with multiple instances" do
|
16
|
+
let(:report_class) do
|
17
|
+
Class.new(Compendium::Report) do
|
18
|
+
query :test
|
19
|
+
metric :test_metric, ->{}, through: :test
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
subject { report_class.new }
|
24
|
+
let(:report2) { report_class.new }
|
25
|
+
|
26
|
+
its(:queries) { should_not equal report2.queries }
|
27
|
+
its(:queries) { should_not equal report_class.queries }
|
28
|
+
its(:metrics) { should_not equal report2.metrics }
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "#run" do
|
32
|
+
let(:report_class) do
|
33
|
+
Class.new(Compendium::Report) do
|
34
|
+
option :first, :date
|
35
|
+
option :second, :date
|
36
|
+
|
37
|
+
query :test do |params|
|
38
|
+
[params[:first].__getobj__, params[:second].__getobj__]
|
39
|
+
end
|
40
|
+
|
41
|
+
metric :test_metric, -> results { results.to_a.max }, through: :test
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
subject { report_class.new(first: '2010-10-10', second: '2011-11-11') }
|
46
|
+
let!(:report2) { report_class.new }
|
47
|
+
|
48
|
+
before do
|
49
|
+
Compendium::Query.any_instance.stub(:fetch_results) { |c| c }
|
50
|
+
subject.run
|
51
|
+
end
|
52
|
+
|
53
|
+
its('test_results.records') { should == [Date.new(2010, 10, 10), Date.new(2011, 11, 11)] }
|
54
|
+
|
55
|
+
it "should run its metrics" do
|
56
|
+
subject.test.metrics[:test_metric].result.should == Date.new(2011, 11, 11)
|
57
|
+
subject.metrics[:test_metric].result.should == Date.new(2011, 11, 11)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should not affect other instances of the report class" do
|
61
|
+
report2.test.results.should be_nil
|
62
|
+
report2.metrics[:test_metric].result.should be_nil
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should not affect the class collections" do
|
66
|
+
report_class.test.results.should be_nil
|
67
|
+
end
|
68
|
+
|
69
|
+
context "with through queries" do
|
70
|
+
let(:report_class) do
|
71
|
+
Class.new(Compendium::Report) do
|
72
|
+
option :first, :boolean, default: false
|
73
|
+
query(:test) { |params| !!params[:first] ? [100, 200, 400, 800] : [1600, 3200, 6400]}
|
74
|
+
query(:through, through: :test) { |results| [results.first] }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
subject { report_class.new(first: true) }
|
79
|
+
|
80
|
+
its('through.results') { should == [100] }
|
81
|
+
|
82
|
+
it "should not mark other instances' queries as ran" do
|
83
|
+
report2.test.should_not have_run
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should not affect other instances" do
|
87
|
+
report2.queries.each { |q| q.stub(:fetch_results) { |c| c } }
|
88
|
+
report2.run
|
89
|
+
report2.through.results.should == [1600]
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
$:.unshift File.expand_path("../../app/classes", __FILE__)
|