y_petri 2.4.8 → 2.4.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Introduction_to_Ruby_for_YPetri_and_YNelson_Users.lyx +2859 -0
- data/Introduction_to_Ruby_for_YPetri_and_YNelson_Users.pdf +0 -0
- data/Introduction_to_YPetri_and_YNelson.lyx +3429 -0
- data/Introduction_to_YPetri_and_YNelson.pdf +0 -0
- data/Object_model_of_YPetri_and_YNelson.lyx +3837 -0
- data/Object_model_of_YPetri_and_YNelson.pdf +0 -0
- data/lib/y_petri.rb +1 -3
- data/lib/y_petri/net/visualization.rb +11 -6
- data/lib/y_petri/version.rb +1 -1
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8f83f0887d223b3a2308affbf576dde1f679600a
|
4
|
+
data.tar.gz: ddf1656fa619380fe37bf3510cd75765cb89ed23
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e51425e2c03fe86a3e4aaf488021aefaec837906a4d4a5af41e4947eb6e137586fb5947ee7c0211351cbb8e810af749f5153d2ff994746f5f996e6db52c1c3fa
|
7
|
+
data.tar.gz: 5554e2d1264c3c26419097169109e02b7697fccbb7efab0523e29f6055c1b6e6ab0c3aa87d12f90e166a3e3bdf8bd0be59569e6ade332110bdda09a2affd9d52
|
@@ -0,0 +1,2859 @@
|
|
1
|
+
#LyX 2.1 created this file. For more info see http://www.lyx.org/
|
2
|
+
\lyxformat 474
|
3
|
+
\begin_document
|
4
|
+
\begin_header
|
5
|
+
\textclass article
|
6
|
+
\use_default_options false
|
7
|
+
\maintain_unincluded_children false
|
8
|
+
\language english
|
9
|
+
\language_package default
|
10
|
+
\inputencoding auto
|
11
|
+
\fontencoding global
|
12
|
+
\font_roman default
|
13
|
+
\font_sans default
|
14
|
+
\font_typewriter default
|
15
|
+
\font_math auto
|
16
|
+
\font_default_family default
|
17
|
+
\use_non_tex_fonts false
|
18
|
+
\font_sc false
|
19
|
+
\font_osf false
|
20
|
+
\font_sf_scale 100
|
21
|
+
\font_tt_scale 100
|
22
|
+
\graphics default
|
23
|
+
\default_output_format default
|
24
|
+
\output_sync 0
|
25
|
+
\bibtex_command default
|
26
|
+
\index_command default
|
27
|
+
\paperfontsize default
|
28
|
+
\spacing single
|
29
|
+
\use_hyperref false
|
30
|
+
\papersize default
|
31
|
+
\use_geometry true
|
32
|
+
\use_package amsmath 1
|
33
|
+
\use_package amssymb 1
|
34
|
+
\use_package cancel 1
|
35
|
+
\use_package esint 1
|
36
|
+
\use_package mathdots 1
|
37
|
+
\use_package mathtools 1
|
38
|
+
\use_package mhchem 1
|
39
|
+
\use_package stackrel 1
|
40
|
+
\use_package stmaryrd 1
|
41
|
+
\use_package undertilde 1
|
42
|
+
\cite_engine natbib
|
43
|
+
\cite_engine_type authoryear
|
44
|
+
\biblio_style plainnat
|
45
|
+
\use_bibtopic false
|
46
|
+
\use_indices false
|
47
|
+
\paperorientation portrait
|
48
|
+
\suppress_date false
|
49
|
+
\justification true
|
50
|
+
\use_refstyle 0
|
51
|
+
\index Index
|
52
|
+
\shortcut idx
|
53
|
+
\color #008000
|
54
|
+
\end_index
|
55
|
+
\leftmargin 2.2cm
|
56
|
+
\topmargin 3cm
|
57
|
+
\rightmargin 2.2cm
|
58
|
+
\bottommargin 3cm
|
59
|
+
\secnumdepth 3
|
60
|
+
\tocdepth 3
|
61
|
+
\paragraph_separation indent
|
62
|
+
\paragraph_indentation default
|
63
|
+
\quotes_language english
|
64
|
+
\papercolumns 1
|
65
|
+
\papersides 1
|
66
|
+
\paperpagestyle default
|
67
|
+
\tracking_changes false
|
68
|
+
\output_changes false
|
69
|
+
\html_math_output 0
|
70
|
+
\html_css_as_file 0
|
71
|
+
\html_be_strict false
|
72
|
+
\end_header
|
73
|
+
|
74
|
+
\begin_body
|
75
|
+
|
76
|
+
\begin_layout Title
|
77
|
+
Introduction to Ruby for YPetri / YNelson Users
|
78
|
+
\end_layout
|
79
|
+
|
80
|
+
\begin_layout Standard
|
81
|
+
For
|
82
|
+
\family typewriter
|
83
|
+
YPetri
|
84
|
+
\family default
|
85
|
+
/
|
86
|
+
\family typewriter
|
87
|
+
YNelson
|
88
|
+
\family default
|
89
|
+
(further only
|
90
|
+
\family typewriter
|
91
|
+
YPetri
|
92
|
+
\family default
|
93
|
+
) users, basic Ruby syntax is necessary.
|
94
|
+
This document is a Ruby primer for
|
95
|
+
\family typewriter
|
96
|
+
YPetri
|
97
|
+
\family default
|
98
|
+
users.
|
99
|
+
This document should be used in the same way as
|
100
|
+
\family typewriter
|
101
|
+
YPetri
|
102
|
+
\family default
|
103
|
+
tutorial (Introduction to
|
104
|
+
\family typewriter
|
105
|
+
YPetri
|
106
|
+
\family default
|
107
|
+
) – that is, get an
|
108
|
+
\emph on
|
109
|
+
irb
|
110
|
+
\emph default
|
111
|
+
session running, and type all the examples in by yourself.
|
112
|
+
Line output is shown after
|
113
|
+
\family typewriter
|
114
|
+
#=>
|
115
|
+
\family default
|
116
|
+
.You might also wish to install
|
117
|
+
\family typewriter
|
118
|
+
YPetri
|
119
|
+
\family default
|
120
|
+
by by typing "
|
121
|
+
\family typewriter
|
122
|
+
gem install y_petri
|
123
|
+
\family default
|
124
|
+
" from your command line.
|
125
|
+
\end_layout
|
126
|
+
|
127
|
+
\begin_layout Standard
|
128
|
+
If you happen to be well familiar with Ruby, you do not need to read this
|
129
|
+
document at all.
|
130
|
+
Otherwise, this document is not a replacement for a Ruby textbook.
|
131
|
+
For more thorough introduction to the language, I recommend the document
|
132
|
+
|
133
|
+
\begin_inset CommandInset href
|
134
|
+
LatexCommand href
|
135
|
+
target "http://www.rubyist.net/~slagell/ruby/index.html"
|
136
|
+
|
137
|
+
\end_inset
|
138
|
+
|
139
|
+
, or a Ruby textbook.
|
140
|
+
\end_layout
|
141
|
+
|
142
|
+
\begin_layout Part*
|
143
|
+
Variables and constants
|
144
|
+
\end_layout
|
145
|
+
|
146
|
+
\begin_layout Standard
|
147
|
+
In Ruby, everything
|
148
|
+
\begin_inset Foot
|
149
|
+
status open
|
150
|
+
|
151
|
+
\begin_layout Plain Layout
|
152
|
+
Almost everything.
|
153
|
+
Non-objects include eg.
|
154
|
+
variables or argument fields.
|
155
|
+
\end_layout
|
156
|
+
|
157
|
+
\end_inset
|
158
|
+
|
159
|
+
is an
|
160
|
+
\emph on
|
161
|
+
\color red
|
162
|
+
object
|
163
|
+
\emph default
|
164
|
+
\color inherit
|
165
|
+
.
|
166
|
+
Objects can be assigned to
|
167
|
+
\emph on
|
168
|
+
\color red
|
169
|
+
variables
|
170
|
+
\emph default
|
171
|
+
\color inherit
|
172
|
+
or
|
173
|
+
\emph on
|
174
|
+
\color red
|
175
|
+
constants
|
176
|
+
\emph default
|
177
|
+
\color inherit
|
178
|
+
.
|
179
|
+
Ruby constants
|
180
|
+
\color red
|
181
|
+
must always start with capital letter
|
182
|
+
\color inherit
|
183
|
+
.
|
184
|
+
Variables starting with small letter are
|
185
|
+
\emph on
|
186
|
+
\color red
|
187
|
+
local variables
|
188
|
+
\emph default
|
189
|
+
\color inherit
|
190
|
+
.
|
191
|
+
(Other types of variables are
|
192
|
+
\emph on
|
193
|
+
\color red
|
194
|
+
instance variables
|
195
|
+
\emph default
|
196
|
+
\color inherit
|
197
|
+
,
|
198
|
+
\emph on
|
199
|
+
\color red
|
200
|
+
class variables
|
201
|
+
\emph default
|
202
|
+
\color inherit
|
203
|
+
and
|
204
|
+
\emph on
|
205
|
+
\color red
|
206
|
+
global constants
|
207
|
+
\emph default
|
208
|
+
\color inherit
|
209
|
+
; this is not important at the moment.)
|
210
|
+
\end_layout
|
211
|
+
|
212
|
+
\begin_layout LyX-Code
|
213
|
+
alpha = 1 #=> 1
|
214
|
+
\end_layout
|
215
|
+
|
216
|
+
\begin_layout LyX-Code
|
217
|
+
beta = [1, 2] #=> [1, 2]
|
218
|
+
\end_layout
|
219
|
+
|
220
|
+
\begin_layout LyX-Code
|
221
|
+
Gamma = { x: 1, y: 2, z: 3 } #=> {:x=>1, :y=>2, :z=>3}
|
222
|
+
\end_layout
|
223
|
+
|
224
|
+
\begin_layout Standard
|
225
|
+
You can check this using
|
226
|
+
\family typewriter
|
227
|
+
\color red
|
228
|
+
defined?
|
229
|
+
\family default
|
230
|
+
\color inherit
|
231
|
+
operator:
|
232
|
+
\end_layout
|
233
|
+
|
234
|
+
\begin_layout LyX-Code
|
235
|
+
defined? alpha #=> "local-variable"
|
236
|
+
\end_layout
|
237
|
+
|
238
|
+
\begin_layout LyX-Code
|
239
|
+
defined? Gamma #=> "constant"
|
240
|
+
\end_layout
|
241
|
+
|
242
|
+
\begin_layout Part*
|
243
|
+
Code lines and comments
|
244
|
+
\end_layout
|
245
|
+
|
246
|
+
\begin_layout Standard
|
247
|
+
Comments are denoted by
|
248
|
+
\family typewriter
|
249
|
+
#
|
250
|
+
\family default
|
251
|
+
sign.
|
252
|
+
Anything on the line following the
|
253
|
+
\family typewriter
|
254
|
+
#
|
255
|
+
\family default
|
256
|
+
sign is ignored:
|
257
|
+
\end_layout
|
258
|
+
|
259
|
+
\begin_layout LyX-Code
|
260
|
+
puts "Hello world!" # this line prints the words "Hello world!"
|
261
|
+
\end_layout
|
262
|
+
|
263
|
+
\begin_layout Standard
|
264
|
+
Ruby lines can be written with or without semicolons:
|
265
|
+
\end_layout
|
266
|
+
|
267
|
+
\begin_layout LyX-Code
|
268
|
+
a = "with";
|
269
|
+
\end_layout
|
270
|
+
|
271
|
+
\begin_layout LyX-Code
|
272
|
+
b = "without"
|
273
|
+
\end_layout
|
274
|
+
|
275
|
+
\begin_layout LyX-Code
|
276
|
+
puts [ a, b ].join " or "
|
277
|
+
\end_layout
|
278
|
+
|
279
|
+
\begin_layout Standard
|
280
|
+
Semicolon is compulsory only when two or more logical lines are crammed
|
281
|
+
together like this:
|
282
|
+
\end_layout
|
283
|
+
|
284
|
+
\begin_layout LyX-Code
|
285
|
+
a = "Hello"; b = "world!"; puts a + ' ' + b
|
286
|
+
\end_layout
|
287
|
+
|
288
|
+
\begin_layout Part*
|
289
|
+
Methods
|
290
|
+
\end_layout
|
291
|
+
|
292
|
+
\begin_layout Standard
|
293
|
+
Different classes respond to different
|
294
|
+
\emph on
|
295
|
+
\color red
|
296
|
+
methods
|
297
|
+
\emph default
|
298
|
+
\color inherit
|
299
|
+
, and respond to them differently:
|
300
|
+
\end_layout
|
301
|
+
|
302
|
+
\begin_layout LyX-Code
|
303
|
+
beta.
|
304
|
+
\color red
|
305
|
+
size
|
306
|
+
\color inherit
|
307
|
+
#=> 2
|
308
|
+
\end_layout
|
309
|
+
|
310
|
+
\begin_layout LyX-Code
|
311
|
+
Gamma.size #=> 3
|
312
|
+
\end_layout
|
313
|
+
|
314
|
+
\begin_layout LyX-Code
|
315
|
+
Gamma.
|
316
|
+
\color red
|
317
|
+
keys
|
318
|
+
\color inherit
|
319
|
+
#=> [:x, :y, :z]
|
320
|
+
\end_layout
|
321
|
+
|
322
|
+
\begin_layout LyX-Code
|
323
|
+
Gamma.
|
324
|
+
\color red
|
325
|
+
values
|
326
|
+
\color inherit
|
327
|
+
#=> [1, 2, 3]
|
328
|
+
\end_layout
|
329
|
+
|
330
|
+
\begin_layout LyX-Code
|
331
|
+
beta.keys #=> NoMethodError: undefined method `keys' for [1, 2]:Array
|
332
|
+
\end_layout
|
333
|
+
|
334
|
+
\begin_layout Standard
|
335
|
+
Methods can be defined by
|
336
|
+
\family typewriter
|
337
|
+
\color red
|
338
|
+
def
|
339
|
+
\family default
|
340
|
+
\color inherit
|
341
|
+
keyword:
|
342
|
+
\end_layout
|
343
|
+
|
344
|
+
\begin_layout LyX-Code
|
345
|
+
|
346
|
+
\color red
|
347
|
+
def
|
348
|
+
\color inherit
|
349
|
+
average( a, b )
|
350
|
+
\end_layout
|
351
|
+
|
352
|
+
\begin_layout LyX-Code
|
353
|
+
( a + b ).
|
354
|
+
\color red
|
355
|
+
to_f
|
356
|
+
\color inherit
|
357
|
+
/ 2
|
358
|
+
\end_layout
|
359
|
+
|
360
|
+
\begin_layout LyX-Code
|
361
|
+
|
362
|
+
\color red
|
363
|
+
end
|
364
|
+
\color inherit
|
365
|
+
#=> :average
|
366
|
+
\end_layout
|
367
|
+
|
368
|
+
\begin_layout LyX-Code
|
369
|
+
average( 2, 3 ) #=> 2.5
|
370
|
+
\end_layout
|
371
|
+
|
372
|
+
\begin_layout Standard
|
373
|
+
In the code example above, '
|
374
|
+
\family typewriter
|
375
|
+
to_f
|
376
|
+
\family default
|
377
|
+
' method performs conversion of an integer into a floating point number,
|
378
|
+
which is not important.
|
379
|
+
\end_layout
|
380
|
+
|
381
|
+
\begin_layout Part*
|
382
|
+
Classes
|
383
|
+
\end_layout
|
384
|
+
|
385
|
+
\begin_layout Standard
|
386
|
+
Every object belongs to some
|
387
|
+
\emph on
|
388
|
+
\color red
|
389
|
+
class
|
390
|
+
\emph default
|
391
|
+
\color inherit
|
392
|
+
(object type):
|
393
|
+
\end_layout
|
394
|
+
|
395
|
+
\begin_layout LyX-Code
|
396
|
+
alpha.
|
397
|
+
\color red
|
398
|
+
class
|
399
|
+
\color inherit
|
400
|
+
#=>
|
401
|
+
\color red
|
402
|
+
Fixnum
|
403
|
+
\end_layout
|
404
|
+
|
405
|
+
\begin_layout LyX-Code
|
406
|
+
beta.class #=>
|
407
|
+
\color red
|
408
|
+
Array
|
409
|
+
\end_layout
|
410
|
+
|
411
|
+
\begin_layout LyX-Code
|
412
|
+
Gamma.class #=>
|
413
|
+
\color red
|
414
|
+
Hash
|
415
|
+
\end_layout
|
416
|
+
|
417
|
+
\begin_layout Standard
|
418
|
+
New classes can be defined with
|
419
|
+
\family typewriter
|
420
|
+
\color red
|
421
|
+
class
|
422
|
+
\family default
|
423
|
+
\color inherit
|
424
|
+
keyword.
|
425
|
+
The methods defined inside the class will become the
|
426
|
+
\emph on
|
427
|
+
\color red
|
428
|
+
instance methods
|
429
|
+
\emph default
|
430
|
+
\color inherit
|
431
|
+
of that class:
|
432
|
+
\end_layout
|
433
|
+
|
434
|
+
\begin_layout LyX-Code
|
435
|
+
class Dog
|
436
|
+
\end_layout
|
437
|
+
|
438
|
+
\begin_layout LyX-Code
|
439
|
+
def speak!
|
440
|
+
\end_layout
|
441
|
+
|
442
|
+
\begin_layout LyX-Code
|
443
|
+
|
444
|
+
\color red
|
445
|
+
puts
|
446
|
+
\color inherit
|
447
|
+
"Bow wow!"
|
448
|
+
\end_layout
|
449
|
+
|
450
|
+
\begin_layout LyX-Code
|
451
|
+
end
|
452
|
+
\end_layout
|
453
|
+
|
454
|
+
\begin_layout LyX-Code
|
455
|
+
end #=> :speak!
|
456
|
+
\end_layout
|
457
|
+
|
458
|
+
\begin_layout LyX-Code
|
459
|
+
Spot = Dog.
|
460
|
+
\color red
|
461
|
+
new
|
462
|
+
\color inherit
|
463
|
+
#=> #<Dog:0x9c214ac>
|
464
|
+
\end_layout
|
465
|
+
|
466
|
+
\begin_layout LyX-Code
|
467
|
+
Spot.speak! #=> Bow wow!
|
468
|
+
\end_layout
|
469
|
+
|
470
|
+
\begin_layout LyX-Code
|
471
|
+
class Cat
|
472
|
+
\end_layout
|
473
|
+
|
474
|
+
\begin_layout LyX-Code
|
475
|
+
def speak!
|
476
|
+
\end_layout
|
477
|
+
|
478
|
+
\begin_layout LyX-Code
|
479
|
+
puts "Meow!"
|
480
|
+
\end_layout
|
481
|
+
|
482
|
+
\begin_layout LyX-Code
|
483
|
+
end
|
484
|
+
\end_layout
|
485
|
+
|
486
|
+
\begin_layout LyX-Code
|
487
|
+
end #=> :speak!
|
488
|
+
\end_layout
|
489
|
+
|
490
|
+
\begin_layout LyX-Code
|
491
|
+
Lisa = Cat.new #=> #<Cat:0x98efb80>
|
492
|
+
\end_layout
|
493
|
+
|
494
|
+
\begin_layout LyX-Code
|
495
|
+
Lisa.speak! #=> Meow
|
496
|
+
\end_layout
|
497
|
+
|
498
|
+
\begin_layout Standard
|
499
|
+
These two classes now represent respectively dogs and cats in your irb session.
|
500
|
+
In the code above, you could notice '
|
501
|
+
\family typewriter
|
502
|
+
new
|
503
|
+
\family default
|
504
|
+
' method, used to create instances from the defined classes, and '
|
505
|
+
\family typewriter
|
506
|
+
puts
|
507
|
+
\family default
|
508
|
+
' method, used to simply print characters on the screen.
|
509
|
+
\end_layout
|
510
|
+
|
511
|
+
\begin_layout Part*
|
512
|
+
Strings, Symbols, Arrays and Hashes
|
513
|
+
\end_layout
|
514
|
+
|
515
|
+
\begin_layout Standard
|
516
|
+
For
|
517
|
+
\family typewriter
|
518
|
+
YPetri
|
519
|
+
\family default
|
520
|
+
users, it will be especially necessary to learn more about
|
521
|
+
\emph on
|
522
|
+
\color red
|
523
|
+
strings
|
524
|
+
\emph default
|
525
|
+
\color inherit
|
526
|
+
,
|
527
|
+
\emph on
|
528
|
+
\color red
|
529
|
+
symbols
|
530
|
+
\emph default
|
531
|
+
\color inherit
|
532
|
+
,
|
533
|
+
\emph on
|
534
|
+
\color red
|
535
|
+
arrays
|
536
|
+
\emph default
|
537
|
+
\color inherit
|
538
|
+
,
|
539
|
+
\emph on
|
540
|
+
\color red
|
541
|
+
hashes
|
542
|
+
\emph default
|
543
|
+
\color inherit
|
544
|
+
, and how to define and read
|
545
|
+
\emph on
|
546
|
+
\color red
|
547
|
+
closures
|
548
|
+
\emph default
|
549
|
+
\color inherit
|
550
|
+
(aka.
|
551
|
+
|
552
|
+
\emph on
|
553
|
+
anonymous functions
|
554
|
+
\emph default
|
555
|
+
).
|
556
|
+
Strings and symbols are among the most basic Ruby objects, while arrays
|
557
|
+
and hashes are important in understanding
|
558
|
+
\emph on
|
559
|
+
\color red
|
560
|
+
argument passing
|
561
|
+
\emph default
|
562
|
+
\color inherit
|
563
|
+
to methods and closures.
|
564
|
+
|
565
|
+
\series bold
|
566
|
+
\color blue
|
567
|
+
Understanding argument passing and closure writing is essential in using
|
568
|
+
YPetri DSL.
|
569
|
+
\end_layout
|
570
|
+
|
571
|
+
\begin_layout Section*
|
572
|
+
Strings
|
573
|
+
\end_layout
|
574
|
+
|
575
|
+
\begin_layout Standard
|
576
|
+
A string is simply a sequence of characters, which can be defined using
|
577
|
+
single or double quotes (
|
578
|
+
\family typewriter
|
579
|
+
\color red
|
580
|
+
'
|
581
|
+
\family default
|
582
|
+
\color inherit
|
583
|
+
or
|
584
|
+
\family typewriter
|
585
|
+
\color red
|
586
|
+
"
|
587
|
+
\family default
|
588
|
+
\color inherit
|
589
|
+
):
|
590
|
+
\end_layout
|
591
|
+
|
592
|
+
\begin_layout LyX-Code
|
593
|
+
my_string = 'Hello world!' #=> "Hello world!"
|
594
|
+
\end_layout
|
595
|
+
|
596
|
+
\begin_layout LyX-Code
|
597
|
+
my_string.class #=>
|
598
|
+
\color red
|
599
|
+
String
|
600
|
+
\end_layout
|
601
|
+
|
602
|
+
\begin_layout Standard
|
603
|
+
Strings are mutable (can be changed):
|
604
|
+
\end_layout
|
605
|
+
|
606
|
+
\begin_layout LyX-Code
|
607
|
+
my_string.
|
608
|
+
\color red
|
609
|
+
object_id
|
610
|
+
\color inherit
|
611
|
+
#=> 81571950
|
612
|
+
\end_layout
|
613
|
+
|
614
|
+
\begin_layout LyX-Code
|
615
|
+
7.
|
616
|
+
\color red
|
617
|
+
times
|
618
|
+
\color inherit
|
619
|
+
|
620
|
+
\color red
|
621
|
+
do
|
622
|
+
\color inherit
|
623
|
+
my_string.
|
624
|
+
\color red
|
625
|
+
chop!
|
626
|
+
\color inherit
|
627
|
+
|
628
|
+
\color red
|
629
|
+
end
|
630
|
+
\color inherit
|
631
|
+
#=> 7
|
632
|
+
\end_layout
|
633
|
+
|
634
|
+
\begin_layout LyX-Code
|
635
|
+
my_string #=> "Hello"
|
636
|
+
\end_layout
|
637
|
+
|
638
|
+
\begin_layout LyX-Code
|
639
|
+
my_string.object_id #=> 81571950
|
640
|
+
\end_layout
|
641
|
+
|
642
|
+
\begin_layout LyX-Code
|
643
|
+
my_string.chop! #=>
|
644
|
+
\begin_inset Quotes eld
|
645
|
+
\end_inset
|
646
|
+
|
647
|
+
Hell
|
648
|
+
\begin_inset Quotes erd
|
649
|
+
\end_inset
|
650
|
+
|
651
|
+
|
652
|
+
\end_layout
|
653
|
+
|
654
|
+
\begin_layout LyX-Code
|
655
|
+
my_string.object_id #=> 81571950
|
656
|
+
\end_layout
|
657
|
+
|
658
|
+
\begin_layout Standard
|
659
|
+
Above, you can newly notice
|
660
|
+
\family typewriter
|
661
|
+
times
|
662
|
+
\family default
|
663
|
+
method,
|
664
|
+
\family typewriter
|
665
|
+
do ...
|
666
|
+
end
|
667
|
+
\family default
|
668
|
+
block, and
|
669
|
+
\family typewriter
|
670
|
+
chop!
|
671
|
+
\family default
|
672
|
+
method that removes the last character from
|
673
|
+
\family typewriter
|
674
|
+
my_string
|
675
|
+
\family default
|
676
|
+
7 times, until only
|
677
|
+
\family typewriter
|
678
|
+
"Hello"
|
679
|
+
\family default
|
680
|
+
remains.
|
681
|
+
But the important thing is that as
|
682
|
+
\family typewriter
|
683
|
+
object_id
|
684
|
+
\family default
|
685
|
+
method shows,
|
686
|
+
\family typewriter
|
687
|
+
my_string
|
688
|
+
\family default
|
689
|
+
is still the same object (same
|
690
|
+
\emph on
|
691
|
+
\color red
|
692
|
+
object id
|
693
|
+
\emph default
|
694
|
+
\color inherit
|
695
|
+
), although the contents is changed.
|
696
|
+
\end_layout
|
697
|
+
|
698
|
+
\begin_layout LyX-Code
|
699
|
+
my_string
|
700
|
+
\color red
|
701
|
+
<<
|
702
|
+
\color inherit
|
703
|
+
"o Spot!" #=> "Hello Spot!"
|
704
|
+
\end_layout
|
705
|
+
|
706
|
+
\begin_layout LyX-Code
|
707
|
+
my_string.object_id #=> 81571950
|
708
|
+
\end_layout
|
709
|
+
|
710
|
+
\begin_layout Standard
|
711
|
+
Again,
|
712
|
+
\family typewriter
|
713
|
+
<<
|
714
|
+
\family default
|
715
|
+
operator changed the contents, but the object id remained the same.
|
716
|
+
\end_layout
|
717
|
+
|
718
|
+
\begin_layout Section*
|
719
|
+
Symbols
|
720
|
+
\end_layout
|
721
|
+
|
722
|
+
\begin_layout Standard
|
723
|
+
Unlike strings, symbols are immutable – they never change.
|
724
|
+
They are written with colon (
|
725
|
+
\family typewriter
|
726
|
+
\color red
|
727
|
+
:
|
728
|
+
\family default
|
729
|
+
\color inherit
|
730
|
+
):
|
731
|
+
\end_layout
|
732
|
+
|
733
|
+
\begin_layout LyX-Code
|
734
|
+
:Spot.class #=>
|
735
|
+
\color red
|
736
|
+
Symbol
|
737
|
+
\end_layout
|
738
|
+
|
739
|
+
\begin_layout Section*
|
740
|
+
Arrays
|
741
|
+
\end_layout
|
742
|
+
|
743
|
+
\begin_layout Standard
|
744
|
+
As seen earlier, they can be defined with square brackets
|
745
|
+
\family typewriter
|
746
|
+
[]
|
747
|
+
\family default
|
748
|
+
.
|
749
|
+
Square brackets are also used to address the array elements, counting from
|
750
|
+
0.
|
751
|
+
\end_layout
|
752
|
+
|
753
|
+
\begin_layout LyX-Code
|
754
|
+
my_array = [ Spot, Lisa ] #=> [#<Dog:0x9c214ac>, #<Cat:0x98efb80>]
|
755
|
+
\end_layout
|
756
|
+
|
757
|
+
\begin_layout LyX-Code
|
758
|
+
my_array[0] #=> #<Dog:0x9c214ac>
|
759
|
+
\end_layout
|
760
|
+
|
761
|
+
\begin_layout Standard
|
762
|
+
Negative numbers can be used to address the elements from the end of the
|
763
|
+
array:
|
764
|
+
\end_layout
|
765
|
+
|
766
|
+
\begin_layout LyX-Code
|
767
|
+
my_array[-1] #=> #<Cat:0x98efb80>
|
768
|
+
\end_layout
|
769
|
+
|
770
|
+
\begin_layout LyX-Code
|
771
|
+
my_array[-2] #=> #<Dog:0x9c214ac>
|
772
|
+
\end_layout
|
773
|
+
|
774
|
+
\begin_layout Section*
|
775
|
+
Hashes
|
776
|
+
\end_layout
|
777
|
+
|
778
|
+
\begin_layout Standard
|
779
|
+
As for hashes, there are two ways of defining them.
|
780
|
+
The first way uses
|
781
|
+
\emph on
|
782
|
+
\color red
|
783
|
+
Ruby rocket
|
784
|
+
\emph default
|
785
|
+
\color inherit
|
786
|
+
(
|
787
|
+
\family typewriter
|
788
|
+
\color red
|
789
|
+
=>
|
790
|
+
\family default
|
791
|
+
\color inherit
|
792
|
+
):
|
793
|
+
\end_layout
|
794
|
+
|
795
|
+
\begin_layout LyX-Code
|
796
|
+
h1 = { Spot => "dog", Lisa => "cat" }
|
797
|
+
\end_layout
|
798
|
+
|
799
|
+
\begin_layout LyX-Code
|
800
|
+
#=> {#<Dog:0x9c214ac>=>"dog", #<Cat:0x98efb80>=>"cat"}
|
801
|
+
\end_layout
|
802
|
+
|
803
|
+
\begin_layout LyX-Code
|
804
|
+
h1[ Lisa ] #=> "cat"
|
805
|
+
\end_layout
|
806
|
+
|
807
|
+
\begin_layout LyX-Code
|
808
|
+
h1[ Spot ] #=> "dog"
|
809
|
+
\end_layout
|
810
|
+
|
811
|
+
\begin_layout Standard
|
812
|
+
The second way is possible only when the keys are symbols.
|
813
|
+
It is done by shifting the colon to the right side of the symbol:
|
814
|
+
\end_layout
|
815
|
+
|
816
|
+
\begin_layout LyX-Code
|
817
|
+
h2 = { dog: Spot, cat: Lisa }
|
818
|
+
\end_layout
|
819
|
+
|
820
|
+
\begin_layout LyX-Code
|
821
|
+
#=> {:dog=>#<Dog:0x9c214ac>, :cat=>#<Cat:0x98efb80>}
|
822
|
+
\end_layout
|
823
|
+
|
824
|
+
\begin_layout LyX-Code
|
825
|
+
h2[:dog] #=> #<Dog:0x9c214ac>
|
826
|
+
\end_layout
|
827
|
+
|
828
|
+
\begin_layout Part*
|
829
|
+
Code blocks and Closures
|
830
|
+
\end_layout
|
831
|
+
|
832
|
+
\begin_layout Standard
|
833
|
+
|
834
|
+
\emph on
|
835
|
+
\color red
|
836
|
+
Code blocks
|
837
|
+
\emph default
|
838
|
+
\color inherit
|
839
|
+
, or simply
|
840
|
+
\emph on
|
841
|
+
\color red
|
842
|
+
blocks
|
843
|
+
\emph default
|
844
|
+
\color inherit
|
845
|
+
, are pieces of code enclosed by
|
846
|
+
\family typewriter
|
847
|
+
\color red
|
848
|
+
do
|
849
|
+
\family default
|
850
|
+
\color inherit
|
851
|
+
/
|
852
|
+
\family typewriter
|
853
|
+
\color red
|
854
|
+
end
|
855
|
+
\family default
|
856
|
+
\color inherit
|
857
|
+
pair, or by curly brackets
|
858
|
+
\family typewriter
|
859
|
+
\color red
|
860
|
+
{}
|
861
|
+
\family default
|
862
|
+
\color inherit
|
863
|
+
.
|
864
|
+
Code blocks can be passed to methods:
|
865
|
+
\end_layout
|
866
|
+
|
867
|
+
\begin_layout LyX-Code
|
868
|
+
[1, 2, 3, 4].map
|
869
|
+
\color red
|
870
|
+
{ |
|
871
|
+
\color inherit
|
872
|
+
n
|
873
|
+
\color red
|
874
|
+
|
|
875
|
+
\color inherit
|
876
|
+
n + 3
|
877
|
+
\color red
|
878
|
+
}
|
879
|
+
\color inherit
|
880
|
+
#=> [4, 5, 6, 7]
|
881
|
+
\end_layout
|
882
|
+
|
883
|
+
\begin_layout LyX-Code
|
884
|
+
my_array.
|
885
|
+
\color red
|
886
|
+
each
|
887
|
+
\color inherit
|
888
|
+
do
|
889
|
+
\color red
|
890
|
+
|
|
891
|
+
\color inherit
|
892
|
+
member
|
893
|
+
\color red
|
894
|
+
|
|
895
|
+
\color inherit
|
896
|
+
member.speak! end
|
897
|
+
\end_layout
|
898
|
+
|
899
|
+
\begin_layout LyX-Code
|
900
|
+
#=> Bow wow! Meow!
|
901
|
+
\end_layout
|
902
|
+
|
903
|
+
\begin_layout Standard
|
904
|
+
In the first case, '
|
905
|
+
\family typewriter
|
906
|
+
map
|
907
|
+
\family default
|
908
|
+
' method was passed a block specifying addition of 3.
|
909
|
+
In the second case, '
|
910
|
+
\family typewriter
|
911
|
+
each
|
912
|
+
\family default
|
913
|
+
' method was passed a block calling
|
914
|
+
\family typewriter
|
915
|
+
speak!
|
916
|
+
\family default
|
917
|
+
method on the array elements.
|
918
|
+
Please note the pipe, or vertical line charecters (
|
919
|
+
\color red
|
920
|
+
|
|
921
|
+
\color inherit
|
922
|
+
), that delimit the block arguments (both blocks above happen to have only
|
923
|
+
one argument).
|
924
|
+
Code blocks can be understood as anonymous functions – a way of specifying
|
925
|
+
an operation, when one does not want to write a method for it.
|
926
|
+
Their semantics corresponds to
|
927
|
+
\emph on
|
928
|
+
lambda calculus
|
929
|
+
\emph default
|
930
|
+
.
|
931
|
+
\end_layout
|
932
|
+
|
933
|
+
\begin_layout Section*
|
934
|
+
Return values
|
935
|
+
\end_layout
|
936
|
+
|
937
|
+
\begin_layout Standard
|
938
|
+
Code blocks (and actually, all Ruby statements) have return value.
|
939
|
+
With code blocks, the return value will typically be the last statement:
|
940
|
+
\end_layout
|
941
|
+
|
942
|
+
\begin_layout LyX-Code
|
943
|
+
[1, 2, 3, 4].map { |v|
|
944
|
+
\end_layout
|
945
|
+
|
946
|
+
\begin_layout LyX-Code
|
947
|
+
v + 3 # this value will be ignored
|
948
|
+
\end_layout
|
949
|
+
|
950
|
+
\begin_layout LyX-Code
|
951
|
+
v - 1 # last value of the block will be returned
|
952
|
+
\end_layout
|
953
|
+
|
954
|
+
\begin_layout LyX-Code
|
955
|
+
}
|
956
|
+
\end_layout
|
957
|
+
|
958
|
+
\begin_layout LyX-Code
|
959
|
+
#=> [0, 1, 2, 3]
|
960
|
+
\end_layout
|
961
|
+
|
962
|
+
\begin_layout Section*
|
963
|
+
Closures
|
964
|
+
\end_layout
|
965
|
+
|
966
|
+
\begin_layout Standard
|
967
|
+
A block packaged for future use is called a
|
968
|
+
\emph on
|
969
|
+
\color red
|
970
|
+
closure
|
971
|
+
\emph default
|
972
|
+
\color inherit
|
973
|
+
.
|
974
|
+
Ruby closures come in two flavors:
|
975
|
+
\family typewriter
|
976
|
+
\color red
|
977
|
+
proc
|
978
|
+
\family default
|
979
|
+
\color inherit
|
980
|
+
and
|
981
|
+
\family typewriter
|
982
|
+
\color red
|
983
|
+
lambda
|
984
|
+
\family default
|
985
|
+
\color inherit
|
986
|
+
.
|
987
|
+
They are created by passing a block to the
|
988
|
+
\family typewriter
|
989
|
+
proc
|
990
|
+
\family default
|
991
|
+
/
|
992
|
+
\family typewriter
|
993
|
+
lambda
|
994
|
+
\family default
|
995
|
+
keyword:
|
996
|
+
\end_layout
|
997
|
+
|
998
|
+
\begin_layout LyX-Code
|
999
|
+
my_proc =
|
1000
|
+
\color red
|
1001
|
+
proc
|
1002
|
+
\color inherit
|
1003
|
+
do |organism| organism.speak! end
|
1004
|
+
\end_layout
|
1005
|
+
|
1006
|
+
\begin_layout LyX-Code
|
1007
|
+
#=> #<Proc:0x952674c@(irb):136>
|
1008
|
+
\end_layout
|
1009
|
+
|
1010
|
+
\begin_layout LyX-Code
|
1011
|
+
my_lambda =
|
1012
|
+
\color red
|
1013
|
+
lambda
|
1014
|
+
\color inherit
|
1015
|
+
do |organism| organism.speak! end
|
1016
|
+
\end_layout
|
1017
|
+
|
1018
|
+
\begin_layout LyX-Code
|
1019
|
+
#=> #<Proc:0x942faf0@(irb):137 (lambda)>
|
1020
|
+
\end_layout
|
1021
|
+
|
1022
|
+
\begin_layout Standard
|
1023
|
+
Once defined, they can be reused in code.
|
1024
|
+
Notice the ampersand (
|
1025
|
+
\family typewriter
|
1026
|
+
\color red
|
1027
|
+
&
|
1028
|
+
\family default
|
1029
|
+
\color inherit
|
1030
|
+
) indicating block reuse:
|
1031
|
+
\end_layout
|
1032
|
+
|
1033
|
+
\begin_layout LyX-Code
|
1034
|
+
my_array.each
|
1035
|
+
\color red
|
1036
|
+
&
|
1037
|
+
\color inherit
|
1038
|
+
my_proc #=> Bow wow! Meow!
|
1039
|
+
\end_layout
|
1040
|
+
|
1041
|
+
\begin_layout LyX-Code
|
1042
|
+
my_array.each &my_lambda #=> Bow wow! Meow!
|
1043
|
+
\end_layout
|
1044
|
+
|
1045
|
+
\begin_layout Standard
|
1046
|
+
Closures can also be called alone, a little bit like methods:
|
1047
|
+
\end_layout
|
1048
|
+
|
1049
|
+
\begin_layout LyX-Code
|
1050
|
+
my_proc.
|
1051
|
+
\color red
|
1052
|
+
call
|
1053
|
+
\color inherit
|
1054
|
+
( Spot ) #=> Bow wow!
|
1055
|
+
\end_layout
|
1056
|
+
|
1057
|
+
\begin_layout LyX-Code
|
1058
|
+
my_lambda.call( Lisa ) #=> Meow!
|
1059
|
+
\end_layout
|
1060
|
+
|
1061
|
+
\begin_layout Standard
|
1062
|
+
Instead of
|
1063
|
+
\family typewriter
|
1064
|
+
call
|
1065
|
+
\family default
|
1066
|
+
keyword, you can just use dot before the parenthesis to call closures:
|
1067
|
+
\end_layout
|
1068
|
+
|
1069
|
+
\begin_layout LyX-Code
|
1070
|
+
my_proc
|
1071
|
+
\color red
|
1072
|
+
.
|
1073
|
+
\color inherit
|
1074
|
+
( Lisa ) #=> Meow!
|
1075
|
+
\end_layout
|
1076
|
+
|
1077
|
+
\begin_layout LyX-Code
|
1078
|
+
my_lambda.( Spot ) #=> Bow wow!
|
1079
|
+
\end_layout
|
1080
|
+
|
1081
|
+
\begin_layout Standard
|
1082
|
+
Differences between
|
1083
|
+
\family typewriter
|
1084
|
+
proc
|
1085
|
+
\family default
|
1086
|
+
and
|
1087
|
+
\family typewriter
|
1088
|
+
lambda
|
1089
|
+
\family default
|
1090
|
+
closures are minor.
|
1091
|
+
For
|
1092
|
+
\family typewriter
|
1093
|
+
YNelson
|
1094
|
+
\family default
|
1095
|
+
users, the most noticeable difference will be, that
|
1096
|
+
\family typewriter
|
1097
|
+
proc
|
1098
|
+
\family default
|
1099
|
+
less finicky about its arguments than
|
1100
|
+
\family typewriter
|
1101
|
+
lambda
|
1102
|
+
\family default
|
1103
|
+
:
|
1104
|
+
\end_layout
|
1105
|
+
|
1106
|
+
\begin_layout LyX-Code
|
1107
|
+
my_proc.( Lisa, "garbage" ) #=> Meow!
|
1108
|
+
\end_layout
|
1109
|
+
|
1110
|
+
\begin_layout LyX-Code
|
1111
|
+
my_lambda.( Lisa, "garbage" )
|
1112
|
+
\end_layout
|
1113
|
+
|
1114
|
+
\begin_layout LyX-Code
|
1115
|
+
#=> ArgumentError: wrong number of arguments (2 for 1)
|
1116
|
+
\end_layout
|
1117
|
+
|
1118
|
+
\begin_layout Standard
|
1119
|
+
Finally, let us notice the alternative syntax for defining lambdas:
|
1120
|
+
\end_layout
|
1121
|
+
|
1122
|
+
\begin_layout LyX-Code
|
1123
|
+
my_lambda = lambda do |animal| animal.speak! end
|
1124
|
+
\end_layout
|
1125
|
+
|
1126
|
+
\begin_layout LyX-Code
|
1127
|
+
my_lambda = lambda { |animal| animal.speak! }
|
1128
|
+
\end_layout
|
1129
|
+
|
1130
|
+
\begin_layout LyX-Code
|
1131
|
+
my_lambda =
|
1132
|
+
\color red
|
1133
|
+
->
|
1134
|
+
\color inherit
|
1135
|
+
animal do animal.speak! end
|
1136
|
+
\end_layout
|
1137
|
+
|
1138
|
+
\begin_layout LyX-Code
|
1139
|
+
my_lambda = -> animal { animal.speak! }
|
1140
|
+
\end_layout
|
1141
|
+
|
1142
|
+
\begin_layout Standard
|
1143
|
+
All of the four above statements define exactly the same thing.
|
1144
|
+
\end_layout
|
1145
|
+
|
1146
|
+
\begin_layout Section*
|
1147
|
+
Passing arguments
|
1148
|
+
\end_layout
|
1149
|
+
|
1150
|
+
\begin_layout Standard
|
1151
|
+
Earlier, we have defined method
|
1152
|
+
\family typewriter
|
1153
|
+
average
|
1154
|
+
\family default
|
1155
|
+
, expecting two arguments.
|
1156
|
+
If wrong number of arguments is supplied,
|
1157
|
+
\family typewriter
|
1158
|
+
ArgumentError
|
1159
|
+
\family default
|
1160
|
+
will ensue:
|
1161
|
+
\end_layout
|
1162
|
+
|
1163
|
+
\begin_layout LyX-Code
|
1164
|
+
average( 3, 5 ) #=> 4
|
1165
|
+
\end_layout
|
1166
|
+
|
1167
|
+
\begin_layout LyX-Code
|
1168
|
+
average( 3, 5, 8 ) #=> ArgumentError: wrong number of arguments (3
|
1169
|
+
for 2)
|
1170
|
+
\end_layout
|
1171
|
+
|
1172
|
+
\begin_layout Standard
|
1173
|
+
Obviously, this is not a very nice behavior when it comes to averages.
|
1174
|
+
It is a general situation, that when calling more advanced methods, we
|
1175
|
+
need to modify their behavior, or pass more complicated structures to them.
|
1176
|
+
This is seen eg.
|
1177
|
+
with
|
1178
|
+
\family typewriter
|
1179
|
+
YNelson::Transition
|
1180
|
+
\family default
|
1181
|
+
constructors, and will be further encountered in
|
1182
|
+
\family typewriter
|
1183
|
+
YCell
|
1184
|
+
\family default
|
1185
|
+
and
|
1186
|
+
\family typewriter
|
1187
|
+
YChem
|
1188
|
+
\family default
|
1189
|
+
DSLs.
|
1190
|
+
Furthermore,
|
1191
|
+
\family typewriter
|
1192
|
+
YNelson
|
1193
|
+
\family default
|
1194
|
+
users have to be able to write their own closures, because that is how
|
1195
|
+
|
1196
|
+
\emph on
|
1197
|
+
functions
|
1198
|
+
\emph default
|
1199
|
+
of
|
1200
|
+
\emph on
|
1201
|
+
functional transitions
|
1202
|
+
\emph default
|
1203
|
+
are specified.
|
1204
|
+
In other words,
|
1205
|
+
\family typewriter
|
1206
|
+
\series bold
|
1207
|
+
YNelson
|
1208
|
+
\family default
|
1209
|
+
users have to master argument passing from both user and programmer side
|
1210
|
+
\series default
|
1211
|
+
.
|
1212
|
+
There is no way around this.
|
1213
|
+
With functional Petri nets, one cannot avoid writing functions.
|
1214
|
+
It is possible to avoid using
|
1215
|
+
\family typewriter
|
1216
|
+
YNelson
|
1217
|
+
\family default
|
1218
|
+
, but it is not possible to avoid learning to write functions.
|
1219
|
+
Every simulator of functional Petri nets brings with itself some sort of
|
1220
|
+
function language, which one has to learn.
|
1221
|
+
With
|
1222
|
+
\family typewriter
|
1223
|
+
YNelson
|
1224
|
+
\family default
|
1225
|
+
, this is the language of Ruby closures.
|
1226
|
+
\end_layout
|
1227
|
+
|
1228
|
+
\begin_layout Section*
|
1229
|
+
Optional arguments
|
1230
|
+
\end_layout
|
1231
|
+
|
1232
|
+
\begin_layout Standard
|
1233
|
+
Arguments with prescribed default value are optional.
|
1234
|
+
Let us write an improved
|
1235
|
+
\family typewriter
|
1236
|
+
average
|
1237
|
+
\family default
|
1238
|
+
method that can accept either 2 or 3 arguments:
|
1239
|
+
\end_layout
|
1240
|
+
|
1241
|
+
\begin_layout LyX-Code
|
1242
|
+
def average( a, b, c
|
1243
|
+
\color red
|
1244
|
+
=
|
1245
|
+
\color inherit
|
1246
|
+
nil )
|
1247
|
+
\end_layout
|
1248
|
+
|
1249
|
+
\begin_layout LyX-Code
|
1250
|
+
|
1251
|
+
\color red
|
1252
|
+
#
|
1253
|
+
\color inherit
|
1254
|
+
If c argument was not given, it will default to nil
|
1255
|
+
\end_layout
|
1256
|
+
|
1257
|
+
\begin_layout LyX-Code
|
1258
|
+
|
1259
|
+
\color red
|
1260
|
+
if
|
1261
|
+
\color inherit
|
1262
|
+
c
|
1263
|
+
\color red
|
1264
|
+
==
|
1265
|
+
\color inherit
|
1266
|
+
nil
|
1267
|
+
\color red
|
1268
|
+
then
|
1269
|
+
\end_layout
|
1270
|
+
|
1271
|
+
\begin_layout LyX-Code
|
1272
|
+
( a + b ).to_f / 2
|
1273
|
+
\end_layout
|
1274
|
+
|
1275
|
+
\begin_layout LyX-Code
|
1276
|
+
|
1277
|
+
\color red
|
1278
|
+
else
|
1279
|
+
\end_layout
|
1280
|
+
|
1281
|
+
\begin_layout LyX-Code
|
1282
|
+
( a + b + c ).to_f / 3
|
1283
|
+
\end_layout
|
1284
|
+
|
1285
|
+
\begin_layout LyX-Code
|
1286
|
+
|
1287
|
+
\color red
|
1288
|
+
end
|
1289
|
+
\end_layout
|
1290
|
+
|
1291
|
+
\begin_layout LyX-Code
|
1292
|
+
end #=> :average
|
1293
|
+
\end_layout
|
1294
|
+
|
1295
|
+
\begin_layout LyX-Code
|
1296
|
+
average( 3, 5 ) #=> 4
|
1297
|
+
\end_layout
|
1298
|
+
|
1299
|
+
\begin_layout LyX-Code
|
1300
|
+
average( 3, 5, 8 ) #=> 5.333333333333333
|
1301
|
+
\end_layout
|
1302
|
+
|
1303
|
+
\begin_layout LyX-Code
|
1304
|
+
average( 1, 2, 3, 4 ) #=> ArgumentError: wrong number of arguments
|
1305
|
+
(4 for 3)
|
1306
|
+
\end_layout
|
1307
|
+
|
1308
|
+
\begin_layout Standard
|
1309
|
+
The default value for
|
1310
|
+
\family typewriter
|
1311
|
+
c
|
1312
|
+
\family default
|
1313
|
+
argument is prescribed using single equals sign (
|
1314
|
+
\family typewriter
|
1315
|
+
\color red
|
1316
|
+
=
|
1317
|
+
\family default
|
1318
|
+
\color inherit
|
1319
|
+
).
|
1320
|
+
Apart from that, you can notice
|
1321
|
+
\family typewriter
|
1322
|
+
\color red
|
1323
|
+
if
|
1324
|
+
\family default
|
1325
|
+
\color inherit
|
1326
|
+
...
|
1327
|
+
|
1328
|
+
\family typewriter
|
1329
|
+
\color red
|
1330
|
+
then
|
1331
|
+
\family default
|
1332
|
+
\color inherit
|
1333
|
+
...
|
1334
|
+
|
1335
|
+
\family typewriter
|
1336
|
+
\color red
|
1337
|
+
else
|
1338
|
+
\family default
|
1339
|
+
\color inherit
|
1340
|
+
...
|
1341
|
+
|
1342
|
+
\family typewriter
|
1343
|
+
\color red
|
1344
|
+
end
|
1345
|
+
\family default
|
1346
|
+
\color inherit
|
1347
|
+
statement, which needs no explanation, equality test (double equals sign,
|
1348
|
+
|
1349
|
+
\family typewriter
|
1350
|
+
\color red
|
1351
|
+
==
|
1352
|
+
\family default
|
1353
|
+
\color inherit
|
1354
|
+
), used to test whether
|
1355
|
+
\family typewriter
|
1356
|
+
c
|
1357
|
+
\family default
|
1358
|
+
contains
|
1359
|
+
\family typewriter
|
1360
|
+
:pochi
|
1361
|
+
\family default
|
1362
|
+
symbol (indicating missing value), and comment character (octothorpe aka.
|
1363
|
+
sharp,
|
1364
|
+
\family typewriter
|
1365
|
+
\color red
|
1366
|
+
#
|
1367
|
+
\family default
|
1368
|
+
\color inherit
|
1369
|
+
).
|
1370
|
+
Comment character
|
1371
|
+
\family typewriter
|
1372
|
+
\color red
|
1373
|
+
#
|
1374
|
+
\family default
|
1375
|
+
\color inherit
|
1376
|
+
causes all characters until the end of the line to be ignored by Ruby.
|
1377
|
+
All code lines, exception the obvious ones, should have comments.
|
1378
|
+
\end_layout
|
1379
|
+
|
1380
|
+
\begin_layout Section*
|
1381
|
+
Variable-length argument lists
|
1382
|
+
\end_layout
|
1383
|
+
|
1384
|
+
\begin_layout Standard
|
1385
|
+
We will now improve our
|
1386
|
+
\family typewriter
|
1387
|
+
average
|
1388
|
+
\family default
|
1389
|
+
method, so that it can calculate averages of any number of arguments.
|
1390
|
+
For this, we will use asterisk (
|
1391
|
+
\family typewriter
|
1392
|
+
\color red
|
1393
|
+
*
|
1394
|
+
\family default
|
1395
|
+
\color inherit
|
1396
|
+
) syntactic modifier, also known as
|
1397
|
+
\emph on
|
1398
|
+
splash
|
1399
|
+
\emph default
|
1400
|
+
.
|
1401
|
+
The asterisk will cause a method to collect the arguments into an array.
|
1402
|
+
Let's try it out first:
|
1403
|
+
\end_layout
|
1404
|
+
|
1405
|
+
\begin_layout LyX-Code
|
1406
|
+
def examine_arguments( x,
|
1407
|
+
\color red
|
1408
|
+
*
|
1409
|
+
\color inherit
|
1410
|
+
aa )
|
1411
|
+
\end_layout
|
1412
|
+
|
1413
|
+
\begin_layout LyX-Code
|
1414
|
+
puts "x is a
|
1415
|
+
\color red
|
1416
|
+
#{
|
1417
|
+
\color inherit
|
1418
|
+
x.class
|
1419
|
+
\color red
|
1420
|
+
}
|
1421
|
+
\color inherit
|
1422
|
+
."
|
1423
|
+
\end_layout
|
1424
|
+
|
1425
|
+
\begin_layout LyX-Code
|
1426
|
+
puts "aa is #{aa.class} of #{aa.size} elements."
|
1427
|
+
\end_layout
|
1428
|
+
|
1429
|
+
\begin_layout LyX-Code
|
1430
|
+
end #=> :examine_arguments
|
1431
|
+
\end_layout
|
1432
|
+
|
1433
|
+
\begin_layout Standard
|
1434
|
+
Method examine arguments takes one normal argument (
|
1435
|
+
\family typewriter
|
1436
|
+
x
|
1437
|
+
\family default
|
1438
|
+
), and collects the rest of the arguments into an array (
|
1439
|
+
\family typewriter
|
1440
|
+
aa
|
1441
|
+
\family default
|
1442
|
+
), thanks to the splash modifier.
|
1443
|
+
(Apart from that, you can notice string interpolation using
|
1444
|
+
\family typewriter
|
1445
|
+
#{ ...
|
1446
|
+
}
|
1447
|
+
\family default
|
1448
|
+
notation in the above code.) Then it prints the class of
|
1449
|
+
\family typewriter
|
1450
|
+
x
|
1451
|
+
\family default
|
1452
|
+
, class of
|
1453
|
+
\family typewriter
|
1454
|
+
aa
|
1455
|
+
\family default
|
1456
|
+
(which should be an array), and the number of elements after
|
1457
|
+
\family typewriter
|
1458
|
+
x
|
1459
|
+
\family default
|
1460
|
+
.
|
1461
|
+
\end_layout
|
1462
|
+
|
1463
|
+
\begin_layout LyX-Code
|
1464
|
+
examine_arguments( 1 )
|
1465
|
+
\end_layout
|
1466
|
+
|
1467
|
+
\begin_layout LyX-Code
|
1468
|
+
#=> x is a Fixnum.
|
1469
|
+
\end_layout
|
1470
|
+
|
1471
|
+
\begin_layout LyX-Code
|
1472
|
+
aa is Array of 0 elements.
|
1473
|
+
\end_layout
|
1474
|
+
|
1475
|
+
\begin_layout LyX-Code
|
1476
|
+
nil
|
1477
|
+
\end_layout
|
1478
|
+
|
1479
|
+
\begin_layout LyX-Code
|
1480
|
+
examine_arguments( :hello, nil, 3, 5, "a string" )
|
1481
|
+
\end_layout
|
1482
|
+
|
1483
|
+
\begin_layout LyX-Code
|
1484
|
+
#=> x is a Symbol.
|
1485
|
+
\end_layout
|
1486
|
+
|
1487
|
+
\begin_layout LyX-Code
|
1488
|
+
aa is Array of 4 elements.
|
1489
|
+
\end_layout
|
1490
|
+
|
1491
|
+
\begin_layout LyX-Code
|
1492
|
+
nil
|
1493
|
+
\end_layout
|
1494
|
+
|
1495
|
+
\begin_layout Standard
|
1496
|
+
With this, we can go on to define our improved average method:
|
1497
|
+
\end_layout
|
1498
|
+
|
1499
|
+
\begin_layout LyX-Code
|
1500
|
+
def average( *aa )
|
1501
|
+
\end_layout
|
1502
|
+
|
1503
|
+
\begin_layout LyX-Code
|
1504
|
+
aa.
|
1505
|
+
\color red
|
1506
|
+
reduce( :+ )
|
1507
|
+
\color inherit
|
1508
|
+
.to_f / aa.size
|
1509
|
+
\end_layout
|
1510
|
+
|
1511
|
+
\begin_layout LyX-Code
|
1512
|
+
end #=> :average
|
1513
|
+
\end_layout
|
1514
|
+
|
1515
|
+
\begin_layout LyX-Code
|
1516
|
+
average 3, 5, 7, 11 #=> 6.5
|
1517
|
+
\end_layout
|
1518
|
+
|
1519
|
+
\begin_layout Standard
|
1520
|
+
You can also newly notice
|
1521
|
+
\family typewriter
|
1522
|
+
reduce( :+ )
|
1523
|
+
\family default
|
1524
|
+
method, used to calculate the sum of the
|
1525
|
+
\family typewriter
|
1526
|
+
aa
|
1527
|
+
\family default
|
1528
|
+
array.
|
1529
|
+
To also practice closures, let us define a lambda doing the same as the
|
1530
|
+
|
1531
|
+
\family typewriter
|
1532
|
+
average
|
1533
|
+
\family default
|
1534
|
+
method above:
|
1535
|
+
\end_layout
|
1536
|
+
|
1537
|
+
\begin_layout LyX-Code
|
1538
|
+
avg = lambda { |*aa| aa.reduce( :+ ).to_f / aa.size }
|
1539
|
+
\end_layout
|
1540
|
+
|
1541
|
+
\begin_layout LyX-Code
|
1542
|
+
#=> #<Proc:0x9dbd220@(irb):208 (lambda)>
|
1543
|
+
\end_layout
|
1544
|
+
|
1545
|
+
\begin_layout LyX-Code
|
1546
|
+
avg.( 11, 7, 5, 3 ) #=> 6.5
|
1547
|
+
\end_layout
|
1548
|
+
|
1549
|
+
\begin_layout Section*
|
1550
|
+
Named arguments
|
1551
|
+
\end_layout
|
1552
|
+
|
1553
|
+
\begin_layout Standard
|
1554
|
+
The main purpose of named arguments is to make the interface (or DSL) easier
|
1555
|
+
to remember, and the code easier to read.
|
1556
|
+
Easy-to-read code is a crucial requirement for scalable development.
|
1557
|
+
In Ruby methods, named arguments can be specified
|
1558
|
+
\color red
|
1559
|
+
as hash pairs in the method call
|
1560
|
+
\color inherit
|
1561
|
+
:
|
1562
|
+
\end_layout
|
1563
|
+
|
1564
|
+
\begin_layout LyX-Code
|
1565
|
+
def density( x: 1, y: 1, z: 1, weight: 1 )
|
1566
|
+
\end_layout
|
1567
|
+
|
1568
|
+
\begin_layout LyX-Code
|
1569
|
+
weight.to_f / ( x * y * z )
|
1570
|
+
\end_layout
|
1571
|
+
|
1572
|
+
\begin_layout LyX-Code
|
1573
|
+
end #=> :density
|
1574
|
+
\end_layout
|
1575
|
+
|
1576
|
+
\begin_layout LyX-Code
|
1577
|
+
density( x: 2, y: 2, z: 2, weight: 10 ) #=> 1.25
|
1578
|
+
\end_layout
|
1579
|
+
|
1580
|
+
\begin_layout Standard
|
1581
|
+
The above method calculates mean density of boxes of certain height, width,
|
1582
|
+
length and weight.
|
1583
|
+
Double splash (
|
1584
|
+
\family typewriter
|
1585
|
+
\color red
|
1586
|
+
**
|
1587
|
+
\family default
|
1588
|
+
\color inherit
|
1589
|
+
) can be used to collect all the options in a hash.
|
1590
|
+
Let's use it to define a closure that does exactly the same thing as the
|
1591
|
+
method
|
1592
|
+
\family typewriter
|
1593
|
+
density
|
1594
|
+
\family default
|
1595
|
+
we have just defined, in a slightly different way:
|
1596
|
+
\end_layout
|
1597
|
+
|
1598
|
+
\begin_layout LyX-Code
|
1599
|
+
dens_closure =
|
1600
|
+
\color red
|
1601
|
+
->
|
1602
|
+
\color inherit
|
1603
|
+
**nn do
|
1604
|
+
\end_layout
|
1605
|
+
|
1606
|
+
\begin_layout LyX-Code
|
1607
|
+
nn[:weight].to_f / ( nn[:x] * nn[:y] * nn[:z] ) end
|
1608
|
+
\end_layout
|
1609
|
+
|
1610
|
+
\begin_layout LyX-Code
|
1611
|
+
#=> #<Proc:0x9a5d60c@(irb):241 (lambda)>
|
1612
|
+
\end_layout
|
1613
|
+
|
1614
|
+
\begin_layout LyX-Code
|
1615
|
+
dens_closure.( x: 2, y: 2, z: 2, weight: 10 ) #=> 1.25
|
1616
|
+
\end_layout
|
1617
|
+
|
1618
|
+
\begin_layout Standard
|
1619
|
+
Above, note the alternative syntax for lambdas:
|
1620
|
+
\family typewriter
|
1621
|
+
-> arg do ...
|
1622
|
+
end
|
1623
|
+
\family default
|
1624
|
+
is the same as
|
1625
|
+
\family typewriter
|
1626
|
+
lambda do |arg| ...
|
1627
|
+
end
|
1628
|
+
\family default
|
1629
|
+
.
|
1630
|
+
Having hereby introduced the named arguments, let us notice hash-collecting
|
1631
|
+
behavior for square bracket (
|
1632
|
+
\family typewriter
|
1633
|
+
[]
|
1634
|
+
\family default
|
1635
|
+
) array constructor syntax.
|
1636
|
+
\end_layout
|
1637
|
+
|
1638
|
+
\begin_layout Section*
|
1639
|
+
Hash-collecting behavior of square brackets
|
1640
|
+
\end_layout
|
1641
|
+
|
1642
|
+
\begin_layout Standard
|
1643
|
+
In more complicated method argument structures, it can be advantageous to
|
1644
|
+
take use of the hash-collecting by square brackets.
|
1645
|
+
It is normal for curly braces to create hashes:
|
1646
|
+
\end_layout
|
1647
|
+
|
1648
|
+
\begin_layout LyX-Code
|
1649
|
+
h = { x: 2, y: 3, z: 4 } #=> {:x=>2, :y=>3, :z=>4}
|
1650
|
+
\end_layout
|
1651
|
+
|
1652
|
+
\begin_layout LyX-Code
|
1653
|
+
h.class #=> Hash
|
1654
|
+
\end_layout
|
1655
|
+
|
1656
|
+
\begin_layout Standard
|
1657
|
+
However, square brackets, that generally create arrays, are also
|
1658
|
+
\color red
|
1659
|
+
able to collect hashes just like the argument fields with named arguments
|
1660
|
+
\color inherit
|
1661
|
+
:
|
1662
|
+
\end_layout
|
1663
|
+
|
1664
|
+
\begin_layout LyX-Code
|
1665
|
+
a0 = [ 1, 2, 3 ] #=> [1, 2, 3]
|
1666
|
+
\end_layout
|
1667
|
+
|
1668
|
+
\begin_layout LyX-Code
|
1669
|
+
a0.class #=> Array
|
1670
|
+
\end_layout
|
1671
|
+
|
1672
|
+
\begin_layout LyX-Code
|
1673
|
+
a1 = [ 1, 2, 3, x: 2, y: 3, z: 4 ] #=> [1, 2, 3, {:x=>2, :y=>3, :z=>4}]
|
1674
|
+
\end_layout
|
1675
|
+
|
1676
|
+
\begin_layout LyX-Code
|
1677
|
+
a1.class #=> Array
|
1678
|
+
\end_layout
|
1679
|
+
|
1680
|
+
\begin_layout LyX-Code
|
1681
|
+
a1.map &:class #=> [Fixnum, Fixnum, Fixnum, Hash]
|
1682
|
+
\end_layout
|
1683
|
+
|
1684
|
+
\begin_layout LyX-Code
|
1685
|
+
a1[-1] #=> {:x=>2, :y=>3, :z=>4}
|
1686
|
+
\end_layout
|
1687
|
+
|
1688
|
+
\begin_layout Standard
|
1689
|
+
In other words, if there are any trailing
|
1690
|
+
\family typewriter
|
1691
|
+
key/value
|
1692
|
+
\family default
|
1693
|
+
pairs inside square brackets, they will be collected into a hash, which
|
1694
|
+
will become the last element of the array.
|
1695
|
+
This possibility to mix ordered elements with
|
1696
|
+
\family typewriter
|
1697
|
+
key/value
|
1698
|
+
\family default
|
1699
|
+
pairs is used eg.
|
1700
|
+
in
|
1701
|
+
\family typewriter
|
1702
|
+
YCell
|
1703
|
+
\family default
|
1704
|
+
|
1705
|
+
\family typewriter
|
1706
|
+
enzyme
|
1707
|
+
\family default
|
1708
|
+
constructor method.
|
1709
|
+
\end_layout
|
1710
|
+
|
1711
|
+
\begin_layout Section*
|
1712
|
+
Arity
|
1713
|
+
\end_layout
|
1714
|
+
|
1715
|
+
\begin_layout Standard
|
1716
|
+
Every closure and every method has arity, which is basically the number
|
1717
|
+
of input arguments.
|
1718
|
+
(Closures with 0 arguments are null
|
1719
|
+
\emph on
|
1720
|
+
ary
|
1721
|
+
\emph default
|
1722
|
+
, with 1 argument un
|
1723
|
+
\emph on
|
1724
|
+
ary
|
1725
|
+
\emph default
|
1726
|
+
, with 2 arguments bin
|
1727
|
+
\emph on
|
1728
|
+
ary
|
1729
|
+
\emph default
|
1730
|
+
, with 3 arguments tern
|
1731
|
+
\emph on
|
1732
|
+
ary
|
1733
|
+
\emph default
|
1734
|
+
etc.
|
1735
|
+
– therefrom
|
1736
|
+
\emph on
|
1737
|
+
arity
|
1738
|
+
\emph default
|
1739
|
+
.)
|
1740
|
+
\end_layout
|
1741
|
+
|
1742
|
+
\begin_layout LyX-Code
|
1743
|
+
doubler = lambda { |a| a * 2 } #=> #<Proc:0xa19b5b8@(irb):1 (lambda)>
|
1744
|
+
\end_layout
|
1745
|
+
|
1746
|
+
\begin_layout LyX-Code
|
1747
|
+
doubler.call( 3 ) #=> 6
|
1748
|
+
\end_layout
|
1749
|
+
|
1750
|
+
\begin_layout LyX-Code
|
1751
|
+
doubler.arity #=> 1
|
1752
|
+
\end_layout
|
1753
|
+
|
1754
|
+
\begin_layout LyX-Code
|
1755
|
+
adder = -> p, q { p + q } #=> #<Proc:0xa27d940@(irb):6 (lambda)>
|
1756
|
+
\end_layout
|
1757
|
+
|
1758
|
+
\begin_layout LyX-Code
|
1759
|
+
adder.call( 5, 6 ) #=> 11
|
1760
|
+
\end_layout
|
1761
|
+
|
1762
|
+
\begin_layout LyX-Code
|
1763
|
+
adder.arity #=> 2
|
1764
|
+
\end_layout
|
1765
|
+
|
1766
|
+
\begin_layout LyX-Code
|
1767
|
+
scaler = -> number, p, q { number * ( q.to_f / p ) }
|
1768
|
+
\end_layout
|
1769
|
+
|
1770
|
+
\begin_layout LyX-Code
|
1771
|
+
#=> #<Proc:0xa2825e4@(irb):7 (lambda)>
|
1772
|
+
\end_layout
|
1773
|
+
|
1774
|
+
\begin_layout LyX-Code
|
1775
|
+
scaler.call( 10, 2, 5 ) #=> 25.0
|
1776
|
+
\end_layout
|
1777
|
+
|
1778
|
+
\begin_layout LyX-Code
|
1779
|
+
scaler.arity #=> 3
|
1780
|
+
\end_layout
|
1781
|
+
|
1782
|
+
\begin_layout LyX-Code
|
1783
|
+
constant_function = -> { 42 } #=> #<Proc:0xa2825e4@(irb):7 (lambda)>
|
1784
|
+
\end_layout
|
1785
|
+
|
1786
|
+
\begin_layout LyX-Code
|
1787
|
+
constant_function.call #=> 42
|
1788
|
+
\end_layout
|
1789
|
+
|
1790
|
+
\begin_layout LyX-Code
|
1791
|
+
constant_function.arity #=> 0
|
1792
|
+
\end_layout
|
1793
|
+
|
1794
|
+
\begin_layout Standard
|
1795
|
+
Closures / methods with variable length arguments indicate this by reporting
|
1796
|
+
negative arity:
|
1797
|
+
\end_layout
|
1798
|
+
|
1799
|
+
\begin_layout LyX-Code
|
1800
|
+
summation = -> *array { array.reduce( :+ ) }
|
1801
|
+
\end_layout
|
1802
|
+
|
1803
|
+
\begin_layout LyX-Code
|
1804
|
+
#=> #<Proc:0xa296ddc@(irb):9 (lambda)>
|
1805
|
+
\end_layout
|
1806
|
+
|
1807
|
+
\begin_layout LyX-Code
|
1808
|
+
summation.call( 1, 2, 3, 4 ) #=> 10
|
1809
|
+
\end_layout
|
1810
|
+
|
1811
|
+
\begin_layout LyX-Code
|
1812
|
+
summation.arity #=> -1
|
1813
|
+
\end_layout
|
1814
|
+
|
1815
|
+
\begin_layout LyX-Code
|
1816
|
+
array_scale = -> *a, coeff { a.map { |e| e * coeff } }
|
1817
|
+
\end_layout
|
1818
|
+
|
1819
|
+
\begin_layout LyX-Code
|
1820
|
+
#=> #<Proc:0xa2a9edc@(irb):12 (lambda)>
|
1821
|
+
\end_layout
|
1822
|
+
|
1823
|
+
\begin_layout LyX-Code
|
1824
|
+
array_scale.call( 1, 2, 3, 4, 7 ) #=> [7, 14, 21, 28]
|
1825
|
+
\end_layout
|
1826
|
+
|
1827
|
+
\begin_layout LyX-Code
|
1828
|
+
array_scale.arity #=> -2
|
1829
|
+
\end_layout
|
1830
|
+
|
1831
|
+
\begin_layout Section*
|
1832
|
+
Return value
|
1833
|
+
\end_layout
|
1834
|
+
|
1835
|
+
\begin_layout Standard
|
1836
|
+
The last statement in a closure or method becomes the return value.
|
1837
|
+
In methods and lambda-type closures, return statement can also be used
|
1838
|
+
explicitly:
|
1839
|
+
\end_layout
|
1840
|
+
|
1841
|
+
\begin_layout LyX-Code
|
1842
|
+
divider = -> u, v {
|
1843
|
+
\end_layout
|
1844
|
+
|
1845
|
+
\begin_layout LyX-Code
|
1846
|
+
if v == 0 then
|
1847
|
+
\end_layout
|
1848
|
+
|
1849
|
+
\begin_layout LyX-Code
|
1850
|
+
return :division_by_zero # explicit return
|
1851
|
+
\end_layout
|
1852
|
+
|
1853
|
+
\begin_layout LyX-Code
|
1854
|
+
end
|
1855
|
+
\end_layout
|
1856
|
+
|
1857
|
+
\begin_layout LyX-Code
|
1858
|
+
u.to_f / v # implicit return - last statement
|
1859
|
+
\end_layout
|
1860
|
+
|
1861
|
+
\begin_layout LyX-Code
|
1862
|
+
} #=> #<Proc:0xa21e878@(irb):15 (lambda)>
|
1863
|
+
\end_layout
|
1864
|
+
|
1865
|
+
\begin_layout LyX-Code
|
1866
|
+
divider.call( 15, 3 ) #=> 5.0
|
1867
|
+
\end_layout
|
1868
|
+
|
1869
|
+
\begin_layout LyX-Code
|
1870
|
+
divider.call( 15, 0 ) #=> :division_by_zero
|
1871
|
+
\end_layout
|
1872
|
+
|
1873
|
+
\begin_layout LyX-Code
|
1874
|
+
experimental_closure = proc {
|
1875
|
+
\end_layout
|
1876
|
+
|
1877
|
+
\begin_layout LyX-Code
|
1878
|
+
42 # ignored
|
1879
|
+
\end_layout
|
1880
|
+
|
1881
|
+
\begin_layout LyX-Code
|
1882
|
+
41 # returned
|
1883
|
+
\end_layout
|
1884
|
+
|
1885
|
+
\begin_layout LyX-Code
|
1886
|
+
} #=> #<Proc:0xa249460@(irb):28>
|
1887
|
+
\end_layout
|
1888
|
+
|
1889
|
+
\begin_layout LyX-Code
|
1890
|
+
experimental_closure.call #=> 41
|
1891
|
+
\end_layout
|
1892
|
+
|
1893
|
+
\begin_layout LyX-Code
|
1894
|
+
experimental_lambda = lambda {
|
1895
|
+
\end_layout
|
1896
|
+
|
1897
|
+
\begin_layout LyX-Code
|
1898
|
+
1 # ignored
|
1899
|
+
\end_layout
|
1900
|
+
|
1901
|
+
\begin_layout LyX-Code
|
1902
|
+
return 3 # returned
|
1903
|
+
\end_layout
|
1904
|
+
|
1905
|
+
\begin_layout LyX-Code
|
1906
|
+
7 # never executed
|
1907
|
+
\end_layout
|
1908
|
+
|
1909
|
+
\begin_layout LyX-Code
|
1910
|
+
} #=> #<Proc:0xa3200dc@(irb):38 (lambda)>
|
1911
|
+
\end_layout
|
1912
|
+
|
1913
|
+
\begin_layout LyX-Code
|
1914
|
+
experimental_lambda.call #=> 3
|
1915
|
+
\end_layout
|
1916
|
+
|
1917
|
+
\begin_layout Section*
|
1918
|
+
Return value arity
|
1919
|
+
\end_layout
|
1920
|
+
|
1921
|
+
\begin_layout Standard
|
1922
|
+
It is possible to return more than one value
|
1923
|
+
\begin_inset Foot
|
1924
|
+
status open
|
1925
|
+
|
1926
|
+
\begin_layout Plain Layout
|
1927
|
+
Technically, methods and closures always return exactly 1 object – multiple
|
1928
|
+
values are returned via a single array object.
|
1929
|
+
But pragmatically, and especially with respect to
|
1930
|
+
\family typewriter
|
1931
|
+
YPetri
|
1932
|
+
\family default
|
1933
|
+
, the notion of return value arity is useful.
|
1934
|
+
\end_layout
|
1935
|
+
|
1936
|
+
\end_inset
|
1937
|
+
|
1938
|
+
.
|
1939
|
+
For example:
|
1940
|
+
\end_layout
|
1941
|
+
|
1942
|
+
\begin_layout LyX-Code
|
1943
|
+
mult_table = -> number {
|
1944
|
+
\end_layout
|
1945
|
+
|
1946
|
+
\begin_layout LyX-Code
|
1947
|
+
[1, 2, 3, 4, 5].map { |e| e * number }
|
1948
|
+
\end_layout
|
1949
|
+
|
1950
|
+
\begin_layout LyX-Code
|
1951
|
+
} #=> #<Proc:0xa36a0d8@(irb):55 (lambda)>
|
1952
|
+
\end_layout
|
1953
|
+
|
1954
|
+
\begin_layout Standard
|
1955
|
+
This closure returns 5 values.
|
1956
|
+
We can receive them by using a simultaneous assignment statement:
|
1957
|
+
\end_layout
|
1958
|
+
|
1959
|
+
\begin_layout LyX-Code
|
1960
|
+
by_one, by_two, by_three, by_four, by_five = mult_table.call( 7 ) #=>
|
1961
|
+
[7, 14, 21, 28, 35]
|
1962
|
+
\end_layout
|
1963
|
+
|
1964
|
+
\begin_layout LyX-Code
|
1965
|
+
by_one #=> 7
|
1966
|
+
\end_layout
|
1967
|
+
|
1968
|
+
\begin_layout LyX-Code
|
1969
|
+
by_two #=> 14
|
1970
|
+
\end_layout
|
1971
|
+
|
1972
|
+
\begin_layout LyX-Code
|
1973
|
+
by_five #=> 35
|
1974
|
+
\end_layout
|
1975
|
+
|
1976
|
+
\begin_layout Standard
|
1977
|
+
Or we can simply collect them in an array:
|
1978
|
+
\end_layout
|
1979
|
+
|
1980
|
+
\begin_layout LyX-Code
|
1981
|
+
collection = mult_table.( 3 ) #=> [3, 6, 9, 12, 15]
|
1982
|
+
\end_layout
|
1983
|
+
|
1984
|
+
\begin_layout Standard
|
1985
|
+
In
|
1986
|
+
\family typewriter
|
1987
|
+
YNelson
|
1988
|
+
\family default
|
1989
|
+
, it sometimes becomes necessary to write closures with higher return arity
|
1990
|
+
(returning more than one value).
|
1991
|
+
This is normally done by returning an array.
|
1992
|
+
Also, lambda return statement can be used to return multiple values:
|
1993
|
+
\end_layout
|
1994
|
+
|
1995
|
+
\begin_layout LyX-Code
|
1996
|
+
constant_vector = -> { return 1, 2, 3 }
|
1997
|
+
\end_layout
|
1998
|
+
|
1999
|
+
\begin_layout LyX-Code
|
2000
|
+
#=> #<Proc:0xa3cb338@(irb):72 (lambda)>
|
2001
|
+
\end_layout
|
2002
|
+
|
2003
|
+
\begin_layout LyX-Code
|
2004
|
+
x, y, z = constant_vector.call #=> [1, 2, 3]
|
2005
|
+
\end_layout
|
2006
|
+
|
2007
|
+
\begin_layout LyX-Code
|
2008
|
+
x #=> 1
|
2009
|
+
\end_layout
|
2010
|
+
|
2011
|
+
\begin_layout LyX-Code
|
2012
|
+
y #=> 2
|
2013
|
+
\end_layout
|
2014
|
+
|
2015
|
+
\begin_layout LyX-Code
|
2016
|
+
z #=> 3
|
2017
|
+
\end_layout
|
2018
|
+
|
2019
|
+
\begin_layout Part*
|
2020
|
+
|
2021
|
+
\family typewriter
|
2022
|
+
YSupport
|
2023
|
+
\family default
|
2024
|
+
library
|
2025
|
+
\end_layout
|
2026
|
+
|
2027
|
+
\begin_layout Standard
|
2028
|
+
Finally, having introduced the basic Ruby syntax, let us mention
|
2029
|
+
\family typewriter
|
2030
|
+
YSupport
|
2031
|
+
\family default
|
2032
|
+
gem (gem = published Ruby library), that collects the assets (modules,
|
2033
|
+
classes, methods...) of general concern in use by
|
2034
|
+
\family typewriter
|
2035
|
+
YPetri
|
2036
|
+
\family default
|
2037
|
+
/
|
2038
|
+
\family typewriter
|
2039
|
+
YNelson
|
2040
|
+
\family default
|
2041
|
+
.
|
2042
|
+
Of these, a particular mention goes to
|
2043
|
+
\family typewriter
|
2044
|
+
NameMagic
|
2045
|
+
\family default
|
2046
|
+
, widely used in
|
2047
|
+
\family typewriter
|
2048
|
+
YPetri
|
2049
|
+
\family default
|
2050
|
+
,
|
2051
|
+
\family typewriter
|
2052
|
+
YNelson
|
2053
|
+
\family default
|
2054
|
+
and
|
2055
|
+
\family typewriter
|
2056
|
+
SY
|
2057
|
+
\family default
|
2058
|
+
(physical units) libraries.
|
2059
|
+
\end_layout
|
2060
|
+
|
2061
|
+
\begin_layout Section*
|
2062
|
+
|
2063
|
+
\family typewriter
|
2064
|
+
NameMagic
|
2065
|
+
\end_layout
|
2066
|
+
|
2067
|
+
\begin_layout Standard
|
2068
|
+
In software engineering,
|
2069
|
+
\emph on
|
2070
|
+
magic
|
2071
|
+
\emph default
|
2072
|
+
is a technical term for irregular side effects of language expressions.
|
2073
|
+
The problem that
|
2074
|
+
\family typewriter
|
2075
|
+
NameMagic
|
2076
|
+
\family default
|
2077
|
+
solves is, that objects (such as chemical species encoded in
|
2078
|
+
\family typewriter
|
2079
|
+
YNelson
|
2080
|
+
\family default
|
2081
|
+
) are frequently named, and naming them is an annoying chore.
|
2082
|
+
Consider a simple case:
|
2083
|
+
\end_layout
|
2084
|
+
|
2085
|
+
\begin_layout LyX-Code
|
2086
|
+
class Student
|
2087
|
+
\end_layout
|
2088
|
+
|
2089
|
+
\begin_layout LyX-Code
|
2090
|
+
attr_accessor :name
|
2091
|
+
\end_layout
|
2092
|
+
|
2093
|
+
\begin_layout LyX-Code
|
2094
|
+
def initialize name: nil
|
2095
|
+
\end_layout
|
2096
|
+
|
2097
|
+
\begin_layout LyX-Code
|
2098
|
+
@name = name
|
2099
|
+
\end_layout
|
2100
|
+
|
2101
|
+
\begin_layout LyX-Code
|
2102
|
+
end
|
2103
|
+
\end_layout
|
2104
|
+
|
2105
|
+
\begin_layout LyX-Code
|
2106
|
+
end
|
2107
|
+
\end_layout
|
2108
|
+
|
2109
|
+
\begin_layout Standard
|
2110
|
+
Now, to create named
|
2111
|
+
\family typewriter
|
2112
|
+
Student
|
2113
|
+
\family default
|
2114
|
+
instances, one has to mention
|
2115
|
+
\family typewriter
|
2116
|
+
:name
|
2117
|
+
\family default
|
2118
|
+
named argument in the constructor, and frequently, the same name has to
|
2119
|
+
be mentioned twice, such as when assigning to constants or variables:
|
2120
|
+
\end_layout
|
2121
|
+
|
2122
|
+
\begin_layout LyX-Code
|
2123
|
+
richard = Student.new( name: "Richard" )
|
2124
|
+
\end_layout
|
2125
|
+
|
2126
|
+
\begin_layout LyX-Code
|
2127
|
+
richard.name #=> "Richard"
|
2128
|
+
\end_layout
|
2129
|
+
|
2130
|
+
\begin_layout Standard
|
2131
|
+
In Ruby, we can notice that some objects have built-in capability to be
|
2132
|
+
named simply by constant assignment:
|
2133
|
+
\end_layout
|
2134
|
+
|
2135
|
+
\begin_layout LyX-Code
|
2136
|
+
foo = Class.new
|
2137
|
+
\end_layout
|
2138
|
+
|
2139
|
+
\begin_layout LyX-Code
|
2140
|
+
foo.name #=> nil
|
2141
|
+
\end_layout
|
2142
|
+
|
2143
|
+
\begin_layout LyX-Code
|
2144
|
+
Car = foo
|
2145
|
+
\end_layout
|
2146
|
+
|
2147
|
+
\begin_layout LyX-Code
|
2148
|
+
foo.name #=> "Car"
|
2149
|
+
\end_layout
|
2150
|
+
|
2151
|
+
\begin_layout Standard
|
2152
|
+
Magically, upon assigning
|
2153
|
+
\family typewriter
|
2154
|
+
Car = foo
|
2155
|
+
\family default
|
2156
|
+
, the object referred to by the
|
2157
|
+
\family typewriter
|
2158
|
+
foo
|
2159
|
+
\family default
|
2160
|
+
variable received an attribute
|
2161
|
+
\family typewriter
|
2162
|
+
name
|
2163
|
+
\family default
|
2164
|
+
, with value set to "
|
2165
|
+
\family typewriter
|
2166
|
+
Car
|
2167
|
+
\family default
|
2168
|
+
".
|
2169
|
+
This standard behavior is termed
|
2170
|
+
\emph on
|
2171
|
+
constant magic
|
2172
|
+
\emph default
|
2173
|
+
.
|
2174
|
+
|
2175
|
+
\family typewriter
|
2176
|
+
NameMagic
|
2177
|
+
\family default
|
2178
|
+
mixin (part of
|
2179
|
+
\family typewriter
|
2180
|
+
YSupport
|
2181
|
+
\family default
|
2182
|
+
) extends this standard behavior to any chosen object, and also takes care
|
2183
|
+
of keeping the instance registry and doing general naming related chores
|
2184
|
+
for its includers:
|
2185
|
+
\end_layout
|
2186
|
+
|
2187
|
+
\begin_layout LyX-Code
|
2188
|
+
require 'y_support/name_magic'
|
2189
|
+
\end_layout
|
2190
|
+
|
2191
|
+
\begin_layout LyX-Code
|
2192
|
+
|
2193
|
+
\end_layout
|
2194
|
+
|
2195
|
+
\begin_layout LyX-Code
|
2196
|
+
class Chemical
|
2197
|
+
\end_layout
|
2198
|
+
|
2199
|
+
\begin_layout LyX-Code
|
2200
|
+
include NameMagic
|
2201
|
+
\end_layout
|
2202
|
+
|
2203
|
+
\begin_layout LyX-Code
|
2204
|
+
end
|
2205
|
+
\end_layout
|
2206
|
+
|
2207
|
+
\begin_layout LyX-Code
|
2208
|
+
|
2209
|
+
\end_layout
|
2210
|
+
|
2211
|
+
\begin_layout LyX-Code
|
2212
|
+
NaCl = Chemical.new
|
2213
|
+
\end_layout
|
2214
|
+
|
2215
|
+
\begin_layout LyX-Code
|
2216
|
+
NaCl.name #=> "NaCl"
|
2217
|
+
\end_layout
|
2218
|
+
|
2219
|
+
\begin_layout Standard
|
2220
|
+
It might seem like a small thing, but in a big file full of complicated
|
2221
|
+
statements, it really matters whether you have to write each time "
|
2222
|
+
\family typewriter
|
2223
|
+
NaCl = Chemical.new( name: NaCl )
|
2224
|
+
\family default
|
2225
|
+
", or just "
|
2226
|
+
\family typewriter
|
2227
|
+
NaCl = Chemical.new
|
2228
|
+
\family default
|
2229
|
+
".
|
2230
|
+
|
2231
|
+
\family typewriter
|
2232
|
+
NameMagic
|
2233
|
+
\family default
|
2234
|
+
is a part of
|
2235
|
+
\family typewriter
|
2236
|
+
YSupport
|
2237
|
+
\family default
|
2238
|
+
library accompanying
|
2239
|
+
\family typewriter
|
2240
|
+
YPetri
|
2241
|
+
\family default
|
2242
|
+
and
|
2243
|
+
\family typewriter
|
2244
|
+
YNelson
|
2245
|
+
\family default
|
2246
|
+
.
|
2247
|
+
You can install
|
2248
|
+
\family typewriter
|
2249
|
+
YSupport
|
2250
|
+
\family default
|
2251
|
+
from the command line by "
|
2252
|
+
\family typewriter
|
2253
|
+
gem install y_support
|
2254
|
+
\family default
|
2255
|
+
".
|
2256
|
+
\end_layout
|
2257
|
+
|
2258
|
+
\begin_layout Part*
|
2259
|
+
Other essential concepts
|
2260
|
+
\end_layout
|
2261
|
+
|
2262
|
+
\begin_layout Standard
|
2263
|
+
There are a few more essential concepts of Ruby that
|
2264
|
+
\family typewriter
|
2265
|
+
YNelson
|
2266
|
+
\family default
|
2267
|
+
users should be familiar with, such as namespaces and parametrized subclassing.
|
2268
|
+
Code examples in this section are slightly more complicated, and also,
|
2269
|
+
they make use of
|
2270
|
+
\family typewriter
|
2271
|
+
YSupport
|
2272
|
+
\family default
|
2273
|
+
gem.
|
2274
|
+
Install
|
2275
|
+
\family typewriter
|
2276
|
+
YSupport
|
2277
|
+
\family default
|
2278
|
+
by typing
|
2279
|
+
\family typewriter
|
2280
|
+
gem install y_support
|
2281
|
+
\family default
|
2282
|
+
in your command line before studying code examples in this section.
|
2283
|
+
\end_layout
|
2284
|
+
|
2285
|
+
\begin_layout Section*
|
2286
|
+
Namespaces
|
2287
|
+
\end_layout
|
2288
|
+
|
2289
|
+
\begin_layout Standard
|
2290
|
+
In Ruby, namespaces are known as modules (objects of
|
2291
|
+
\family typewriter
|
2292
|
+
Module
|
2293
|
+
\family default
|
2294
|
+
class).
|
2295
|
+
These objects are containers for constants and method definitions.
|
2296
|
+
For example, let us imagine that we want to define constants, classes and
|
2297
|
+
methods related to the game of chess.
|
2298
|
+
We could simply define them in the command line, without any considerations,
|
2299
|
+
We could do it directly, but that way, all of them would be defined in
|
2300
|
+
the root of Ruby namespace – on
|
2301
|
+
\family typewriter
|
2302
|
+
Object
|
2303
|
+
\family default
|
2304
|
+
class.
|
2305
|
+
The reason why this is not a good idea is the same as the reason why it
|
2306
|
+
is not a good idea to put all your files in the root of your filesystem.
|
2307
|
+
Chess-related terms such as
|
2308
|
+
\family typewriter
|
2309
|
+
Field
|
2310
|
+
\family default
|
2311
|
+
or
|
2312
|
+
\family typewriter
|
2313
|
+
Piece
|
2314
|
+
\family default
|
2315
|
+
could collide with concepts from other domains not related to chess.
|
2316
|
+
For that reason, we will collect all the chess-related assets into a single
|
2317
|
+
namespace:
|
2318
|
+
\end_layout
|
2319
|
+
|
2320
|
+
\begin_layout LyX-Code
|
2321
|
+
module Chess
|
2322
|
+
\end_layout
|
2323
|
+
|
2324
|
+
\begin_layout LyX-Code
|
2325
|
+
class Board < Array
|
2326
|
+
\end_layout
|
2327
|
+
|
2328
|
+
\begin_layout LyX-Code
|
2329
|
+
SIZE = 8 # standard chessboard
|
2330
|
+
\end_layout
|
2331
|
+
|
2332
|
+
\begin_layout LyX-Code
|
2333
|
+
|
2334
|
+
\end_layout
|
2335
|
+
|
2336
|
+
\begin_layout LyX-Code
|
2337
|
+
class Field # chessboard field
|
2338
|
+
\end_layout
|
2339
|
+
|
2340
|
+
\begin_layout LyX-Code
|
2341
|
+
attr_accessor :contents
|
2342
|
+
\end_layout
|
2343
|
+
|
2344
|
+
\begin_layout LyX-Code
|
2345
|
+
end
|
2346
|
+
\end_layout
|
2347
|
+
|
2348
|
+
\begin_layout LyX-Code
|
2349
|
+
|
2350
|
+
\end_layout
|
2351
|
+
|
2352
|
+
\begin_layout LyX-Code
|
2353
|
+
def self.new # constructs 8 × 8 array of arrays
|
2354
|
+
\end_layout
|
2355
|
+
|
2356
|
+
\begin_layout LyX-Code
|
2357
|
+
super( SIZE, Array.new( SIZE ) { Field.new } )
|
2358
|
+
\end_layout
|
2359
|
+
|
2360
|
+
\begin_layout LyX-Code
|
2361
|
+
end
|
2362
|
+
\end_layout
|
2363
|
+
|
2364
|
+
\begin_layout LyX-Code
|
2365
|
+
# chessboard is defined here
|
2366
|
+
\end_layout
|
2367
|
+
|
2368
|
+
\begin_layout LyX-Code
|
2369
|
+
end
|
2370
|
+
\end_layout
|
2371
|
+
|
2372
|
+
\begin_layout LyX-Code
|
2373
|
+
|
2374
|
+
\end_layout
|
2375
|
+
|
2376
|
+
\begin_layout LyX-Code
|
2377
|
+
Piece = Class.new # chess piece
|
2378
|
+
\end_layout
|
2379
|
+
|
2380
|
+
\begin_layout LyX-Code
|
2381
|
+
Pawn = Class.new Piece # chess pawn
|
2382
|
+
\end_layout
|
2383
|
+
|
2384
|
+
\begin_layout LyX-Code
|
2385
|
+
Knight = Class.new Piece # chess knight
|
2386
|
+
\end_layout
|
2387
|
+
|
2388
|
+
\begin_layout LyX-Code
|
2389
|
+
Rook = Class.new Piece # chess rook
|
2390
|
+
\end_layout
|
2391
|
+
|
2392
|
+
\begin_layout LyX-Code
|
2393
|
+
# etc.
|
2394
|
+
\end_layout
|
2395
|
+
|
2396
|
+
\begin_layout LyX-Code
|
2397
|
+
end
|
2398
|
+
\end_layout
|
2399
|
+
|
2400
|
+
\begin_layout Standard
|
2401
|
+
We then access the contents of the namespace in the way similar to the way
|
2402
|
+
we address the files in the filesystem:
|
2403
|
+
\end_layout
|
2404
|
+
|
2405
|
+
\begin_layout LyX-Code
|
2406
|
+
Chess::Board # namespace Chess, constant Board
|
2407
|
+
\end_layout
|
2408
|
+
|
2409
|
+
\begin_layout LyX-Code
|
2410
|
+
Chess::Piece # namespace Chess, constant Piece
|
2411
|
+
\end_layout
|
2412
|
+
|
2413
|
+
\begin_layout LyX-Code
|
2414
|
+
Chess::Pawn # namespace Chess, constant Pawn
|
2415
|
+
\end_layout
|
2416
|
+
|
2417
|
+
\begin_layout LyX-Code
|
2418
|
+
Chess::Board::SIZE # namespace Chess::Board, constant SIZE
|
2419
|
+
\end_layout
|
2420
|
+
|
2421
|
+
\begin_layout LyX-Code
|
2422
|
+
Chess::Board::Field # namespace Chess::Board, constant Field
|
2423
|
+
\end_layout
|
2424
|
+
|
2425
|
+
\begin_layout LyX-Code
|
2426
|
+
# etc.
|
2427
|
+
\end_layout
|
2428
|
+
|
2429
|
+
\begin_layout Standard
|
2430
|
+
Let us note that in the above example,
|
2431
|
+
\family typewriter
|
2432
|
+
Board
|
2433
|
+
\family default
|
2434
|
+
,
|
2435
|
+
\family typewriter
|
2436
|
+
Piece
|
2437
|
+
\family default
|
2438
|
+
,
|
2439
|
+
\family typewriter
|
2440
|
+
Pawn
|
2441
|
+
\family default
|
2442
|
+
are merely constants of the namespace
|
2443
|
+
\family typewriter
|
2444
|
+
Chess
|
2445
|
+
\family default
|
2446
|
+
.
|
2447
|
+
Similarly, in
|
2448
|
+
\family typewriter
|
2449
|
+
YPetri
|
2450
|
+
\family default
|
2451
|
+
, when talking about
|
2452
|
+
\family typewriter
|
2453
|
+
YPetri::Place
|
2454
|
+
\family default
|
2455
|
+
,
|
2456
|
+
\family typewriter
|
2457
|
+
YPetri::Transition
|
2458
|
+
\family default
|
2459
|
+
or
|
2460
|
+
\family typewriter
|
2461
|
+
YPetri::Net
|
2462
|
+
\family default
|
2463
|
+
, it means constants
|
2464
|
+
\family typewriter
|
2465
|
+
Place
|
2466
|
+
\family default
|
2467
|
+
,
|
2468
|
+
\family typewriter
|
2469
|
+
Transition
|
2470
|
+
\family default
|
2471
|
+
and
|
2472
|
+
\family typewriter
|
2473
|
+
Net
|
2474
|
+
\family default
|
2475
|
+
belonging to the module
|
2476
|
+
\family typewriter
|
2477
|
+
YPetri
|
2478
|
+
\family default
|
2479
|
+
and containing the relevant class objects.
|
2480
|
+
But each of these classes is a namespace of its own, that can have constants
|
2481
|
+
defined on it.
|
2482
|
+
For example,
|
2483
|
+
\family typewriter
|
2484
|
+
YPetri::Simulation
|
2485
|
+
\family default
|
2486
|
+
has constants
|
2487
|
+
\family typewriter
|
2488
|
+
YPetri::Simulation::PlaceRepresentation
|
2489
|
+
\family default
|
2490
|
+
and
|
2491
|
+
\family typewriter
|
2492
|
+
YPetri::Simulation::TransitionRepresentation
|
2493
|
+
\family default
|
2494
|
+
, representing copies of the net's places and transitions when executed
|
2495
|
+
inside a
|
2496
|
+
\family typewriter
|
2497
|
+
Simulation
|
2498
|
+
\family default
|
2499
|
+
instance.
|
2500
|
+
\end_layout
|
2501
|
+
|
2502
|
+
\begin_layout Section*
|
2503
|
+
Parametrized subclassing
|
2504
|
+
\end_layout
|
2505
|
+
|
2506
|
+
\begin_layout Standard
|
2507
|
+
One of the core techniques used in
|
2508
|
+
\family typewriter
|
2509
|
+
YNelson
|
2510
|
+
\family default
|
2511
|
+
/
|
2512
|
+
\family typewriter
|
2513
|
+
YPetri
|
2514
|
+
\family default
|
2515
|
+
domain model is parametrized subclassing.
|
2516
|
+
Literature on the topic does exist, but the concept is best explained on
|
2517
|
+
examples:
|
2518
|
+
\end_layout
|
2519
|
+
|
2520
|
+
\begin_layout LyX-Code
|
2521
|
+
require 'y_support/all'
|
2522
|
+
\end_layout
|
2523
|
+
|
2524
|
+
\begin_layout LyX-Code
|
2525
|
+
|
2526
|
+
\end_layout
|
2527
|
+
|
2528
|
+
\begin_layout LyX-Code
|
2529
|
+
class Human
|
2530
|
+
\end_layout
|
2531
|
+
|
2532
|
+
\begin_layout LyX-Code
|
2533
|
+
include NameMagic # allows humans to be named easily
|
2534
|
+
\end_layout
|
2535
|
+
|
2536
|
+
\begin_layout LyX-Code
|
2537
|
+
end
|
2538
|
+
\end_layout
|
2539
|
+
|
2540
|
+
\begin_layout Standard
|
2541
|
+
Humans generally live in settlements.
|
2542
|
+
Let us create class
|
2543
|
+
\family typewriter
|
2544
|
+
Village
|
2545
|
+
\family default
|
2546
|
+
representing settlements.
|
2547
|
+
\end_layout
|
2548
|
+
|
2549
|
+
\begin_layout LyX-Code
|
2550
|
+
class Village
|
2551
|
+
\end_layout
|
2552
|
+
|
2553
|
+
\begin_layout LyX-Code
|
2554
|
+
include NameMagic # allows villages to be named easily
|
2555
|
+
\end_layout
|
2556
|
+
|
2557
|
+
\begin_layout LyX-Code
|
2558
|
+
end
|
2559
|
+
\end_layout
|
2560
|
+
|
2561
|
+
\begin_layout Standard
|
2562
|
+
At this point, we are standing in front of the problem of making humans
|
2563
|
+
associated with their settlements.
|
2564
|
+
One way to do it is to make each
|
2565
|
+
\family typewriter
|
2566
|
+
Human
|
2567
|
+
\family default
|
2568
|
+
instance remember which settlement they belong to.
|
2569
|
+
This approach, which you can certainly imagine well even without demonstration,
|
2570
|
+
is in common use.
|
2571
|
+
But we have a more powerful approach at our disposal – subclassing.
|
2572
|
+
This is how we can define a subclass of humans living in London:
|
2573
|
+
\end_layout
|
2574
|
+
|
2575
|
+
\begin_layout LyX-Code
|
2576
|
+
London = Village.new
|
2577
|
+
\end_layout
|
2578
|
+
|
2579
|
+
\begin_layout LyX-Code
|
2580
|
+
|
2581
|
+
\end_layout
|
2582
|
+
|
2583
|
+
\begin_layout LyX-Code
|
2584
|
+
class Londoner
|
2585
|
+
\color red
|
2586
|
+
<
|
2587
|
+
\color inherit
|
2588
|
+
Human # using < sign
|
2589
|
+
\end_layout
|
2590
|
+
|
2591
|
+
\begin_layout LyX-Code
|
2592
|
+
def self.settlement; London end # let the class know its city
|
2593
|
+
\end_layout
|
2594
|
+
|
2595
|
+
\begin_layout LyX-Code
|
2596
|
+
end
|
2597
|
+
\end_layout
|
2598
|
+
|
2599
|
+
\begin_layout LyX-Code
|
2600
|
+
|
2601
|
+
\end_layout
|
2602
|
+
|
2603
|
+
\begin_layout LyX-Code
|
2604
|
+
John = Londoner.new
|
2605
|
+
\end_layout
|
2606
|
+
|
2607
|
+
\begin_layout LyX-Code
|
2608
|
+
John.class.settlement #=> London
|
2609
|
+
\end_layout
|
2610
|
+
|
2611
|
+
\begin_layout Standard
|
2612
|
+
To make it easier to ask humans about their settlement, let's reopen class
|
2613
|
+
|
2614
|
+
\family typewriter
|
2615
|
+
Human
|
2616
|
+
\family default
|
2617
|
+
and delegate method
|
2618
|
+
\family typewriter
|
2619
|
+
#settlement
|
2620
|
+
\family default
|
2621
|
+
to the class:
|
2622
|
+
\end_layout
|
2623
|
+
|
2624
|
+
\begin_layout LyX-Code
|
2625
|
+
class Human
|
2626
|
+
\end_layout
|
2627
|
+
|
2628
|
+
\begin_layout LyX-Code
|
2629
|
+
def settlement; self.class.settlement end
|
2630
|
+
\end_layout
|
2631
|
+
|
2632
|
+
\begin_layout LyX-Code
|
2633
|
+
end
|
2634
|
+
\end_layout
|
2635
|
+
|
2636
|
+
\begin_layout Standard
|
2637
|
+
Alternative syntax for subclassing is this:
|
2638
|
+
\end_layout
|
2639
|
+
|
2640
|
+
\begin_layout LyX-Code
|
2641
|
+
Dublin = Village.new
|
2642
|
+
\end_layout
|
2643
|
+
|
2644
|
+
\begin_layout LyX-Code
|
2645
|
+
|
2646
|
+
\end_layout
|
2647
|
+
|
2648
|
+
\begin_layout LyX-Code
|
2649
|
+
Dubliner = Class.new Human do # Dubliner becomes a subclass of Human
|
2650
|
+
\end_layout
|
2651
|
+
|
2652
|
+
\begin_layout LyX-Code
|
2653
|
+
def self.settlement; Dublin end
|
2654
|
+
\end_layout
|
2655
|
+
|
2656
|
+
\begin_layout LyX-Code
|
2657
|
+
end
|
2658
|
+
\end_layout
|
2659
|
+
|
2660
|
+
\begin_layout LyX-Code
|
2661
|
+
|
2662
|
+
\end_layout
|
2663
|
+
|
2664
|
+
\begin_layout LyX-Code
|
2665
|
+
Finnegan = Dubliner.new
|
2666
|
+
\end_layout
|
2667
|
+
|
2668
|
+
\begin_layout LyX-Code
|
2669
|
+
Finnegan.class.settlement #=> Dublin
|
2670
|
+
\end_layout
|
2671
|
+
|
2672
|
+
\begin_layout LyX-Code
|
2673
|
+
|
2674
|
+
\end_layout
|
2675
|
+
|
2676
|
+
\begin_layout Standard
|
2677
|
+
Simply, each settlement has its own class of humans – its inhabitants.
|
2678
|
+
But since there are many settlements, it is inconvenient to manually define
|
2679
|
+
the inhabitant class for each of them.
|
2680
|
+
We therefore make each village automatically construct its own subclass
|
2681
|
+
of
|
2682
|
+
\family typewriter
|
2683
|
+
Human
|
2684
|
+
\family default
|
2685
|
+
and parametrize it with
|
2686
|
+
\family typewriter
|
2687
|
+
settlement
|
2688
|
+
\family default
|
2689
|
+
attribute.
|
2690
|
+
|
2691
|
+
\family typewriter
|
2692
|
+
YSupport
|
2693
|
+
\family default
|
2694
|
+
supports parametrized subclassing with method
|
2695
|
+
\family typewriter
|
2696
|
+
#param_class
|
2697
|
+
\family default
|
2698
|
+
, and makes it easy to construct a PS of
|
2699
|
+
\family typewriter
|
2700
|
+
Human
|
2701
|
+
\family default
|
2702
|
+
for each
|
2703
|
+
\family typewriter
|
2704
|
+
Village
|
2705
|
+
\family default
|
2706
|
+
istance.
|
2707
|
+
\end_layout
|
2708
|
+
|
2709
|
+
\begin_layout LyX-Code
|
2710
|
+
class Village # reopening the class defined earlier
|
2711
|
+
\end_layout
|
2712
|
+
|
2713
|
+
\begin_layout LyX-Code
|
2714
|
+
def initialize # defining a constructor
|
2715
|
+
\end_layout
|
2716
|
+
|
2717
|
+
\begin_layout LyX-Code
|
2718
|
+
param_class( { Human: Human }, with: { settlement: self } )
|
2719
|
+
\end_layout
|
2720
|
+
|
2721
|
+
\begin_layout LyX-Code
|
2722
|
+
end
|
2723
|
+
\end_layout
|
2724
|
+
|
2725
|
+
\begin_layout LyX-Code
|
2726
|
+
end
|
2727
|
+
\end_layout
|
2728
|
+
|
2729
|
+
\begin_layout Standard
|
2730
|
+
Each village has now its own PS of
|
2731
|
+
\family typewriter
|
2732
|
+
Human
|
2733
|
+
\family default
|
2734
|
+
.
|
2735
|
+
\end_layout
|
2736
|
+
|
2737
|
+
\begin_layout LyX-Code
|
2738
|
+
Stockholm, Riga, Canberra = 3.times.map { Village.new }
|
2739
|
+
\end_layout
|
2740
|
+
|
2741
|
+
\begin_layout LyX-Code
|
2742
|
+
Stockholm.Human # class of Stockholm citizens
|
2743
|
+
\end_layout
|
2744
|
+
|
2745
|
+
\begin_layout LyX-Code
|
2746
|
+
Riga.Human # class of Riga citizens
|
2747
|
+
\end_layout
|
2748
|
+
|
2749
|
+
\begin_layout LyX-Code
|
2750
|
+
Canberra.Human # class of Canberra citizens
|
2751
|
+
\end_layout
|
2752
|
+
|
2753
|
+
\begin_layout LyX-Code
|
2754
|
+
Stockholm.Human == Riga.Human #=> false
|
2755
|
+
\end_layout
|
2756
|
+
|
2757
|
+
\begin_layout LyX-Code
|
2758
|
+
|
2759
|
+
\end_layout
|
2760
|
+
|
2761
|
+
\begin_layout LyX-Code
|
2762
|
+
Fred = Stockholm.Human.new # Stockholm citizen constructor
|
2763
|
+
\end_layout
|
2764
|
+
|
2765
|
+
\begin_layout LyX-Code
|
2766
|
+
Fred.class.settlement #=> Stockholm
|
2767
|
+
\end_layout
|
2768
|
+
|
2769
|
+
\begin_layout Standard
|
2770
|
+
We say that PS of
|
2771
|
+
\family typewriter
|
2772
|
+
Human
|
2773
|
+
\family default
|
2774
|
+
class
|
2775
|
+
\emph on
|
2776
|
+
depends
|
2777
|
+
\emph default
|
2778
|
+
on
|
2779
|
+
\family typewriter
|
2780
|
+
Village
|
2781
|
+
\family default
|
2782
|
+
.
|
2783
|
+
The advantage is that instances of the PS of
|
2784
|
+
\family typewriter
|
2785
|
+
Human
|
2786
|
+
\family default
|
2787
|
+
don't need to be explicitly told which village do they belong to, and have
|
2788
|
+
easy access to the assets of its owner
|
2789
|
+
\family typewriter
|
2790
|
+
Village
|
2791
|
+
\family default
|
2792
|
+
instance.
|
2793
|
+
The concept of parametrized subclassing is actually very simple.
|
2794
|
+
\end_layout
|
2795
|
+
|
2796
|
+
\begin_layout Section*
|
2797
|
+
Convenience methods
|
2798
|
+
\end_layout
|
2799
|
+
|
2800
|
+
\begin_layout Standard
|
2801
|
+
Convenience methods are methods in which the consistency of the behavior
|
2802
|
+
is traded for syntax sweetness.
|
2803
|
+
Convenience methods may do entirely different things for different argument
|
2804
|
+
sets.
|
2805
|
+
For example, in
|
2806
|
+
\family typewriter
|
2807
|
+
YPetri
|
2808
|
+
\family default
|
2809
|
+
,
|
2810
|
+
\family typewriter
|
2811
|
+
Place#marking
|
2812
|
+
\family default
|
2813
|
+
without arguments simply returns the place's marking.
|
2814
|
+
But with arguments, it can be used to define a guard:
|
2815
|
+
\end_layout
|
2816
|
+
|
2817
|
+
\begin_layout LyX-Code
|
2818
|
+
require 'y_petri' and include YPetri
|
2819
|
+
\end_layout
|
2820
|
+
|
2821
|
+
\begin_layout LyX-Code
|
2822
|
+
A = Place marking: 42
|
2823
|
+
\end_layout
|
2824
|
+
|
2825
|
+
\begin_layout LyX-Code
|
2826
|
+
A.marking # Returns the place's marking
|
2827
|
+
\end_layout
|
2828
|
+
|
2829
|
+
\begin_layout LyX-Code
|
2830
|
+
# But with different arguments, same method can be used to
|
2831
|
+
\end_layout
|
2832
|
+
|
2833
|
+
\begin_layout LyX-Code
|
2834
|
+
# define a guard.
|
2835
|
+
\end_layout
|
2836
|
+
|
2837
|
+
\begin_layout LyX-Code
|
2838
|
+
A.marking "must never be above 100" do |m| m <= 100 end
|
2839
|
+
\end_layout
|
2840
|
+
|
2841
|
+
\begin_layout LyX-Code
|
2842
|
+
A.marking = 99 # no problem
|
2843
|
+
\end_layout
|
2844
|
+
|
2845
|
+
\begin_layout LyX-Code
|
2846
|
+
A.marking #=> 99
|
2847
|
+
\end_layout
|
2848
|
+
|
2849
|
+
\begin_layout LyX-Code
|
2850
|
+
A.marking = 101 # YPetri::GuardError is raised
|
2851
|
+
\end_layout
|
2852
|
+
|
2853
|
+
\begin_layout Standard
|
2854
|
+
Convenience methods are especially suited for non-reusable code, but their
|
2855
|
+
use may sometimes be efficient also in reusable code.
|
2856
|
+
\end_layout
|
2857
|
+
|
2858
|
+
\end_body
|
2859
|
+
\end_document
|