Class: RecurringTodos::AbstractRepeatPattern

Inherits:
Object
  • Object
show all
Defined in:
app/models/recurring_todos/abstract_repeat_pattern.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(user) ⇒ AbstractRepeatPattern



7
8
9
# File 'app/models/recurring_todos/abstract_repeat_pattern.rb', line 7

def initialize(user)
  @user = user
end

Instance Attribute Details

#attributesObject

Returns the value of attribute attributes



5
6
7
# File 'app/models/recurring_todos/abstract_repeat_pattern.rb', line 5

def attributes
  @attributes
end

Instance Method Details

#build_from_recurring_todo(recurring_todo) ⇒ Object



71
72
73
74
# File 'app/models/recurring_todos/abstract_repeat_pattern.rb', line 71

def build_from_recurring_todo(recurring_todo)
  @recurring_todo = recurring_todo
  @attributes = Tracks::AttributeHandler.new(@user, recurring_todo.attributes)
end

#build_recurring_todo(attribute_handler) ⇒ Object



62
63
64
# File 'app/models/recurring_todos/abstract_repeat_pattern.rb', line 62

def build_recurring_todo(attribute_handler)
  @recurring_todo = @user.recurring_todos.build(attribute_handler.safe_attributes)
end

#continues_recurring?(previous) ⇒ Boolean



157
158
159
160
161
162
163
164
165
166
167
# File 'app/models/recurring_todos/abstract_repeat_pattern.rb', line 157

def continues_recurring?(previous)
  return @recurring_todo.occurences_count < @recurring_todo.number_of_occurences unless @recurring_todo.number_of_occurences.nil?
  return true if self.end_date.nil? || self.ends_on == 'no_end_date'

  case self.target
  when 'due_date'
    get_due_date(previous) <= self.end_date
  when 'show_from_date'
    get_show_from_date(previous) <= self.end_date
  end
end

#day_of_week_as_text(day) ⇒ Object



54
55
56
# File 'app/models/recurring_todos/abstract_repeat_pattern.rb', line 54

def day_of_week_as_text(day)
  day.nil? ? '??' : I18n.t('todos.recurrence.pattern.day_names')[day]
end

#determine_start(previous, offset = 0.day) ⇒ Object (private)

Determine start date to calculate next date for recurring todo which takes start_from and previous into account. offset needs to be 1.day for daily patterns or the start will be the same day as the previous



175
176
177
178
179
180
181
182
183
184
185
186
# File 'app/models/recurring_todos/abstract_repeat_pattern.rb', line 175

def determine_start(previous, offset=0.day)
  start = self.start_from || NullTime.new
  now = Time.zone.now
  if previous
    # check if the start_from date is later than previous. If so, use
    # start_from as start to search for next date
    start > previous ? start : previous + offset
  else
    # skip to present
    start > now ? start : now
  end
end

#end_dateObject



15
16
17
# File 'app/models/recurring_todos/abstract_repeat_pattern.rb', line 15

def end_date
  get :end_date
end

#ends_onObject



19
20
21
# File 'app/models/recurring_todos/abstract_repeat_pattern.rb', line 19

def ends_on
  get :ends_on
end

#errorsObject



118
119
120
# File 'app/models/recurring_todos/abstract_repeat_pattern.rb', line 118

def errors
  @recurring_todo.errors
end

#find_last_day_x_of_month(weekday, month, year) ⇒ Object (private)



201
202
203
204
205
206
207
208
209
210
# File 'app/models/recurring_todos/abstract_repeat_pattern.rb', line 201

def find_last_day_x_of_month(weekday, month, year)
  # count backwards. use UTC to avoid strange timezone oddities
  # where last_day -= 1.day seems to shift tz+0100 to tz+0000
  last_day = Time.utc(year, month, Time.days_in_month(month))
  while last_day.wday != weekday
    last_day -= 1.day
  end
  # convert back to local timezone
  Time.zone.local(last_day.year, last_day.month, last_day.day)
end

#find_xth_day_of_month(x, weekday, month, year) ⇒ Object (private)



212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# File 'app/models/recurring_todos/abstract_repeat_pattern.rb', line 212

def find_xth_day_of_month(x, weekday, month, year)
  # 1-4th -> count upwards last -> count backwards. use UTC to avoid strange
  # timezone oddities where last_day -= 1.day seems to shift tz+0100 to
  # tz+0000
  start = Time.utc(year,month,1)
  n = x
  while n > 0
    while start.wday() != weekday
      start+= 1.day
    end
    n -= 1
    start+= 1.day unless n==0
  end
  # convert back to local timezone
  Time.zone.local(start.year, start.month, start.day)
end

#get(attribute) ⇒ Object



122
123
124
# File 'app/models/recurring_todos/abstract_repeat_pattern.rb', line 122

def get(attribute)
  @attributes[attribute]
end

#get_due_date(previous) ⇒ Object

gets the next due date. returns nil if recurrence_target is not ‘due_date’



127
128
129
130
131
132
133
134
# File 'app/models/recurring_todos/abstract_repeat_pattern.rb', line 127

def get_due_date(previous)
  case target
  when 'due_date'
    get_next_date(previous)
  when 'show_from_date'
    nil
  end
end

#get_next_date(previous) ⇒ Object



153
154
155
# File 'app/models/recurring_todos/abstract_repeat_pattern.rb', line 153

def get_next_date(previous)
  raise "Should not call AbstractRepeatPattern.get_next_date directly. Overwrite in subclass"
end

#get_show_from_date(previous) ⇒ Object



136
137
138
139
140
141
142
143
144
145
146
# File 'app/models/recurring_todos/abstract_repeat_pattern.rb', line 136

def get_show_from_date(previous)
  case target
  when 'due_date'
    # so set show from date relative to due date unless show_always is true or show_from_delta is nil
    return nil unless put_in_tickler?
    get_due_date(previous) - show_from_delta.days
  when 'show_from_date'
    # Leave due date empty
    get_next_date(previous)
  end
end

#get_xth_day_of_month(x, weekday, month, year) ⇒ Object (private)

Example: get 3rd (x) wednesday (weekday) of december (month) 2014 (year) 5th means last, so it will return the 4th if there is no 5th



190
191
192
193
194
195
196
197
198
199
# File 'app/models/recurring_todos/abstract_repeat_pattern.rb', line 190

def get_xth_day_of_month(x, weekday, month, year)
  raise "Weekday should be between 0 and 6 with 0=sunday. You supplied #{weekday}" unless (0..6).include?(weekday)
  raise "x should be 1-4 for first-fourth or 5 for last. You supplied #{x}" unless (0..5).include?(x)

  if x == 5
    return find_last_day_x_of_month(weekday, month, year)
  else
    return find_xth_day_of_month(x, weekday, month, year)
  end
end

#month_of_year_as_text(month) ⇒ Object



58
59
60
# File 'app/models/recurring_todos/abstract_repeat_pattern.rb', line 58

def month_of_year_as_text(month)
  month.nil? ? '??' : I18n.t('todos.recurrence.pattern.month_names')[month]
end

#number_of_occurencesObject



35
36
37
# File 'app/models/recurring_todos/abstract_repeat_pattern.rb', line 35

def number_of_occurences
  get :number_of_occurences
end

#put_in_tickler?Boolean

checks if the next todos should be put in the tickler for recurrence_target == ‘due_date’



149
150
151
# File 'app/models/recurring_todos/abstract_repeat_pattern.rb', line 149

def put_in_tickler?
  !( show_always? || show_from_delta.nil?)
end

#recurrence_patternObject



43
44
45
# File 'app/models/recurring_todos/abstract_repeat_pattern.rb', line 43

def recurrence_pattern
  raise "Should not call AbstractRepeatPattern.recurrence_pattern directly. Overwrite in subclass"
end

#recurring_target_as_textObject



39
40
41
# File 'app/models/recurring_todos/abstract_repeat_pattern.rb', line 39

def recurring_target_as_text
  target == 'due_date' ? I18n.t("todos.recurrence.pattern.due") : I18n.t("todos.recurrence.pattern.show")
end

#set_recurrence_on_validationsObject



105
106
107
108
109
110
111
112
113
114
115
116
# File 'app/models/recurring_todos/abstract_repeat_pattern.rb', line 105

def set_recurrence_on_validations
  # show always or x days before due date. x not null
  case target
  when 'show_from_date'
    # no validations
  when 'due_date'
    validate_not_nil(show_always?, "Please select when to show the action")
    validate_not_blank(show_from_delta, "Please fill in the number of days to show the todo before the due date") unless show_always?
  else
    errors[:base] << "Unexpected value of recurrence target selector '#{target}'"
  end
end

#show_always?Boolean



27
28
29
# File 'app/models/recurring_todos/abstract_repeat_pattern.rb', line 27

def show_always?
  get :show_always
end

#show_from_deltaObject



31
32
33
# File 'app/models/recurring_todos/abstract_repeat_pattern.rb', line 31

def show_from_delta
  get :show_from_delta
end

#start_fromObject



11
12
13
# File 'app/models/recurring_todos/abstract_repeat_pattern.rb', line 11

def start_from
  get :start_from
end

#starts_and_ends_on_validationsObject



93
94
95
96
97
98
99
100
101
102
103
# File 'app/models/recurring_todos/abstract_repeat_pattern.rb', line 93

def starts_and_ends_on_validations
  validate_not_blank(start_from, "The start date needs to be filled in")
  case ends_on
  when 'ends_on_number_of_times'
    validate_not_blank(number_of_occurences, "The number of recurrences needs to be filled in for 'Ends on'")
  when "ends_on_end_date"
    validate_not_blank(end_date, "The end date needs to be filled in for 'Ends on'")
  else
    errors[:base] << "The end of the recurrence is not selected" unless ends_on == "no_end_date"
  end
end

#targetObject



23
24
25
# File 'app/models/recurring_todos/abstract_repeat_pattern.rb', line 23

def target
  get :target
end

#update_recurring_todo(recurring_todo, attribute_handler) ⇒ Object



66
67
68
69
# File 'app/models/recurring_todos/abstract_repeat_pattern.rb', line 66

def update_recurring_todo(recurring_todo, attribute_handler)
  recurring_todo.assign_attributes(attribute_handler.safe_attributes)
  recurring_todo
end

#valid?Boolean



76
77
78
# File 'app/models/recurring_todos/abstract_repeat_pattern.rb', line 76

def valid?
  @recurring_todo.valid?
end

#validateObject



88
89
90
91
# File 'app/models/recurring_todos/abstract_repeat_pattern.rb', line 88

def validate
  starts_and_ends_on_validations
  set_recurrence_on_validations
end

#validate_not_blank(object, msg) ⇒ Object



80
81
82
# File 'app/models/recurring_todos/abstract_repeat_pattern.rb', line 80

def validate_not_blank(object, msg)
  errors[:base] << msg if object.blank?
end

#validate_not_nil(object, msg) ⇒ Object



84
85
86
# File 'app/models/recurring_todos/abstract_repeat_pattern.rb', line 84

def validate_not_nil(object, msg)
  errors[:base] << msg if object.nil?
end

#xth(x) ⇒ Object



47
48
49
50
51
52
# File 'app/models/recurring_todos/abstract_repeat_pattern.rb', line 47

def xth(x)
  xth_day = [
    I18n.t('todos.recurrence.pattern.first'),I18n.t('todos.recurrence.pattern.second'),I18n.t('todos.recurrence.pattern.third'),
    I18n.t('todos.recurrence.pattern.fourth'),I18n.t('todos.recurrence.pattern.last')]
  x.nil? ? '??' : xth_day[x-1]
end