All I know I learned from GinA (and DGG)

Okay, maybe that’s an exaggeration, but I’ve been digging into Groovy in Action (GinA) and the Definitive Guide to Grails (DGG) more lately and keep finding nuggets that I apparently missed on my first few readings.

(I’m trying not to be annoyed about that, btw. By this stage in my career, I know all too well that I have to re-read things over and over to really “get” them. I just wish I retained more than I apparently do. I guess I’ll always think that.)

Anyway, recently I wrote a blog post about how I was able to iterate over Dates because Groovy treated them as a Range (yes, capital R). I thought that was really cool and wasn’t sure exactly why it worked.

Lo and behold, on page 96 of GinA, Listing 4.1 includes


def today = new Date()
def yesterday = today - 1
assert (yesterday..today).size() == 2

Page 98 points out that “any datatype can be used with ranges,” provided it implements next() and previous() and implements Comparable. This is equivalent to overriding ++, –, and the good ol’ spaceship operator, <=>.

(As a long-time Java developer, I have to say that any language that has a spaceship operator is inherently cool. Except Perl, of course. :))

I keep finding ways to rewrite my code as more idiomatic Groovy (or maybe I should just say, groovier). I used to calculate the number of days in a training course from the start and end dates using:


int days = 0
for (date in startDate..endDate) { days++ }

Now I realize that since a Range is an actual object, it’s simpler just to write:


int days = (startDate..endDate).size()

At least when I wrote the first version, I had a feeling I was making it too complicated.

Moving on to Grails, I wanted to have a “days” property on my Course class, but it’s a dependent property. Its value is determined by the existing startDate and endDate properties. That meant I didn’t want to add it as a formal property, because that would imply the existence of a setter method as well as a getter. Also, it doesn’t exist in the database and doesn’t need to.

I couldn’t find an appropriate annotation in DGG, but a quick question on the mailing list cleared it up. My class now looks something like


class Course {
  int id
  Date startDate
  Date endDate
  String title

  // associations, toString() override, and constraints as usual

  transients = ['days']
  int getDays() { return (startDate..endDate).size() }
}

By providing the getter, I don’t need the attribute, which is a normal JavaBeans convention. By putting the property in the transients closure, I’m telling Grails that it doesn’t have a corresponding column in the database.

Unfortunately, I found that when I tried using “days” as a property in in a GSP, sorting on it didn’t work. I think that’s because the tag actually generates a database query with an order by clause, and that’s going to be a problem with a property that doesn’t exist in the database.

I did realize I could compute my total number of training days in a one-liner:


Course.list()*.days.sum()

That uses the wicked cool spread operator, too. In my CourseStatistics class I don’t actually make that list query more than once, but it’s nice to know I could.

I’ve been using Groovy and Grails for about a year now, and it’s nice to know they’re starting to sink in. 🙂

One response to “All I know I learned from GinA (and DGG)”

  1. One small correction: ‘transients’ is not a closure. It’s a list

    Cheers,

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.