I recently found myself implementing a calendar view and bemoaning the various complexities of doing so. Rendering the first day in the middle of the week is one constraint I found I could abstract out with a little custom iterator in my presenter class. A custom iterator might be a bit of an over-reach for this application, but I’m satisfied with the result.
It came out like this:
module Presenter
class BroadcastCalendar
def initialize(@first_of_month : Time)
end
def days_of_the_month
RenderableMonthIterator.new(@first_of_month)
end
def in_month?(date : Time) : Bool
date.month == @first_of_month.month
end
def month_name : String
@first_of_month.to_s "%Y %B"
end
end
# Iterates the days of the month, and including the "padding" days both
# before the start of the month and after the end which are needed to
# visually render a calendar.
class RenderableMonthIterator
include Iterator(Time)
def initialize(@first_of_month : Time)
@current_day = @first_of_month.at_beginning_of_week
@last_day = @first_of_month.at_end_of_month.at_end_of_week
@first = true
end
def next
if @first
@first = false
return @current_day
end
@current_day = @current_day + 1.day
if @current_day > @last_day
stop
else
@current_day
end
end
end
end
I haven’t traditionally found a use for a custom iterator, but I’ve found a use for them twice in the last month (the other, a bit more traditional on @jgaskins aws/s3 shard). This could have been implemented within the display logic, but calendar display logic is already so complicated – html is verbose, css is verbose, and rendering data itself is verbose. I figure anything I can do to abstract out a component of that logic into another file is worth it.
I wrote some more notes about it over on my website, but I won’t paste another 50 lines of code into this post.
Anyway, cheers! Hope you find this as interesting as I found it satisfying.