Skip to main content

5 Elegant Refactoring for Week and Month Calendars

Episode 74 · July 11, 2015

Since we have a great design for simple_calendar, it makes creating new types super elegant and easy

Refactoring


Transcripts

What's up guys? Today we're going to take a look at taking the calendar we just made and make a month calendar, the audio is being a little weird today so I apologize for that, we were having trouble with it the other day, I'm still sorting some things out in our studio, let's just dive into where we were at yesterday, our last vlog. The last thing that we actually did was we went into the meetings/index.html.erb here, and we've used simple_calendar calendar to render a new two-week-long calendar, and it produced something like this, it's pretty cool, just produces two weeks seven days a piece, voila. You have a calendar, and this is great, but we actually want to produce a month calendar now, so we have our regular generic calendar, and it'd be really killer to have a month long calendar that we could just simply swap out by saying SimpleCalendar::MonthCalendar, we can remove this number of days option because we don't need that, and get rid of these notifications up here, and in theory we should be able to just refresh this page and have a month calendar from our gem, but of course we haven't defined that, so let's go do that and take our code from before, abstract it a little bit, make a month calendar out of it. So we'll do a little refactoring here to pull this off, so I'm going to open up the simple calendar gem, we're going to take a look at the lib directory, and our calendar file here is the one we really want, and we're going to go into the month calendar which is empty right now, and delete all the code out of there before, and we're going to start to make our changes to the simple_calendar calendar to handle the month one. So really, we just need this month calendar here, and it should inherit from the simple_calendar calendar, and that would allow us to skip a lot of these things so we don't need this initializer because we can use the simple_calendar calendar one, our start date would still be date.today unless you've passed in the params, so that's good. Now the date range is going to be a little bit different, and we don't need the additional days anymore because the date range is calculated based upon the month that we're at, so we jump back to our code from before we could grab the date range from our original example and paste that in here as a replacement and voila. Now we get the start date, we can go to the beginning of the month, beginning of the week, and we go to the end of the month in the end of the week and we're done.

We have a render block here, and we need to render a partial, but it's one of those things... This would be amazing if we could just simply take the class name like the month calendar and render out a partial with that name rather than having to use the calendar partial every time, so if you look at this, we have this calendar partial, which is opened up here at the bottom, it has a link to the previous view, the next view, and the titles custom, and you're probably going to want to edit this in your application to make sure that all these tables and classes can be adjusted appropriately. This is one of those things where I would ideally like you to just edit this view, like you would with devise views, if you've ever installed the devise views and customized the sign in page, I want to work very similar to that, I didn't really plan on that, but I knew that I really like the way that devise did it, and we ended up in the same approach which I think is cool. So the thing we've got here is we have this calendar one and we could just render this calendar partial and I think it would be awesome if we took this and we made a custom one for the month calendar so it's independently customizable from the default calendar, so what we really need to do is copy this and we need to edit app/views/simple_calendar/_month_calendar.html.erb and paste in this code so we have a copy of that that we can edit, and this will allow us to say: Now that we have the month calendar partial which should show up here, if that ever updates, we would actually want to render:

month_calendar.rb
partial: "simple_calendar/month_calendar"

Rails has this useful helper that we would be allowed to use here because we're importing rails into our gem, so the gem will always require rails to exist, and there's something really cool about this. Let's go to our calendar application, open the console, let's take a look at this. The idea that you can take the class name of the calendar, and then you could convert that to a partial file name is really nifty, so if we have the calendar class, we could ask it for it's name, which would return the string version of that, and then we can do this thing called underscore, which basically allows you to convert camel case to an underscore thing. This is how rails does a lot of the conversions from file names to class names.

"SimpleCalendar".underscore

We can do that in order to take the month calendar, so we'd have this month calendar string, and we'd be able to underscore it, and that would produce a month calendar string that would make this dynamic and then we would never have to re override this render block, and then we could just simply update the date range inside month calendar which would be ideal. This is really neat, and another thing that's cool is that if you do

"SimpleCalendar::MonthCalendar".underscore

it's smart enough to know to separate the :: section with a slash in the underscored version, now this is actually how rails actually is able to convert your class names and modules into file and folder structures and this allows us to say the class name of the month calendar can get converted to the directory, and month calendar as well, so we can tackle that all at one time. Here we could just delete all of this out of the month calendar, and then if we go into our calendar.rb we could replace this hard coded string with partial: self.class.name.underscore and because we're in an instance, we have to say self.class to access the simple calendar calendar, and then that name will get converted to an underscore, so self.class here will return SimpleCalendar::Calendar because we're inside a module. This will allow us to dynamically render partials based upon the class names, which generate a new calendar we'll just have a new type of partial, and if you wanted to, you could create an empty calendar or an empty file like this and you could just have it render the partial for calendar <%= render partial: "calendar" %> and you could just delegate away to the other one if you wanted to, but most of the time you're going to want to customize it, so we're going to leave this as it is, but that's a really cool way for us to simplify even further overriding and making your own other types of calendars based upon on this generic calendars, so that's really neat and an awesome feature of Ruby and rails, like the underscore method is awesome. So now that we have that, if we restart our rails app, and hop back into our view, if we refresh the page, we now have a functional month calendar, and if you notice here, it's already working with our meetings that we have from before, which is really cool, so within like just a couple minutes, we're able to build a new calendar, override one single line of code, and then make a new partial and voila you have a new calendar, the beauty of all this is that we can build new calendars easily, we can override their views super easily, because we can just override them in our rails app, and there will be names based in the simple calendar folder, we have such a good thing going on that we can build the week calendar in like two seconds, so let's grab this, go into the week calendar, rename from month to WeekCalendar:

week_calendar

module SimpleCalendar
    class WeekCalendar < SimpleCalendar::Calendar
        private

        def data_range
            (start_date.beginning_of_week..start_date.end_of_week).to_a
        end
    end
end

and then we'll grab the month calendar partial, paste this in, and rather than doing a month title, we could leave that if we wanted, or we could display, because it's a week, we can say: This is week 32 of the year, we could totally do that too. We need to find that week number, there's gotta be a way to find that. Interestingly %U and %W do two different things, one if if the week starts on Sunday, one starts on Monday which is kind of annoying, so maybe there's a better way to do it, but regardless, we can just take this and we can say: Let's grab this, let's replace this code here with

week_calendar.html.erb

Week <%= start_date.strftime("%U").to_i %>

I believe we're going to have to restart our rails server, and once this is back up and loaded, we now have a week calendar, we have a week 26 and you can see these weeks are counting up and counting down and everything, voila. We're done, and we've customized the default title for it, which is super cool as well. That's really it, we've magically built this week calendar and that's all we had to do, we didn't have to do anything crazy, it took us like two seconds to do that. So that's cool, we've made some serious progress, we can make new calendars, we can override these easily, we can make any changes to these we want, if you don't want abbreviated day names you can just delete that part, whatever. I think the next piece that we need to do is get rid of this @meetings, because that's hard coded in and we need to dynamically pass that in through the calendar at the very beginning when we instantiate it, so that will be tomorrow's episode, we just did some cool re factorings and just kind of showcased how wonderfully flexible this result has been, and now we're off to the races, so I'll see you next episode. Peace v

Transcript written by Miguel

Discussion