Skip to content

Commit 760ecad

Browse files
committed
full pass
1 parent 4a0e0fa commit 760ecad

File tree

10 files changed

+2791
-296
lines changed

10 files changed

+2791
-296
lines changed

Chapters/Counter/Counter.md

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,8 @@ Creating a class requires four steps. They consist basically in editing the clas
6262
You should get the following class definition.
6363

6464
```
65-
Object subclass: #Counter
66-
instanceVariableNames: 'count'
67-
classVariableNames: ''
65+
Object << #Counter
66+
slots: { #count };
6867
package: 'MyCounter'
6968
```
7069

@@ -157,17 +156,15 @@ Writing tests is an important activity that will support the evolution of your a
157156
To define a test case we will define a class that inherits from `TestCase`. Therefore define a class named `CounterTest` as follows:
158157

159158
```
160-
TestCase subclass: #CounterTest
161-
instanceVariableNames: ''
162-
classVariableNames: ''
159+
TestCase << #CounterTest
163160
package: 'MyCounter'
164161
```
165162

166163

167164
Now we can write a first test by defining one method. Test methods should start with _test_ to be automatically executed by the TestRunner or when you press on the icon of the method. Now to make sure that you understand in which class we define the method we prefix the method body with the class name and `>>`.
168165
`CounterTest>>` means that the method is defined in the class `CounterTest`.
169166

170-
Define the following method. It first creates an instance, sets its value and verifies that the value is correct. The message `assert:equals:` is a special message verifying if the test passed or not.
167+
Define the following method. It first creates an instance, sets its value, and verifies that the value is correct. The message `assert:equals:` is a special message verifying if the test passed or not.
171168

172169
```
173170
CounterTest >> testCountIsSetAndRead
@@ -310,7 +307,7 @@ If you run it, it will turn yellow indicating a failure \(a situation that you a
310307
#### Define an initialize method
311308

312309

313-
Now we have to write an initialization method that sets a default value of the `count` instance variable. However, as we mentioned the `initialize` message is sent to the newly created instance. This means that the `initialize` method should be defined at the instance side as any method that is sent to an instance of `Counter` \(like `increment`\) and `decrement`. The `initialize` method is responsible to set up the default value of instance variables.
310+
Now we have to write an initialization method that sets a default value of the `count` instance variable. However, as we mentioned the `initialize` message is sent to the newly created instance. This means that the `initialize` method should be defined at the instance side as any method that is sent to an instance of `Counter` (like `increment`) and `decrement`. The `initialize` method is responsible to set up the default value of instance variables.
314311

315312
Therefore at the instance side, you should create a protocol `initialization`, and create the following method \(the body of this method is left blank. Fill it in!\).
316313

Chapters/DSL/DSL.md

Lines changed: 473 additions & 42 deletions
Large diffs are not rendered by default.

Chapters/Expressions/Expressions.md

Lines changed: 1093 additions & 131 deletions
Large diffs are not rendered by default.

Chapters/Inheritance/Extending.md

Lines changed: 258 additions & 19 deletions
Large diffs are not rendered by default.

Chapters/Inheritance/Inheritance.md

Lines changed: 405 additions & 32 deletions
Large diffs are not rendered by default.

Chapters/Katas/GramKatas.md

Lines changed: 522 additions & 44 deletions
Large diffs are not rendered by default.

Chapters/NewCounterMaterial/Exo-Counter.md

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,8 @@ The lower pane of the Browser should now be open with a tab showing the template
4040
You should get the following class definition:
4141

4242
```
43-
Object subclass: #Counter
44-
instanceVariableNames: 'count'
45-
classVariableNames: ''
43+
Object << #Counter
44+
slots: { #count };
4645
package: 'MyCounter'
4746
```
4847

@@ -73,6 +72,8 @@ The class we have defined has one instance variable named `count`, and we're goi
7372

7473
And so there is no other mechanism to access our instance variable from outside of our counter than by sending a message to the object. What must do is define a method that returns the value of the instance variable. Such methods are called _getter_ methods. So, let's define an accessor method for our instance variable `count`.
7574
A method is usually placed into a _protocol_. These protocols are just a group of methods - they have no meaning in Pharo, but they do convey important information to the readers of your class. Although protocols can have any name, Pharo programmers follow certain conventions when naming protocols. If you define a method and are not sure what protocol it should be in, first take a look through existing code and see if you can find an appropriate protocol that already exists.
75+
76+
7677
### Create a method
7778

7879
Now let us create the getter method for the instance variable `count`. Start by selecting the class `Counter` in a Browser, and make sure you are editing the instance side of the class (i.e., we define methods on _instances_ of our class) by selecting the instance side tab. Then define your method.
@@ -110,21 +111,23 @@ c count
110111
```
111112

112113
The setter method does not currently exist, so as an exercise create the method `count:` such that, when invoked on an instance of `Counter`, the instance variable is set to the argument of the message. Test your method by evaluating the example above in a Playground.
114+
113115
### Define a Test Class
114116

115117
Writing tests - whether you do it before or after you write your code - isn't really optional these days. A collection of well-written tests will support the evolution of your application, and give you confidence that your program does the things you expect it to do. Writing tests for your code is a good investment; test code is written once and executed a million times. For example, if we turned the example above into a test we could have checked automatically that our new setter method is working as expected.
118+
116119
Our test cases, written as methods, need to live inside a test class that inherits from `TestCase`. So we define a class named `CounterTest` as follows:
117120

118121
```
119-
TestCase subclass: #CounterTest
120-
instanceVariableNames: ''
121-
classVariableNames: ''
122+
TestCase << #CounterTest
122123
package: 'MyCounter'
123124
```
124125

125126
Now we can write our first test by defining a method. Test methods should start with _test_ to be automatically executed by the Test Runner or to get the little clickable circle next to the method name that lets you run the test.
126127
Figure *@FirstGreenTest@* shows the definition of the method `testCountIsSetAndRead` in the class `CounterTest`.
127-
![A first test is defined and it passes.](figures/FirstGreenTest.png label=FirstGreenTest)
128+
129+
![A first test is defined and it passes. % anchor=FirstGreenTest](figures/FirstGreenTest.png)
130+
128131
Define the following method for our test case. It first creates an instance of a `Counter`, sets its value and then verifies that the value has been set. The message `assert:equals:` is a message implemented in our test class. It verifies a fact (in this case that two objects are equal), and will fail the test if the fact isn't true.
129132

130133
```
@@ -138,19 +141,26 @@ CounterTest >> testCountIsSetAndRead
138141
#### A typographic convention
139142

140143
Pharoers frequently use the notation `ClassName >> methodName` to identify the class to which a method belongs. For example, the `count` method we wrote above in our class `Counter` would be referred to as `Counter >> count`. Just keep in mind that this is not _exactly_ Pharo syntax, but more like a convenient notation we use to indicate "the instance method `count` which belongs to the class `Counter`".
144+
141145
From now on, when we show a method in this book, we will write the name of the method in this form. Of course, when you actually type the code into the browser, you don't have to type the class name or the `>>`; instead, you just make sure that the appropriate class is selected in the class pane.
142146
Verify that the test passes by executing either pressing the circle icon in front of the method (as shown by Figure *@FirstGreenTest@*) or using the Test Runner.
143147
As you now have your first green test, it's a good time to save your work.
148+
149+
144150
### Saving your code as a git repository with Iceberg
145151

146152
Saving your work in the Pharo image is good, but it's not ideal for sharing your work or collaborating with others. Much of modern software development is mediated through git, an open-source version control system. Services such as GitHub are built on top of git, providing places where developers can work together building open source projects - like Pharo!
147153
Pharo works with git through the tool **Iceberg**. This section will show you how to create a local git repository for your code, commit your changes to it, and also push those changes to a remote repository such as GitHub.
154+
148155
#### Open Iceberg
149156

150157
Open Iceberg through the **Sources** menu, or by hitting `Cmd-O,I`.
151-
![Iceberg _Repositories_ browser on a fresh image indicates that if you want to version modifications to Pharo itself you will have to tell Iceberg where the Pharo clone is located. But you do not care.](figures/Save1-EmptyIceberg.png width=75&label=EmptyIceberg)
158+
159+
![Iceberg _Repositories_ browser on a fresh image indicates that if you want to version modifications to Pharo itself you will have to tell Iceberg where the Pharo clone is located. But you do not care. %width=75&anchor=EmptyIceberg](figures/Save1-EmptyIceberg.png )
160+
152161
You should now see something similar to Figure *@EmptyIceberg@* which shows the top-level Iceberg pane. It shows the Pharo project, and a few other projects that also come with your image, and indicates that it could not find a local repository for them by showing 'Local repository missing'. You do not have to worry about the Pharo project or having a local repository if you do not want to contribute to Pharo.
153162
We're going to create a new project of our own.
163+
154164
#### Add and configure a project
155165

156166
Press the button `Add` to create a new project. Select 'New Repository' from the left and you should see a configuration pane similar to the one in Figure *@CreateProject@*. Here we name our project, declare a directory on our local disk where the project's source should be saved, and also a subdirectory in the project itself which will be used to keep the Pharo code in - conventionally this is the `src` directory.
@@ -227,11 +237,13 @@ CounterTest >> testInitialize
227237
```
228238

229239
This time the test will turn _yellow_, indicating a test failure - the test ran fine, but the assertion did not pass. This is different to the _red_ tests we've seen so far, where the tests have failed because an error occurred (when a method has not been implemented, for instance).
240+
230241
### Define an initialize method
231242

232243
Now we have to write an initialization method that sets a default value of the `count` instance variable.
233244
In Pharo, when creating a new object sending the message `new` to a class, the newly created instance is sent a message `initialize`. This gives the opportunity to the instance to initialize itself.
234-
Therefore we will define a `initialize` method that will correctly initialize the default value of a counter.
245+
246+
Therefore we will define an `initialize` method that will correctly initialize the default value of a counter.
235247

236248
Since the `initialize` message is sent to a new instance, it means that the `initialize` method should be defined on the _instance side_, just like any method that is sent to an instance of `Counter` (`increment` and `decrement`). The `initialize` method is responsible for setting up the default values of instance variables.
237249
And so, on the instance side of `Counter`, and in the `initialization` protocol, write the following method (the body of this method is left blank. Fill it in!).
@@ -250,6 +262,7 @@ As always, save your work before moving on to the next step.
250262

251263
We just discussed how the `initialize` method is defined on the _instance side_ of our class, as it is responsible for altering an instance of `Counter`. Now let's take a look at defining a method on the _class side_ of a class. Class methods will be executed as a result of sending messages to the class itself, rather than to instances of the class. To define the method on the class, we need to toggle the Code Browser over to the class side by selecting **Class side**.
252264
Define a new instance creation method called `startingAt:`. This method receives an integer as an argument and returns a new instance of `Counter` with the count set to the specified value.
265+
253266
What do we do first? Why, we define a test of course:
254267

255268
```
@@ -266,6 +279,7 @@ Counter class >> startingAt: anInteger
266279
```
267280

268281
Here we see the notation for identifying a _class side_ method in our text: `ClassName class >> methodName` just means "the class side method `startingAt:` on the class `Counter`".
282+
269283
What does `self` refer to here? As always, `self` refers to the object that the method is defined in, and so here it refers to the `Counter` class itself.
270284
Let's write another test just to make sure that everything is working:
271285

Chapters/OOPNutshell/OOPNutshell.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ What the diagram shows is that we have:
360360
- directories that have a name and can contain other files or directories. Here we get the `manga`, `comics`, `oldcomics`, and `belgiumSchool` directories. Directories can be nested: `comics` contains three repositories. The `belgiumSchool` directory contains `tintinEtLesPicaros`.
361361

362362

363-
![Some directories and files organised in a file system. % width=50&anchor=figdirectories](figures/comicsFileTree.png)
363+
![Some directories and files organized in a file system. % width=50&anchor=figdirectories](figures/comicsFileTree.png)
364364

365365

366366
### Studying a first scenario
@@ -370,14 +370,15 @@ In the rest of this book, we will code such examples as tests that can automatic
370370
For now, it would make the discourse too complex, so we just use little code examples.
371371

372372
We create two directories.
373+
373374
```
374375
| dComics dOldComics dManga |
375376
dComics := MFDirectory new name: 'comics'.
376377
dOldComics := MFDirectory new name: 'oldcomics'.
377378
```
378379

379380

380-
We add the oldcomics folder to comics and we check that the parent children relationship is well set.
381+
We add the oldcomics folder to comics and we check that the parent-child relationship is well set.
381382

382383
```
383384
...
@@ -407,7 +408,7 @@ dComics parent
407408
```
408409

409410

410-
Here we verify that `dOldComics` is comprised in the children of `dComics`.
411+
Here we verify that `dOldComics` is comprised of the children of `dComics`.
411412
```
412413
...
413414
dComics children includes: dOldComics.
@@ -578,7 +579,7 @@ MFDirectory >> printOn: aStream
578579
Try it and it should print the expected results.
579580
What do we see with this definition: it is a kind of recursive definition. The name of a directory is in fact the concatenation (here we just add in the stream but this is the same. ) of the name of its parents (as shown in Figure *@InstancesRecursion@*).
580581

581-
Similar to a recursive function navigating a structure composed of similar elements (like a linked-list or any structure defined by induction), each parent receives and executes another time the `printOn:` method and returns the name for its part.
582+
Similar to a recursive function navigating a structure composed of similar elements (like a linked list or any structure defined by induction), each parent receives and executes another time the `printOn:` method and returns the name for its part.
582583

583584
### Adding files
584585

Chapters/SimpleLan/Simple-LAN-Definition.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ From an object-oriented point of view, it is really interesting because it shows
99

1010
You will define step by step an application that simulates a simple Local Area Network (LAN). You will create several classes: `LNPacket`, `LNNode`, `LNWorkstation`, and `LNPrintServer`. We start with the simplest version of a LAN. In subsequent exercises, we will add new requirements and modify the proposed implementation to take them into account.
1111

12-
![An example of a LAN with packets.](figures/lan-simple width=60)
12+
![An example of a LAN with packets. % width=60](figures/lan-simple)
1313

1414

1515
### Creating the class `LNNode`
@@ -39,7 +39,6 @@ To help you write tests, we will define a test class.
3939

4040
```
4141
TestCase << #LNNodeTest
42-
slots: {};
4342
package: 'SimpleLAN'
4443
```
4544

@@ -51,6 +50,7 @@ Create a subclass of `Object` called `LNNode`, with two instance variables: `nam
5150

5251

5352
#### Exercise: Accessors
53+
5454
Create accessors and mutators for the two instance variables. Document the mutators to inform users that the argument passed to `name:` should be a `Symbol`, and the arguments passed to `nextNode:` should be a `LNNode`.
5555
Define the following test to validate such a simple behavior.
5656

@@ -108,7 +108,7 @@ Note that:
108108

109109
##### A little example.
110110

111-
The following snippet shows basic behavior of an open LAN composed of two nodes, Mac and PC1.
111+
The following snippet shows the basic behavior of an open LAN composed of two nodes, Mac and PC1.
112112

113113
```
114114
(LNNode new

Chapters/SnakesAndLadders/SnakesAndLadders.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ game play
3939

4040
Since we want to focus on the game logic, you will develop a textual version of the game and avoid any lengthy user interface descriptions.
4141

42-
The following is an example of game execution: Two players are on the first tile. The board contains two ladders, \[2->6] and [7->9], and one snake [5<-11].
42+
The following is an example of game execution: Two players are on the first tile. The board contains two ladders, [2->6] and [7->9], and one snake [5<-11].
4343

4444
Jill rolls a die, throws a 3, and moves to the corresponding tile.
4545
Jack rolls a die, throws a 6, moves to the corresponding tile, and follows its effect, climbing the ladder at tile 7 up to tile 9.
@@ -675,7 +675,7 @@ SLTile >> removePlayer: aPlayer
675675

676676

677677
Now propose an implementation of the method `movePlayer: aPlayer distance: anInteger`.
678-
You should get the destination tile for the player, remove the player from its current tile, add it to the destination tile and change the position of the player to reflect its new position.
678+
You should get the destination tile for the player, remove the player from its current tile, add it to the destination tile, and change the position of the player to reflect its new position.
679679

680680
```
681681
SLGame >> movePlayer: aPlayer distance: anInteger
@@ -688,7 +688,7 @@ We suspect that when we will introduce ladder and snake tiles, we will have to r
688688
#### About our implementation
689689

690690

691-
The implementation that we propose below for the method `movePlayer: aPlayer distance: anInteger` is not as nice as we would like it to be. Why? Because it does not give a chance to the tiles to extend this behavior and our experience tells us that we will need it when we will introduce the snake and ladder. We will discuss that when we will arrive there.
691+
The implementation that we propose below for the method `movePlayer: aPlayer distance: anInteger` is not as nice as we would like it to be. Why? Because it does not give a chance to the tiles to extend this behavior and our experience tells us that we will need it when we will introduce the snake and ladder. We will discuss that when we will arrive there.
692692

693693
```
694694
SLGame >> movePlayer: aPlayer distance: anInteger
@@ -950,7 +950,7 @@ SLSnakeTile >> printInsideOn: aStream
950950
#### super does not have to be the first expression
951951

952952

953-
Now we show you our definition of `printInsideOn:` for the class `SLSnakeTile`. Why do we show it? Because it shows you that an expression invoking an overriden method can be placed anywhere. It does not have to be the first expression of a method. Here it is the last one.
953+
Now we show you our definition of `printInsideOn:` for the class `SLSnakeTile`. Why do we show it? Because it shows you that an expression invoking an overridden method can be placed anywhere. It does not have to be the first expression of a method. Here it is the last one.
954954

955955
```
956956
SLSnakeTile >> printInsideOn: aStream

0 commit comments

Comments
 (0)