After a debate on the Pharo mailing list, we ended up choosing to rename all variations of the
example* pragmas to
gtExample*. Furthermore, as a second step, we also wanted all methods annotated with
gtExample* to start with an
example prefix because this would not conflict with the behavior from the code browser.
With this occasion, we also decided to go through the list manually to review. This is not a terribly complicated issue except that we are talking about some couple of hundred methods scattered through dozens of classes.
Having to affect multiple pieces of code scattered throughout the system is not an atypical software development problem, and I find it odd at how little support there exists in typical IDEs for something like this. So, how do you keep track of something like this in Pharo?
Here is a variation of a script that we used to keep track of the second step of renaming the method names:
(Object withAllSubclasses flatCollectAsSet: [ :each |
(Pragma allNamed: #gtExample in: each) ,
(Pragma allNamed: #gtExample: in: each) ,
(Pragma allNamed: #gtExampleFrom: in: each) ])
select: [ :each | each selector beginsWith: 'example' ]
Inspecting the result in the inspector, reveals a small query-scoped browser that allows you to focus only on the task at hand and know precisely when you are finished.
This solution is terribly inexpensive. Essentially, it is a short query combined with some object inspection. The code involved is minimal, too. This is possible exactly because we turned the concept of an IDE on its head, and as a consequence many use cases that are otherwise seen as the exclusive realm of dedicated tools can be handled with compositions of modular and small ones.
Magritte is a meta-engine that can be instantiated for any Pharo object. One of its applications is that of generating forms out of the meta-descriptions to enable the user to manipulate the values of an object. These forms can be rendered in multiple ways, such as a web form. Given that the engine also offers a backend for rendering morphs directly in the Pharo image, this can be leveraged to be integrated as well in the GTInspector.
Let’s take a look at an example.
In the latest Moose 5.1 distribution, the
GLMMagrittePersonExample class provides an simple example for describing a person with a name and an address, and if you inspect an instance of this class, you get a form with which you can manipulate those fields:
How does this work? Both the name and the address are described as Magritte properties like this:
^ MAStringDescription new
Glamour, the engine behind the GTInspector, can embed Magritte forms directly. As our annotated object already provides a description, the extension to offer the presentation in the inspector is as simple as:
display: [ self ]
That’s it. Once you have Magritte annotations, you can directly use them to provide form manipulation directly in the inspector, or for that matter, in any other Glamour browser.
In an effort to ease continuous delivery for a system, we needed to ensure that all installation projects (for various sites and customers) had a uniform structure. Specifically, after refactoring the package assembly part of the continuous delivery pipeline, we wanted to ensure that all installation projects had a
configs/srv/deployments/ path in them.
To check this, we created a tiny script. First, we invoked the Windows command line to get the list of all installation names from Subversion and we dumped these in a
WinProcess createAndWaitForProcess: 'cmd /c "svn list https://svn/svn/delivery/installations > installations.txt"'.
Afterwards, to check that each of these projects we traversed all the corresponding Subversion repositories. The simplest way we could think of was to simply check that the header of the http request is not an error (such as 404):
'installations.txt' asFileReference readStreamDo: [ :s |
s contents lines select: [ :each |
url: 'https://svn/svn/delivery/installations/', each, 'trunk/configs/srv/deployments/';
username: ‘username' password: ‘password';
response) isError ] ].
We got some 80 such projects that needed to be redone (out of a couple of hundred). The whole exercise took less than 10 minutes and could be done with a stock Moose (or even Pharo in this case) distribution, but it was a useful test that guided a multi-hour work. At the end, we reran the same script to check that we are truly done. And we were done.
The classic Smalltalk Workspace has the possibility of saving and loading script files explicitly. GTPlayground does not have these options because we think they are not needed. Indeed, in most cases, all you want is to play with code and be able to retrieve it later without worrying of where you stored it. To this end, the playground saves transparently all scripts and GTSpotter helps you find them afterwards.
However, on the Pharo mailing list, Phil described recently an interesting use case that goes like this:
- some Pharo scripts are placed in a folder where a sysadmin has the possibility of tweaking them with basic text editors. These scripts are taken into account by various running images.
- at the same time, a Pharo developer would like to be able to look at these scripts from a development image and debug them with Pharo tools.
Indeed, this type of use cases is what can lead an IDE developer to create an save/load feature in a workspace. But, there exists another way. Suppose you want to you want to edit a
demo-scripts/get-pharo-picture.st script. You first search for the
demo-scripts folder and find the script.
Triggering the default action, opens an inspector which already gives you a built in playground with all navigation options it entails. And because we have a dedicated file reference in hand, we can just save the contents in place.
And if you want a more persistent navigator for your files, you can also inspect the containing folder and manipulate the scripts exclusively in the inspector.
The Glamorous Toolkit comes with very few classes of operations but the combinations that spawn from these cover a surprising amount of use cases. In our case, all of a sudden the inspector is turned into a full blown playground with no extra effort. At the same time the global Playground is freed by the quaint constraint of saving and loading files.
GTSpotter let’s you search flexibly for all sorts of objects, and the results are typically split into multiple search categories. In this post we take a quick look at scoping your search to a specific category only.
Let’s say that you want to search for some Collection* package. Typing
Collec produces matches in multiple search categories, including classes, packages or implementors:
Using a hashed word filters the search for the category name. In our case, adding
#pa retrieves only the desired packages: