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}}\)
\( \newcommand{\vectorA}[1]{\vec{#1}} % arrow\)
\( \newcommand{\vectorAt}[1]{\vec{\text{#1}}} % arrow\)
\( \newcommand{\vectorB}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vectorC}[1]{\textbf{#1}} \)
\( \newcommand{\vectorD}[1]{\overrightarrow{#1}} \)
\( \newcommand{\vectorDt}[1]{\overrightarrow{\text{#1}}} \)
\( \newcommand{\vectE}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash{\mathbf {#1}}}} \)
\( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)
\(\newcommand{\avec}{\mathbf a}\) \(\newcommand{\bvec}{\mathbf b}\) \(\newcommand{\cvec}{\mathbf c}\) \(\newcommand{\dvec}{\mathbf d}\) \(\newcommand{\dtil}{\widetilde{\mathbf d}}\) \(\newcommand{\evec}{\mathbf e}\) \(\newcommand{\fvec}{\mathbf f}\) \(\newcommand{\nvec}{\mathbf n}\) \(\newcommand{\pvec}{\mathbf p}\) \(\newcommand{\qvec}{\mathbf q}\) \(\newcommand{\svec}{\mathbf s}\) \(\newcommand{\tvec}{\mathbf t}\) \(\newcommand{\uvec}{\mathbf u}\) \(\newcommand{\vvec}{\mathbf v}\) \(\newcommand{\wvec}{\mathbf w}\) \(\newcommand{\xvec}{\mathbf x}\) \(\newcommand{\yvec}{\mathbf y}\) \(\newcommand{\zvec}{\mathbf z}\) \(\newcommand{\rvec}{\mathbf r}\) \(\newcommand{\mvec}{\mathbf m}\) \(\newcommand{\zerovec}{\mathbf 0}\) \(\newcommand{\onevec}{\mathbf 1}\) \(\newcommand{\real}{\mathbb R}\) \(\newcommand{\twovec}[2]{\left[\begin{array}{r}#1 \\ #2 \end{array}\right]}\) \(\newcommand{\ctwovec}[2]{\left[\begin{array}{c}#1 \\ #2 \end{array}\right]}\) \(\newcommand{\threevec}[3]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \end{array}\right]}\) \(\newcommand{\cthreevec}[3]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \end{array}\right]}\) \(\newcommand{\fourvec}[4]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \\ #4 \end{array}\right]}\) \(\newcommand{\cfourvec}[4]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \\ #4 \end{array}\right]}\) \(\newcommand{\fivevec}[5]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \\ #4 \\ #5 \\ \end{array}\right]}\) \(\newcommand{\cfivevec}[5]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \\ #4 \\ #5 \\ \end{array}\right]}\) \(\newcommand{\mattwo}[4]{\left[\begin{array}{rr}#1 \amp #2 \\ #3 \amp #4 \\ \end{array}\right]}\) \(\newcommand{\laspan}[1]{\text{Span}\{#1\}}\) \(\newcommand{\bcal}{\cal B}\) \(\newcommand{\ccal}{\cal C}\) \(\newcommand{\scal}{\cal S}\) \(\newcommand{\wcal}{\cal W}\) \(\newcommand{\ecal}{\cal E}\) \(\newcommand{\coords}[2]{\left\{#1\right\}_{#2}}\) \(\newcommand{\gray}[1]{\color{gray}{#1}}\) \(\newcommand{\lgray}[1]{\color{lightgray}{#1}}\) \(\newcommand{\rank}{\operatorname{rank}}\) \(\newcommand{\row}{\text{Row}}\) \(\newcommand{\col}{\text{Col}}\) \(\renewcommand{\row}{\text{Row}}\) \(\newcommand{\nul}{\text{Nul}}\) \(\newcommand{\var}{\text{Var}}\) \(\newcommand{\corr}{\text{corr}}\) \(\newcommand{\len}[1]{\left|#1\right|}\) \(\newcommand{\bbar}{\overline{\bvec}}\) \(\newcommand{\bhat}{\widehat{\bvec}}\) \(\newcommand{\bperp}{\bvec^\perp}\) \(\newcommand{\xhat}{\widehat{\xvec}}\) \(\newcommand{\vhat}{\widehat{\vvec}}\) \(\newcommand{\uhat}{\widehat{\uvec}}\) \(\newcommand{\what}{\widehat{\wvec}}\) \(\newcommand{\Sighat}{\widehat{\Sigma}}\) \(\newcommand{\lt}{<}\) \(\newcommand{\gt}{>}\) \(\newcommand{\amp}{&}\) \(\definecolor{fillinmathshade}{gray}{0.9}\)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.

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 pragmaversion:
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:
, andrepository:
. - 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 methodmetacelloPlatformAttributes
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']

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.