Tuesday, May 29, 2012

QueryTwo

As promised, here's one of those "tying up loose ends" things.

A couple months ago, I posted a prototype of some code inspired by JQuery like behavior for VisualWorks view trees. It got a variety of feedback. A lot positive, some skeptical, some mixed.

Recently, I've been working on modifying the newer VisualWorks comparison tool that presents changes in a disclosure/rollup navigation style. I've been working to put filters in it, so you can filter out different kinds of changes (e.g. hide all the category changes, or show just the additions).

I found myself wanting that JQuery like behavior to have lightweight communication between view tree objects again. I did not want to fabricate a model with dependencies just to facilitate some cross talk. So I took a "go around #2" at the idea. This time, no funky syntax. More based on real world needs. Definitely lighter weight.

It's been published as QueryTwo to the Open Repository. What will come of it? I don't know at this point. Maybe it'll get integrated, maybe not, that's up to others to decide now.

Here is an example of me using it in real life (instead of hypothetical examples).

<pre><code>

propogateChanges

(self query)
top;
type: AbstractComparisonRollupView;
do: [:view | view hideTypes: hiddenTypes].
self updateCellFills

</code></pre>

It reminds me a lot of writing Glorp queries. Similar patterns, you create one, send messages to configure it, and then enumerate it. Or kind of like Seaside html writer pattern too. Make one, configure it, execute a block for it.

What follows is a portion of the class comment that describes usage:


The most common case is to ask a VisualPart or Window to create one for you using


self query


This will return a query that has the receiver as the root of its query path. One can send top to the query to shift the root of the query to the top most element of the view tree (e.g. the window at the top).


You can also ask an ApplicationModel to create one


myApplicationModel viewQuery


The pattern is that after creating a query, one sends configurations messages to it, and then invokes various collection methods (e.g. do:). The enumeration methods should be sent after configuration methods. There are couple of different methods that govern which objects in the view tree are traversed, they come in pairs:


Traversal Configuration Messages


up - causes the query to proceed upwards through the parent path from the root object
down - causes the query to proceed downwards through the children of the root object (this is the defaut if neither up nor down is sent to configure the query)


withRoot - causes the query to include the root in its traversal
withoutRoot - causes only parents or children (as configured by up/down) to be traversed (this is the default if neither withRoot or withoutRoot is sent to configure the query)


one - causes the query to cease traversal after the first match is found and enumerated
many - causes the query to traverse all elements, matching as many as encountered that match (this is the default if neither one or many or sent to configure the query)


Queries


Adding queries controls which elements of the traversal are "matched" and thus show up in things like do: enumerations. By default the query will match everything. Methods found in the queries method category provide utility methods for setting up some common queries. Ultimately, they all pass through the addQuery: method. The argument to the this method is a block, which is cull:ed for every element in the traversal, and for those that answer true to this block, they will be enumerated. Repeated query configuration messages, will AND the queries together. The method reset will return the query to its default [true] state.


Examples


(self query id: #foobar) any
"will return the first element with id of #foobar"


(self query top property: #frame satisfies: [:rect | rect area isZero]) not invalidate
"invalidate all widgets in my window that have real area to them"


(self query up withRoot) do: [:each | each flash]
"flash me and all my parents"


(self query top hasProperty: #UpdateGroup) do: #update
"send #update to all elements in my window that are marked with the #UpdateGroup property"

No comments:

Post a Comment