Fork me on GitHub
Showing posts with label scaffolding. Show all posts
Showing posts with label scaffolding. Show all posts

12 Aug 2010

Auto-generate Spock specs for Grails artifacts

When creating artifacts such as domain classes, controllers and tag libs Grails generates a JUnit test case. If, like me, you're digging writing specifications with Spock you'd probably rather have Grails generate one of those. The last thing I want is to manually transform every generated test case into a specification for every artifact I create.

It's very simple to create a CreateUnitSpec or CreateIntegrationSpec script with a template specification. Hooking in to the other types of artifact creation turned out to be fiddlier. Each create-* command calls a Closure called createUnitTest. Reassigning that Closure should be the solution. The trick is in figuring out where that can be done.

Any time one of its Gant targets is invoked the Grails build system fires an event. You can respond to those events by declaring a closure called event<target name>Start in scripts/_Events.groovy. The only Gant target directly invoked when an artifact is created is called 'default'. It is possible to intercept that although that means the event handler will be invoked any time any Gant target called 'default' runs. For this purpose that's no problem since we're just overriding a closure in the build binding.

The other factor is that the superclass for the unit test is specified by the individual create-* scripts (or defaulted to GrailsUnitTestCase). Rather than having to override those scripts as well, I've just mapped the non-standard unit test superclasses to the Spock equivalents.

Here's the code for your _Events.groovy script:
The template specification should be placed in src/templates/artifacts/Spec.groovy and is simply:
It goes without saying that this is a slightly hairy and it would be great if Grails provided a proper hook for overriding the test generation. I can live with some fun-size evil in _Events.groovy for the sake of the convenience of getting template specs for all my artifacts, though.

13 Jun 2009

Hacking on Grails scaffolding templates

Grails scaffolding is a fantastic mechanism for getting you up and running quickly. I love the fact that you can provide your own implementation of some controller actions or views and scaffolding will just fill in the gaps. That way you can start hand-crafting things when complexity increases past a certain point but still have Grails do a bunch of work for you.

I'd done some customising of scaffolding templates before for the Joda Time plugin but recently started playing with them again with a view to creating some I could re-use for future projects. Because scaffolding templates are not only used for dynamic views but also provide the basis of generated views that you go on to customise it's worth having a solid baseline. A couple of things I wanted to do were:

  1. Mark up create and edit forms without using tables
  2. Provide automatic indication of mandatory fields

I'm pretty happy with the result. This is how a standard create form now appears. The grab is from Safari 4 but the rendering is all but consistent across Firefox 3 on my Ubuntu box, Safari 4 on my Mac and even IE6, IE7, Google Chrome and Opera 9 on the Windows XP VirtualBox instances I use for cross-browser testing.

Forms Without Tables

Each form element is simply:

<div class="prop">
<label for="${p.name}">Property Name</label>
${renderEditor(p)}
</div>

Which is reasonable semantic markup. Styling it cross-browser took me a while (I know just enough CSS to make me dangerous) but with a few helpful pointers from our resident front-end guru Jeff I was able to achieve that with a lot less browser-specific tweaking than I would have thought would be necessary.

The necessary CSS is just:

.prop {
margin: 1em 0;
}
label {
display: inline-block;
margin-right: 1.5em;
text-align: right;
width: 8em;
}
input, select {
vertical-align: middle;
}
textarea {
vertical-align: top;
}

Making the label inline-block meant I can apply a width to it so all the fields will line up nicely but also keeps the label inline so I can then use vertical-align on the input to centre it on the text line of the label. The results are consistent cross-browser. Most solutions I've seen around the internet are horribly inconsistent between browsers (and operating systems with different font rendering) and often rely on nasty pixel-perfect margin and padding tweaks to try to align things nicely. That approach rapidly becomes a game of whack-a-mole as a tweak that fixes some alignment on IE will screw it up on Opera, fixing that will make Firefox do something odd, etc.

Automatically Indicating Mandatory Fields

A polite form should really indicate to the user what fields are mandatory and it turns out this isn't hard to achieve automatically in Grails scaffolded views. The scaffolding templates already use the constrained properties of the domain class to determine whether to display a form field for each property. It's a very small step to use the isNullable() and in the case of String properties isBlank() methods to decide whether to render a mandatory indicator.

I simply output a span with an asterisk inside the label then styled it with:

label {
/* other label properties as above */
position: relative;
}
label .mandatory {
color: #c00;
position: absolute;
right: -1.25em;
}

The absolute positioning takes the asterisk out of the flow of the page so the labels and inputs line up neatly regardless of whether there's an asterisk or not and the right: -1.25em shoves it over into the space of the label's right margin. Positioning the asterisk perfectly in between the label and the input is tricky and not reliable cross browser. On IE the asterisk is too far to the right.

I tried other techniques such as disabling the label's right margin when the asterisk is present and setting the asterisk's span to the exact same size the margin would have been. Unfortunately it seems 1.5em as an element width is not quite the same thing as 1.5em as a right margin so the alignment of the labels and inputs was thrown off. Absolute positioning is necessary to maintain that alignment which is far more important to the eye than pixel-perfect placement of the asterisk itself.

Source Code

Here's the source code. Any suggestions for improvements would be very welcome. I based the templates on Marcel Overdijk's excellent i18n-templates, the only differences are in the rendering of the form fields and the surrounding fieldset.

Something this exercise has driven home for me is that when it comes to cross-browser styling less is definitely more. Taking away everything, setting the font size consistently cross-browser, then gradually building up with the simplest markup and styling possible yields the best results.