In a previous post, I introduced the DeepTraverser
infrastructure for specifying traversals. One consequence of having such an infrastructure is that we do not need hardcoded traversals all over the code. As we have seen, there already exist such traversals. But, where are them?
Many traversals follow a recursive approach like this one:
TBehavior>>allSubclassesDo: aBlock self subclassesDo: [:cl | aBlock value: cl. cl allSubclassesDo: aBlock]
Not all traversals follow this pattern, but enough do. Let’s identify all such patterns. Essentially, we need to find all methods that have follow a alldo:
pattern, and that send a message with the same name.
The code below does exactly that:
traversals := OrderedCollection new. Object withDeep: #subclasses do: [ :each | traversals addAll: (each methods select: [ :m | ('all*do:*' match: m selector) and: [ (m parseTree deepCollect: #children) anySatisfy: [ :node | node isMessage and: [ node selector = m selector ] ] ] ]) ]. traversals.
As you can see it uses two nested traversals: one to go over all classes in the system, and one to go through all nodes of the abstract syntax tree of each method.
The result is a list of potential traversals. Doing this in a Moose image, raises 37 candidates. Are all of these true traversals?
To find this answer we need to quickly browse these methods. The GTInspector provides this ability out of the box:
Traversal enable advanced queries. And the power of queries is greatly enhanced when you combine them with interactive interfaces to digest the result.