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

Runtime Callbacks

You can be notified whenever one of the following events occurs:

Event

Callback Method

Adding an instance method

Module#method_added

Adding a singleton method

Kernel::singleton_method_added

Subclassing a class

Class#inherited

Mixing in a module

Module#extend_object

These techniques are all illustrated in the library descriptions for each callback method. At runtime, these methods will be called by the system when the specified event occurs. By default, these methods do nothing. If you want to be notified when one of these events happens, just define the callback method, and you're in.

Keeping track of method creation and class and module usage lets you build an accurate picture of the dynamic state of your program. This can be important. For example, you may have written code that wraps all the methods in a class, perhaps to add transactional support or to implement some form of delegation. This is only half the job: the dynamic nature of Ruby means that users of this class could add new methods to it at any time. Using these callbacks, you can write code that wraps these new methods as they are created.

Tracing Your Program's Execution

While we're having fun reflecting on all the objects and classes in our programs, let's not forget about the humble statements that make our code actually do things. It turns out that Ruby lets us look at these statements, too.

First, you can watch the interpreter as it executes code. set_trace_funcexecutes aProcwith all sorts of juicy debugging information whenever a new source line is executed, methods are called, objects are created, and so on. There's a full description on page 422, but here's a taste.

class Test

  def test

    a = 1

    b = 2

  end

end

set_trace_func proc { |event, file, line, id, binding, classname|

  printf "%8s %s:%-2d %10s %8s\n", event, file, line, id, classname

}

t = Test.new

t.test

produces:

    line prog.rb:11               false

  c-call prog.rb:11        new    Class

  c-call prog.rb:11 initialize   Object

c-return prog.rb:11 initialize   Object

c-return prog.rb:11        new    Class

    line prog.rb:12               false

    call prog.rb:2        test     Test

    line prog.rb:3        test     Test

    line prog.rb:4        test     Test

  return prog.rb:4        test     Test

There's also a method trace_var(described on page 427) that lets you add a hook to a global variable; whenever an assignment is made to the global, yourProcobject is invoked.

How Did We Get Here?

A fair question, and one we ask ourselves regularly. Mental lapses aside, in Ruby at least you can find out exactly ``how you got there'' by using the method caller, which returns anArrayofStringobjects representing the current call stack.

def catA

  puts caller.join("\n")

end

def catB

  catA

end

def catC

  catB

end

catC

produces:

prog.rb:5:in `catB'

prog.rb:8:in `catC'

prog.rb:10

Once you've figured out how you got there, where you go next is up to you.

Marshaling and Distributed Ruby

Java features the ability to serializeobjects, letting you store them somewhere and reconstitute them when needed. You might use this facility, for instance, to save a tree of objects that represent some portion of application state---a document, a CAD drawing, a piece of music, and so on.

Ruby calls this kind of serialization marshaling.[Think of railroad marshaling yards where individual cars are assembled in sequence into a complete train, which is then dispatched somewhere.]Saving an object and some or all of its components is done using the methodMarshal::dump . Typically, you will dump an entire object tree starting with some given object. Later on, you can reconstitute the object usingMarshal::load .

Here's a short example. We have a class Chordthat holds a collection of musical notes. We'd like to save away a particularly wonderful chord so our grandchildren can load it into Ruby Version 23.5 and savor it, too. Let's start off with the classes forNoteandChord.

class Note

  attr :value

  def initialize(val)

    @value = val

  end

  def to_s

    @value.to_s

  end

end

class Chord

  def initialize(arr)

    @arr = arr

  end

  def play

    @arr.join('-')

  end

end

Now we'll create our masterpiece, and use Marshal::dump to save a serialized version of it to disk.

c = Chord.new( [ Note.new("G"),  Note.new("Bb"),

                 Note.new("Db"), Note.new("E") ] )

File.open("posterity", "w+") do |f|

  Marshal.dump(c, f)

end

Finally, our grandchildren read it in, and are transported by our creation's beauty.

File.open("posterity") do |f|

  chord = Marshal.load(f)

end

chord.play

»

"G-Bb-Db-E"

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