Metacello-Tutorial

MetacelloProjectRefTutorialConfig
A MetacelloProjectRefTutorialConfig is xxxxxxxxx.
Instance Variables
project: <Object>
project
- xxxxx
baseline07:
baseline10:
baseline11:
baseline12:
baseline14:
bootstrapPackage:from:
ensureMetacello
isMetacelloConfig
lesson07
[ see method: #baseline07: #version07: ]
NOTE: you should run through the lessons in MetacellTutorialConfig first.
In this configuration we are defining a project that utilizes the packages from the
Example project (MetacelloTutorialConfig): 'Example-Core', 'Example-AddOn',
'Example-Tests' and 2 packages specific to the project: 'Project-Core' and
'Project-Tests':
(MetacelloProjectRefTutorialConfig project version: '0.7') load.
lesson10
[ see method: #baseline10: #version10: ]
In lesson07 it was obvious that we copied the configuration information from
MetacelloTutorialConfig and adapted it to our project.
There is a better way.
In #baseline10: we've created a project reference for the Example project.
The #className: specifies the name of the class that contains the project metadata. If
the class is not present in the image, then we know that we need to load the
configuration for the project.
The #file: and #repository: specifications give us the information needed to load the
project metadata from a repository.
Finally, the #versionString: and #loads: tell us which version of the project to load
and which packages to load from the project.
We've named the project reference 'Example ALL' and in the specification for the
'Project-Core' package, we've specified that 'Example ALL' is required:
(MetacelloProjectRefTutorialConfig project version: '1.0') load.
Note that the entire Example project is loaded before 'Project-Core'
lesson11
[ see method: #baseline11: #version11: ]
As is often the case, it is useful to separate the test package from the core packages
for a project.
In #baseline11: we've created two project references. The reference named
'Example Default' loads the 'default' group and the reference named 'Example Tests'
loads the 'Tests' group.
We then made 'Project-Core' require 'Example Default' and 'Project-Tests' requires
'Project-Core' and 'Example Tests'.
Now it is possible to load just the core packages:
(MetacelloProjectRefTutorialConfig project version: '1.1') load: 'Project-Core'.
or the whole enchilada including tests:
(MetacelloProjectRefTutorialConfig project version: '1.1') load: 'Project-Tests'.
lesson12
[ see method: #baseline11: #baseline12: #version12: ]
In #baseline11: there is redundant information for each of the project references.
In #baseline12: we use the #project:copyFrom:with: method to eliminate the need to
specify the bulk of the project information twice.
Evaluate and compare the results of the following expressions:

(MetacelloProjectRefTutorialConfig project version: '1.1') load: 'Project-Core'.
(MetacelloProjectRefTutorialConfig project version: '1.2') load: 'Project-Core'.
(MetacelloProjectRefTutorialConfig project version: '1.1') load: 'Project-Tests'.
(MetacelloProjectRefTutorialConfig project version: '1.2') load: 'Project-Tests'.
lesson13
[ see method: #version13: ]
In #version13: we are importing the '1.2-baseline', but changing the Example project
version to 1.3, so project versions can be updated in the verson method jus like
package versions.
Evaluate and compare the results of these expressions:
(MetacelloProjectRefTutorialConfig project version: '1.2') load: 'Project-Core'.
(MetacelloProjectRefTutorialConfig project version: '1.3') load: 'Project-Core'.
(MetacelloProjectRefTutorialConfig project version: '1.2') load: 'Project-Tests'.
(MetacelloProjectRefTutorialConfig project version: '1.3') load: 'Project-Tests'.
It is worth noting that in version 1.3 of the Example project, the platform-specific
'Example-Platform' was introduced and nothing special had to be done in the project
reference to get the package included.
lesson14
[ see method: #baseline14: #version14: ]
In this lesson we'll cover the querying API for Metacello. The querying API is useful for analyzing the contents and structure of a version.
To start with we'll look at version '1.4' of the MetacelloProjectRefTutorialConfig. You can list the packages in the version:
(MetacelloProjectRefTutorialConfig project version: '1.4') packages
The list project references:
(MetacelloProjectRefTutorialConfig project version: '1.4') projects
And the groups:
(MetacelloProjectRefTutorialConfig project version: '1.4') groups
You can access individual packages/project refs/groups using the #packageNamed: method. Here you can access the package named: 'Project-Core':
(MetacelloProjectRefTutorialConfig project version: '1.4') packageNamed: 'Project-Core'
The project reference named 'Example Default':
(MetacelloProjectRefTutorialConfig project version: '1.4') packageNamed: 'Example Default'
The group named 'Core':
(MetacelloProjectRefTutorialConfig project version: '1.4') packageNamed: 'Core'
Each of the attributes of the package can be accessed (#requires, #includes, #file, #repository, #preLoadDoIt, and #postLoadDoit). For example:
((MetacelloProjectRefTutorialConfig project version: '1.4') packageNamed: 'Project-Core') requires
Each of the attributes of the project can be accessed (#className, #versionString, #operator, #loads, #file, and #repository). For example:
((MetacelloProjectRefTutorialConfig project version: '1.4') packageNamed: 'Example Default') repository
Each of the attributes of the group can be accessed (#includes). For example:
((MetacelloProjectRefTutorialConfig project version: '1.4') packageNamed: 'default') includes
When looking at the 'Core' group, there is only one package listed:
(MetacelloProjectRefTutorialConfig project version: '1.4') packageNamed: 'Core'
In the case of the 'Core' group, it is defined in terms of the 'default', which isn't very useful. When looking at the contents of groups you'd like to see the complete list of packages, without having to explicitly expanding each group you encounter. #packagesForSpecNamed: does just that:
(MetacelloProjectRefTutorialConfig project version: '1.4') packagesForSpecNamed: 'Core'
If you were to load the 'Core' package:
(MetacelloProjectRefTutorialConfig project version: '1.4') load: 'Core'
You end up seeing the packages from the Example project. If you want to get the list of packages that _would_ be loaded, you can use #allPackagesForSpecNamed:. For example:
(MetacelloProjectRefTutorialConfig project version: '1.4') allPackagesForSpecNamed: 'Core'
If you use #allPackagesForSpecNamed: with a project refernce name, you'll see the packages that _would_ be loaded:
(MetacelloProjectRefTutorialConfig project version: '1.4') load: 'Example Default'
(MetacelloProjectRefTutorialConfig project version: '1.4') allPackagesForSpecNamed: 'Example Default'
You can also send #version to a project reference. This is useful if you want to explicitly walk the tree of projects:
((MetacelloProjectRefTutorialConfig project version: '1.4') packageNamed: 'Example Default') version
project
NOTE: The MetacelloNullRecordingMCSpecLoader is being used to prevent packages
from being loaded, see MetacelloConfigTemplate>>project for an example #project
method that loads the package for real
version07:
version10:
version11:
version12:
version13:
version14:
MetacelloTutorialConfig
A MetacelloTutorialConfig is xxxxxxxxx.
Instance Variables
project: <Object>
project
- xxxxx
baseline07:
baseline10:
baseline13:
bootstrapPackage:from:
ensureMetacello
isMetacelloConfig
lesson01
[ see metod: #version01: ]
Version 0.1 represents the simplest version specification possible.
In the method #version01, version 0.1 is defined with a single package 'Example-Core-anon.8'
that is loaded from the repository 'http://www.example.com/Example'.
Looking at this method you will notice a couple of things.
Immediately after the method selector you see the pragma definition:
<version: '0.1'>
The pragma indicates that the version created in this method should be associated with version
'0.1' of the Tutorial project.
Looking a little closer you see that the argument to the method, <spec>, is the only variable in
the method and it is used as the receiver to four different messages:
- #for:do:
- #package:with:
- #file:
- #repository:
With the evaluation of each block expression, 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.
So the method should be read as:
Create version '0.1'. The #common code for version '0.1' (#for:do:) consists of a package named
'Example-Core' (#package:with:) whose file attribute is 'Example-Core-anon.8' (#file:) and whose
repository attribute is 'http://www.example.com/Example' (#repository:).
We can see the spec created for version 0.1 by printing the following expression:
(MetacelloTutorialConfig project version: '0.1') spec
Note that in creating version '0.1' the #common attribute is extracted out.
In addition to #common, there are pre-defined attributes for each of the platforms upon which
Metacello runs (#pharo, #squeak, #gemstone and #squeakCommon).
#squeakCommon is used for both #pharo and #squeak.
lesson02
[ see method: #version02: ]
For version 0.2, we've simply updated the package version to 'Example-Core-anon.9', which
can be confirmed by printing the following expression:
(MetacelloTutorialConfig project version: '0.2') spec
lesson03
[ see method: #version03: ]
For version 0.3, we've updated the package version to 'Example-Core-anon.10' and added an additional
package 'Example-Tests-anon.3', which can be confirmed by printing the following expression:
(MetacelloTutorialConfig project version: '0.3') spec
As is often the case, the two packages share the same repository, so specifying a repository with
each package is redundant.
lesson04
[ see method: #version04: ]
The specification for version 0.4 is basically the same as version 0.3. Instead of listing a
repository with each package we specify a project repository that applies to all packages.
Compare the printStrings for the specs for each version:
(MetacelloTutorialConfig project version: '0.3') spec
(MetacelloTutorialConfig project version: '0.4') spec
lesson05
[ see method: #version05: ]
For version 0.5 we've added an additional package to the mix: 'Example-AddOn':
(MetacelloTutorialConfig project version: '0.5') spec
Of course, the point of specifiying packages in Metacello is to be able to load versions. Here are
a couple examples of loading versions of the Tutorial. If you print the result of each expression,
you will see the list of packages in load order (note that for the tutorial, we are using the
MetacelloNullRecordingMCSpecLoader. This class records which packages are loaded and the order that they are loaded in among other things instead of actually loading the packages.
(MetacelloTutorialConfig project version: '0.1') load.
(MetacelloTutorialConfig project version: '0.4') load.
(MetacelloTutorialConfig project version: '0.5') load.
You will note that in each case, all of the packages associated with the version are loaded, which
is the default.
If you want to load a subset of the packages in a project, you may list the packages that you
are interested in as an argument to the #load: method:
(MetacelloTutorialConfig project version: '0.5') load: { 'Example-Tests'. 'Example-Core' }.
Note that the ordering of the packages is based on the order in which the packages are specified.
If you evaluate the following expression:
(MetacelloTutorialConfig project version: '0.5') load: { 'Example-Tests'. }.
Only the package is 'Example-Tests'. By default the packages are ordered, but there are no implicit
dependencies.
lesson06
[ see method: #version06: ]
In version 0.6 we've added dependency information in the form of the #requires: directive.
Both 'Example-Tests' and 'Example-AddOn' require 'Example-Core' to be loaded before they are
loaded. Print the following expressions to see that the requires directives are being followed:
(MetacelloTutorialConfig project version: '0.5') load: { 'Example-Tests'. }.
(MetacelloTutorialConfig project version: '0.6') load: { 'Example-Tests'. }.
(MetacelloTutorialConfig project version: '0.6') load: 'Example-AddOn'.
(MetacelloTutorialConfig project version: '0.6') load: { 'Example-AddOn'. 'Example-Tests'. }.
With version 0.6 we are mixing structural information (required packages and repository) with the
dynamic file version info. It is expected that over time the file version info will change from
version to version while the structural information will remain relatively static.
lesson07
[ see method: #baseline07: and #version07: ]
For version 0.7, we are ceating a baseline version specification which is expected to be used
across several versions and the version specification which is restricted to the file versions.
In method #baseline07: the structure of version '0.7-baseline' is specified. The repository is
listed, the packages are listed and the required packages are defined. We'll cover the #blessing:
in a later lesson.
In method #version07: the file versions are specified. You will note that the pragma as an #imports: component that specifies the list of versions that this version (version '0.7') is based upon. In
fact, if you print the spec for '0.7-baseline' and then print the spec for '0.7' you can see that
'0.7' is a composition of both versions:
(MetacelloTutorialConfig project version: '0.7-baseline') spec.
(MetacelloTutorialConfig project version: '0.7') spec.
Of course if you print the '0.6' spec and the '0.7' spec you can see that they specify exactly the
same information in a slightly different way:
(MetacelloTutorialConfig project version: '0.6') spec.
(MetacelloTutorialConfig project version: '0.7') spec.
and if you load each of the versions, you will see that they load the same packages, in the same
order:
(MetacelloTutorialConfig project version: '0.6') load.
(MetacelloTutorialConfig project version: '0.7') load.
Finally, even though version '0.7-baseline' does not have explicit package versions, you may load
the version. When the 'real' loader encounters a package name (without version information) it will
attempt to load the latest version of the package from the repository. With the
MetacelloNullRecordingMCSpecLoader the packages names are 'loaded':
(MetacelloTutorialConfig project version: '0.7-baseline') load.
Of course when a number of developers are working on a project it may be useful to load a
#baseline version so that you get the latest work from all of the project members.
lesson08
[ see method: #version08: ]
In version 0.8 we've simply updated the package versions, which can be seen by comparing the
results of loading version 0.7 and 0.8:
(MetacelloTutorialConfig project version: '0.7') load.
(MetacelloTutorialConfig project version: '0.8') load.
lesson10
[ see method: #baseline10: #version10: ]
In #baseline10: we've added two things: the 'Example-AddOnTests' package and a specification for
groups.
The 'Example-AddOnTests' package has been added to make the idea of needing to group packages a
little more appealing. The package requires 'Example-AddOn' and 'Example-Tests'.
With two Test packages it would be convenient to be able to load all of the tests with a simple
expression like the following:
(MetacelloTutorialConfig project version: '1.0') load: { 'Tests'. }.
instead of having to explicitly list all of the test projects like this:
(MetacelloTutorialConfig project version: '1.0')
load: { 'Example-Tests'. 'Example-AddOnTests'. }.
This becomes especially useful if over time the project evolves to have more component and test
packages.
The 'default' group is special in that when a 'default' group is defined, the #load method loads
the members of the 'default' group instead of loading all of the packages:
(MetacelloTutorialConfig project version: '1.0') load.
If you want to load all of the packages in a project, then the pseudo group 'ALL' may be used as
follows:
(MetacelloTutorialConfig project version: '1.0') load: 'ALL'.
lesson11
[ see method: #version11: ]
In version 0.11 we've defined a couple of attributes that are expected to be used all of the time
in a version specification:
#blessing:
#description:
#author:
#timestamp:
The following lessons cover each of these attributes in more detail.
lesson11Author
[ see method: #version11: ]
The author of a version can be defined:
(MetacelloTutorialConfig project version: '1.1') author.
When using the OB-Metacello tools the author field is automatically updated to reflect the current
author as defined in the image.
lesson11Blessing
[ see method: #version11: ]
A version can be tagged with a blessing like #alpha, #beta, #release, #development or any
other tag that you find useful. The blessing for version 1.1 is #development
(MetacelloTutorialConfig project version: '1.1') blessing.
The default blessing is #release, so even though we didn't specify a blessing for version
0.5, the blessing is set:
(MetacelloTutorialConfig project version: '0.5') blessing.

For version 1.1, it is important to explicitly set the blessing, because it imports version
'1.0-baseline' whose blessing is #baseline:
(MetacelloTutorialConfig project version: '1.0-baseline') blessing.
Blessings can be used as a filter. For example, you will notice that the result of the
following expression is version 0.6, because #latestVersion answers the latest version whose
blessing is _not_ #development, #broken, or #blessing:
MetacelloTutorialConfig project latestVersion.
MetacelloTutorialConfig project latestVersion load.
The blessing of version 1.1 is #development. To find the latest #development version you
would execute this expression:
MetacelloTutorialConfig project latestVersion: #development.
(MetacelloTutorialConfig project latestVersion: #development) load.
You can get the very last version independent of blessing by executing this expression:
MetacelloTutorialConfig project lastVersion.
MetacelloTutorialConfig project lastVersion load.

In general, the #development blessing should be used for any version that is unstable. Once a
version has stabilized, a different blessing should be applied.
The following expression will load the latest version of all of the packages for the latest
#baseline version:
(MetacelloTutorialConfig project latestVersion: #baseline) load.
Since the latest #baseline version should reflect the most up-to-date project structure, executing
the previous expression should load the absolute bleeding edge of the project.
lesson11Descripton
[ see method: #version11: ]
A description can be defined for a version:
(MetacelloTutorialConfig project version: '1.1') description.
lesson11Timestamp
[ see method: #version11: ]
The timestamp of a version can be defined:
(MetacelloTutorialConfig project version: '1.1') timestamp.
When using the OB-Metacello tools the timestamp field is automatically updated to reflect the current
DateAndTime that the update was made.
The timestamp is a String
lesson12DoIts
[ see methods: #version12: #preloadForCore #postloadForCore:package: ]
Occassionally, you find that you need to perform an expression either before a package is loaded, or
after a package is loaded. To do that in Metacello, you can define a preLoadDoIt selector and a
postLoadDoIt selector:
(MetacelloTutorialConfig project version: '1.2') spec.
If you open a Transcript and execute the following expression, you will see that the pre load and
post load methods were executed:
(MetacelloTutorialConfig project version: '1.2') load.
The pre/post load methods may take 0, 1 or 2 args. The loader is the first optional argument and the
loaded packageSpec is the second optional argument.
lesson13
[ see methods: #baseline13: #version13: ]
For version 1.3 we are adding a platform specific package 'Example-Platform'. 'Example-Platform'
requires 'Example-Core'. On GemStone, Pharo and Squeak, a branch of the 'Example-Platform' package
will be loaded: 'Example-Platform.gemstone', 'Example-Platform.pharo', 'Example-Platform.squeak'
respectively will be loaded.
Consequently we've updated the baselines with #baseline13: to reflect the structural changes and
#version13: reflects the package versions.
The platform-specific versions and branches are defined in the #for:do: block for the corresponding
platforms: #gemstone, #pharo, #squeak (in both methods)
The result of the following expression will depend on the platform upon which you are running:
(MetacelloTutorialConfig project version: '1.3') load.
Note that when you execute the following expresson to load 'Example-Core' that the correct
'Example-Platform' is loaded as well:
(MetacelloTutorialConfig project version: '1.3') load: 'Example-Core'.
If you look at the specification for 'Example-Core' (in #baseline13:) you will note that
'Example-Core' #includes: 'Example-Platform'. The #includes: directive means that the package
'Example-Platform' should be loaded whenever the 'Example-Core' package is loaded.
Also note when you evaluate the following expression that the 'Example-Platform' package is loaded
before 'Example-Tests' as if 'Example-Tests' #requires: 'Example-Platform':
(MetacelloTutorialConfig project version: '1.3') load: 'Example-Tests'.
When you use the #includes: directive, you are not only specifying that the listed packages should
be loaded when the parent package is loaded, but that the #included: packages should be loaded
_before_ any packages that require the parent package.
lesson14
STILL UNDER CONSTRUCTION: Open your browsers on the class MetacelloProjectRefTutorial to continue the tutorial.
postloadForCore:package:
preloadForCore
project
NOTE: The MetacelloNullRecordingMCSpecLoader is being used to prevent packages
from being loaded, see MetacelloConfigTemplate>>project for an example #project
method that loads the package for real
version01:
version02:
version03:
version04:
version05:
version06:
version07:
version08:
version10:
version11:
version12:
version13: