Skip to content

Instantly share code, notes, and snippets.

@sixtyfive
Created September 16, 2011 19:08
Show Gist options
  • Save sixtyfive/1222856 to your computer and use it in GitHub Desktop.
Save sixtyfive/1222856 to your computer and use it in GitHub Desktop.
class Datespan < ActiveRecord::Base
include Enumerable
attr_accessor :results
def initialize(start_date, end_date, user)
build_results(start_date, end_date, user)
end
def each(&block)
@results.each(&block)
end
private
def build_results(start_date, end_date, user)
r = {}
years = Year.date_range_scoped_by_user(start_date, end_date, user)
r[:years] = {}
# Loop through all Years contained in the given range,
# adding each year to the array.
for year in years do
months = Month.date_range_scoped_by_user_and_year(start_date, end_date, user, year)
r[:years][year.id] = {
:name => year.name,
:number_of_months => months.count,
:total_hours => year.total_hours.human_duration,
:target_hours => year.target_hours.human_duration,
:overtime_hours => year.overtime_hours.human_duration
}
r[:years][year.id][:months] = {}
# Likewise, loop through all the Months in the given range
# now, and add them to the respective year they belong in.
for month in months do
weeks = Week.date_range_scoped_by_user_and_month(start_date, end_date, user, month)
r[:years][year.id][:months][month.id] = {
:name => month.name,
:number_of_weeks => weeks.count,
:total_hours => month.total_hours.human_duration,
:target_hours => month.target_hours.human_duration,
:overtime_hours => month.overtime_hours.human_duration
}
r[:years][year.id][:months][month.id][:weeks] = {}
# Same thing again, only do it with the weeks now. Note that
# the weeks were obtained above by giving them the month they're
# supposed to belong to, so some weeks will be shown twice in the
# results!
for week in weeks do
r[:years][year.id][:months][month.id][:weeks][week.id] = {
:name => week.name,
:number_of_days => week.days.count,
:total_hours => week.total_hours.human_duration,
:target_hours => week.target_hours.human_duration,
:overtime_hours => week.overtime_hours.human_duration
}
r[:years][year.id][:months][month.id][:weeks][week.id][:days] = {}
# And another loop to get through the days that are in a week.
# Here it is clear again where a day belongs, and every day must
# only appear once in a given range or result.
for day in week.days do
# Usually, only Mondays to Fridays are added to the list. Saturdays and Sundays
# will be added if there are Activities associated with them. Other holidays would
# be added regardless of wether or not they have any activities.
if (day.is_weekday? || (day.is_weekend_day? && day.activities.any?))
r[:years][year.id][:months][month.id][:weeks][week.id][:days][day.id] = {
:in_range => day.within_range?(start_date, end_date),
:name => day.name,
:date => day.date.strftime('%d.%m.%Y'),
:activity_count => day.activities.count,
:total_hours => day.total_hours.human_duration,
:target_hours => day.target_hours.human_duration,
:overtime_hours => day.overtime_hours.human_duration
}
r[:years][year.id][:months][month.id][:weeks][week.id][:days][day.id][:activities] = {}
# The last of these nested loops will add a day's activities
# to the array. The line above will create an empty hash for
# the activities anyways, whether there are any or not. This
# is in order for the array to be consistent and not cause nil
# errors when it is being looped through.
for activity in day.activities do
r[:years][year.id][:months][month.id][:weeks][week.id][:days][day.id][:activities][activity.id] = {
:category => activity.category.name,
:description => activity.description.html_safe,
:duration => activity.duration(day.date.beginning_of_day, day.date.end_of_day).human_duration
}
end
end
end
end
end
end
@results = r
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment