Software Development

gonsole weeks: oops – it’s a framework

While Eclipse ships with a comprehensive Git tool, it seems that for certain tasks many developers switch to the command line. This gave Rüdiger and me the idea, to start an open source project to provide a git console integration for the IDE. What happened so far during the gonsole weeks can be read in git init gonsole, eclipse egit integration and content assist for git commands.

Since our last update we have been busy replacing most of the explorative code passages with clean implementations based on unit tests. Additionally the architecture got a thorough overhaul which resulted into a split of reusable core functionality and the gonsole specific implementations. Though this wasn’t the main intent the rework led to an API that allows to implement other consoles with the same characteristics easily. In this post we will take an excursion to explain the few steps needed to write your own console.

Assume that you want to create a command line based calculator that provides arithmetic operations like sum, sub etc. The basic set of features is provided by the com.codeaffine.console.core plug-in that supplies the API to contribute the calculator console.

First of all we need a plug-in project that declares the necessary imports:

calculator-project

In the gonsole project we got used to nested TDD. That’s why we want start by writing an acceptance test. Luckily com.codeaffine.console.core.pdetest exports a class called ConsoleBot that enables us to create such tests comfortably. Since these tests run in a plug-in environment we will place them in a fragment.

calculator-test-fragment

With these two projects in place we are ready to write our first happy path test:

calculator-end-to-end

As you can see, the ConsoleBot is a JUnit Rule that hides the details of how to create a ready-to-test console. Furthermore it allows to simulate user interaction like typing commands and opening content assist. To check the expected outcome conveniently, there is a custom AssertJ assertion.

ConsoleBot#open() expects an implementation of ConsoleConfigurer as its first parameter. Simply to get our test compiling, the next step is to provide a skeleton implementation thereof. Such configurations contribute the pluggable parts that make up a particular console implementation. But before we can launch our console for the first time there is one last thing to do:

first-launch

To hook the console into the Eclipse console view our plug-in has to provide an extension to the org.eclipse.ui.console.consoleFactories extension-point. The latter expects an implementation of IConsoleFactory which is provided by our console API type ConsoleFactory. The sole coding needed is to override ConsoleFactory#getConsoleConfigurer() as shown above.

Of course having only a scaffold, the runtime console does nothing useful yet and running our PDETest leads to a red bar:

calculator-first-failure

Now we are ready to develop the interpreter, content-assist and input prompt components in the usual TTD manner. We proceed doing this until our end-to-end test turns up green. We even have encountered that this can be a good starting point for an explorative break-out in case we are not sure which way to go. Once the end-to-end tests are green and we have gained enough confidence in our solution, we start to replace the hacked passages step by step with test driven solutions.

For the example we took the hacking approach:

class CalculatorConsoleCommandInterpreter 
  implements ConsoleCommandInterpreter
{

  static final String SUM = "sum";

  private static final String SUM_RESULT
    = "The sum of %s and %s is %s" + LINE_DELIMITER;

  private final ConsoleOutput consoleOutput;

  CalculatorConsoleCommandInterpreter( ConsoleOutput consoleOutput ) {
    this.consoleOutput = consoleOutput;
  }

  @Override
  public boolean isRecognized( String... commandLine ) {
    return commandLine.length > 0 && SUM.equals( commandLine[ 0 ] );
  }

  @Override
  public String execute( String... commandLine ) {
    int sum =   parseInt( commandLine[ 1 ] ) 
              + parseInt( commandLine[ 2 ] );
    consoleOutput.write( format( SUM_RESULT, 
                                 commandLine[ 1 ],
                                 commandLine[ 2 ],
                                 valueOf( sum ) ) );
    return null;
  }
}

The snippet makes our test happy by providing a simplistic ConsoleCommandInterpreter that supports the sum command. Supplemented with a similarly elaborated ContentProposalProvider our calculator in action now looks like this:

calculator-sum-and-sum-assist

Although there could be said much more about custom console implementations it is time to bring this excursion to an end. Please note that the console core API is still under development and might undergo substancial changes. For those interested we have added the calculator projects to the gonsole git repository and its build:

Repository: https://github.com/rherrmann/gonsole

Build: https://travis-ci.org/rherrmann/gonsole

This ensures that the example will be kept up to date. And of course for a more grown-up solution you might always have a look at the gonsole implementations.

That’s it for today folks, let’s get back to work. And maybe the next time we are indeed able to show you more content assist features…

Reference: gonsole weeks: oops – it’s a framework from our JCG partner Frank Appel at the Code Affine blog.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button