Class: Streak

Inherits:
Object
  • Object
show all
Defined in:
lib/streakable/streak.rb

Overview

Represents a streak of calendar days as computed by a date column on an association.

So for example if you have a User that has_many :posts, then Streak.new(user, :posts, :created_at).length will tell you how many consecutive days a given user created posts.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(instance, association, column, except_today: false) ⇒ Streak

Creates a new Streak

Parameters:

  • instance (ActiveRecord::Base)

    an ActiveRecord object instance

  • association (Symbol)

    a key representing the ActiveRecord association on the instance

  • column (Symbol)

    a key representing the column on the association that you want to calculate the streak against

  • except_today (Boolean) (defaults to: false)

    whether to include today in the streak length calculation or not. If this is true, then you are assuming there is still time today for the streak to be extended



28
29
30
31
32
33
34
# File 'lib/streakable/streak.rb', line 28

def initialize(instance, association, column, except_today: false)
  @instance = instance
  @association = association
  @column = column
  # Don't penalize the current day being absent when determining streaks
  @except_today = except_today
end

Instance Attribute Details

#associationObject (readonly)

the AR association through which we want to grab a column to caculate a streak



12
13
14
# File 'lib/streakable/streak.rb', line 12

def association
  @association
end

#columnObject (readonly)

an AR column resolving to a date. the column that we want to calculate a calendar date streak against



15
16
17
# File 'lib/streakable/streak.rb', line 15

def column
  @column
end

#except_todayObject (readonly)

whether to include today in the streak length calculation or not. If this is true, then you are assuming there is still time today for the streak to be extended



20
21
22
# File 'lib/streakable/streak.rb', line 20

def except_today
  @except_today
end

#instanceObject (readonly)

the base ActiveRecord object instance for this streak calculation



9
10
11
# File 'lib/streakable/streak.rb', line 9

def instance
  @instance
end

Instance Method Details

#length(longest: false) ⇒ Object

Calculate the length of this calendar day streak

not just the current one

Parameters:

  • longest (Boolean) (defaults to: false)

    if true, calculate the longest day streak in the sequence,



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/streakable/streak.rb', line 40

def length(longest: false)
  # no streaks
  if streaks.empty?
    0

  # calculate the longest one?
  elsif longest
    streaks.sort do |x, y|
      y.size <=> x.size
    end.first.size

  # default streak calculation
  else
    # pull the first streak
    streak = streaks.first
    
    # either the streak includes today,
    # or we don't care about today and it includes yesterday
    if streak.include?(Date.current) || except_today && streak.include?(Date.current - 1.day)
      streak.size
    else
      0
    end
  end
end

#streaksObject

Get a list of all calendar day streaks, sorted descending (from most recent to farthest away) Includes 1-day streaks. If you want to filter the results further, for example if you want 2 only include 2+ day streaks, you’ll have to filter on the result



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/streakable/streak.rb', line 71

def streaks
  return [] if days.empty?

  streaks = []
  streak = []
  days.each.with_index do |day, i|
    # first day
    if i == 0
      # since this is the first one,
      # push to our new streak
      streak << day

    # consecutive day, the previous day was "tomorrow" 
    # relative to day (since we're date descending)
    elsif days[i-1] == (day+1.day)
      # push to existing streak
      streak << day

    # streak was broken
    else
      # push our current streak
      streaks << streak

      # start a new streak
      # and push day to our new streak
      streak = []
      streak << day
    end

    # the jig is up, push the current streak
    if i == (days.size-1) 
      streaks << streak 
    end
  end
 
  streaks
end