chartnado 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gemrelease +2 -0
- data/.gitignore +20 -0
- data/.travis.yml +9 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +23 -0
- data/README.md +137 -0
- data/Rakefile +7 -0
- data/chartnado.gemspec +35 -0
- data/lib/assets/javascripts/chartkick-chartnado.js +864 -0
- data/lib/assets/javascripts/jquery.ajax.queue-concurrent.coffee +76 -0
- data/lib/chartnado.rb +39 -0
- data/lib/chartnado/engine.rb +10 -0
- data/lib/chartnado/evaluator.rb +82 -0
- data/lib/chartnado/group_by.rb +92 -0
- data/lib/chartnado/hash.rb +3 -0
- data/lib/chartnado/helper.rb +7 -0
- data/lib/chartnado/helpers/chart_helper.rb +60 -0
- data/lib/chartnado/helpers/series_helper.rb +35 -0
- data/lib/chartnado/renderer.rb +127 -0
- data/lib/chartnado/series.rb +186 -0
- data/lib/chartnado/version.rb +3 -0
- data/spec/controllers/controller_spec.rb +68 -0
- data/spec/dsl_spec.rb +7 -0
- data/spec/helpers/chart_helper_spec.rb +55 -0
- data/spec/helpers/series_helper_spec.rb +33 -0
- data/spec/rails_helper.rb +4 -0
- data/spec/renderer_spec.rb +50 -0
- data/spec/series_spec.rb +138 -0
- data/spec/spec_helper.rb +16 -0
- metadata +250 -0
@@ -0,0 +1,186 @@
|
|
1
|
+
require 'active_support/core_ext'
|
2
|
+
|
3
|
+
module Chartnado
|
4
|
+
module Series
|
5
|
+
# @api public
|
6
|
+
# @example
|
7
|
+
# series_product(2.0, {0 => 1}) => {0 => 2.0}
|
8
|
+
# series_product({0 => 1}, 2.0) => {0 => 2.0}
|
9
|
+
#
|
10
|
+
# @return [Series/Multiple-Series]
|
11
|
+
def series_product(val, series, precision: 2)
|
12
|
+
if dimensions(val) > dimensions(series)
|
13
|
+
return series_product(series, val)
|
14
|
+
end
|
15
|
+
|
16
|
+
return with_precision(precision, val.to_f * series.to_f) unless series.respond_to?(:length)
|
17
|
+
return series unless series.length > 0
|
18
|
+
|
19
|
+
if is_an_array_of_named_series?(series) || series.is_a?(Array) && series.first.is_a?(Array)
|
20
|
+
series.map { |(name, data)| [name, series_product(val, data)] }
|
21
|
+
elsif series.is_a?(Hash)
|
22
|
+
series.to_a.reduce({}) do |hash, (key, value)|
|
23
|
+
if val.is_a?(Hash)
|
24
|
+
if key.is_a?(Array)
|
25
|
+
scalar = val[key.second]
|
26
|
+
else
|
27
|
+
scalar = val[key]
|
28
|
+
end
|
29
|
+
else
|
30
|
+
scalar = val
|
31
|
+
end
|
32
|
+
scalar ||= 0
|
33
|
+
hash[key] = scalar * value
|
34
|
+
hash
|
35
|
+
end
|
36
|
+
else
|
37
|
+
series.map do |value|
|
38
|
+
val * value
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# @api public
|
44
|
+
# @example
|
45
|
+
# series_ratio({0 => 1}, 2.0) => {0 => 0.5}
|
46
|
+
#
|
47
|
+
# @return [Series/Multiple-Series]
|
48
|
+
def series_ratio(top_series, bottom_series, multiplier: 1.0, precision: 2)
|
49
|
+
if bottom_series.is_a?(Numeric)
|
50
|
+
return series_product(1.0 * multiplier / bottom_series, top_series, precision: precision)
|
51
|
+
end
|
52
|
+
if has_multiple_series?(top_series) && !has_multiple_series?(bottom_series)
|
53
|
+
top_series_by_name = data_by_name(top_series)
|
54
|
+
if is_an_array_of_named_series?(top_series)
|
55
|
+
top_series_by_name.map do |name, top_values|
|
56
|
+
[
|
57
|
+
name,
|
58
|
+
series_ratio(top_values, bottom_series, multiplier: multiplier, precision: precision)
|
59
|
+
]
|
60
|
+
end
|
61
|
+
else
|
62
|
+
bottom_series.reduce({}) do |hash, (key, value)|
|
63
|
+
top_series_by_name.keys.each do |name|
|
64
|
+
top_key = [name, *key]
|
65
|
+
top_value = top_series_by_name[name][top_key]
|
66
|
+
if top_value
|
67
|
+
hash[top_key] = series_ratio(top_value, value, multiplier: multiplier, precision: precision)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
hash
|
71
|
+
end
|
72
|
+
end
|
73
|
+
elsif is_an_array_of_named_series?(bottom_series)
|
74
|
+
top_series_by_name = data_by_name(top_series)
|
75
|
+
bottom_series.map do |(name, data)|
|
76
|
+
[
|
77
|
+
name,
|
78
|
+
series_ratio(top_series_by_name[name], data, multiplier: multiplier, precision: precision)
|
79
|
+
]
|
80
|
+
end
|
81
|
+
elsif bottom_series.respond_to?(:reduce)
|
82
|
+
bottom_series.reduce({}) do |hash, (key, value)|
|
83
|
+
hash[key] = series_ratio(top_series[key] || 0, value, multiplier: multiplier, precision: precision)
|
84
|
+
hash
|
85
|
+
end
|
86
|
+
else
|
87
|
+
with_precision(precision, top_series.to_f * multiplier.to_f / bottom_series.to_f)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# @api public
|
92
|
+
# @example
|
93
|
+
# series_sum({0 => 1}, 2.0) => {0 => 3.0}
|
94
|
+
# series_sum({0 => 1}, {0 => 1}) => {0 => 2}
|
95
|
+
# series_sum({0 => 1}, 2.0, 3.0) => {0 => 6.0}
|
96
|
+
# series_sum(1, 2) => 3
|
97
|
+
# series_sum() => []
|
98
|
+
#
|
99
|
+
# @return [Series/Multiple-Series/Scalar]
|
100
|
+
def series_sum(*series, scalar_sum: 0.0)
|
101
|
+
return [] unless series.length > 0
|
102
|
+
|
103
|
+
(series, scalars) = series.partition { |s| s.respond_to?(:map) }
|
104
|
+
scalar_sum += scalars.reduce(:+) || 0.0
|
105
|
+
|
106
|
+
if series.first.is_a?(Hash)
|
107
|
+
keys = series.map(&:keys).flatten(1).uniq
|
108
|
+
keys.reduce({}) do |hash, key|
|
109
|
+
hash[key] = (series.map { |s| s[key] }.compact.reduce(:+) || 0) + scalar_sum
|
110
|
+
hash
|
111
|
+
end
|
112
|
+
elsif is_an_array_of_named_series?(series.first)
|
113
|
+
series.flatten(1).group_by(&:first).map do |name, values|
|
114
|
+
data = values.map(&:second).reduce(Hash.new(scalar_sum)) do |hash, values|
|
115
|
+
values.each do |key, value|
|
116
|
+
hash[key] += value
|
117
|
+
end
|
118
|
+
hash
|
119
|
+
end
|
120
|
+
[
|
121
|
+
name, data
|
122
|
+
]
|
123
|
+
end
|
124
|
+
elsif series.first.is_a?(Array)
|
125
|
+
series.map { |s| s.reduce(:+) + scalar_sum }
|
126
|
+
else
|
127
|
+
scalar_sum
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# @api public
|
132
|
+
# @example
|
133
|
+
# median([0,1]) => {0.5}
|
134
|
+
# median([0,1,1,2,2]) => {1}
|
135
|
+
#
|
136
|
+
# @return Value
|
137
|
+
def median(array)
|
138
|
+
sorted = array.sort
|
139
|
+
len = sorted.length
|
140
|
+
(sorted[(len - 1) / 2] + sorted[len / 2]) / 2.0
|
141
|
+
end
|
142
|
+
|
143
|
+
private
|
144
|
+
|
145
|
+
def data_by_name(series)
|
146
|
+
if is_an_array_of_named_series?(series)
|
147
|
+
series.reduce({}) do |hash, value|
|
148
|
+
hash[value.first] = value.second
|
149
|
+
hash
|
150
|
+
end
|
151
|
+
else
|
152
|
+
series.reduce({}) do |hash, (key, value)|
|
153
|
+
new_key = Array.wrap(key.first).first
|
154
|
+
hash[new_key] = {key => value }
|
155
|
+
hash
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def series_names(series)
|
161
|
+
series.map { |key| key.first }.uniq
|
162
|
+
end
|
163
|
+
|
164
|
+
def has_multiple_series?(series)
|
165
|
+
is_an_array_of_named_series?(series) || series.is_a?(Hash) && series.first && series.first[0].is_a?(Array) && series.first[0].length > 1
|
166
|
+
end
|
167
|
+
|
168
|
+
def is_an_array_of_named_series?(series)
|
169
|
+
series.is_a?(Array) && series.first.second.is_a?(Hash)
|
170
|
+
end
|
171
|
+
|
172
|
+
def dimensions(series)
|
173
|
+
return 1 unless series.respond_to?(:length)
|
174
|
+
if series.first && series.first.is_a?(Array)
|
175
|
+
3
|
176
|
+
else
|
177
|
+
2
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def with_precision(precision, value)
|
182
|
+
value = value.round(precision) if precision
|
183
|
+
value
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'rails_helper'
|
3
|
+
|
4
|
+
describe "Controller Methods", type: :controller do
|
5
|
+
render_views
|
6
|
+
|
7
|
+
routes do
|
8
|
+
ActionDispatch::Routing::RouteSet.new.tap do |routes|
|
9
|
+
routes.draw { get "show" => "anonymous#show" }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
controller do
|
14
|
+
include Chartnado
|
15
|
+
|
16
|
+
chartkick_remote remote: false
|
17
|
+
|
18
|
+
define_method :_routes do
|
19
|
+
ActionDispatch::Routing::RouteSet.new.tap do |routes|
|
20
|
+
routes.draw { get "show" => "anonymous#show" }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def show
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe ".chartnado_wrapper" do
|
29
|
+
describe "when the wrapper is referenced by symbol" do
|
30
|
+
before do
|
31
|
+
controller.singleton_class.class_eval do
|
32
|
+
chartnado_wrapper :wrap_chart
|
33
|
+
|
34
|
+
def show
|
35
|
+
render inline: "<% area_chart { {0 => 1} / 2.0 } %>"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
it "calls the wrapper in the context of the helpers" do
|
41
|
+
routes.draw { get "show" => "anonymous#show" }
|
42
|
+
expect(controller).to receive(:wrap_chart)
|
43
|
+
get :show
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "when the wrapper is desribed by a block" do
|
48
|
+
before do
|
49
|
+
controller.singleton_class.class_eval do
|
50
|
+
chartnado_wrapper do |*args, **options, &block|
|
51
|
+
throw :wrapper_was_called
|
52
|
+
end
|
53
|
+
|
54
|
+
def show
|
55
|
+
render inline: "<% area_chart { {0 => 1} / 2.0 } %>"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
it "calls the wrapper in the context of the helpers" do
|
61
|
+
routes.draw { get "show" => "anonymous#show" }
|
62
|
+
expect {
|
63
|
+
get :show
|
64
|
+
}.to throw_symbol :wrapper_was_called
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/spec/dsl_spec.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'rails_helper'
|
3
|
+
|
4
|
+
describe Chartnado::Helpers::Chart, type: :helper do
|
5
|
+
def works?(&block)
|
6
|
+
expect {
|
7
|
+
block.call
|
8
|
+
}.not_to raise_exception
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "#area_chart" do
|
12
|
+
it "supports the dsl" do
|
13
|
+
works? { helper.area_chart { {1 => 2} / 2.0 } }
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "with a custom renderer" do
|
17
|
+
it "calls the custom renderer" do
|
18
|
+
wrapper_proc = proc { throw :wrapper_was_called }
|
19
|
+
expect {
|
20
|
+
expect(controller).to receive(:chartnado_options).and_return({wrapper_proc: wrapper_proc})
|
21
|
+
helper.area_chart { {1 => 2} / 2.0 }
|
22
|
+
}.to throw_symbol :wrapper_was_called
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#stacked_area_chart" do
|
28
|
+
it "supports the dsl" do
|
29
|
+
works? { helper.stacked_area_chart { {1 => 2} / 2.0 } }
|
30
|
+
end
|
31
|
+
describe "percentage option" do
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#pie_chart" do
|
36
|
+
it "supports the dsl" do
|
37
|
+
works? { helper.pie_chart { {1 => 2} / 2.0 } }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#geo_chart" do
|
42
|
+
it "supports the dsl" do
|
43
|
+
works? { helper.geo_chart { {1 => 2} / 2.0 } }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "#line_chart" do
|
48
|
+
it "supports the dsl" do
|
49
|
+
works? { helper.line_chart { {1 => 2} / 2.0 } }
|
50
|
+
end
|
51
|
+
xit "includes total"
|
52
|
+
describe "percentage option" do
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'rails_helper'
|
3
|
+
|
4
|
+
describe Chartnado::Helpers::Series, type: :helper do
|
5
|
+
let(:test_class) {
|
6
|
+
Class.new do
|
7
|
+
include Chartnado::Helpers::Series
|
8
|
+
end
|
9
|
+
}
|
10
|
+
|
11
|
+
describe ".define_series" do
|
12
|
+
it "lets the user define a series using the chartnado dsl" do
|
13
|
+
test_class.class_eval do
|
14
|
+
define_series :my_series do
|
15
|
+
{0 => 1} / 2
|
16
|
+
end
|
17
|
+
end
|
18
|
+
expect(test_class.new.my_series).to eq({0 => 0.5})
|
19
|
+
end
|
20
|
+
end
|
21
|
+
describe ".define_multiple_series" do
|
22
|
+
it "lets the user define multiple series using the chartnado dsl" do
|
23
|
+
test_class.class_eval do
|
24
|
+
define_multiple_series(
|
25
|
+
my_first_series: -> { {0 => 1} / 2 },
|
26
|
+
my_second_series: -> { {1 => 1} / 2 }
|
27
|
+
)
|
28
|
+
end
|
29
|
+
expect(test_class.new.my_first_series).to eq({0 => 0.5})
|
30
|
+
expect(test_class.new.my_second_series).to eq({1 => 0.5})
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Chartnado::Renderer do
|
4
|
+
describe "#chart_json" do
|
5
|
+
def chart_json(*series, **options)
|
6
|
+
Chartnado::Renderer.new(nil, nil).chart_json(*series, **options)
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "for data formatted as a hash" do
|
10
|
+
it "can generate chartkick compatible series" do
|
11
|
+
expect(chart_json({[:a, 1] => 10, [:b, 1] => 20})).
|
12
|
+
to eq [{name: :a, data: [[1, 10]]}, {name: :b, data: [[1,20]]}]
|
13
|
+
end
|
14
|
+
it "can add totals" do
|
15
|
+
expect(chart_json({[:a, 1] => 10, [:b, 1] => 20}, show_total: true)).
|
16
|
+
to eq [{name: 'Total', data: [[1, 0]], tooltip: [[1, 30.0]]},
|
17
|
+
{name: :a, data: [[1, 10]]},
|
18
|
+
{name: :b, data: [[1, 20]]}]
|
19
|
+
end
|
20
|
+
describe "with multiple scalar series" do
|
21
|
+
it "can handle scalars" do
|
22
|
+
expect(chart_json({:a => 10, :b => 20})).
|
23
|
+
to eq([[:a, 10], [:b, 20]])
|
24
|
+
end
|
25
|
+
it "can add totals" do
|
26
|
+
expect(chart_json({:a => 10, :b => 20}, show_total: true)).
|
27
|
+
to eq([[:a, 10], [:b, 20], ['Total', 30]])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
describe "for data formatted as an array" do
|
32
|
+
it "can generate chartkick compatible series" do
|
33
|
+
expect(chart_json([[:a, {1 => 10}], [:b, {1 => 20}]])).
|
34
|
+
to eq [{name: :a, data: [[1, 10]]}, {name: :b, data: [[1,20]]}]
|
35
|
+
end
|
36
|
+
it "can add totals" do
|
37
|
+
expect(chart_json([[:a, {1 => 10}], [:b, {1 => 20}]], show_total: true)).
|
38
|
+
to eq [{name: 'Total', data: [[1, 0]], tooltip: [[1, 30.0]]},
|
39
|
+
{name: :a, data: [[1, 10]]},
|
40
|
+
{name: :b, data: [[1, 20]]}]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
describe "for data that is just a scalar" do
|
44
|
+
it "shows the scalar as the total" do
|
45
|
+
expect(chart_json(10)).
|
46
|
+
to eq [['Total', 10]]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/spec/series_spec.rb
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Chartnado::Series do
|
4
|
+
before do
|
5
|
+
class << self
|
6
|
+
include Chartnado::Series
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "#series_product" do
|
11
|
+
describe "multiplying a hash by a scalar" do
|
12
|
+
it "returns the product of a scalar and a hash" do
|
13
|
+
expect(series_product(2, {0 => 3})).to eq ({0 => 6})
|
14
|
+
end
|
15
|
+
end
|
16
|
+
describe "multiplying an array by a scalar" do
|
17
|
+
it "returns the product of a scalar and a hash" do
|
18
|
+
expect(series_product(2, [3, 7])).to eq [6, 14]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
describe "multiplying an scalar by a scalar" do
|
22
|
+
it "returns the product of a scalar and a hash" do
|
23
|
+
expect(series_product(2, 3)).to eq 6
|
24
|
+
end
|
25
|
+
end
|
26
|
+
describe "multiplying an hash of named series by a scalar" do
|
27
|
+
it "returns the product of a scalar and each named_series" do
|
28
|
+
expect(
|
29
|
+
series_product(
|
30
|
+
2,
|
31
|
+
{[:series_a, 0] => 3,
|
32
|
+
[:series_b, 1] => 4}
|
33
|
+
)).to eq ({[:series_a, 0] => 6, [:series_b, 1] => 8})
|
34
|
+
end
|
35
|
+
end
|
36
|
+
describe "multiplying an array of named series by a scalar" do
|
37
|
+
it "returns the product of a scalar and each named_series" do
|
38
|
+
expect(
|
39
|
+
series_product(
|
40
|
+
2,
|
41
|
+
[[:series_a, {0 => 3}],
|
42
|
+
[:series_b, {1 => 4}]]
|
43
|
+
)).to eq [[:series_a, {0 => 6}], [:series_b, {1 => 8}]]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "#series_sum" do
|
49
|
+
describe "adding two scalars" do
|
50
|
+
it "returns the sum of the scalars" do
|
51
|
+
expect(series_sum(2,3)).to eq 5
|
52
|
+
end
|
53
|
+
end
|
54
|
+
describe "adding a scalar to an array" do
|
55
|
+
it "returns each item of the array with a scalar added" do
|
56
|
+
expect(series_sum(2,[3])).to eq [5]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
describe "adding a scalar to a hash" do
|
60
|
+
it "returns each item of the array with a scalar added" do
|
61
|
+
expect(series_sum(2,{0 => 3})).to eq ({0 => 5})
|
62
|
+
end
|
63
|
+
end
|
64
|
+
describe "adding a scalar to an array of named series" do
|
65
|
+
it "returns each item of the array with a scalar added" do
|
66
|
+
expect(series_sum(2,[[:a, {0 => 3}]])).to eq ([[:a, {0 => 5}]])
|
67
|
+
end
|
68
|
+
end
|
69
|
+
describe "adding two hashes" do
|
70
|
+
it "returns each item of the array with a scalar added" do
|
71
|
+
expect(series_sum({0 => 1},{0 => 2})).to eq ({0 => 3})
|
72
|
+
end
|
73
|
+
end
|
74
|
+
describe "adding two hashes and a scalar" do
|
75
|
+
it "returns each item of the array with a scalar added" do
|
76
|
+
expect(series_sum({0 => 1},{0 => 2}, 5)).to eq ({0 => 8})
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "#series_ratio" do
|
82
|
+
describe "ratio of two scalars" do
|
83
|
+
it "returns the ratio" do
|
84
|
+
expect(series_ratio(1, 2)).to eq 0.5
|
85
|
+
end
|
86
|
+
end
|
87
|
+
describe "ratio of two hashes" do
|
88
|
+
it "returns the ratio" do
|
89
|
+
expect(series_ratio({0 => 1}, {0 => 2})).to eq ({0 => 0.5})
|
90
|
+
end
|
91
|
+
end
|
92
|
+
describe "ratio of a named series to another named series" do
|
93
|
+
it "returns the ratio" do
|
94
|
+
expect(series_ratio({[:series_a, 0] => 1},
|
95
|
+
{[:series_a, 0] => 2})).to eq ({[:series_a, 0] => 0.5})
|
96
|
+
end
|
97
|
+
end
|
98
|
+
describe "ratio of an array of named series to another array of named series" do
|
99
|
+
it "returns the ratio" do
|
100
|
+
expect(series_ratio([[:series_a, {0 => 1}]],
|
101
|
+
[[:series_a, {0 => 2}]])).to eq [[:series_a, {0 => 0.5}]]
|
102
|
+
end
|
103
|
+
end
|
104
|
+
describe "ratio of a named series to a non-named series" do
|
105
|
+
it "returns the ratio" do
|
106
|
+
expect(series_ratio({[:series_a, 0] => 1},
|
107
|
+
{0 => 2})).to eq ({[:series_a, 0] => 0.5})
|
108
|
+
end
|
109
|
+
end
|
110
|
+
describe "ratio of an array of named series to a non-named series" do
|
111
|
+
it "returns the ratio" do
|
112
|
+
expect(series_ratio([[:series_a, {0 => 1}]],
|
113
|
+
{0 => 2})).to eq [[:series_a, {0 => 0.5}]]
|
114
|
+
end
|
115
|
+
end
|
116
|
+
describe "ratio of a series to a scalar" do
|
117
|
+
xit "returns the ratio" do
|
118
|
+
expect(series_ratio({0 => 1}, 2)).to eq ({0 => 0.5})
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
describe "including a multiplier" do
|
123
|
+
describe "for ratio of two scalars" do
|
124
|
+
it "returns the ratio times the multiplier" do
|
125
|
+
expect(series_ratio(1, 2, multiplier: 100)).to eq 50
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe "specifying the precision" do
|
131
|
+
describe "for ratio of two scalars" do
|
132
|
+
it "returns the ratio rounded to the specified precision" do
|
133
|
+
expect(series_ratio(1, 3, precision: 1)).to eq 0.3
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|