Sponsored Link •
|
Summary
Ruby is the cool new kid of on the block and has some significant cred in code-generation circles. Python has whitespace sensitivities that make it a poorer fit for templating solutions. This sounds like a no-brainer decision but is the real argument about which language the market wants to see used?
Advertisement
|
With my return to running my own business as a full-time activity and freedom to indulge entrepeneurial instincts, one of the projects I'll be putting more time into is AppMaker. AppMaker is a long-standing Mac product for application generation to which I acquired the rights when the original author, Spec Bowers, retired. Progress has been stalled for much of the time of OS/X with Apple's closed attitude on Cocoa - a contributing factor to Spec's retirement.
Given the length of time that has elapsed since there was a new release of AppMaker and the fact that very few users seemed to customise templates significantly, I feel some freedom to vary the template approach. For a start, I'm planning to replace the somewhat-idiosyncratic OO language with Python or Ruby. There's no justification for maintaining a complex language, with an old code base, when the world has moved on to create outstanding scripting and text manipulation languages. The startup cost for any new AppMaker user wanting to customise their templates will be drastically reduced if they are based on a standard language.
I was very impressed with Jack Herrington's Code Generation in Action which includes a taxonomy of code generators, and Ruby examples. His book, and the growth of Ruby in the somewhat code-generationy Rails framework, have put me in the position of having to choose - would you use Ruby or Python for a code generator language?
The AppMaker generators best fit what he calls a Partial Class Generator where a definition file (the AppMaker Project) is combined with a set of templates (the selected language/framework) to generate the code. The previous market for the product included a strong educational segment as the code generated was deliberately made representative of best practice for a given framework.
Many people would be familiar with JSP templates as an example of the Partial Class Generator approach. However, the AppMaker templates have somewhat of a twist and I'm trying to decide if it is a style worth preserving. Here's a reminder of the traditional bounded template that Herrington shows or JSP conditional logic:
public class <%= class_name %>Base { <% fields.each { |field| %> protected String _<%= field %>;<% } %> public <%= class_name %>Base() { <% fields.each { |field| %> _<%= field %> = new String();<% } %> } <% fields.each { |field| %> public String get<%= field.capitalize %>() { return _<%= field %>; } public void set<%= field.capitalize %>( String value ) { _<%= field %> = value; } <% } %> }
<% if ("someValue".equals(request.getParameter("param1"))) { %> Generate this template text if param1 equals someValue <% } else { %> Otherwise generate this template text <% } %>
The AppMaker proprietary template language flips between a literal text state and a code state, using the percentage sign as the escape character to flip states. This results in templates that have less noise and probably would cause less confusion than using angle-bracketed tags like JSP. Of course, they are no longer viewable by a simple HTML browser which can ignore the JSP tags but the domains we're targetting for such generation are more likely to be generating traditional source code into multiple files such as shown (with elisions...) below.
procedure Window.genWindow import appName: string declare cmdList: list of Command getViewCommands (/* cmdList */) declare dlgList: list of Dialog getDialogList (/* cmdList, dlgList */) import firstWindow: bool // param declare windName: string = window.name ... declare hdrFile: file filename = windName + ".h" hdrFile.create (name = filename/*, creator, fileType*/) hdrFile.open () hdrFile.genText () % // %filename% #pragma once #include "AMWindow.h" %genHdrItemInclude ()% class %dataName%; class %WindName% : public AMWindow { public: %WindName% ( AMAEObject* inSuperObject); virtual ~%WindName% (); public: static void Create (AMDoc* inDoc, %dataName%* inData); public: virtual void Open (AMDoc* inDoc); virtual void Close (); ... % for each cmd in cmdList cmd.declareDoCommand () end for % protected: virtual void ActivateData (); %for each WindowItem windowItem.genAllAuxWinDecl () end for% public: %dataName%* mData; %for each windowItem% %windowItem.genAllWindowField ()% %end for% }; % hdrFile.close () //----- declare srcFile: file filename = windName + ".cp" srcFile.create (name = filename/*, creator, fileType*/) srcFile.open () srcFile.genText () % // %filename% #include "%windname%.h" #include <Types.h> ... % for each dlg in dlgList //declare itsClassName: string dlg.getClassName () % #include "%itsClassName%.h" % end for % %genIncludeData ()% %genSrcItemInclude ()% %genCommandIncludes (/* cmdList */)% %If lang = "MPW"% #pragma segment %windname% %end if% void %WindName%::Create ( AMDoc* inDoc, %dataName%* inData) { %WindName%* winObj = new %WindName% (inDoc); if (winObj != nil) { winObj->Open (inDoc); winObj->ConnectToData (inData); ShowWindow (winObj->mWindow); } } %WindName%::%WindName% ( AMAEObject* inSuperObject) : AMWindow (inSuperObject) { mData = nil; } %WindName%::~%WindName% () { mData->RemoveResponder (this); } } void %WindName%::Close () { delete this; } ... % srcFile.close () end genWindow
Have an opinion? Readers have already posted 16 comments about this weblog entry. Why not add yours?
If you'd like to be notified whenever Andy Dent adds a new entry to his weblog, subscribe to his RSS feed.
Andy is a free-lance developer in C++, REALbasic, Python, AJAX and other XML technologies. He works out of Perth, Western Australia for a local and international clients on cross-platform projects with a focus on usability for naive and infrequent users. Included in his range of interests are generative solutions, software usability and small-team software processes. He still bleeds six colors, even though Apple stopped, and uses migration projects from legacy Mac OS to justify the hardware collection. |
Sponsored Links
|