Start major refactoring of recurring_todos. Started with creating new recurring todos.

All current and new tests pass
This commit is contained in:
Reinier Balt 2014-01-27 16:42:54 +01:00
parent 8e13059df1
commit 78c07d52b7
26 changed files with 1218 additions and 32 deletions

View file

@ -107,7 +107,7 @@ class RecurringTodo < ActiveRecord::Base
errors[:base] << "Please fill in the number of days to show the todo before the due date" if show_from_delta.blank?
end
else
raise Exception.new, "unexpected value of recurrence target selector '#{recurrence_target}'"
raise Exception.new, "unexpected value of recurrence target selector '#{target}'"
end
end

View file

@ -0,0 +1,72 @@
module RecurringTodos
class AbstractRecurringTodosBuilder
def initialize(user, attributes)
@user = user
@attributes = attributes
@filterred_attributes = filter_attributes(attributes)
@saved = false
end
def filter_attributes(attributes)
raise Exception.new, "filter_attributes should be overridden"
end
def filter_generic_attributes(attributes)
attributes['tag_list'] =
{
recurring_period: attributes["recurring_period"],
description: attributes['description'],
notes: attributes['notes'],
tag_list: tag_list_or_empty_string(attributes),
start_from: attributes['start_from'],
end_date: attributes['end_date'],
ends_on: attributes['ends_on'],
show_always: attributes['show_always'],
target: attributes['target'],
project: attributes[:project],
context: attributes[:context],
target: attributes['recurring_target'],
show_from_delta: attributes['recurring_show_days_before'],
show_always: attributes['recurring_show_always']
}
end
# build does not add tags. For tags, the recurring todos needs to be saved
def build
@recurring_todo = @pattern.build_recurring_todo
@recurring_todo.context = @filterred_attributes[:context]
@recurring_todo.project = @filterred_attributes[:project]
end
def save
build
@saved = @recurring_todo.save
@recurring_todo.tag_with(@filterred_attributes[:tag_list]) if @saved && @filterred_attributes[:tag_list].present?
return @saved
end
def saved_recurring_todo
if !@saved
raise Exception.new, @recurring_todo.valid? ? "Recurring todo was not saved yet" : "Recurring todos was not saved because of validation errors"
end
@recurring_todo
end
def attributes
@pattern.attributes
end
private
def tag_list_or_empty_string(attributes)
# avoid nil
attributes['tag_list'].blank? ? "" : attributes['tag_list'].strip
end
end
end

View file

@ -0,0 +1,42 @@
module RecurringTodos
class AbstractRepeatPattern
def initialize(user, attributes)
@attributes = attributes
@user = user
end
def build_recurring_todo
@recurring_todo = @user.recurring_todos.build(mapped_attributes)
end
def mapped_attributes
@attributes
end
def attributes
mapped_attributes
end
def map(mapping, key, source_key)
mapping[key] = mapping[source_key]
mapping.except(source_key)
end
def get_selector(key)
raise Exception.new, "recurrence selector pattern (#{key}) not given" unless @attributes.key?(key)
raise Exception.new, "unknown recurrence selector pattern: '#{@attributes[key]}'" unless valid_selector?(@attributes[key])
selector = @attributes[key]
@attributes = @attributes.except(key)
return selector
end
def valid_selector?(selector)
raise Exception.new, "valid_selector? should be overridden in subclass of AbstractRepeatPattern"
end
end
end

View file

@ -0,0 +1,19 @@
module RecurringTodos
class DailyRecurringTodosBuilder < AbstractRecurringTodosBuilder
attr_reader :recurring_todo, :pattern
def initialize(user, attributes)
super(user, attributes)
@pattern = DailyRepeatPattern.new(user, @filterred_attributes)
end
def filter_attributes(attributes)
@filterred_attributes = filter_generic_attributes(attributes)
%w{daily_selector daily_every_x_days}.each{|key| @filterred_attributes[key] = attributes[key] if attributes.key?(key)}
@filterred_attributes
end
end
end

View file

@ -0,0 +1,42 @@
module RecurringTodos
class DailyRepeatPattern < AbstractRepeatPattern
def initialize(user, attributes)
super user, attributes
@selector = get_selector('daily_selector')
end
def mapped_attributes
mapping = @attributes
mapping[:only_work_days] = only_work_days?(@selector)
mapping[:every_other1] = mapping['daily_every_x_days']
mapping = mapping.except('daily_every_x_days')
mapping
end
def every_x_days
@recurring_todo.every_other1
end
private
def only_work_days?(daily_selector)
case daily_selector
when 'daily_every_x_day'
return false
when 'daily_every_work_day'
return true
end
end
def valid_selector?(selector)
%w{daily_every_x_day daily_every_work_day}.include?(selector)
end
end
end

View file

@ -0,0 +1,25 @@
module RecurringTodos
class MonthlyRecurringTodosBuilder < AbstractRecurringTodosBuilder
def initialize(user, attributes)
super(user, attributes)
@pattern = MonthlyRepeatPattern.new(user, @filterred_attributes)
end
def filter_attributes(attributes)
@filterred_attributes = filter_generic_attributes(attributes)
%w{
monthly_selector monthly_every_x_day monthly_every_x_month
monthly_every_x_month2 monthly_every_xth_day monthly_day_of_week
}.each do |key|
@filterred_attributes[key] = attributes[key] if attributes.key?(key)
end
@filterred_attributes
end
end
end

View file

@ -0,0 +1,49 @@
module RecurringTodos
class MonthlyRepeatPattern < AbstractRepeatPattern
def initialize(user, attributes)
super user, attributes
@selector = get_selector('monthly_selector')
end
def mapped_attributes
mapping = @attributes
mapping = map(mapping, :every_other1, 'monthly_every_x_day')
mapping = map(mapping, :every_other3, 'monthly_every_xth_day')
mapping = map(mapping, :every_count, 'monthly_day_of_week')
mapping[:every_other2] = mapping[get_every_other2]
mapping = mapping.except('monthly_every_x_month').except('monthly_every_x_month2')
mapping[:recurrence_selector] = get_recurrence_selector
mapping
end
def every_x_day?
@recurring_todo.recurrence_selector == 0
end
def every_xth_day?
@recurring_todo.recurrence_selector == 1
end
private
def get_recurrence_selector
@selector=='monthly_every_x_day' ? 0 : 1
end
def get_every_other2
get_recurrence_selector == 0 ? 'monthly_every_x_month' : 'monthly_every_x_month2'
end
def valid_selector?(selector)
%w{monthly_every_x_day monthly_every_xth_day}.include?(selector)
end
end
end

View file

@ -0,0 +1,104 @@
module RecurringTodos
class RecurringTodosBuilder
attr_reader :builder, :project, :context, :tag_list, :user
def initialize (user, attributes)
@user = user
@attributes = attributes
parse_dates
parse_project
parse_context
@builder = create_builder(attributes['recurring_period'])
end
def create_builder(selector)
if %w{daily weekly monthly yearly}.include?(selector)
return eval("RecurringTodos::#{selector.capitalize}RecurringTodosBuilder.new(@user, @attributes)")
else
raise Exception.new("Unknown recurrence selector (#{selector})")
end
end
def build
@builder.build
end
def save
@project.save if @new_project_created
@context.save if @new_context_created
return @builder.save
end
def saved_recurring_todo
@builder.saved_recurring_todo
end
def recurring_todo
@builder.recurring_todo
end
def attributes
@builder.attributes
end
private
def parse_dates
%w{end_date start_from}.each {|date| @attributes[date] = @user.prefs.parse_date(@attributes[date])}
end
def parse_project
if project_specified_by_name?
@project = @user.projects.where(:name => project_name).first
unless @project
@project = @user.projects.build(:name => project_name)
@new_project_created = true
end
else
@project = @attributes['project_id'].present? ? @user.projects.find(@attributes['project_id']) : nil
end
@attributes[:project] = @project
end
def parse_context
if context_specified_by_name?
@context = @user.contexts.where(:name => context_name).first
unless @context
@context = @user.contexts.build(:name => context_name)
@new_context_created = true
end
else
@context = @attributes['context_id'].present? ? @user.contexts.find(@attributes['context_id']) : nil
end
@attributes[:context] = @context
end
def project_specified_by_name?
return false if @attributes['project_id'].present?
return false if project_name.blank?
return false if project_name == 'None'
true
end
def context_specified_by_name?
return false if @attributes['context_id'].present?
return false if context_name.blank?
true
end
def project_name
@attributes['project_name'].strip unless @attributes['project_name'].nil?
end
def context_name
@attributes['context_name'].strip unless @attributes['context_name'].nil?
end
end
end

View file

@ -0,0 +1,22 @@
module RecurringTodos
class WeeklyRecurringTodosBuilder < AbstractRecurringTodosBuilder
def initialize(user, attributes)
super(user, attributes)
@pattern = WeeklyRepeatPattern.new(user, @filterred_attributes)
end
def filter_attributes(attributes)
@filterred_attributes = filter_generic_attributes(attributes)
weekly_attributes = %w{weekly_selector weekly_every_x_week}
%w{monday tuesday wednesday thursday friday saturday sunday}.each{|day| weekly_attributes << "weekly_return_#{day}"}
weekly_attributes.each{|key| @filterred_attributes[key] = attributes[key] if attributes.key?(key)}
@filterred_attributes
end
end
end

View file

@ -0,0 +1,29 @@
module RecurringTodos
class WeeklyRepeatPattern < AbstractRepeatPattern
def initialize(user, attributes)
super user, attributes
end
def mapped_attributes
mapping = @attributes
mapping = map(mapping, :every_other1, 'weekly_every_x_week')
{ monday: 1, tuesday: 2, wednesday: 3, thursday: 4, friday: 5, saturday: 6, sunday: 0 }.each{|day, index| mapping = map_day(mapping, :every_day, "weekly_return_#{day}", index)}
mapping
end
def map_day(mapping, key, source_key, index)
mapping[key] ||= ' ' # avoid nil
mapping[source_key] ||= ' ' # avoid nil
mapping[key] = mapping[key][0, index] + mapping[source_key] + mapping[key][index+1, mapping[key].length]
mapping
end
end
end

View file

@ -0,0 +1,24 @@
module RecurringTodos
class YearlyRecurringTodosBuilder < AbstractRecurringTodosBuilder
def initialize(user, attributes)
super(user, attributes)
@pattern = YearlyRepeatPattern.new(user, @filterred_attributes)
end
def filter_attributes(attributes)
@filterred_attributes = filter_generic_attributes(attributes)
%w{ yearly_selector yearly_month_of_year yearly_month_of_year2
yearly_every_x_day yearly_every_xth_day yearly_day_of_week
}.each do |key|
@filterred_attributes[key] = attributes[key] if attributes.key?(key)
end
@filterred_attributes
end
end
end

View file

@ -0,0 +1,46 @@
module RecurringTodos
class YearlyRepeatPattern < AbstractRepeatPattern
def initialize(user, attributes)
super user, attributes
@selector = get_selector('yearly_selector')
end
def mapped_attributes
mapping = @attributes
mapping[:recurrence_selector] = get_recurrence_selector
mapping[:every_other2] = mapping[get_every_other2]
mapping = mapping.except('yearly_month_of_year').except('yearly_month_of_year2')
mapping = map(mapping, :every_other1, 'yearly_every_x_day')
mapping = map(mapping, :every_other3, 'yearly_every_xth_day')
mapping = map(mapping, :every_count, 'yearly_day_of_week')
mapping
end
private
def get_recurrence_selector
@selector=='yearly_every_x_day' ? 0 : 1
end
def get_every_other2
case get_recurrence_selector
when 0
'yearly_month_of_year'
when 1
'yearly_month_of_year2'
end
end
def valid_selector?(selector)
%w{yearly_every_x_day yearly_every_xth_day}.include?(selector)
end
end
end