tricle 0.1.0 → 0.2.0

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.
@@ -0,0 +1,11 @@
1
+ require_relative '../../lib/tricle/mailer'
2
+ require_relative 'test_metric_with_no_total'
3
+
4
+ class NoTotalTestMailer < Tricle::Mailer
5
+ default(
6
+ to: ['recipient1@test.com', 'recipient2@test.com'],
7
+ from: 'sender@test.com'
8
+ )
9
+
10
+ metric TestMetricWithNoTotal
11
+ end
@@ -1,38 +1,6 @@
1
- require 'csv'
2
- require_relative '../../lib/tricle/metric'
3
- require_relative '../../lib/tricle/range_data'
4
-
5
- class TestMetric < Tricle::Metric
6
- attr_accessor :data_by_start_on
7
-
8
- def initialize
9
- super
10
- self.load_data
11
- end
12
-
13
- def load_data
14
- filename = File.join(File.dirname(__FILE__), '..', 'fixtures', 'weeks.csv')
15
- data = CSV.read(filename)
16
-
17
- self.data_by_start_on = Tricle::RangeData.new
18
-
19
- data.each do |row|
20
- start_on = Date.parse(row[0])
21
- val = row[2].to_i
22
- self.data_by_start_on.add(start_on, val)
23
- end
24
- end
25
-
26
- def size_for_range(start_at, end_at)
27
- self.items_for_range(start_at, end_at).reduce(&:+)
28
- end
29
-
30
- def items_for_range(start_at, end_at)
31
- start_on = start_at.to_date
32
- end_on = end_at.to_date
33
- self.data_by_start_on.items_for_range(start_on, end_on)
34
- end
1
+ require_relative 'test_metric_with_no_total'
35
2
 
3
+ class TestMetric < TestMetricWithNoTotal
36
4
  def total
37
5
  self.data_by_start_on.all_items.reduce(&:+)
38
6
  end
@@ -0,0 +1,35 @@
1
+ require 'csv'
2
+ require_relative '../../lib/tricle/metric'
3
+ require_relative '../../lib/tricle/range_data'
4
+
5
+ class TestMetricWithNoTotal < Tricle::Metric
6
+ attr_accessor :data_by_start_on
7
+
8
+ def initialize
9
+ super
10
+ self.load_data
11
+ end
12
+
13
+ def load_data
14
+ filename = File.join(File.dirname(__FILE__), '..', 'fixtures', 'weeks.csv')
15
+ data = CSV.read(filename)
16
+
17
+ self.data_by_start_on = Tricle::RangeData.new
18
+
19
+ data.each do |row|
20
+ start_on = Date.parse(row[0])
21
+ val = row[2].to_i
22
+ self.data_by_start_on.add(start_on, val)
23
+ end
24
+ end
25
+
26
+ def size_for_range(start_at, end_at)
27
+ self.items_for_range(start_at, end_at).reduce(&:+)
28
+ end
29
+
30
+ def items_for_range(start_at, end_at)
31
+ start_on = start_at.to_date
32
+ end_on = end_at.to_date
33
+ self.data_by_start_on.items_for_range(start_on, end_on)
34
+ end
35
+ end
@@ -2,6 +2,6 @@ require 'timecop'
2
2
 
3
3
  def reset_time
4
4
  # need to freeze the time for the TestMetric
5
- now = Time.new(2013, 8, 1, 1, 0, 0, '-04:00')
5
+ now = Time.new(2013, 8, 1, 1, 0, 0)
6
6
  Timecop.freeze(now)
7
7
  end
@@ -8,10 +8,9 @@ describe Tricle::Presenters::Group do
8
8
  describe '#add_metric' do
9
9
  it "should add a new metric instance" do
10
10
  group.add_metric(TestMetric)
11
- group.metric_presenters.size.should eq(1)
12
- presenter = group.metric_presenters.first
13
- presenter.should be_a(Tricle::Presenters::Metric)
14
- presenter.metric.should be_a(TestMetric)
11
+ expect(group.metrics.size).to eq(1)
12
+ metric = group.metrics.first
13
+ expect(metric).to be_a(TestMetric)
15
14
  end
16
15
  end
17
16
  end
@@ -7,13 +7,13 @@ describe Tricle::Presenters::Report do
7
7
 
8
8
  describe '#add_metric' do
9
9
  it "should add a new group if none are present" do
10
- report.sections.should eq([])
10
+ expect(report.sections).to eq([])
11
11
  report.add_metric(TestMetric)
12
- report.sections.size.should eq(1)
12
+ expect(report.sections.size).to eq(1)
13
13
 
14
- presenters = report.sections.first.metric_presenters
15
- presenters.size.should eq(1)
16
- presenters.first.metric.should be_a(TestMetric)
14
+ metrics = report.sections.first.metrics
15
+ expect(metrics.size).to eq(1)
16
+ expect(metrics.first).to be_a(TestMetric)
17
17
  end
18
18
  end
19
19
  end
data/spec/spec_helper.rb CHANGED
@@ -17,7 +17,6 @@ reset_time
17
17
 
18
18
  # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
19
19
  RSpec.configure do |config|
20
- config.treat_symbols_as_metadata_keys_with_true_values = true
21
20
  config.run_all_when_everything_filtered = true
22
21
  config.filter_run :focus
23
22
 
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+ require_relative '../../lib/tricle/aggregation'
3
+
4
+ describe Tricle::Aggregation do
5
+ let(:metric) { TestMetric.new }
6
+
7
+ describe '#days_ago' do
8
+ it "should start and end at midnight" do
9
+ expect(metric).to receive(:size_for_range).with(Time.new(2013, 7, 29), Time.new(2013, 7, 30))
10
+ metric.days_ago(3)
11
+ end
12
+ end
13
+
14
+ describe '#yesterday' do
15
+ it "should start and end at midnight" do
16
+ expect(metric).to receive(:size_for_range).with(Time.new(2013, 7, 31), Time.new(2013, 8, 1))
17
+ metric.yesterday
18
+ end
19
+ end
20
+
21
+ describe '#weeks_ago' do
22
+ it "should start and end on Monday" do
23
+ expect(metric).to receive(:size_for_range).with(Time.new(2013, 7, 8), Time.new(2013, 7, 15))
24
+ metric.weeks_ago(3)
25
+ end
26
+ end
27
+
28
+ describe '#last_week' do
29
+ it "should start and end on Monday" do
30
+ expect(metric).to receive(:size_for_range).with(Time.new(2013, 7, 22), Time.new(2013, 7, 29))
31
+ metric.last_week
32
+ end
33
+ end
34
+
35
+ describe '#week_average_this_quarter' do
36
+ it "should average the values provided by #size_for_range" do
37
+ expect(metric).to receive(:size_for_range).exactly(13).times.and_return(1)
38
+ expect(metric.week_average_this_quarter).to eq(1)
39
+ end
40
+ end
41
+ end
@@ -10,25 +10,105 @@ describe Tricle::EmailHelper do
10
10
 
11
11
  describe "#number_with_delimiter" do
12
12
  it "should put commas between every three digits" do
13
- helper.number_with_delimiter(1234567.89).should eq('1,234,567.89')
13
+ expect(helper.number_with_delimiter(1234567.89)).to eq('1,234,567.89')
14
+ expect(helper.number_with_delimiter(1234567)).to eq('1,234,567')
15
+ end
16
+
17
+ it "should not put commas between every three digits of the decimal portion of non-integers" do
18
+ expect(helper.number_with_delimiter(0.123456789)).to eq('0.123456789')
19
+ expect(helper.number_with_delimiter(1234.56789)).to eq('1,234.56789')
20
+ expect(helper.number_with_delimiter(-0.123456789)).to eq('-0.123456789')
21
+ expect(helper.number_with_delimiter(-1234.56789)).to eq('-1,234.56789')
22
+ end
23
+ end
24
+
25
+ describe "#sig_figs" do
26
+ it "works for large numbers, positive and negative" do
27
+ expect(helper.sig_figs(1234.56789)).to eq(1230)
28
+ expect(helper.sig_figs(-1234.56789)).to eq(-1230)
29
+ expect(helper.sig_figs(1234.56789).to_s).to eq('1230')
30
+ expect(helper.sig_figs(-1234.56789).to_s).to eq('-1230')
31
+ end
32
+
33
+ it "works for small numbers, positive and negative" do
34
+ expect(helper.sig_figs(0.123456789)).to eq(0.123)
35
+ expect(helper.sig_figs(-0.123456789)).to eq(-0.123)
36
+ expect(helper.sig_figs(0.123456789).to_s).to eq('0.123')
37
+ expect(helper.sig_figs(-0.123456789).to_s).to eq('-0.123')
38
+ end
39
+
40
+ it "works for numbers with leading zeroes, positive and negative" do
41
+ expect(helper.sig_figs(0.00000123456789)).to eq(0.00000123)
42
+ expect(helper.sig_figs(-0.00000123456789)).to eq(-0.00000123)
43
+ expect(helper.sig_figs(0.00000123456789).to_s).to eq('1.23e-06')
44
+ expect(helper.sig_figs(-0.00000123456789).to_s).to eq('-1.23e-06')
45
+ end
46
+
47
+ it "works for integer-like numbers, positive and negative" do
48
+ expect(helper.sig_figs(10).is_a?(Float)).to be_truthy
49
+ expect(helper.sig_figs(10).to_s).to eq('10.0')
50
+ expect(helper.sig_figs(-10).is_a?(Float)).to be_truthy
51
+ expect(helper.sig_figs(-10).to_s).to eq('-10.0')
52
+ end
53
+ end
54
+
55
+ describe "#format_number" do
56
+ it "does not decrease the precision of large integers" do
57
+ expect(helper.format_number(123456789)).to eq('123,456,789')
58
+ expect(helper.format_number(-123456789)).to eq('-123,456,789')
59
+ end
60
+
61
+ it "decreases the precision of large numbers to no fewer than 3 sig figs" do
62
+ expect(helper.format_number(123.45)).to eq('123')
63
+ expect(helper.format_number(-123.45)).to eq('-123')
64
+ end
65
+
66
+ it "decreases the precision of small numbers to no fewer than 3 sig figs" do
67
+ expect(helper.format_number(0.00123456789)).to eq('0.00123')
68
+ expect(helper.format_number(-0.00123456789)).to eq('-0.00123')
14
69
  end
15
70
  end
16
71
 
17
72
  describe "#percent_change" do
18
73
  it "should prefix positive values with a +" do
19
- helper.percent_change(110, 100).should eq('+10.0%')
74
+ expect(helper.percent_change(110, 100)).to eq('+10.0%')
20
75
  end
21
76
 
22
77
  it "should prefix negative values with a -" do
23
- helper.percent_change(90, 100).should eq('-10.0%')
78
+ expect(helper.percent_change(90, 100)).to eq('-10.0%')
24
79
  end
25
80
 
26
81
  it "should handle a zero as the old value with positive change" do
27
- helper.percent_change(10, 0).should eq('+')
82
+ expect(helper.percent_change(10, 0)).to eq('+')
28
83
  end
29
84
 
30
85
  it "should handle a zero as the old value with negative change" do
31
- helper.percent_change(-20, 0).should eq('-')
86
+ expect(helper.percent_change(-20, 0)).to eq('-')
87
+ end
88
+
89
+ it "should not display small values as 0" do
90
+ expect(helper.percent_change(100_001_234, 100_000_000)).to eq('+0.00123%')
91
+ expect(helper.percent_change(100_000_000, 100_001_234)).to eq('-0.00123%')
92
+ end
93
+
94
+ it "should display 'no change' when unchanged" do
95
+ expect(helper.percent_change(100, 100)).to eq('No change')
96
+ expect(helper.percent_change(0, 0)).to eq('No change')
97
+ end
98
+ end
99
+
100
+ describe '#percent_change_cell' do
101
+ it "should be positive with positive change and better = :higher" do
102
+ expect(helper.percent_change_cell(4, 2, :higher)).to match('good')
103
+ end
104
+
105
+ it "should be negative with positive change and better = :lower" do
106
+ expect(helper.percent_change_cell(4, 2, :lower)).to match('bad')
107
+ end
108
+
109
+ it "should not be positive or negative with positive change and better = :none" do
110
+ expect(helper.percent_change_cell(4, 2, :none)).to_not match('good')
111
+ expect(helper.percent_change_cell(4, 2, :none)).to_not match('bad')
32
112
  end
33
113
  end
34
114
 
@@ -36,8 +116,8 @@ describe Tricle::EmailHelper do
36
116
  it "should not include the last day of the week" do
37
117
  start_at = Time.new(2013, 7, 22) # a Monday
38
118
  markup = helper.single_week_dates_cell(start_at)
39
- markup.should include('7/22/13')
40
- markup.should include('7/28/13')
119
+ expect(markup).to include('7/22/13')
120
+ expect(markup).to include('7/28/13')
41
121
  end
42
122
  end
43
123
  end
@@ -5,11 +5,11 @@ require_relative '../../lib/tricle/mail_preview'
5
5
  describe Tricle::MailPreview do
6
6
  describe 'mailer methods' do
7
7
  it "should have methods corresponding to all mailers" do
8
- Tricle::MailPreview.instance_methods(false).should include(:test_mailer)
8
+ expect(Tricle::MailPreview.instance_methods(false)).to include(:test_mailer)
9
9
  end
10
10
 
11
11
  it "should return a Mail::Message" do
12
- Tricle::MailPreview.new.test_mailer.should be_a(Mail::Message)
12
+ expect(Tricle::MailPreview.new.test_mailer).to be_a(Mail::Message)
13
13
  end
14
14
  end
15
15
  end
@@ -2,12 +2,13 @@ require 'spec_helper'
2
2
  require_relative '../../lib/tricle/mailer'
3
3
  require_relative '../app/group_test_mailer'
4
4
  require_relative '../app/list_test_mailer'
5
+ require_relative '../app/no_total_test_mailer'
5
6
  require_relative '../app/test_mailer'
6
7
 
7
8
  describe Tricle::Mailer do
8
9
  def deliver(klass)
9
10
  klass.email.deliver
10
- ActionMailer::Base.deliveries.length.should eq(1)
11
+ expect(ActionMailer::Base.deliveries.length).to eq(1)
11
12
  end
12
13
 
13
14
  let(:message) { ActionMailer::Base.deliveries.last }
@@ -19,48 +20,54 @@ describe Tricle::Mailer do
19
20
  end
20
21
 
21
22
  it "should respect all the options in the 'default hash'" do
22
- message.to.should eq(['recipient1@test.com', 'recipient2@test.com'])
23
- message.from.should eq(['sender@test.com'])
23
+ expect(message.to).to eq(['recipient1@test.com', 'recipient2@test.com'])
24
+ expect(message.from).to eq(['sender@test.com'])
24
25
  end
25
26
 
26
27
  it "should set the subject based on the class name" do
27
- message.subject.should eq("Your Test Mailer")
28
+ expect(message.subject).to eq("Your Test Mailer")
28
29
  end
29
30
 
30
31
  it "should include the Metric values in the HTML part" do
31
- markup.should include('Test Metric')
32
- markup.should match(/\b62\b/) # last week
33
- markup.should match(/\b787\b/) # total
32
+ expect(markup).to include('Test Metric')
33
+ expect(markup).to match(/\b62\b/) # last week
34
+ expect(markup).to match(/\b787\b/) # total
34
35
  end
35
36
 
36
37
  it "should link to the Issues page in the text part" do
37
38
  source = message.text_part.body.to_s
38
- source.should include('github.com/artsy/tricle')
39
+ expect(source).to include('github.com/artsy/tricle')
39
40
  end
40
41
  end
41
42
 
43
+ it "should exclude the total if not defined" do
44
+ deliver(NoTotalTestMailer)
45
+ expect(markup).to_not include('total')
46
+ expect(markup).to_not match(/\b787\b/)
47
+ end
48
+
42
49
  describe '.group' do
43
50
  it "should include the group title" do
44
51
  deliver(GroupTestMailer)
45
- markup.should include("Test Group 1")
46
- markup.should include("Test Group 2")
47
- markup.should include("Test Metric")
52
+ expect(markup).to include("Test Group 1")
53
+ expect(markup).to include("Test Group 2")
54
+ expect(markup).to include("Test Metric")
48
55
  end
49
56
  end
50
57
 
51
58
  describe '.list' do
52
59
  it "should include the list title" do
53
60
  deliver(ListTestMailer)
54
- markup.should include("Test Metric")
55
- markup.should include('62.0')
56
- markup.should_not include('79.0')
61
+ expect(markup).to include("Test Metric")
62
+ expect(markup).to include('62.0')
63
+ expect(markup).not_to include('79.0')
57
64
  end
58
65
  end
59
66
 
60
67
  describe '.send_all' do
61
68
  it "should .deliver all defined mailers" do
62
69
  Tricle::Mailer.send_all
63
- ActionMailer::Base.deliveries.length.should eq(3)
70
+ expect(ActionMailer::Base.deliveries.length).to eq(4)
64
71
  end
65
72
  end
66
73
  end
@@ -11,8 +11,8 @@ describe Tricle::Metric do
11
11
  end
12
12
 
13
13
  it "should use the number of items by default" do
14
- metric.stub(:items_for_range) { [1,2,3] }
15
- metric.size_for_range(Time.now.yesterday, Time.now).should eq(3)
14
+ allow(metric).to receive(:items_for_range) { [1,2,3] }
15
+ expect(metric.size_for_range(Time.now.yesterday, Time.now)).to eq(3)
16
16
  end
17
17
  end
18
18
  end
@@ -11,14 +11,14 @@ describe Tricle::RangeData do
11
11
 
12
12
  describe '#all_items' do
13
13
  it "should return all the items" do
14
- rd.all_items.sort.should eq([5, 6, 7])
14
+ expect(rd.all_items.sort).to eq([5, 6, 7])
15
15
  end
16
16
  end
17
17
 
18
18
  describe '#items_for_range' do
19
19
  it "should return the items for the days provided" do
20
20
  items = rd.items_for_range(11.days.ago, 3.days.ago)
21
- items.sort.should eq([5, 6])
21
+ expect(items.sort).to eq([5, 6])
22
22
  end
23
23
  end
24
24
  end
@@ -1,20 +1,19 @@
1
1
  require 'spec_helper'
2
2
  require_relative '../app/test_metric'
3
- require_relative '../../lib/tricle/presenters/metric'
4
3
 
5
4
  # test the tests
6
5
  describe TestMetric do
7
- let(:presenter) { Tricle::Presenters::Metric.new(TestMetric) }
6
+ let(:metric) { TestMetric.new }
8
7
 
9
8
  describe '#weeks_ago' do
10
9
  it "should start and end on Monday" do
11
- presenter.weeks_ago(3).should eq(51)
10
+ expect(metric.weeks_ago(3)).to eq(51)
12
11
  end
13
12
  end
14
13
 
15
14
  describe '#last_week' do
16
15
  it "should start and end on Monday" do
17
- presenter.last_week.should eq(62)
16
+ expect(metric.last_week).to eq(62)
18
17
  end
19
18
  end
20
19
  end