When we code new behavior as methods, we must must repeatedly change our context to incrementally develop the logic. Testing the code requires a separate setup. How can we efficiently prototype and test the new behavior?
An editor for coding new methods typically provides no facilities for testing the code.
Setting up code to prototype and test logic can be cumbersome.
Writing tests first for parts of the logic of a complex method may can be overkill.
Prototype new behavior in the Playground of a Moldable object, i.e., an Inspector on a live instance of the class. The Playground will be bound to the
of the instance, so
self and all slots can be accessed exactly as they would in a running method.
From the moldable object you can navigate to any parts of the instance, to explore the APIs, or to test experimental code.
Code snippets that work as expected can then be copy-pasted to existing methods, or extracted to new methods using an Extract method refactoring.
The following steps illustrate how the Inspector Playground can be leveraged to explore an object's state, experiment with code, extract methods, extract (test) examples, and add custom views to a live object.
Suppose we are implementing a
StackMachine class to simulate an RPN calculator. So far it just holds a
stack slot initialized to an empty
SequenceableCollection subclass: #OrderedCollection
instanceVariableNames: 'array firstIndex lastIndex'
, and nothing else. We want to implement operations to perform calculations with the stack machine.
Exploring the object's state
We start by exploring a live instance.
We would like to push some values onto the stack but we need to explore the API of the underlying objects.
From the Inspector we dive into the stack slot and query its
view to see which
add operations it has.
We find the
addLast: selector, and experiment with it in the Inspector Playground.
We see in the stack's Items view that it has been updated.
Extracting a method
We generalize the code as follows.
We select the code and perform an
refactoring, and name the new (binary) method
(For illustrative purposes we have multiple StackMachine classes to represent the different versions. In reality we would just have one class.)
We push two values onto the stack from the Inspector Playground.
Extending the API
It would be nice to inspect the stack and the top of the stack, so we test each of the following snippets in the Playground, and extract them as methods.
stack. stack isEmpty. stack last "top".
Our API now looks like this.
Extracting an example method
We rewrite our scenario as an example:
example := self class new. example ! 3. example ! 4. example
And again we extract a method. We add a
<gtExample> pragma, with some assertions.
| example |
example := self class new.
self assert: example isEmpty.
example ! 3.
self assert: example isEmpty not.
self assert: example top equals: 3.
example ! 4.
self assert: example top equals: 4.
We can generate an instance directly from this method ( Play and inspect ).
Adding a custom view
We'd like a custom view for the StackMachine that mirrors the
From the live example, we navigate using the
view to the stack's
view, Secondary-click on the tab and see that the method that implements this view is called
gtItemsFor: (implemented in
^ aView columnedList
items: [ self ];
actionUpdateButtonTooltip: 'Update item list';
text: [ :eachItem :eachIndex |
eachIndex asRopedText foreground: Color gray ]
text: [ :eachItem | eachItem gtDisplayText ].
Now we can quickly implement a forwarding view as follows:
^ aView forward
object: [ stack ];
It looks like this:
Start with a Moldable object, in order to get a live instance to prototype from.
You can also see this process at work in the short video Exploring the GitHub REST API in 7'.