chartnado 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|