Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Ruby / Yukihiro Matsumoto_Programming Ruby.doc
Скачиваний:
144
Добавлен:
06.06.2015
Размер:
2.71 Mб
Скачать

Independent Children

Sometimes we don't need to be quite so hands-on: we'd like to give the subprocess its assignment and then go on about our business. Some time later, we'll check in with it to see if it has finished. For instance, we might want to kick off a long-running external sort.

exec("sort testfile > output.txt") if fork == nil

# The sort is now running in a child process

# carry on processing in the main program

# then wait for the sort to finish

Process.wait

The call to Kernel::fork returns a process id in the parent, andnilin the child, so the child process will perform theKernel::exec call and run sort. Sometime later, we issue aProcess::wait call, which waits for the sort to complete (and returns its process id).

If you'd rather be notified when a child exits (instead of just waiting around), you can set up a signal handler using Kernel::trap (described on page 427). Here we set up a trap onSIGCLD, which is the signal sent on ``death of child process.''

trap("CLD") {

  pid = Process.wait

  puts "Child pid #{pid}: terminated"

  exit

}

exec("sort testfile > output.txt") if fork == nil

# do other stuff...

produces:

Child pid 19326: terminated

Blocks and Subprocesses

IO.popen works with a block in pretty much the same way asFile.open does. Passpopena command, such asdate, and the block will be passed anIOobject as a parameter.

IO.popen ("date") { |f| puts "Date is #{f.gets}" }

produces:

Date is Sun Nov 25 23:43:36 CST 2001

The IOobject will be closed automatically when the code block exits, just as it is withFile.open .

If you associate a block with Kernel::fork , the code in the block will be run in a Ruby subprocess, and the parent will continue after the block.

fork do

  puts "In child, pid = #$$"

  exit 99

end

pid = Process.wait

puts "Child terminated, pid = #{pid}, exit code = #{$? >> 8}"

produces:

In child, pid = 19333

Child terminated, pid = 19333, exit code = 99

One last thing. Why do we shift the exit code in $?8 bits to the right before displaying it? This is a ``feature'' of Posix systems: the bottom 8 bits of an exit code contain the reason the program terminated, while the higher-order 8 bits hold the actual exit code.

When Trouble Strikes

Sad to say, it is possible to write buggy programs using Ruby. Sorry about that.

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.

Ruby Debugger

Ruby comes with a debugger, which is conveniently built into the base system. You can run the debugger by invoking the interpreter with the -r debugoption, along with any other Ruby options and the name of your script:

ruby -r debug [

options

][

programfile

][

arguments

]

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.

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 131 lists all of the commands that are available under the debugger.

If your Ruby has readlinesupport enabled, you can use cursor keys to move back and forth in command history and use line editing commands to amend previous input.

To give you an idea of what the Ruby debugger is like, here is a sample session.

%

ruby -rdebug t.rb

Debug.rb

Emacs support available.

t.rb:1:def fact(n)

(rdb:1)

list 1-9

[1, 10] in t.rb

=> 1 def fact(n)

2 if n <= 0

3 1

4 else

5 n * fact(n-1)

6 end

7 end

8

9 p fact(5)

(rdb:1)

b 2

Set breakpoint 1 at t.rb:2

(rdb:1)

c

breakpoint 1, fact at t.rb:2

t.rb:2: if n <= 0

(rdb:1)

disp n

1: n = 5

(rdb:1)

del 1

(rdb:1)

watch n==1

Set watchpoint 2

(rdb:1)

c

watchpoint 2, fact at t.rb:fact

t.rb:1:def fact(n)

1: n = 1

(rdb:1)

where

--> #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)

del 2

(rdb:1)

c

120

Соседние файлы в папке Ruby