Warmup: understanding the Money classes

TL;DR

In this exercise we explore the various Money classes, and see how examples are used to cover the features of these classes. We will need these classes next to model Prices.

Building on the Money classes

To simplify the Price modeling exercise somewhat, we assume that we already have classes to model money in different currencies.

An amount of money can be created by sending a currency type to a number, for example:

42 euros.
  

#euros is just a factory method that constructs an instance of GtTCurrencyMoney GtTMoney subclass: #GtTCurrencyMoney instanceVariableNames: 'amount currency' classVariableNames: '' package: 'GToolkit-Tutorial-Prices-Model' with euros as the currency, like this:

GtTCurrencyMoney new
	amount: 42;
	currency: GtTCurrency euros.
  

Task: Have a closer look at the method Number>>#euros euros ^ GtTCurrencyMoney new amount: self; currency: GtTCurrency euros . See that its category is “*GToolkit-Tutorial-Prices”.

NB: The “category” of a method can be found in the first of two buttons at the bottom right of the method Coder window. The other button distinguishes instance methods from class methods.

Categories starting with * are extension methods that are defined in a different package from the class. In this case the package GToolkit-Tutorial-Prices extends the Number Magnitude subclass: #Number instanceVariableNames: '' classVariableNames: '' package: 'Kernel-Numbers' class with the euros method, without touching its original Kernel package.

Using examples to test and explore

This particular example is also an example method : GtTMoneyExamples>>#fortyTwoEuros fortyTwoEuros <gtExample> | money | money := 42 euros. self assert: money isZero not. self assert: money equals: 42 euros. ^ money

An example is any unary method that has the <gtExample> pragma, and returns an object. Examples also serve as tests, as we can see with the assertions above. Finally, we can inspect and explore examples.

Task: Inspect the fortyTwoEuros example by clicking on the Play and Inspect Example button. (Black triangle + i.)

See that the result has a dedicated Details view. See how the view is implemented by ALT-clicking on the Details label. Don't worry too much about the details of the implementation for now, but note that it is just a few lines of code.

Open a contextual playground at the bottom of the inspector on the fortyTwoEuros instance (pull up the handle with the two grey bars) and evaluate (inspect) self isZero. Click on the grey triangle next to isZero to open the code bubble and see how it is implemented.

Note that this example is an instance of a GtTCurrencyMoney GtTMoney subclass: #GtTCurrencyMoney instanceVariableNames: 'amount currency' classVariableNames: '' package: 'GToolkit-Tutorial-Prices-Model' , but the example is defined in the classs GtTMoneyExamples Object subclass: #GtTMoneyExamples instanceVariableNames: '' classVariableNames: '' package: 'GToolkit-Tutorial-Prices-Examples' . It is common practice to defined examples in a separate class from the class that they exemplify, just like unit tests for a class X will be defined in a separate class TestX. In this case there is a hierarchy of Money classes with GtTMoney Object subclass: #GtTMoney instanceVariableNames: '' classVariableNames: '' package: 'GToolkit-Tutorial-Prices-Model' at the root, and we put all the examples in GtTMoneyExamples Object subclass: #GtTMoneyExamples instanceVariableNames: '' classVariableNames: '' package: 'GToolkit-Tutorial-Prices-Examples' .

The Money hierarchy

A GtTCurrency Object subclass: #GtTCurrency instanceVariableNames: 'name' classVariableNames: 'Currencies' package: 'GToolkit-Tutorial-Prices-Model' represents a specific sum of money in a given currency. Its superclass is GtTMoney Object subclass: #GtTMoney instanceVariableNames: '' classVariableNames: '' package: 'GToolkit-Tutorial-Prices-Model' , which is the abstract root of the Money hierarchy.

NB: The UML diagram below is live. Click on the classes to browse them.

A GtTMoneyBag GtTMoney subclass: #GtTMoneyBag instanceVariableNames: 'monies' classVariableNames: '' package: 'GToolkit-Tutorial-Prices-Model' represents a bag of money in multiple currencies, for example:

bagWithEurosAndDollars
	<gtExample>
	| bag |
	bag := self fortyTwoEuros + self fortyTwoDollars.
	self assert: (bag isKindOf: GtTMoneyBag).
	self assert: bag monies size equals: 2.
	^ bag
    

Task: Inspect the example above and evaluate self - 42 usd. What is the class of the result? Is it GtTCurrencyMoney GtTMoney subclass: #GtTCurrencyMoney instanceVariableNames: 'amount currency' classVariableNames: '' package: 'GToolkit-Tutorial-Prices-Model' or GtTMoneyBag GtTMoney subclass: #GtTMoneyBag instanceVariableNames: 'monies' classVariableNames: '' package: 'GToolkit-Tutorial-Prices-Model' ? Can you explain the result? In which method is the class of the result determined?

Task: Explore GtTMoneyExamples Object subclass: #GtTMoneyExamples instanceVariableNames: '' classVariableNames: '' package: 'GToolkit-Tutorial-Prices-Examples' . Can you find an example that tests this scenario in which we remove the euros from a money bag with euros and dollars?

Task: Are there examples for GtTZeroMoney GtTMoney subclass: #GtTZeroMoney instanceVariableNames: '' classVariableNames: '' package: 'GToolkit-Tutorial-Prices-Model' ? What is it used for?

Hint: Browse the GtTZeroMoney GtTMoney subclass: #GtTZeroMoney instanceVariableNames: '' classVariableNames: '' package: 'GToolkit-Tutorial-Prices-Model' class and explore the References tab. Then look for Senders to see where these methods are used.