Skip to main content
Engineering LibreTexts

8.4: A Simple Case Study

  • Page ID
    43837
  • \( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \) \( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)\(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\) \(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\)\(\newcommand{\AA}{\unicode[.8,0]{x212B}}\)

    In this example we start with a simple configuration expressed only with versions and then we gradually add baselines. In normal life, it is better to start by definining a baseline followed by the version.

    Let’s start using Metacello to manage a software project called CoolBrowser. The first step is to create a Metacello configuration for the project by simply copying the class MetacelloConfigTemplate and naming it ConfigurationOfCoolBrowser by right clicking in the class name and select copy, or using the +Config of the Monticello browser (see Chapter 7). A configuration is a class that describes the currently available configurations of a project (set of baselines and versions), i.e., what we previously called metadata. A configuration represents different versions of projects so that you can load a project in a different environment or in different versions of Pharo. By convention, the name of a Metacello configuration is constructed by prefixing the name of the project with ConfigurationOf.

    This is the class definition:

    Object subclass: #ConfigurationOfCoolBrowser
        instanceVariableNames: 'project'
        classVariableNames: 'LastVersionLoad'
        poolDictionaries: ''
        category: 'Metacello-MC-Model'
    

    You will notice that ConfigurationOfCoolBrowser has some instance- and class-side methods; we will explain later how they are used. Notice also that this class inherits from Object. It is important that Metacello configurations can be loaded without any prerequisites, including Metacello itself, so Metacello configurations cannot rely on a common superclass.

    Now imagine that the project CoolBrowser has several versions, for example, 1.0, 1.0.1, 1.4, and 1.67. With Metacello, you create configuration methods, instance-side methods that describe the contents of each version of the project. Method names for version methods are unimportant as long as the method is annotated with the <version: > pragma, as shown below. However, there is a convention that version methods are named versionXXX:, where XXX is the version number without illegal characters (like ’.’).

    Suppose for the moment that the project CoolBrowser contains two packages: CoolBrowser-Core and CoolBrowser-Tests (see Figure \(\PageIndex{1}\)). A configuration method (here a version) method might look like the following one.

    Simple version diagram.
    Figure \(\PageIndex{1}\): Simple version.
    ConfigurationOfCoolBrowser>>version01: spec
        <version: '0.1'>
    
        spec for: #common do: [
        spec blessing: #release.
            spec repository: 'http://www.example.com/CoolBrowser'.
            spec
                package: 'CoolBrowser-Core' with: 'CoolBrowser-Core-BobJones.10';
                package: 'CoolBrowser-Tests' with: 'CoolBrowser-Tests-JohnLewis.3' ]
    

    The method version01: spec builds a description of version 0.1 of the project in the object spec. The common code for version 0.1 (specified using the message for:do:) consists of particular versions of the packages named CoolBrowser-Core and CoolBrowser-Tests. These are specified with the message package: packageName with: versionName. These versions are available in the Monticello repository http://www.example.com/CoolBrowser, which is specified using the message repository:. The blessing: method is used to denote that this is a released version and that the specification will not be changed in the future. The blessing #development should be used when the version has not stabilized.

    Now let us look at more details.

    • Immediately after the method selector you see the pragma definition: <version: '0.1'>. The pragma version: indicates that the version created in this method should be associated with version 0.1 of the CoolBrowser project. That is why we said that the name of the method is not that important. Metacello uses the pragma, not the method name, to identify the version being defined.
    • The argument of the method, spec, is the only variable in the method and it is used as the receiver of four different messages: for:do:, blessing:, package:with:, and repository:.
    • Each time a block is passed as argument of the messages (for:do:, package:with:...) a new object is pushed on a stack and the messages within the block are sent to the object on the top of the stack.
    • The symbol #common indicates that this project version is common to all platforms. In addition to #common, there are pre-defined attributes for each of the platforms on which Metacello runs (#pharo, #squeak, #gemstone, #squeakCommon, #pharo, #pharo1.3.x, etc.). In Pharo, the method metacelloPlatformAttributes defines the attribute values that you can use.

    About passwords. Sometimes, a Monticello repository requires a username and password. In this case, you can use the message repository:username:password: instead of repository:.

    spec repository: 'http://www.example.com/private' username: 'foo' password: 'bar'
    

    Specification objects. A spec object is an object representing all the information about a given version. A version is just a number while the specification is the object. You can access the specification using the spec message, though normally this is not needed.

    (ConfigurationOfCoolBrowser project version: '0.1') spec
    

    This answers an object (instance of class MetacelloMCVersionSpec) that contains exactly the information of the method that defines version ’0.1’.

    Creating a new version. Let us assume that version 0.2 of our project consists of the package versions CoolBrowser-Core-BobJones.15 and CoolBrowser-Tests-JohnLewis.8 and a new package CoolBrowser-Addons with version CoolBrowser-Addons-JohnLewis.3. We specify this new configuration by creating the following method named version02:.

    ConfigurationOfCoolBrowser>>version02: spec
        <version: '0.2'>
    
        spec for: #common do: [
            spec repository: 'http://www.example.com/CoolBrowser'.
            spec
                package: 'CoolBrowser-Core' with: 'CoolBrowser-Core-BobJones.15';
                package: 'CoolBrowser-Tests' with: 'CoolBrowser-Tests-JohnLewis.8';
                package: 'CoolBrowser-Addons' with: 'CoolBrowser-Addons-JohnLewis.3']
    
    A diagram of two versions of a project.
    Figure \(\PageIndex{2}\): Two versions of a project.

    How to manage multiple repositories. You can also add multiple repositories to a spec. You just have to specify multiple times repository: expression.

    ConfigurationOfCoolBrowser>>version02: spec
        ...
        
        spec for: #common do: [
            spec repository: 'http://www.example.com/CoolBrowser'.
            spec repository: 'http://www.anotherexample.com/CoolBrowser'.
            ...
            ] 
    

    You can also use the message repositoryOverrides:

    self whateverVersion repositoryOverrides: (self whateverRepo); load
    

    Note that these messages do not recursively propagate to dependent configurations.

    Naming your Configuration. Previously, we learned the convention to name configuration classes. In our example, ConfigurationOfCoolBrowser. There is also a convention to create a Monticello package with the same name as the configuration class, and to put the class in that package. In this example you will create a package ConfigurationOfCoolBrowser containing exactly one class, ConfigurationOfCoolBrowser.

    By making the package name and the configuration class name the same, and by starting them with the string ConfigurationOf, we make it easy to scan through a repository listing the available projects. It is also very convenient to have the configurations stored in their own Monticello repository.


    This page titled 8.4: A Simple Case Study is shared under a CC BY-SA 3.0 license and was authored, remixed, and/or curated by Alexandre Bergel, Damien Cassou, Stéphane Ducasse, Jannik Laval (Square Bracket Associates) via source content that was edited to the style and standards of the LibreTexts platform; a detailed edit history is available upon request.