This post originated from an RSS feed registered with Agile Buzz
by James Robertson.
Original Post: Reflection and init.d
Feed Title: Travis Griggs - Blog
Feed URL: http://www.cincomsmalltalk.com/rssBlog/travis-rss.xml
Feed Description: This TAG Line is Extra
I had this idea. I wanted to have a menu option that would open a RefactoringBrowser on all/any packages that were not published. I usually know the main packages I need to publish at the end of a "unit o' work," but it'd be nice to gather them all, things that got touched because of a method rename or whatever. I might then publish them all, or run tests, or compare with parent or whatever.
So I contacted John Brant for some hints/tips on how I might pull this off. He was quite helpful. One thing that I needed to do was get an additional 'specGenerationBlock' in the BrowserNavigator. Said class maintains a class instance variable with blocks. Basically, these blocks are probed with a candidate navigator, if they respond with a proper window spec, then it uses that, if not, they return nil, and the next in the list is tried. What I wanted was a special case to detect a PundleEnvironment with more than one pundle in it.
Getting there to do it though, I discovered that someone had beat me to it! The GLORP dudes had been there and done this already. They overrode the class's initializeSpecBlocs method to get their block in there, and in the right slot. Arghh... a double override? Probably not a good idea. A similar problem caused me to build ExtraEmphases once upon a time. Basically, how do you provide a "framework" that multiple independent parties can plug into?
For a brief moment, I thought about some sort of pragma solution. It's all the rave these days, and I've neglected my obligation as a Smalltalk afficiendo by not embracing them. Instead, I took my inspiration from the init.d directory.
Smalltalk has all this wonderful reflective mechanism, along with implicit structured state, but we tend to pass it up sometimes. My solution, published as RBBetterNavigatorSpecLookup in the Open Repository, introduces a method name convention: start your method with 'probeForSpec'. Kind of like naming your testMethods with 'test' as the first four characters. Basically, a simple method gathers all the methods that start with that signature, sorts them, and then enumerates them until one returns a spec. The various add*Spec methods are moved to the instance side and transformed into a probeForSpec* equivalent. Becuase they are invoked on the instance side, there is no need to pass the navigator anymore, instance methods can reference it and more directly. There is no class instance variable that needs to be synced, ordered, kept up to date, and no contention for it. A package wishing to add a new spec type, just adds a method that starts with probeForSpec. I used numbers in my method names, just like the S## scripts you find in an init.d directory. Worked like a charm and used less code, more extensible.
Hmmm... I know <menu> pragmas carry a little more state with them, but I wonder if there's not something similar here that could be done with them. It seems to me that if one could solve the same problems the menu pragmas solved with a more Smalltalk-80 biased solution, it would be a strong proof for pragma's reason or not to be.