File: trouble.xml

package info (click to toggle)
rubybook 0.2-2
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 4,252 kB
  • ctags: 1,043
  • sloc: xml: 60,486; makefile: 25
file content (549 lines) | stat: -rw-r--r-- 18,073 bytes parent folder | download | duplicates (3)
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
<ppdoc>
<copyright>
    Copyright (c) 2001 by Addison Wesley Longman.  This
    material may be distributed only subject to the terms and
    conditions set forth in the Open Publication License, v1.0 or
    later (the latest version is presently available at
    http://www.opencontent.org/openpub/).
</copyright>
<chapter name="When Trouble Strikes">
<p/>
Sad to say, it is possible to write buggy programs using Ruby.  Sorry
about that.
<p/>
But not to worry!  Ruby has several features that will help debug your
programs.  We'll look at these features, and then we'll show some common
mistakes you can make in Ruby and how to fix them.
<section>Ruby Debugger</section>
<p/>
Ruby comes with a debugger,
which is conveniently built into the base
system.  You can run the debugger by invoking the interpreter with the
<tt>-r<nbsp/>debug</tt> option, along with any other Ruby options and the name of
your script:
<p/>
<syntax>
ruby -r debug <opt><nt>options</nt></opt> <opt><nt>programfile</nt></opt> <opt><nt>arguments</nt></opt>
</syntax>
<p/>
The debugger supports the usual range of features you'd expect,
including the ability to set breakpoints, to step into and step over
method calls, and to display stack frames and variables.
<p/>
It can also list the instance methods defined for a particular object
or class, and allows you to list and control separate threads within
Ruby.  Table 12.1 on page 133 lists all of
the commands that are available under the debugger.
<p/>
If your Ruby has <tt>readline</tt> support enabled, you can use cursor
keys to
move back and forth in command history and use line editing commands to
amend previous input.
<p/>
To give you an idea of what the Ruby debugger is like, here
is a sample session.
<p/>
<codefragment>
<alltt>
% <code><b>ruby -rdebug t.rb</b></code>
Debug.rb
Emacs support available.
t.rb:1:def fact(n)
(rdb:1) <code><b>list 1-9</b></code>
[1, 10] in t.rb
=&gt; 1  def fact(n)
   2    if n &lt;= 0
   3      1
   4    else
   5      n * fact(n-1)
   6    end
   7  end
   8
   9  p fact(5)
(rdb:1) <code><b>b 2</b></code>
Set breakpoint 1 at t.rb:2
(rdb:1) <code><b>c</b></code>
breakpoint 1, fact at t.rb:2
t.rb:2:  if n &lt;= 0
(rdb:1) <code><b>disp n</b></code>
  1: n = 5
(rdb:1) <code><b>del 1</b></code>
(rdb:1) <code><b>watch n==1</b></code>
Set watchpoint 2
(rdb:1) <code><b>c</b></code>
watchpoint 2, fact at t.rb:fact
t.rb:1:def fact(n)
1: n = 1
(rdb:1) <code><b>where</b></code>
--&gt; #1  t.rb:1:in `fact'
    #2  t.rb:5:in `fact'
    #3  t.rb:5:in `fact'
    #4  t.rb:5:in `fact'
    #5  t.rb:5:in `fact'
    #6  t.rb:9
(rdb:1) <code><b>del 2</b></code>
(rdb:1) <code><b>c</b></code>
120
</alltt>
</codefragment>
<section>Interactive Ruby</section>
<p/>
If you want to play with Ruby, there is a facility called Interactive
Ruby---irb, for short.
irb is essentially a Ruby ``shell'' similar in
concept to an operating system shell (complete with job control). It
provides an environment where you can ``play around'' with the
language in real time.  You launch irb at the command prompt:
<p/>
<syntax>
irb <opt><nt>irb-options</nt></opt> <opt><nt>ruby_script</nt></opt> <opt><nt>options</nt></opt>
</syntax>
<p/>
irb will display the value of each expression as you complete it. For
instance:
<p/>
<codefragment>
<alltt>
% irb
irb(main):001:0&gt; <code><b>a = 1 +</b></code>
irb(main):002:0* <code><b>2 * 3 /</b></code>
irb(main):003:0* <code><b>4 % 5</b></code>
2
irb(main):004:0&gt; <code><b>2+2</b></code>
4
irb(main):005:0&gt; <code><b>def test</b></code>
irb(main):006:1&gt; <code><b>puts "Hello, world!"</b></code>
irb(main):007:1&gt; <code><b>end</b></code>
nil
irb(main):008:0&gt; <code><b>test</b></code>
Hello, world!
nil
irb(main):009:0&gt; 
</alltt>
</codefragment>
<p/>
irb also allows you to create subsessions, each one of which may have
its own context.  For example, you can create a subsession with the
same (top-level) context as the original session, or create a
subsession in the context of a particular class or instance.  The
sample session shown in Figure 12.1 on page 128 is a bit longer,
but shows how you can create subsessions and switch between them.
<p/>
<figure type="figure">Figure not available...</figure>
<p/>
For a full description of all the commands that irb supports, see 
the reference beginning on page 523.
<p/>
As with the debugger, if your version of Ruby was built with GNU
Readline support, you can use arrow keys (as with Emacs) or vi-style
key bindings to edit individual lines or to go back and reexecute or
edit a previous line---just like a command shell.
<p/>
irb is a great learning tool: it's very handy if you want to try out
an idea quickly and see if it works.
<subsection>Editor Support</subsection>
<p/>
Ruby is designed to read a program in one pass; this means you can
pipe an entire program to Ruby's standard input and it will work just
fine.
<p/>
We can take advantage of this feature to run Ruby code from inside an
editor.  In Emacs, for instance, you can select a region of Ruby text
and use the command <tt>Meta-|</tt> to execute Ruby.  The Ruby interpreter
will use the selected region as standard input and output will go to a
buffer named ``<tt>*Shell Command Output*</tt>.''  This feature has come in
quite handy for us while writing this book---just select a few lines
of Ruby in the middle of a paragraph and try it out!
<p/>
You can do something similar in the vi editor using ``<tt>:!ruby</tt>''
which <em>replaces</em> the program text with its output, or
``<tt>:w<visible_space/>!ruby</tt>'', which displays the output without
affecting the buffer. Other editors have similar features.
<p/>
While we are on the subject, this would probably be a good place to
mention that there is a Ruby mode for Emacs included in the
distribution as <tt>misc/ruby-mode.el</tt>.  There are also several
syntax-highlighting modules for vim (an enhanced version of the vi
editor), jed, and other editors available on the net as well. Check
the Ruby FAQ for current locations and availability.
<section>But It Doesn't Work!</section>
<p/>
So you've read through enough of the book, you start to write your
very own Ruby program, and it doesn't work.  Here's a list of common
gotchas and other tips.
<p/>
<ul>
<li> Attribute setter not being called.  
  Within an object, Ruby will
  parse <tt>setter=</tt> as an assignment to a local variable, not as a
  method call.  Use <tt>self.setter=</tt> to indicate the method call.
<p/>
 </li><li> A parse error   
   at the last line of the source often
   indicates a missing <kw>end</kw> keyword.
<p/>
 </li><li> Make sure that the type of the object you are using is what you
   think it is.  If in doubt, use <cim><file>object</file><front>Object</front><back>type</back><mref>type</mref></cim> to check the type
   of an object.
<p/>
 </li><li> Make sure that your methods start with a lowercase letter and
   that classes and constants start with an uppercase letter.
<p/>
 </li><li> If you happen to forget a ``,'' in an argument
   list---especially to print---you can produce some very odd error messages.
<p/>
 </li><li> Block parameters are actually local variables. If an existing
   local of the same name exists when the block executes, that
   variable will be modified by the call to the block. This may or may
   not be a good thing.
<p/>
 </li><li> Watch out for precedence, especially when using <tt>{}</tt>
   instead of <kw>do</kw>/<kw>end</kw>.
<p/>
 </li><li> Make sure that the open parenthesis of a method's parameter
   list butts up against the end of the method name with no
   intervening spaces.
<p/>
 </li><li> Output written to a terminal may be buffered. This means that
   you may not see a message you write immediately.      
   In addition, if you write
   messages to both <tt>$stdout</tt> and <tt>$stderr</tt>, the output may
   not appear in the order you were expecting.  Always use nonbuffered
   I/O (set <tt>sync=true</tt>) for debug messages.
<p/>
 </li><li> If numbers don't come out right, perhaps they're strings.  Text
   read from a file will be a <classname>String</classname>, and will not be
   automatically converted to a number by Ruby.  A call to <tt>to_i</tt>
   will work wonders.  A
   common mistake Perl programmers make is:   
<p/>
<codefragment>
<alltt><fullcode><![CDATA[   while gets
     num1, num2 = split /,/
     # ...
   end
]]></fullcode>
while<nbsp/>gets
<nbsp/><nbsp/>num1,<nbsp/>num2<nbsp/>=<nbsp/>split<nbsp/>/,/
<nbsp/><nbsp/>#<nbsp/>...
end
</alltt>
</codefragment>
<p/>
 </li><li> Unintended aliasing---if you are using an object as the key of
   a hash, make sure it doesn't change its hash value (or arrange to
   call <cim><file>hash</file><front>Hash</front><back>rehash</back><mref>rehash</mref></cim> if it does).
<p/>
 </li><li> Use <kw>trace_var</kw> to watch when a variable changes value.
<p/>
 </li><li> Use the debugger.
<p/>
 </li><li> Use <cim><file>object</file><front>Object</front><back>freeze</back><mref>freeze</mref></cim>.  If you suspect that some unknown
   portion of code is setting a variable to a bogus value, try
   freezing the variable.  The culprit will then be caught during the
   attempt to modify the variable.
</li></ul>
<p/>
There's one major technique that makes writing Ruby code both easier
and more fun. <em>Develop your applications incrementally.</em>
Write a
few lines of code, then run them. Write a few more, then run those.
One of the major benefits of an untyped language is that things don't
have to be complete before you use them.
<section>But It's Too Slow!</section>
<p/>
Ruby is an interpreted, high-level language, and as such it may not
perform as fast as a lower-level language such as C.  In this section,
we'll list some basic things you can do to improve performance; also
have a look in the index
under <em>Performance</em> for other pointers.
<subsection>Create Locals Outside Blocks</subsection>
<p/>
Try defining the variables used in a block before the block executes.
When iterating over a very large set of elements, you can improve
execution speed somewhat by predeclaring any iterator variables.  In
the first example below, Ruby has to create new <tt>x</tt> and <tt>y</tt>
variables
on each
iteration, but in the second version it doesn't.  We'll use the
<tt>benchmark</tt> package from the Ruby Application Archive to compare
the loops:
<p/>
<codefragment>
<alltt><fullcode><![CDATA[  require "benchmark"
  include Benchmark
  n = 1000000
  bm(12) do |test|
    test.report("normal:")    do
      n.times do |x|
        y = x + 1 
      end
    end
    test.report("predefine:") do
      x = y = 0
      n.times do |x|
        y = x + 1
      end
    end
  end
]]></fullcode>
require<nbsp/>"benchmark"
include<nbsp/>Benchmark
n<nbsp/>=<nbsp/>1000000
bm(12)<nbsp/>do<nbsp/>|test|
<nbsp/><nbsp/>test.report("normal:")<nbsp/><nbsp/><nbsp/><nbsp/>do
<nbsp/><nbsp/><nbsp/><nbsp/>n.times<nbsp/>do<nbsp/>|x|
<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>y<nbsp/>=<nbsp/>x<nbsp/>+<nbsp/>1
<nbsp/><nbsp/><nbsp/><nbsp/>end
<nbsp/><nbsp/>end
<nbsp/><nbsp/>test.report("predefine:")<nbsp/>do
<nbsp/><nbsp/><nbsp/><nbsp/>x<nbsp/>=<nbsp/>y<nbsp/>=<nbsp/>0
<nbsp/><nbsp/><nbsp/><nbsp/>n.times<nbsp/>do<nbsp/>|x|
<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>y<nbsp/>=<nbsp/>x<nbsp/>+<nbsp/>1
<nbsp/><nbsp/><nbsp/><nbsp/>end
<nbsp/><nbsp/>end
end
</alltt>
</codefragment>
<em>produces:</em>
<codefragment><alltt>
<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>user<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>system<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>total<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>real
normal:<nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/><nbsp/>2.510000<nbsp/><nbsp/><nbsp/>0.000000<nbsp/><nbsp/><nbsp/>2.510000<nbsp/>(<nbsp/><nbsp/>2.390549)
predefine:<nbsp/><nbsp/><nbsp/><nbsp/>2.220000<nbsp/><nbsp/><nbsp/>0.010000<nbsp/><nbsp/><nbsp/>2.230000<nbsp/>(<nbsp/><nbsp/>2.157877)
</alltt>
</codefragment>
<subsection>Use the Profiler</subsection>
<p/>
Ruby comes with a code profiler (documentation begins on
on page 458).  In and of itself, that isn't too surprising,
but when you realize that the profiler is written in just about 50
lines of Ruby, that makes
for a pretty impressive language.
<p/>
You can add profiling to your code using the command-line option
<cmdopt>-r</cmdopt><tt><nbsp/>profile</tt>, or from within the code using <tt>require
  "profile"</tt>. For example:
<p/>
<codefragment>
<alltt><fullcode><![CDATA[  require "profile"
  class Peter
    def initialize(amt)
      @value = amt
    end

    def rob(amt)
      @value -= amt
      amt
    end
  end

  class Paul
    def initialize
      @value = 0
    end

    def pay(amt)
      @value += amt
      amt
    end
  end

  peter = Peter.new(1000)
  paul = Paul.new
  1000.times do
    paul.pay(peter.rob(10))
  end
]]></fullcode>
require<nbsp/>"profile"
class<nbsp/>Peter
<nbsp/><nbsp/>def<nbsp/>initialize(amt)
<nbsp/><nbsp/><nbsp/><nbsp/>@value<nbsp/>=<nbsp/>amt
<nbsp/><nbsp/>end
<p/>
<nbsp/><nbsp/>def<nbsp/>rob(amt)
<nbsp/><nbsp/><nbsp/><nbsp/>@value<nbsp/>-=<nbsp/>amt
<nbsp/><nbsp/><nbsp/><nbsp/>amt
<nbsp/><nbsp/>end
end
<p/>
class<nbsp/>Paul
<nbsp/><nbsp/>def<nbsp/>initialize
<nbsp/><nbsp/><nbsp/><nbsp/>@value<nbsp/>=<nbsp/>0
<nbsp/><nbsp/>end
<p/>
<nbsp/><nbsp/>def<nbsp/>pay(amt)
<nbsp/><nbsp/><nbsp/><nbsp/>@value<nbsp/>+=<nbsp/>amt
<nbsp/><nbsp/><nbsp/><nbsp/>amt
<nbsp/><nbsp/>end
end
<p/>
peter<nbsp/>=<nbsp/>Peter.new(1000)
paul<nbsp/>=<nbsp/>Paul.new
1000.times<nbsp/>do
<nbsp/><nbsp/>paul.pay(peter.rob(10))
end
</alltt>
</codefragment>
<p/>
Run this, and you'll get something like the following.
<p/>
<verbatim>
 time   seconds   seconds    calls  ms/call  ms/call  name
 40.22     0.37      0.37        1   370.00   920.00  Fixnum#times
 25.00     0.60      0.23     1000     0.23     0.25  Paul#pay
 25.00     0.83      0.23     1000     0.23     0.30  Peter#rob
  7.61     0.90      0.07     1000     0.07     0.07  Fixnum#-
  2.17     0.92      0.02     1000     0.02     0.02  Fixnum#+
  0.00     0.92      0.00        1     0.00     0.00  Peter#initialize
  0.00     0.92      0.00        2     0.00     0.00  Class#inherited
  0.00     0.92      0.00        1     0.00     0.00  Paul#initialize
  0.00     0.92      0.00        4     0.00     0.00  Module#method_added
  0.00     0.92      0.00        2     0.00     0.00  Class#new
  0.00     0.92      0.00        1     0.00   920.00  #toplevel
</verbatim>
With the profiler, you can quickly identify and fix bottlenecks.
Remember to check the code without the profiler afterward,
though---sometimes the slowdown the profiler introduces can mask other
problems.
<p/>
Ruby is a wonderfully transparent and expressive language, but it does
not relieve the programmer of the need to apply common sense: creating
unnecessary objects, performing unneeded work, and creating generally
bloated code are wasteful in any language.
<figure type="table">
  <caption>Debugger commands</caption>  
  <table>
<th>
  <td>b[reak] [file:]line</td>
  <td>Set breakpoint at given line in <obj>file</obj>
                      (default current file).</td>
</th>
<th>
  <td>b[reak] [file:]name</td>
  <td>Set breakpoint at <obj>method</obj> in <obj>file</obj>.</td>
</th>
<th>
  <td>b[reak]</td>
  <td>Display breakpoints and watchpoints.</td>
</th>
<th>
  <td>wat[ch] expr</td>
  <td>Break when expression becomes true.</td>
</th>
<th>
  <td>del[ete] [nnn]</td>
  <td>Delete breakpoint <obj>nnn</obj> (default all).</td>
</th>
<tr>
  <td>disp[lay] expr</td>
  <td>Display value of <obj>nnn</obj> every time debugger gets control.</td>
</tr>
<tr>
  <td>disp[lay]</td>
  <td>Show current displays.</td>
</tr>
<tr>
  <td>undisp[lay] [nnn]</td>
  <td>Remove display (default all).</td>
</tr>
<th>
  <td>c[ont]</td>
  <td>Continue execution.</td>
</th>
<th>
  <td>s[tep]  nnn=1</td>
  <td>Execute next <obj>nnn</obj> lines, stepping into methods.</td>
</th>
<th>
  <td>n[ext]  nnn=1</td>
  <td>Execute next <obj>nnn</obj> lines, stepping over methods.</td>
</th>
<th>
  <td>fi[nish]</td>
  <td>Finish execution of the current function.</td>
</th>
<th>
  <td>q[uit]</td>
  <td>Exit the debugger.</td>
</th>
<tr>
  <td>w[here]</td>
  <td>Display current stack frame.</td>
</tr>
<tr>
  <td>f[rame]</td>
  <td>Synonym for <tt>where</tt>.</td>
</tr>
<tr>
  <td>l[ist] [start--end]</td>
  <td>List source lines from start to end.</td>
</tr>
<tr>
  <td>up  nnn=1</td>
  <td>Move up <obj>nnn</obj> levels in the stack frame.</td>
</tr>
<tr>
  <td>down nnn=1</td>
  <td>Move down <obj>nnn</obj> levels in the stack frame.</td>
</tr>
<th>
  <td>v[ar] g[lobal]</td>
  <td>Display global variables.</td>
</th>
<th>
  <td>v[ar] l[ocal]</td>
  <td>Display local variables.</td>
</th>
<th>
  <td>v[ar] i[stance] <obj>obj</obj></td>
  <td>Display instance variables of <obj>obj</obj>.</td>
</th>
<th>
  <td>v[ar] c[onst] Name</td>
  <td>Display constants in class or module name.</td>
</th>
<tr>
  <td>m[ethod] i[nstance] <obj>obj</obj></td>
  <td>Display instance methods of
                                    <obj>obj</obj>.</td>
</tr>
<tr>
  <td>m[ethod] Name</td>
  <td>Display instance methods of the class or module name.</td>
</tr>
<th>
  <td>th[read] l[ist]</td>
  <td>List all threads.</td>
</th>
<th>
  <td>th[read] [c[ur[rent]]]</td>
  <td>Display status of current thread.</td>
</th>
<th>
  <td>th[read] [c[ur[rent]]] nnn</td>
  <td>Make thread <obj>nnn</obj> current and
                                   stop it.</td>
</th>
<th>
  <td>th[read] stop nnn</td>
  <td>Make thread <obj>nnn</obj> current and stop it.</td>
</th>
<th>
  <td>th[read] resume nnn</td>
  <td>Resume thread <obj>nnn</obj>.</td>
</th>
<tr>
  <td>[p] expr</td>
  <td>Evaluate <obj>expr</obj> in the current context. <obj>expr</obj> may
               include assignment to variables and method invocations.</td>
</tr>
<th>
  <td><obj>empty</obj></td>
  <td>A null command repeats the last command.</td>
</th>
<bottomrule/></table>
<p/>
</figure>
<p/>
</chapter>
</ppdoc>