Proposal for implementing services in squeak, need feedback

Romain Robbes rrobbes at info.unicaen.fr
Tue Mar 16 08:56:48 UTC 2004


Hi all,

	While trying to dissociate the RB's ui, in order to use it for other 
browsers, like
OmniBrowser and Whisker, I have come up with a more general Service 
design
(and a part of the implementation), that I'd like to share with you, to 
know if you agree
with it, or have propositions to enhance it.

The goal is to have a registry of services, classified by categories, 
and usable by menus,
buttons, keystrokes (linking with the KeyMapper should be possible),
and a kind of commandline like Vim's one or Emacs' minibuffer
(won't you emacs freaks like to type : M-x extract-method  ?;-)))

Categories should mainly be used by menus, to display relevant actions,
otherwise services could be triggered by the commandline or by shortcuts
from nearly anywhere (M-x close-window, Alt-w c ...).

Categories of services registered could be :
-World Menu services
-Open/Help/Appearance/Windows/... Menu services (subcategories of the 
world menu)
-Class services
-Methods services
-Text Selection  services
-Refactoring services, as subcategories of the Class/Methods and Text 
Selection services
-Browser's button bar services.

This way adding services to the system could be much easier.
This could permit other services as :
- Typing services, using the RefactoryTyper
- BrowseUnit services for my case, ....

I've also looked at the FileList services, and I think I have a more 
general solution.


So here would be the way to define a service

ExtractMethodRefactoring  >> service :
	"answer a service using the current code selection to extract it"
	^ Service new	label: 'Extract method';
				description: 'Extracts the current code selection, in a new method
						using the necessary parameters, replacing the selection
						with a self message send.'
				action: [:class :selector :selection |
						(self extract: selection from: selector in: class) execute]

These would be the default parameters to provide, optional one includes 
:

	condition: [:selectionNode | selectionNode isMessage]
		
		Precondition for the service to execute/ to be displayed in a menu.

	shortLabel: 'extract'

		shorter label for a button / label is for a menu/ or for the command 
name

	answerDo: [:answer | self inform: 'extraction was succesfull']
	
		if the service user wants to use the result of the service

Now you must be wondering how to fetch the parameters to fill the 
blocks used.
The idea would be to use a Requestor object, using the #requestor: 
message,
  which wil act as an interface between the service user and the service 
:

For each of the arguments needed by the service (for the refactoring 
service, these would
be : selectionNode, and then class, selector, selection), a method is 
triggered in the
Requestor : requestSelectionNode, requestClass, requestSelector, 
requestSelection.

The Requestor base class handles them in a default way, asking the 
users for the
parameters, via FillInTheBlanks at the moment, and is able to handle 
unknow requests
in a default way.

The requestor can them be subclassed to handle particular queries, i.e

BrowserRequestor >> requestClass
	^ myBrowser selectedClassOrMetaclass

BrowserRequestor >> requestSelector
	^ myBrowser selectedMessageName

BrowserRequestor >> requestSelection
	^ myBrowser selectionInterval

FileRequestor >> requestFileName

WindowRequestor >> requestSystemWindow
	^ myWindow

Requestor >> requestSystemWindow
	"pop up a window list and ask the user for a window"

The service would be used by an object by finding them, querying
the Service class for available services or service categories,
giving the services the object's requestor, and displaying them.

What do you think of this (If you read this far that is) ?

So far I have implemented Services and their displaying as menu and 
buttons,
Some requestor classes and methods, tested them with various services
(The ExtractMethodRefactoring works with the basic requestor and the 
browser
requestor for example, asking the user for parameters in one case, 
fetching them in
the current browsed method for the other), and I am implementing 
services categories
  and the service registry. Remaining works includes referencing a lot 
of services
(senders/implementors, the world menu ...) but the refactorings are 
working with a
previous version of the stuff, so they won't be hard to include.

	Thanks for any feedback,
		Romain




More information about the Squeak-dev mailing list