Jetbrains MPS is an amazingly flexible tool which permits to use several kinds of projections. Today we are going to take a look at tables.
What is Jetbrains MPS to me
Jetbrains MPS is a Language Workbench: a system to design languages and supporting tools.
This is one definition of MPS, but for me it is also something different. I think of it as Lisp where you can customize also tool support, instead of being confined to parenthesis. It is a tool to write very easily metamodels and editors which I can evolve and extend. If I need it I can insert code I do whatever I want. I guess it is for programmers what Excel can be for other human-beings: a very flexible tool that give you the power to play with your ideas.
What are we going to build?
So, after a few months that I started my consulting activities business is going well. Which is very nice but it also means that I am getting a bit tired of doing all the accounting: writing invoices, tracking expenses. Sure, my business consultant handle the tax part but still I need to ensure I deliver to him all the right documents. In addition to that I think it is healthy to keep an eye on your finances, right?
So I started to build a simple solution, customized for my needs. Something that I could evolve over time as my business evolves and my needs change, leading to changes in the processes I follow.
I started building a template system to generate the invoice using the Google Drive API and the Google Execution Service (presented in this post). After that I needed something to collect the data of my invoices and track the expenses.
Tables, my kingdom for some tables
We are going to use a plugin named mps-tables. Mps-tables has been written by Sascha Lißon and it is used in the mbeddr platform. You can think of the mbeddr platform as a sort of “MPS++”: a collection of nice extensions to simplify your life as language designer.
This is how I would edit my invoices:
- The number of the invoice and date could be automatically filled in (and I could change them if I want)
- The emitter would be me, with the possibility to change it
- I could select the client from the clients I defined in another file
- I would just add lines with a description, an amount and a VAT rate
- The VAT amount and the totals would be calculated
Now, I could want to add later some support to calculate the VAT automatically considering a few rules. In particular, I am a French company and most of my clients are companies outside France so I have not to apply VAT to them. That means that the VAT Rate is 0% in most cases. I have instead to apply a VAT of 20% to French companies and private customers. In practice the VAT rate could be determined looking at the customer.
Ok, how we build this?
All the magic happens in the editor:
We start by adding a cell of type de.slisson.mps.tables.structure.table. Then we insert a vertical element inside the table. In the header part of the vertical element (the one starting with “c<” and terminated by “>”) we just list the titles of the columns: Description, Amount, VAT Rate, VAT, Total. Contained in this vertical element we have the horizontal element. Here in the header, we specify the line-numbers of our invoice. We basically say that:
- We have just to display the line number as the index + 1 (indexes start from 0)
- We can insert new lines
- We can remove new lines until we have just one line left. That one cannot be removed
Time to show the content of each line. Nothing too fancy here: the number of columns is always 5 and we want one line for each line of the invoice (not surprising, eh?). In the first three cells we just put the values for description, amount, and vatRate. The user can edit it freely. The last two columns are instead calculated. They are the VAT amount (amount * vatRate) and the total (amount + VAT amount).
Finally, we show the total. Here all the cells are calculated. Note also the custom cell just before the query element. It is a hack to show an horizontal line as long as the table.
Conclusions and Code
This is just a simple example of using MPS to build a simple application to collect data. This is not the “official” goal of MPS. MPS is intended to build languages and language extensions. However it has:
- the power to define a metamodel very easy,
- the possibility to mix several projections (we have seen text and tables, but there is more),
- the freedom to easily integrate logic wherever I need it
All of these features MPS very convenient to build applications to manipulate data, validate it, and process it for any goal. I think this make MPS somehow usable in place of frameworks like EMF Parsley (however Parsley has the big advantage of producing both desktop and web applications). I want to think more about this. After all it seems that we are just starting to understand the power of MPS.
Code is available on GitHub:
After I published the code I received a PR from the author of mps-tables. He kindly suggested a much cleaner way to obtain the same result.
Basically in the table we can simply says that we are going to iterate on the invoice lines. We just specify how to represent the headers. How to represent the single lines is defined in the editor for the InvoiceLine itself, by using a partial table.
We just specify how to represent the headers. How to represent the single lines is defined in the editor for the InvoiceLine itself, by using a partial table.
I really think that the potentiality of mps-tables and the rest of the extensions available in the mbeddr platform are amazing and yet to be understood by many MPS users. My little goal is try to share some of their potentialities with the rest of the community.