Skip to content

Instantly share code, notes, and snippets.

@henrik
Last active January 12, 2018 22:31
Show Gist options
  • Save henrik/a8ba47c9b8ae4529cff4 to your computer and use it in GitHub Desktop.
Save henrik/a8ba47c9b8ae4529cff4 to your computer and use it in GitHub Desktop.
Ruby Month class.
require "attr_extras" # gem
class Month
vattr_initialize :year, :month_number
def self.from(object)
case object
when Month then object
else new(object.year, object.month)
end
end
# Relies on Rails' Time.zone.
def self.now
from(Time.zone.now)
end
def first_date
Date.new(year, month_number, 1)
end
def last_date
Date.new(year, month_number, -1)
end
def last_day
last_date.day
end
def date_for_day(number)
Date.new(year, month_number, number)
end
def previous
self.class.from(first_date - 1)
end
def next
self.class.from(last_date + 1)
end
end
require "spec_helper"
describe Month do
it "has value object equality" do
expect(Month.new(2014, 6)).to eq Month.new(2014, 6)
end
end
describe Month, ".from" do
it "builds a Month from a Date" do
month = Month.from(Date.new(2014, 6, 1))
expect(month).to eq Month.new(2014, 6)
end
it "builds a Month from a Time" do
month = Month.from(Time.zone.local(2014, 6, 1, 0, 0, 0))
expect(month).to eq Month.new(2014, 6)
end
it "returns the input when given a Month, since it's a value object" do
month = Month.from(Month.new(2014, 6))
expect(month).to eq Month.new(2014, 6)
end
end
describe Month, ".now" do
it "is the current month" do
Timecop.freeze(Time.zone.local(2014, 1, 1, 0, 0, 0)) do
expect(Month.now).to eq Month.new(2014, 1)
end
end
end
describe Month, "#first_date" do
it "is the first date of the month" do
month = Month.new(2014, 2)
expect(month.first_date).to eq Date.new(2014, 2, 1)
end
end
describe Month, "#last_date" do
it "is the last date of the month" do
month = Month.new(2014, 2)
expect(month.last_date).to eq Date.new(2014, 2, 28)
end
end
describe Month, "#last_day" do
it "is the last day number of the month" do
month = Month.new(2014, 2)
expect(month.last_day).to eq 28
end
end
describe Month, "#date_for_day" do
it "gives you such a date" do
date = Month.new(2014, 1).date_for_day(2)
expect(date).to eq Date.new(2014, 1, 2)
end
end
describe Month, "#previous" do
it "is the previous month" do
month = Month.new(2014, 2)
expect(month.previous).to eq Month.new(2014, 1)
expect(month.previous.previous).to eq Month.new(2013, 12)
end
end
describe Month, "#next" do
it "is the next month" do
month = Month.new(2013, 11)
expect(month.next).to eq Month.new(2013, 12)
expect(month.next.next).to eq Month.new(2014, 1)
end
end
@dasch
Copy link

dasch commented Jul 2, 2014

If you use pred and succ rather than previous and next you'll get range support for free...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment