Coasters collection

Or how to create a minimal model in Moose 8

Posted by Benoit Verhaeghe on February 15, 2021 · 7 mins read

Updated: March 04, 2021

Introduction

I’m a coasters collector. I’m not a huge collector but I want to inventory them in one place. For sure, I can create a PostgreSQL database. But, at the same time, it appears that I can also design my collection using Moose.

So, you’re going to use a complete system analysis software to manage your coasters collection?

Exactly! And why? Because I think it’s simpler.

Design

As for every software system, the first step is to design the model. In my case, I want to represent a collection of coasters. Let’s say a coaster is an entity. It can belong to a brewery or not (for example event coasters). A coaster also has a form. It can be round, squared, oval, or others. A Coaster can also be specific to a country. Because it is a collection, I can register coaster I own and other I do not. Finally, each coaster can have an associated image.

From this description of the problem, I designed my UML schema:

"coasters UML"

The most complicated part is done. We just need to implement the meta-model in Moose now :smile:.

Implementation

First of all, we’ll need a Moose 8 image. You can find everything you need to install Moose in the moose-wiki.

Configuration

Ok! Let’s create a generator that will generate for us the meta-model. We only need to describe the meta-model in the generator. We will name this generator CoasterCollectorMetamodelGenerator.

FamixMetamodelGenerator subclass: #CoasterCollectorMetamodelGenerator
    slots: {  }
    classVariables: {  }
    package: 'CoasterCollector-Model-Generator'

The generator needs to define two methods class side for the configuration:

  • #packageName defines where the meta-model will be generated
  • #prefix defines the prefix of each class when they are generated.

We used for #packageName:

CoasterCollectorMetamodelGenerator class >>#packageName
    ^ #'CoasterCollector-Model'

We used for #prefix:

CoasterCollectorMetamodelGenerator class >>#prefix
    ^ #'CC'

Now, we have to define the entities, their properties, and their relations.

Define entities

A meta-model is composed of entities. In our case, it corresponds to the entities identified in the UML. We use the method #defineClasses to define the entities of our meta-model.

CoasterCollectorMetamodelGenerator>>#defineClasses
    super defineClasses.
    coaster := builder newClassNamed: #Coaster.

    country := builder newClassNamed: #Country.

    shape := builder newClassNamed: #Shape.
    round := builder newClassNamed: #Round.
    square := builder newClassNamed: #Square.
    oval := builder newClassNamed: #Oval.

    creator := builder newClassNamed: #Creator.
    brewery := builder newClassNamed: #Brewery

We also need to define the hierarchy of those entities:

CoasterCollectorMetamodelGenerator>>#defineHierarchy
    super defineHierarchy.
    brewery --|> creator.
    oval --|> shape.
    square --|> shape.
    round --|> shape

Define properties

As we have defined the classes, we defined the properties of the entities using the #defineProperties method.

defineProperties
    super defineProperties.
    creator property: #name type: #String.
    country property: #name type: #String.
    coaster property: #image type: #String.
    coaster property: #owned type: #Boolean

In this example, we did not use Trait already created in Moose. However, it is possible to use the Trait TNamedEntity to define that countries and creators have a name instead of using properties.

Define relations

Finally, we defined the relations between our entities:

defineRelations
    super defineRelations.
    (coaster property: #shape) *- (shape property: #coasters).
    (coaster property: #country) *- (country property: #coasters).
    (coaster property: #creator) *- (creator property: #coasters)

Generate

Once everything is defined, we only need to use the generator to build our meta-model.

CoasterCollectorMetamodelGenerator generate

The generation creates a new package with our entities. It also generates a class named Model used to create an instance of our meta-model.

Create my collection

I have created my meta-model. Now I need to fill my collection. First of all, I will create a collection of coasters. To do so, I instantiate a model with: model := CCModel new. And now I can add the entities of my real collection in my model and I can explore it in Moose.

For example, to add a new brewery I execute: model add: (CCBrewery new name: 'Badetitou'; yourself).

The code is available on github.

Save the collection

Once I have created the collection, I can save it using the Moose export format (currently JSON and mse). To do so, I execute the following snippet:

'/my/collection/model.json' asFileReference ensureCreateFile
    writeStreamDo: [ :stream | model exportToJSONStream: stream ]

Then I can select where I want to export my model.

To import it back into an image, I use the following code

'/my/collection/model.json' asFileReference
    readStreamDo: [ :stream | model := CCModel importFromJSONStream: stream ]