forked from SquareBracketAssociates/UpdatedPharoByExample
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPharoTour.pillar
789 lines (588 loc) · 37.7 KB
/
PharoTour.pillar
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
!A quick tour of Pharo
@cha:tour
This chapter will take you on a high level tour of Pharo, to help you get
comfortable with the environment. There will be plenty of opportunities to try
things out, so it would be a good idea if you have a computer handy when you
read this chapter.
In particular, you will fire up Pharo, learn about the different ways of
interacting with the system, and discover some of the basic tools. You will also
learn how to define a new method, create an object and send it messages.
''Note:'' Most of the introductory material in this book will work with any
Pharo version, so if you already have one installed, you may as well continue to
use it. However, since this chapter is written for Pharo 4, if you notice
differences between the appearance or behaviour of your system and what is
described here, do not be surprised.
!!Pharo components
Like many Smalltalk-derived systems, Pharo consists of four main component files.
Although you do not need to deal with them directly for the purposes
of this book, it is useful to understand the roles they play.
""1."" The ""virtual machine"" (VM) is the only component that is
different for each operating system. The VM executable is named:
- ==Pharo.exe== for Windows;
- ==pharo== for Linux ; and
- ==Pharo== for OSX (inside a package also named ==Pharo==).
The other components below are portable across operating systems,
and can be copied and run on any appropriate virtual machine.
""2."" The ""sources"" file contains source code for parts of
Pharo that don't change frequently. Typically a new ""sources""
file is generated once per major release of Pharo.
For Pharo 4.0, this file is named ==PharoV40.sources==.
""3."" The ""changes"" file logs of all source code
modifications since the ==.sources== file was generated.
This facilitates a per method history for diffs or reverting.
Each release provides a near empty file named for the release,
for example ==Pharo4.0.changes==.
""4."" The ""image"" file provides a frozen in time snapshot
of a running Pharo system. This is the heart of Pharo,
containing the live state of all objects in the system
(including classes and methods, since they are objects too).
The file is named for the release (like ==Pharo4.0.image==).
The ==.image== and ==.changes== files provided by a Pharo release
are the starting point for a live environment that you adapt to your needs.
As you work in Pharo, these files are modified,
so you need to make sure that they are writable.
The ==.image== and ==.changes== files are intimately linked
and should always be kept together, with matching base filenames.
Never edit them directly with a text editor, as ==.images== holds your
live object runtime memory, which indexes into the ==.changes== files
for the source.
It is a good idea to keep a backup copy of the downloaded ==.image== and ==.changes==
files so you can always start from a fresh image and reload your code.
The four main component files above can be placed in the same directory,
although it's also possible to put the Virtual Machine and sources file in a
separate directory where everyone has read-only access to them.
Do whatever works best for your style of working and your operating system.
!!Getting started
Pharo is available as a free download from
*http://pharo.org/download>http://pharo.org/download*. Click the button for your
operating system to download the appropriate ==.zip== file. For example, the
full Pharo 4.0 distribution for Mac OS X will be available at
*http://files.pharo.org/platform/Pharo4.0-mac.zip>http://files.pharo.org/platform/Pharo4.0-mac.zip*.
Once that file is unzipped, it will contain everything you need to run
Pharo (this includes the VM, the image, and the sources, as explained below).
!!Installing Pharo
Pharo does not need to install anything in your system, as it's perfectly
capable of running standalone. Depending on your platform, download the
appropriate zip file, uncompress it in a directory of your choice and now you
are ready to launch Pharo. In case of Ubuntu Linux, there is also the extra
option of installing Pharo via the Pharo PPA.
!!Launching Pharo
To start Pharo, double click on the Pharo executable (or, for more advanced
users, drag and drop the ==.image== file onto the VM, or use the command line).
On ""Mac OS X"", double click the ==Pharo4.0.app== bundle in the unzipped download.
On ""Linux"", double click (or invoke from the command line) the ==pharo==
executable bash script from the unzipped Pharo folder.
On ""Windows"", enter the unzipped Pharo folder and double click ==Pharo.exe==.
In general, Pharo tries to "do the right thing". If you double click on the VM,
it looks for an image file in the default location. If you double click on an
==.image== file, it tries to find the nearest VM to launch it with.
Once you have multiple VMs (or multiple images) installed on your
machine, the operating system may no longer be able to guess the right one. In this
case, it is safer to specify exactly which ones you meant to launch, either
by dragging and dropping the image file onto the VM, or specifying the image on
the command line (see the next section).
!!!Launching Pharo via the command line
The general pattern for launching Pharo from a terminal is:
[[[caption=Launching pattern|label=src:launchingPattern
<Pharo executable> <path to Pharo image>
]]]
!!!!Linux command line
For Linux, assuming that you're in the unzipped ==pharo4.0== folder:
[[[caption=Launching Pharo from Linux|label=src:launchingFromLinux
./pharo shared/Pharo4.0.image
]]]
!!!!Mac OS X command line
For Mac OS X, assuming that you're in the directory with the unzipped
==Pharo4.0.app== bundle:
[[[caption=Launching Pharo from Mac OS X|label=src:launchingFromMac
Pharo4.0.app/Contents/MacOS/Pharo Pharo4.0.app/Contents/Resources/Pharo4.0.image
]]]
Incidentally, to drag-and-drop images on Mac OS in Finder, you need to
right-click on ==Pharo4.0.app== and select 'Show Package Contents'.
!!!!Windows command line
For Windows, assuming that you're in the unzipped ==Pharo4.0== folder:
[[[caption=Launching Pharo from Windows|label=src:launchingFromWindows
Pharo.exe Pharo4.0.image
]]]
!!PharoLauncher
==PharoLauncher== is a tool that helps you download and manage Pharo images. It
is very useful for getting new versions of Pharo (as well as updates to the
existing versions that contain important bug fixes). It also gives you access to
images preloaded with specific libraries that make it very easy to use
those tools without having to manually install and configure them.
PharoLauncher can be found on SmalltalkHub at
*http://smalltalkhub.com/#!/~Pharo/PharoLauncher>http://smalltalkhub.com/#!/~Pharo/PharoLauncher*
together with installation instructions and download links depending on your
platform.
+PharoLauncher - GUI>file://figures/PharoLauncher.png|width=70|label=fig:PharoLauncher+
After installing PharoLauncher and opening it (like you would any Pharo image),
you will see a GUI that contains two columns. The left column lists images that
live locally on your machine (usually in a shared system folder). You can
launch any local image directly (either by double-clicking, or by selecting it
and pressing the ==Launch== button). A right-click context menu provides
several useful functions like copying and renaming your images, as well as
locating them on the file system.
The right column lists Templates, which are remote images available for
download. To download a remote image, select it and click the ==Create
image== button (located on the top right, next to the ==Refresh template list==
button).
!!The World Menu
Once Pharo is running, you should see a single large window, possibly containing
some open playground windows (see Figure *@fig:worldMenu*). You might notice a
menu bar, but Pharo mainly makes use of context-dependent pop-up menus.
+Clicking anywhere on the Pharo window background activates the World Menu>file://figures/Pharo40.png|width=100|label=fig:worldMenu+
Clicking anywhere on the background of the Pharo window will display the
World Menu, which contains many of the Pharo tools, utilities and settings.
At the top of the World Menu, uou will see a list of several core tools in
Pharo, including the System Browser, the Playground, the Monticello package
manager, and others. We will discuss them in more detail in the coming chapters.
!!!Interacting with Pharo
Pharo offers three ways to interact with the system using a mouse or other
pointing device.
""click"" (or left-click): this is the most often used mouse button, and is
normally equivalent to left-clicking (or clicking a single-mouse button without
any modifier key). For example, click on the background of the Pharo window to
bring up the ==World== menu (Figure *@fig:worldMenu*).
""action-click"" (or right-click): this is the next most used button. It is used
to bring up a contextual menu that offers different sets of actions depending on
where the mouse is pointing (see Figure *@fig:operating*). If you do not have a
multi-button mouse, then normally you will configure the control modifier key to
action-click with the mouse button.
""meta-click"": Finally, you may meta-click on any object displayed in the image
to activate the "morphic halo", an array of handles that are used to perform
operations on the on-screen objects themselves, such as inspecting or resizing
them (see Figure *@fig:halos*). If you let the mouse linger over a handle, a
help balloon will explain its function. In Pharo, how you meta-click depends on
your operating system: either you must hold ==Shift-Ctrl== or ==Shift-Alt== (on
Windows or Linux) or ==Shift-Option== (on Mac OS X) while clicking.
+Action Click (right click) brings the contextual menu.>file://figures/operating.png|width=60|label=fig:operating+
+Meta-Clicking on a window opens the Halos>file://figures/addHalo.png|width=60|label=fig:halos+
!!Sending messages
In the Pharo window, click on an open space to open the ==World Menu==, and then
select the ==Playground== menu option. The Playground tool will open (you may
recognize it as the ==Workspace== tool, from previous versions of Pharo). We can
use the Playground to quickly execute Pharo code. Enter the following code in
it, then right click and select ==Do it==:
[[[caption=Open the Pharo Tutorial from the ==Playground==.|label=src:pharoTutorial
PharoTutorial go.
]]]
+Executing an expression is simple with the ==Do it== menu item.>file://figures/PharoTutorialOption.png|width=60|label=fig:pharotutorial+
This expression will trigger the Pharo tutorial (as shown in Figure
*@fig:ProfStef*). It is a simple and interactive tutorial that will teach you
the basics of Pharo.
Congratulations, you have just sent your first message! Pharo is based on
the concept of sending messages to objects. The Pharo objects are like your
soldiers ready to obey once you send them a message they can understand. We
will see how an object can understand a message, later on.
+PharoTutorial is a simple interactive tutorial to learn about Pharo>file://figures/ProfStef.png|width=60|label=fig:ProfStef+
If you talk to Pharoers for a while, you will notice that they generally do not
use expressions like "call an operation" or "invoke a method", as developers do
in other programming languages. Instead they will say "send a message". This
reflects the idea that objects are responsible for their own actions. You never
tell an object what to do, instead you politely ask it to do something by
sending it a message. The object, and not the sender, selects the appropriate
method for responding to your message.
As a user you don't need to understand how each message works, the only thing
you need to know is what the available messages are for the objects that
interest you. This way an object can hide its complexity, and coding can be kept
as simple as possible without losing flexibility.
!!Saving, quitting and restarting a Pharo session
You can exit Pharo at any point, by closing the Pharo window as you do any other
application window. Additionally you can use the World Menu and select either
==Save and quit== or ==Quit==.
In any case Pharo will display a prompt to ask you about saving your image. If
you do save your image and reopen it, you will see that things are ''exactly''
as you left them. This happens because the image file is capable of storing any
information (created objects, edited text, window positions, added methods... of
course since they are all objects) that Pharo has loaded into your memory so
that nothing is lost on exit.
When you start Pharo for the first time, the Pharo virtual machine loads the
image file that you specified. This file contains a snapshot of a large number
of objects, including a vast amount of pre-existing code and programming tools
(all of which are objects). As you work with Pharo, you will send messages to
these objects, you will create new objects, and some of these objects will die
and their memory will be reclaimed (garbage-collected).
When you quit Pharo, you will normally save a snapshot that contains all of your
objects. If you save normally, you will overwrite your old image file with the
new snapshot. Alternatively, you may save the image under a new name.
As mentioned earlier, in addition to the ==.image== file, there is also a
==.changes== file. This file contains a log of all the changes to the source
code that you have made using the standard tools. Most of the time you do not
need to worry about this file at all. As we shall see, however, the ==.changes==
file can be very useful for recovering from errors, or replaying lost changes.
More about this later!
It may seem like the image is the key mechanism for storing and managing
software projects, but that is not the case. As we shall see soon, there are
much better tools for managing code and sharing software developed by teams.
Images are very useful, but you should learn to be very cavalier about creating
and throwing away images, since tools like ==Monticello== offer much better ways
to manage versions and share code amongst developers. In addition, if you need
to persist objects, you can use several systems such as ==Fuel== (a fast object
binary serializer), ==STON== (a textual object serializer) or a database.
!!Playground and Transcripts
Let us start with some exercises:
# Close all open windows within Pharo.
# Open a Transcript and a Playground/workspace. (The Transcript can be opened from the ==World > Tools > ...== submenu.)
# Position and resize the transcript and playground windows so that the playground just overlaps the transcript (see Figure *@fig:HelloWorld*).
You can resize windows by dragging one of the corners.
At any time only one window is active; it is in front and has its border
highlighted.
The ==Transcript== is an object that is often used for logging system messages.
It is a kind of ''system console''.
==Playgrounds== are useful for typing snippets of code that you would like to
experiment with. You can also use playgrounds simply for typing arbitrarily text
that you would like to remember, such as to-do lists or instructions for anyone
who will use your image. Playgrounds are often used to hold documentation about
a captured image, as well.
Type the following text into the playground:
[[[caption=Hello World in a Transcript|label=src:helloWorld
Transcript show: 'hello world'; cr.
]]]
Try double-clicking at various points on the text you have just typed. Notice
how an entire word, entire string, or all of the text is selected, depending on
whether you click within a word, at the end of the string, or at the end of the
entire expression. In particular, if you place the cursor before the first
character or after the last character and double-click, you select the complete
paragraph.
Select the text you have typed, right click and select ==Do it (d)==. The
==(d)== at the end indicates that you can use the shortcut ==CMD-d== to get the
same result.
Notice how the text "hello world" appears in the transcript window. Do it again.
+Executing an expresssion: displaying a string in the Transcript.>file://figures/HelloWorld_new.png|width=80|label=fig:HelloWorld+
!!Keyboard shortcuts
If you want to evaluate an expression, you do not always have to right click.
Instead, you can use keyboard shortcuts. These are the parenthesized expressions
in the menu. Depending on your platform, you may have to press one of the
modifier keys which are Control, Alt and Command. We will be focusing on the Mac
OS platform since this is the platform most Pharo developers use, where the
command key (a.k.a ==CMD==) is the main modifier key. The corresponding modifier
key in Windows is ==ALT==, and in Linux is either ==ALT== or ==CTRL==,
so each time you see something like ==CMD-d==,
just replace it with the appropriate modifier key depending on your OS.
In addition to ==Do it==, you might have noticed ==Do it and go==, ==Print
it==, ==Inspect it== and several other options. Let's have a quick look at each
of these.
Type the expression ==3 + 4== into the playground. Now ==Do it== with the
keyboard shortcut.
Do not be surprised if you saw nothing happen! What you just did is send the
message ==\+== with argument 4 to the number 3. Normally the resulting 7 would
have been computed and returned to you, but since the playground did not know
what to do with this answer, it simply threw the answer away. If you want to see
the result, you should ==Print it== instead. ==Print it== actually compiles the
expression, executes it, sends the message ==printString== to the result, and
displays the resulting string.
Select ==3\+4== and ==Print it== (==CMD-p==).
This time we see the result we expect.
[[[
3 + 4 --> 7
]]]
We use the notation ==-\->== as a convention in this book to indicate that a
particular Pharo expression yields a given result when you ==Print it==.
Delete the highlighted text "7" (Pharo should have selected it for you, so you
can just press the delete key). Select ==3\+4== again, and this time ==Inspect
it== (==CMD-i==).
Now you should see a new window titled "Inspector on a SmallInteger(7)"
The inspector is an extremely useful tool that will allow you
to browse and interact with any object in the system. The title tells us that 7
is an instance of the class ==SmallInteger==. The left panel allows us to browse
the instance variables of an object, the values of which are shown in the right
panel. The bottom panel can be used to write expressions to send messages to the
object.
Type ==self squared== in the bottom panel of the inspector, and ==Print it==.
+Inspecting an object using ==Basic Inspect==>file://figures/inspector.png|width=80|label=fig:inspector+
Close the inspector.
Other right-click options that may be used are the following:
==Basic Inspect it== opens the classic inspector that offers a more minimal gui
and live updates of changes to the object.
==Debug it== open the debuger on the code.
==Profile it== profiles the code with the Pharo profile tool which show how much
time is spent for each message sent.
==Code search== offers several options provided by System Browser, such as
browsing the source code of an expression, searching for senders and
implementors, and so on.
!!The System Browser
The ==System Browser==, also known as "Class Browser", is one of the key tools
used for programming. As we shall see, there are several interesting browsers
available for Pharo, but this is the basic one you will find in any image.
@@authorToDo TODO: factorial on number would be better. and should redo the screenshot
!!!!Open the System Browser
Open the Browser by selecting ==World > System Browser==.
+The System Browser showing the printString method of class Object>file://figures/system-browser.png|width=100|label=fig:systemBrowser+
+Icons used by the system browser>file://figures/pharoBrowserIcons.png|width=100|label=fig:systemBrowserIcons+
We can see a System Browser in Figure *@fig:systemBrowser*.
Its icons in figure *@fig:systemBrowserIcons* have special meaning, and some can
act as buttons that perfom an action depending on the context of the icon. The
meanings of the icons are as follows (from left to right and top to bottom):
Package, Class with comment, method overriden in subclasses, method inherited
from super class, method both inherited from superclass and overriden by
subclasses, test class that has not been run, test class that has run and passed
all its tests, Trait, Class tag, Class without a comment, button to switch on
the class comment, button to switch to class side, button to show inheritance
hierachy, Announcement class, Group.
The title bar indicates that we are browsing the class Object and its method
==printString==.
When a new System Browser window first opens, all panes are empty but the
leftmost one. This first pane lists all known packages, which contain groups of
related classes.
In Pharo 4 and above, the default System Browser is Nautilus. However,
it is possible to have other System Browsers installed in the Pharo enviroment
such as OmniBrowser, AltBrowser and others. Each System Browser may
have its own GUI that may be very diffirent from the Nautilus GUI. From now on,
we will use the terms ==Browser==, ==System Browser== and (occasionally)
==Nautilus== interchangeably.
!!!!!Expand the ==Kernel== package category and select the ==Objects== package
When we select a package, it causes the second pane to show a list of all of the
classes in the selected package.
!!!!!Select the ==Object== class
When a class is selected, the remaining two panes will be populated. The
third pane displays the protocols of the currently selected class. These are
convenient groupings of related methods. If no protocol is selected you should
see all methods in the fourth pane.
!!!!!Select the ==printing== protocol
You may have to scroll down to find it. You can also click on the third pane and
type ==pr==, to typeahead-find the ==printing== protocol. Now select it, and you
will see in the fourth pane only methods related to printing.
!!!!!Select the ==printString== method
Now we see in the bottom pane the source code of the ==printString== method,
shared by all objects in the system (except those that override it).
!!Finding classes
There are several ways to find a class in Pharo. The first, as we have just
seen above, is to know (or guess) what package it is in, and to navigate to it
using the browser.
A second way is to send the ==browse== message to the class, asking it to open a
browser on itself. Suppose we want to browse the class ==Boolean==.
!!!!Using the message ==browse==
Type ==Boolean browse== into a playground and ==Do it==.
A browser will open on the ==Boolean== class.
!!!!Using ==CMD-b== to browse
There is also a keyboard shortcut ==CMD-b== (browse) that you can use in any
tool where you find a class name; select the name and press ==CMD-b==. Use this
keyboard shortcut to browse the class ==Boolean==.
Notice that when the ==Boolean== class is selected but no protocol or method is
selected, instead of the source code of a method, we see a class definition.
This is nothing more than an ordinary message that is sent to the parent class,
asking it to create a subclass. Here we see that the class ==Object== is being
asked to create a subclass named ==Boolean== with no instance variables, class
variables or ''pool dictionaries'', and to put the class ==Boolean== in the
==Kernel-Objects== package. If you click on the ==Comments== button at the
bottom of the class pane, you can see the class comment in a dedicated pane.
+The Boolean class with the comments section>file://figures/Boolean.png|width=100|label=fig:boolean+
!!!!Find class in System Browser
Often, the fastest way to find a class is to search for it by name. For example,
suppose that you are looking for some unknown class that represents dates and
times.
In the System Browser, click anywhere in the package pane or the class pane, and
launch the Class Search window by typing ==CMD-f CMD-c==, or selecting ==Find
class (f,c)== from the right-click context menu. Type ==time== in the dialog box
and click ==OK== (or press ==Enter==).
You will be presented with a list of classes whose names contain the substring
==time==. Choose one (say, ==Time==), and the browser will show it, along with a
class comment that suggests other classes that might be useful. If you want to
browse one of the others, select its name (in any text pane), and type
==CMD-b==.
Note that if you type the complete (and correctly capitalized) name of a class
in the find dialog, the browser will go directly to that class without showing
you the list of options.
!!!!Using Spotter
Pressing ==Shift-Enter== will open ==Spotter==, a very powerful tool for finding
classes, methods, and many other related actions. Figure *@fig:spotter* shows
that we look for ==Point==. Spotter proposes us several possibilities.
+Spotter>file://figures/spotter.png|width=100|label=fig:spotter+
We can use Spotter to navigate to our search results similarly to how we use
System Browser. Spotter categorizes its search results: for example, classes are
under Classes category, methods under the Implementors category, help topics
under Help Topics category, etc. Clicking on the right arrow will take us to our
selection and create a tab on top that we can click to go back to where we were.
Depending on what we click on, we step into our selection and are exposed to
more categories.
For example, if our selection is the ==Point== class, we will dive inside a
group of categories made for instance methods, class methods, super instance
methods etc.
The interface is fully controllable through the keyboard. The user can move with
==Up==/==Down== arrows between items or ==Cmd-Shift-Up==/==Cmd-Shift-Down==
arrows (note that on Windows and Linux ==Cmd== key is the ==Alt== key) through
categories. At the same time, the search field has the focus, so the user can
switch seamlessly between selecting items and refining the search. Pressing
==Enter== on a selection opens the System Browser on that specific selected
search result.
Spotter can be used even to browse through the OS file system, and has a history
category where previous searches are stored for quickly going back to popular
searches.
!!!!Using the Finder
You can also open the ==Finder== that is available from the ==World > Tools...==
menu, and type part of the name of the class. It is less efficient than using
Spotlight or the SystemBrowser as explained above. The Finder is more useful
for other types of code searches, as we will show later.
!!Finding methods
Sometimes you can guess the name of a method, or at least part of the name of a
method, more easily than the name of a class. For example, if you are interested
in the current time, you might expect that there would be a method called "now",
or containing "now" as a substring. But where might it be? The ==Finder==
can help you.
Select ==World Menu > Tools > Finder==. Type ==now== in the top left search box,
and click ==Search== (or just press the ==Enter== key).
You should see a list of results similar to the one in Figure *@fig:finder*.
The Finder will display a list of all the method names that contain the
substring "now". To scroll to ==now== itself, move the cursor to the list and
type "n"; this type-ahead trick works in all scrolling windows. Expanding the
"now" item shows you the classes that implement a method with this name.
Selecting any one of them will display the source code for the implementation
in the code pane on the bottom.
+The Finder showing all classes defining a method named ==now==.>file://figures/finder.png|width=80|label=fig:finder+
At other times, you may have a good idea that a method exists, but will have no
idea what it might be called. The Finder can still help! For example,
suppose that you would like to find a method that turns a string into upper
case (for example, transforming 'eureka' into 'EUREKA'). We can give the
inputs and expected output of a method and the Finder will try to find it for
you.
!!!!Finding methods using examples
The Finder has a really powerful functionality: you can give the receiver,
arguments and expected result and the finder tries to find the corresponding
message.
In the Finder, select the examples mode using the second combo-box (the one that
shows ==Selectors== by default).
Type =='eureka'. 'EUREKA'== into the search box and press the ==Enter== key.
The Finder will then suggest a method that does what you were looking for, as
well as display a list of classes that implement that method. In this case,
it determined that the ==asUppercase== method is the one that performed the
operation that fit your example.
Click on the =='eureka' asUppercase -\-> 'EUREKA'== expression, to show the list
of classes that implement that method.
An asterisk at the beginning of a line in the list of classes
indicates that this method is the one that was actually used to obtain the
requested result. So, the asterisk in front of ==String== lets us
know that the method ==asUppercase== defined in the class ==String== was
executed and returned the result we wanted. The classes that do not have an
asterisk are just other implementors of ==asUppercase==, which share the method
name but were ''not'' used to return the wanted result. So
==Character>>asUppercase== was not executed in our example, because =='eureka'==
is not a ==Character== instance (but is instead a ==String==).
You can also use the Finder to search for methods by arguments and results. For
example, if you are looking for a method that will find the greatest common
factor of two integers, you might try ==25. 35. 5== as an example. You can also
give the method finder multiple examples to narrow the search space; the help
text in the bottom pane explains how.
!!Defining a new method
The advent of Test Driven Development (TDD) has changed the way that we write
code. The idea behind TDD is that we write a test that defines the desired
behaviour of our code before we write the code itself. Only then do we write the
code that satisfies the test.
Suppose that our assignment is to write a method that "says something loudly and
with emphasis". What exactly could that mean? What would be a good name for such
a method? How can we make sure that programmers who may have to maintain our
method in the future have an unambiguous description of what it should do? We
can answer all of these questions by giving an example.
Our goal is to define a new method named ==shout== in the class ==String==. The
idea is that this message should turn a string into its uppercase version as
shown in the example below:
[[[
'Don''t panic' shout
--> 'DON''T PANIC!'
]]]
However, before creating the ==shout== method itself, we must first create a
test method! In the next section, we can use the "Don't Panic" example to
create our test method.
!!!Defining a new test method
How do we create a new method in Pharo? First, we have to decide which class the
method should belong to. In this case, the ==shout== method that we are testing
will go in class ==String==, so the corresponding test will, by convention, go
in a class called ==StringTest==.
First, open a browser on the class ==StringTest==, and select an appropriate
protocol for our method, in this case =='tests - converting'==. The highlighted
text in the bottom pane is a template that reminds you what a Pharo method looks
like. Delete this template code (remember, you can either click on the beginning
or the end of the text, or press ==CMD-a==, to "Select All"), and start typing
your method. We can turn our "Don't Panic" code example into the test method
itself:
[[[
testShout
self assert: ('Don''t panic' shout = 'DON''T PANIC!')
]]]
Once you have typed the text into the browser, notice that the corner is orange.
This is a reminder that the pane contains unsaved changes. So, select ==Accept
(s)== by right clicking in the bottom pane, or just type ==CMD-s==, to compile
and save your method. You should see a situation similar to the one depicted in
Figure *@fig:testshout*.
+Defining a test method in the class ==StringTest==.>file://figures/testshout-00.png|width=70|label=fig:testshout+
If this is the first time you have accepted any code in your image, you will
likely be prompted to enter your name. Since many people have contributed code
to the image, it is important to keep track of everyone who creates or modifies
methods. Simply enter your first and last names, without any spaces (you can
also use a dot to separate).
Because there is as yet no method called ==shout==, the browser will ask you to
confirm that this is the name that you really want. It will also suggest some
other names that you might have intended. This can be quite useful if you have
merely made a typing mistake, but in this case, we really do mean ==shout==,
since that is the method we are about to create. We confirm this by selecting
the first option from the menu of choices.
!!! Running your test method
Run your newly created test: open the ==Test Runner== from the World Menu.
The leftmost two panes are a bit like the top panes in the System Browser. The
left pane contains a list of packages, but it's restricted to those packages
that contain test classes.
Select ==CollectionsTests-Strings== package, and the pane to the right will show
all of the test classes in it, which includes the class ==StringTest==. The
names of the classes are already selected, so click ==Run Selected== to run all
these tests.
+Failed test - Message not Understood>file://figures/preview-1.png|width=70|label=fig:messageNotUnderstood+
You should see the upper right pane turn red, which indicates that there was an
error in running the tests. The list of tests that gave rise to errors is shown
in the bottom right pane. As you can see, ==StringTest>>testShout== is the
culprit. (Note that ==StringTest>>testShout== is the Pharo way of identifying
the ==testShout== method of the ==StringTest== class.) If you click on that
method in the bottom right pane, the erroneous test will run again, this time in
such a way that you see the error happen: ==MessageNotUnderstood:
ByteString>>shout== (see Figure *@fig:messageNotUnderstood*).
The window that opens with the error message is the Pharo debugger. We will look
at the debugger and how to use it in Chapter *: The Pharo Environment>../Environment/Environment.pillar@cha:env*.
+Pressing the Create button in the debugger prompts you to select which class to create the new method in>file://figures/preview-2.png|width=70|label=fig:createPromptWhichClass+
!!!Implementing the test method
The error is, of course, exactly what we expected: running the test generates an
error because we haven't yet written a method that tells strings how to shout.
Nevertheless, it's good practice to make sure that the test fails because this
confirms that we have set up the testing machinery correctly and that the new
test is actually being run. Once you have seen the error, you can ==Abandon==
the running test, which will close the debugger window.
+You can implement methods in the debugger itself, via the Create button.>file://figures/shouldBeImplemented-3.png|width=70|label=fig:shoutShouldBeImplemented+
+The newly created ==shout== method.>file://figures/shoutInDebugger-4.png|width=70|label=fig:shoutInDebugger+
Instead of pressing ==Abandon==, you can define the missing method using the
==Create== button right in the debugger. This will prompt you to select a class
in which to define the new method (see Figure *@fig:createPromptWhichClass*), then
prompt you to select a protocol for that method, and finally take you to a code
editor window in the debugger, in which you can edit the code for this new
method (see Figure *@fig:shoutShouldBeImplemented*). When you've finished
implementing the method, you can press ==Proceed== and continue with the tests.
Note that ==Proceed== simply continues on running the test suite, and does not
re-run the failed method.
Now let's define the method that will make the test succeed!
Select class ==String== in the browser, select the converting protocol method,
replace the method template with the code of the method below, and ==Accept==
it (==CMD-s==).
[[[
shout
^ self asUppercase,'!'
]]]
The comma is the string concatenation operation, so the body of this method
appends an exclamation mark to an upper-case version of whatever String object
the shout message was sent to. The ==^== tells Pharo that the expression that
follows is the answer to be returned from the method, in this case the new
concatenated string.
Does this method work? Let's run the tests and see.
Click on ==Run Selected== again in the Test Runner, and this time you should see
a green bar and text indicating that all of the tests ran with no failures and
no errors.
When you get to a green bar, it's a good idea to save your work by saving the
image (==World Menu > Save==), and take a break. So, do that right now!
!!Chapter Summary
This chapter has introduced you to the Pharo environment and shown you how to
use some of the major tools, such as the System Browser, Spotter, the Finder,
the Debugger, and the Test Runner. You have also seen a little of Pharo's
syntax, even though you may not understand it all yet.
-A running Pharo system consists of a ''virtual machine'', a ==.sources== file, and ==.image== and ==.changes== files. Only these last two change, as they record a snapshot of the running system.
-When you restore a Pharo image, you will find yourself in exactly the same state (i.e., with exactly the same running objects) that you had when you last saved that image.
-You can click on the Pharo background to bring up the ==World Menu== and launch various tools.
-A ==Playground== is a tool for writing and evaluating snippets of code. You can also use it to store arbitrary text.
-You can use keyboard shortcuts on text in the playground, or any other tool, to evaluate code. The most important of these are ==Do it== (==CMD-d==), ==Print it== (==CMD-p==), ==Inspect it== (==CMD-i==), and ==Browse it== (==CMD-b==).
-The ==System Browser== is the main tool for browsing Pharo code and for developing new code.
-The ==Test runner== is a tool for running unit tests, and aids in Test Driven Development.
-The ==Debugger== allows you to examine errors and exceptions (such as errors or failures encountered when running tests). You can even create new methods right in the debugger.