Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3
by Unlicensed Unknown user

Read Part 11

I've written a few templates over the years. Not as many as template mavens like Mike Hanson and Lee White, but I've touched just about every aspect of the template language at one time or another. And more often than not I find myself peering into a dark place somewhere in the bowels of the template engine, wondering what gyrations I need to go through to get the AppGen to spit out the code I want. That's not because the template system is bad; , it's just very powerful and very complex. 

This complexity is one of the reasons I rarely start with a template. I almost always write code to solve the problem, and then figure out how to get the AppGen to generate the exact same code. Debugging source code can be tricky; debugging template code can be trickier; doing both at the same time is just plain dumb. 

...

Code Block
#At(%DataSection),Priority(3100)
%[2520]M2MClassInstanceName  class
ListCheckbox                   &CML_UI_ListCheckbox
Persister                      &CML_Data_ManyToManyLinksPersisterForABC
Links                          &CML_Data_ManyToManyLinks
Construct              procedure
Destruct       procedure Destruct       procedure
DisplayCheckboxData    procedure
Init          procedure DisplayCheckboxData        procedure
LoadEnrollmentData     procedure
InitSaveEnrollmentData     procedure
SetCheckboxIcon        procedure
            procedure LoadEnrollmentData        end     procedure SaveEnrollmentData             procedure SetCheckboxIcon                procedure
                           end                   
#EndAt

...

  
#EndAt

I've used the %[offset] technique that pads the contents of %M2MClassInstanceName to 25 characters so my class declaration formats nicely. I've even kowtowed to Clarion's annoying and cloying two space indents so my code aligns with the generated code. Nice, eh?

The next #At section embeds code in the window manager's Init method:

...

This is where that checkbox comes into play. Greg Fasolt, who has been alpha testing the classes and the template , told me he had (and who set me on this journey last fall) told me he had a number of forms where he wanted to use this template. In those situations there is no left side browse, which actually makes things a bit simpler. The "left" side primary key value is already in memory so there's no need to reload and redisplay the list box while it's being displayed.

...

Code Block
#AT(%BrowserMethodCodeSection,,'TakeNewSelection','()'),PRIORITY(9000)
    #If(%LeftFileIsInBrowse)
        #If(%ControlInstance = %LeftBrowseControlInstance)
%M2MClassInstanceName.LoadEnrollmentData()  
        #EndIf
    #EndIf
    #If(%ControlInstance = %RightBrowseControlInstance)
%M2MClassInstanceName.DisplayCheckboxData()
    #EndIf
#EndAt

This is the part of the template bit that caused me a lot of grief. This template that is attached to one browse control via the REQ attribute, and it needs to generate code into another browse control. First I tried all kinds of crazy ways to get at the context of the other browse, none of which were successful. I had actually been down a similar road years before when I wrote a template chain to generate ASP.NET MVC code from Clarion, but it took a while and a few conversations with Mike Hanson before I understood/realized/remembered the answer. 

Pay attention, because this is really good stuff.

#AT statements have the ability to progressively filter the possible locations where they can generate code. For instance, the very next #AT statement in the template looks like this:

...

The help points out that the instance values are omittable:

But because Because there's just one #Embed statement for browser method code sections I really can generate the source for one browse from a template attached to another browse, as long as I can identify that other browse from my template. 

...

This code provides me with two vital bits of information for the right and when needed the left browses: the control instance so I can generate the code when neededappropriate, and the name of the left browse's manager class instance. 

Here again is that block of template code that can generate into both browses. Because I've omitted the template instance parameter, the block will generate for all browses. But Unfortunately it's not possible to put a filter outside of the #AT block, but I can add the filtering I need inside the #AT block, so that when the block is generated for a specific browse I include just the code I need. 

This is a very useful technique; if you write a lot of templates you either have come across it or you will come across it. 

...

Both the template and the source can still be improved. The template could pre-fill the primary key values from the file metadata, and the generated class source could use some tightening. And maybe Greg or another reader will find a bug or an obvious feature lack I've missed. But this is a good start. It's been a long road from that first question Greg Fasolt raised about the original class and template. good start. 

Summary

It's been a long road from that first question Greg Fasolt raised about the original class and template. I had the most fun with the classes and the unit tests, and lost the most hair with the template.

This series isn't a perfect analogue for my idealized Clarion development cycle, but it hits a lot of the high points:

  • Test-driven development (TDD): If there's only one thing you take away from these articles, it's the idea that you start with a test. Creating tests first has so many benefits and will drive much of your development in the right direction.
  • Classes: You don't need to develop with classes, but there's a good reason software development is so heavily invested in object-oriented development.
  • Extract business logic into reusable code: Again, much easier with classes.
  • Working code before templates: In fact I don't write that many templates because for simple situations they're not necessary and for complex situation I need a lot of reuse to justify the investment. But when a template is called for it's essential to have working hand code in place for comparison purposes. 
  • Refactor, refactor, refactor: This is an endless process, because almost all code can and usually should be improved in some way. 

And speaking of code improvements, there are still some loose ends to tie up. More to come!

You can get the latest version of the classes and templates at the ClarionMag GitHub repository.