More Groovy Goodness

Yesterday afternoon, I was talking to a friend about one of my apps, and he asked about how big the app was.  I had no idea, and thought I'd write a little app to figure it out for me.  Oh how easy Groovy makes things.  The basic idea was to build a simple parser to return counts of files, directories, lines of code, and bytes, as well as break them down by file types.  Hand that data structure off to a renderer for output, and you're done.

The code is available at https://ssl.barneyb.com/svn/barneyb/code_counter/trunk/, just check it out and execute:

groovy Runner </path/to/project>

Executing the project on itself, you get this output:

                         Count      All Lines     Real Lines          Bytes
---------------------------------------------------------------------------
Paths                        1
Directories                  1
Files                        9            422            291          8,047
   text                      9            422            291          8,047
      groovy                 7            402            271          7,945
      txt                    2             20             20            102
   binary                    0                                            0

<project pathCount='1' fileCount='9' directoryCount='1' byteCount='8047' lineCount='422'>
  <type type='text' fileCount='9' byteCount='8047' lineCount='422' realLineCount='291'>
    <extension extension='groovy' fileCount='7' byteCount='7945' lineCount='402' realLineCount='271' />
    <extension extension='txt' fileCount='2' byteCount='102' lineCount='20' realLineCount='20' />
  </type>
  <type type='binary' fileCount='0' byteCount='0' />
</project>

You can also pass in multiple paths (if your project has multiple components), and you'll get per-path breakdowns as well as the totals.  The two output formats are created by separate renderers (text and xml) operating on the same data structures, and each can be used independently.

Of particular interest was the ease of counting lines (line 2 gets the lines in the file as List of Strings, line 3 counts them, and line 4 counts the ones that have non-whitespace characters):

// 'file' is a java.io.File
def lines = file.readLines()
this.lineCount = lines.size()
this.realLineCount = lines.sum(0, { it.trim().length() == 0 ? 0 : 1 })

Similarly, reading the configuration for which files to ignore, and which extensions are considered text files:

TEXT_EXTENSIONS.addAll(getClass().getResourceAsStream("/text_extensions.txt").readLines())
FILES_TO_IGNORE.addAll(getClass().getResourceAsStream("/ignore.txt").readLines())

This piece, in particular, I'd intended to leave as configured-in-code, because I didn't want to deal with the external resource headache and then the parsing of the files once I got them.  Ha.  As if Groovy would make me do that.

There's a whole bunch of other stuff in there, particularly the mixing of implicit and explicit getters to unify object APIs.  If you want a directed tour, the core of the app resides these methods: CodeCounter's constructor, PathInfo.processDirectory, and FileInfo's constructor.  The output is handled by TextRenderer (using a PrintWriter) and XmlRenderer (using MarkupBuilder).

Total time to build the app was about an hour, required no special editor (I used TextPad), IDE, or compiler.  The classes can be executed in any Groovy environment (including CF Groovy), or run them through groovyc and use them in any Java environment.  Oh how nice it is.

One response to “More Groovy Goodness”

  1. Even More Groovy at BarneyBlog

    [...] Contact « More Groovy Goodness [...]