Friday, February 27, 2009

Okay,  why I really want to learn Groovy is that I need to adapt Unit Testing to a large, ancient legacy java application.   With no existing tests, and more 'spaghetti' than will be eaten in Italy this year,  I'm trying to inject mocks and stubs without having to refactor every class.

I've run the sample found at http://docs.codehaus.org/display/GROOVY/Using+the+Delegating+Meta+Class  where the String class behavior is changed during a script run.   However, the change is not replicated when the string.toString() method is called inside of a Java class (triggered from the Groovy Script).

I figure I'm missing a crucial understanding of the Groovy vs Java Classloader...  Or is that all real coders always design objects with setDepenedency() methods that allow for easy code injection?

Thursday, February 26, 2009

Regex File Search with Groovy

I needed something interesting to get me going.  And then I moved to a new team at work, losing access to my nice tool rich linux account, leaving me with only a shiny new Dell Windows laptop and a need to quickly hunt through a large, legacy codebase.   Hooray - Groovy to the rescue!

The first pass at this script took me about 2 hours from Groovy Console install to working code.  This cleaned up version took me maybe another 2 of tweaking the regex and collapsing code down into more compact closures.    For reference I leaned heavily on Google and the working with files and I/O section from "Groovy in Action".

(Prerequisite note on starting point for true beginners - download the installer from groovy.codehaus.org,  following code was developed and run from the GroovyConsole
My apologies for any syntax bugs introduced in moving code into this format)

Quick Summary of lessons in developing this code:
  • If you don't call flush on writing to a file, file most often empty when script exits.
  • Explicitly calling java.util.Pattern does not produce the same matching behavior as using the Groovy notation
  • I'm still a little confused on where is safe to use single or double quotes, I got lots of errors about parsing the script.  Seemed like comment indicators don't completely insulate against the console recognizing quote marks.
  • I'm not sure how much patience I'll have in the future for the java.io package!

//*************
//Walk through a set of files
//collects information about a target string into an output file.
//*******************

// no need to define type for variables, just use generic def keyword
def outputfile = new File("myresultsfile.out").newWriter()

//This is the class invented for ant 
//spiders through directories to get list of files to search. 
//list of prefixes identifies specific file types of interest.
FileNameFinder dirList = new FileNameFinder();
List sourcefiles = dirList.getFileNames("mysrcdirectory/", "**/*.jsp, **/*.java, **/*.js, **/*.javascript, **/*.properties, **/*.xml, **/*.conf, **/*.props")

//defining a holder for results.  I want unique so using a set
Collection fileList = new HashSet();

//define a simple function to control where results are written. 
//with closures the 'method' is simply defined as another type.  
//Default input variable is it
def collectResults = {
  println it
   outputfile.writeLine(it)
}

//function takes three inputs filename, linenumber, and line
//for the line that holds the pattern
//write out the information to the output file
//save the filename in a set to generate a list of target files

def processfile = {
//defining specific function inputs instead of using default it
   srcfile, srcline, src ->   //newbies note the arrow signature it's important!

//find all text matches in the line, 
//no need to mess with java.util classes
// Groovy's added simple syntax to generate a matcher (like Perl)
   def finder = ( src =~ /.*targetstring*/ )
   if (finder.matches())
   {
     //write file and line number and matched results
       fileList.add(srcfile)
      //another favorite script feature available in Groovy
      //just use token syntax to generate mix of variable and static output
       collectResults( "${srcfile}^${srcline}^${src}")
    }
    else
  {
    //easy to debug - print information to sysout without all the typing.
    println 'did not find ' + finder.pattern()
   }
}

//Now for the meat of the script. 
//Notice the easy for iteration syntax,  
//define a list or collection and a variable to hold each reference (again see perl)

for ( sourceFil in sourcefiles){
//read file in 
  File fileHandle = new File(sourceFil)
   Reader openFile = fileHandle.newReader()
   //for each line - use the Groovy defined easy file line reader method.
   // this method takes a closure and run it each line of a file,
   // notice 'it' is the active line of file
   openFile.eachLine{ processfile(sourceFil, openFile.getLineNumber(), it)}
}

//when done processing files flush output file to ensure capture of text
outputfile.flush()


//Also check if want to write out list of unique file names captured
if (fileList.size() > 0)
{
    def chgFiles = new File("filesofinterest.out").newWriter()
    //First line to tell me how many files were identified to contain the target pattern
    chgFiles.writeLine(fileList.size().toString())

//again using a nifty Groovy method added to every list or collection type 
//passing it a closure to execute for each element in the list
    fileList.each{ 
       chgFiles.writeLine(it)
       println(it)
     }
    //ensuring the output gets written
    chgFiles.flush()
}

How I got started with Groovy (and blogging about it)

My first exposure to Groovy happened at my local Java Users Group (www.ajug.org).  We had a demo over a year ago by none other than Jeff Brown.   I hate to admit that while I was completely blown away by that talk,  I procrastinated actually getting my hands dirty with learning Groovy.   

My first roadblock was being a complete novice to any kind of dynamic language.   My extremely conservative corporate employer had up to now let the Javascript and Web 2.o revolution pass them by.  I had written a few Perl scripts, but never for anything except as a workaround to some of the limitations to shell scripting.    Groovy code doesn't make  whole lotta sense until you can grok closures, and the lightweight syntax.  Thankfully, a coworker pointed me to YUI Theater where Douglas Crockford explains Javascript as a real language.   Now at least I understand the concepts of a robust dynamic language.  

That of course leaves only the small problem of learning to use the language properly.   I find book examples are never all that informative, it doesn't take much to wander off the reservation and end up really lost.  I've recently been advised that lots of free expert advice is available, if only you post to a blog.  Blame Jared Richardson for daring me to post a blog and share my dabblings with the universe at large.