mirror of
https://github.com/TracksApp/tracks.git
synced 2026-01-06 17:28:50 +01:00
Move time to complete stats into separate class
This separates out the calculations from the queries so we can get decent tests around them.
This commit is contained in:
parent
0ebb98d49f
commit
62336f94cd
4 changed files with 142 additions and 50 deletions
|
|
@ -8,23 +8,8 @@ module Stats
|
|||
@user = user
|
||||
end
|
||||
|
||||
def avg_ttc
|
||||
@avg_ttc ||= (sum/count)/SECONDS_PER_DAY
|
||||
end
|
||||
|
||||
def max_ttc
|
||||
@max_ttc ||= max/SECONDS_PER_DAY
|
||||
end
|
||||
|
||||
def min_ttc
|
||||
@min_ttc ||= min/SECONDS_PER_DAY
|
||||
end
|
||||
|
||||
def min_ttc_sec
|
||||
min_ttc_sec = arbitrary_day + min # convert to a datetime
|
||||
@actions_min_ttc_sec = (min_ttc_sec).strftime("%H:%M:%S")
|
||||
@actions_min_ttc_sec = (min / SECONDS_PER_DAY).round.to_s + " days " + @actions_min_ttc_sec if min > SECONDS_PER_DAY
|
||||
@actions_min_ttc_sec
|
||||
def ttc
|
||||
@ttc ||= TimeToComplete.new(completed)
|
||||
end
|
||||
|
||||
def done_last30days
|
||||
|
|
@ -69,10 +54,6 @@ module Stats
|
|||
|
||||
private
|
||||
|
||||
def arbitrary_day
|
||||
@arbitrary_day ||= Time.utc(2000,1,1,0,0)
|
||||
end
|
||||
|
||||
def one_year
|
||||
@one_year ||= 12.months.ago.beginning_of_day
|
||||
end
|
||||
|
|
@ -81,32 +62,6 @@ module Stats
|
|||
@one_month ||= 1.month.ago.beginning_of_day
|
||||
end
|
||||
|
||||
def completed
|
||||
@completed ||= user.todos.completed.select("completed_at, created_at")
|
||||
end
|
||||
|
||||
def durations
|
||||
@durations ||= completed.map do |r|
|
||||
(r.completed_at - r.created_at)
|
||||
end
|
||||
end
|
||||
|
||||
def sum
|
||||
@sum ||= durations.inject(0) {|sum, d| sum + d}
|
||||
end
|
||||
|
||||
def min
|
||||
@min ||= durations.min || 0
|
||||
end
|
||||
|
||||
def max
|
||||
@max ||= durations.max || 0
|
||||
end
|
||||
|
||||
def count
|
||||
completed.empty? ? 1 : completed.size
|
||||
end
|
||||
|
||||
def new_since(cutoff)
|
||||
user.todos.created_after(cutoff).count
|
||||
end
|
||||
|
|
@ -115,5 +70,8 @@ module Stats
|
|||
user.todos.completed.completed_after(cutoff).count
|
||||
end
|
||||
|
||||
def completed
|
||||
@completed ||= user.todos.completed.select("completed_at, created_at")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
59
app/models/stats/time_to_complete.rb
Normal file
59
app/models/stats/time_to_complete.rb
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
module Stats
|
||||
class TimeToComplete
|
||||
|
||||
SECONDS_PER_DAY = 86400;
|
||||
|
||||
attr_reader :actions
|
||||
def initialize(actions)
|
||||
@actions = actions
|
||||
end
|
||||
|
||||
def avg
|
||||
@avg ||= (sum / count) / SECONDS_PER_DAY
|
||||
end
|
||||
|
||||
def max
|
||||
@max ||= max_in_seconds / SECONDS_PER_DAY
|
||||
end
|
||||
|
||||
def min
|
||||
@min ||= min_in_seconds / SECONDS_PER_DAY
|
||||
end
|
||||
|
||||
def min_sec
|
||||
min_sec = arbitrary_day + min_in_seconds # convert to a datetime
|
||||
@min_sec = min_sec.strftime("%H:%M:%S")
|
||||
@min_sec = min.round.to_s + " days " + @min_sec if min >= 1
|
||||
@min_sec
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def min_in_seconds
|
||||
@min_in_seconds ||= durations.min || 0
|
||||
end
|
||||
|
||||
def max_in_seconds
|
||||
@max_in_seconds ||= durations.max || 0
|
||||
end
|
||||
|
||||
def count
|
||||
actions.empty? ? 1 : actions.size
|
||||
end
|
||||
|
||||
def durations
|
||||
@durations ||= actions.map do |r|
|
||||
(r.completed_at - r.created_at)
|
||||
end
|
||||
end
|
||||
|
||||
def sum
|
||||
@sum ||= durations.inject(0) {|sum, d| sum + d}
|
||||
end
|
||||
|
||||
def arbitrary_day
|
||||
@arbitrary_day ||= Time.utc(2000, 1, 1, 0, 0)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<p><%= t('stats.actions_avg_completion_time', :count => (actions.avg_ttc*10).round/10.0) %>
|
||||
<%= t('stats.actions_min_max_completion_days', :max => (actions.max_ttc*10).round/10.0, :min => (actions.min_ttc*10).round/10.0) %>
|
||||
<%= t('stats.actions_min_completion_time', :time => actions.min_ttc_sec) %></p>
|
||||
<p><%= t('stats.actions_avg_completion_time', :count => (actions.ttc.avg*10).round/10.0) %>
|
||||
<%= t('stats.actions_min_max_completion_days', :max => (actions.ttc.max*10).round/10.0, :min => (actions.ttc.min*10).round/10.0) %>
|
||||
<%= t('stats.actions_min_completion_time', :time => actions.ttc.min_sec) %></p>
|
||||
|
||||
<p><%= t('stats.actions_actions_avg_created_30days', :count => (actions.created_last30days*10.0/30.0).round/10.0 )%>
|
||||
<%= t('stats.actions_avg_completed_30days', :count => (actions.done_last30days*10.0/30.0).round/10.0 )%>
|
||||
|
|
|
|||
75
test/unit/time_to_complete_test.rb
Normal file
75
test/unit/time_to_complete_test.rb
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
require 'date'
|
||||
require 'time'
|
||||
require './test/minimal_test_helper'
|
||||
require 'app/models/stats/time_to_complete'
|
||||
|
||||
FakeTask = Struct.new(:created_at, :completed_at)
|
||||
|
||||
class TimeToCompleteTest < Test::Unit::TestCase
|
||||
|
||||
def now
|
||||
@now ||= Time.utc(2013, 1, 2, 3, 4, 5)
|
||||
end
|
||||
|
||||
def day0
|
||||
@day0 ||= Time.utc(2013, 1, 2, 0, 0, 0)
|
||||
end
|
||||
|
||||
def day2
|
||||
@day2 ||= Time.utc(2012, 12, 31, 0, 0, 0)
|
||||
end
|
||||
|
||||
def day4
|
||||
@day4 ||= Time.utc(2012, 12, 29, 0, 0, 0)
|
||||
end
|
||||
|
||||
def day6
|
||||
@day6 ||= Time.utc(2012, 12, 27, 0, 0, 0)
|
||||
end
|
||||
|
||||
def fake_tasks
|
||||
@fake_tasks ||= [
|
||||
FakeTask.new(day2, now),
|
||||
FakeTask.new(day4, now),
|
||||
FakeTask.new(day6, now)
|
||||
]
|
||||
end
|
||||
|
||||
def test_empty_minimum
|
||||
assert_equal 0, Stats::TimeToComplete.new([]).min
|
||||
end
|
||||
|
||||
def test_empty_maximum
|
||||
assert_equal 0, Stats::TimeToComplete.new([]).max
|
||||
end
|
||||
|
||||
def test_empty_avg
|
||||
assert_equal 0, Stats::TimeToComplete.new([]).avg
|
||||
end
|
||||
|
||||
def test_empty_min_sec
|
||||
assert_equal '00:00:00', Stats::TimeToComplete.new([]).min_sec
|
||||
end
|
||||
|
||||
def test_minimum
|
||||
assert_equal 2.127835648148148, Stats::TimeToComplete.new(fake_tasks).min
|
||||
end
|
||||
|
||||
def test_maximum
|
||||
assert_equal 6.127835648148148, Stats::TimeToComplete.new(fake_tasks).max
|
||||
end
|
||||
|
||||
def test_avg
|
||||
assert_equal 4.127835648148148, Stats::TimeToComplete.new(fake_tasks).avg
|
||||
end
|
||||
|
||||
def test_min_sec
|
||||
assert_equal '2 days 03:04:05', Stats::TimeToComplete.new(fake_tasks).min_sec
|
||||
end
|
||||
|
||||
def test_min_sec_with_less_than_a_day
|
||||
task = FakeTask.new(day0, now)
|
||||
assert_equal '03:04:05', Stats::TimeToComplete.new([task]).min_sec
|
||||
end
|
||||
end
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue