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

Reflection, ObjectSpace, and Distributed Ruby

One of the many advantages of dynamic languages such as Ruby is the ability to introspect---to examine aspects of the program from within the program itself. Java, for one, calls this featurereflection.

The word ``reflection'' conjures up an image of looking at oneself in the mirror---perhaps investigating the relentless spread of that bald spot on the top of one's head. That's a pretty apt analogy: we use reflection to examine parts of our programs that aren't normally visible from where we stand.

In this deeply introspective mood, while we are contemplating our navels and burning incense (being careful not to swap the two tasks), what can we learn about our program? We might discover:

  • what objects it contains,

  • the current class hierarchy,

  • the contents and behaviors of objects, and

  • information on methods.

Armed with this information, we can look at particular objects and decide which of their methods to call at runtime---even if the class of the object didn't exist when we first wrote the code. We can also start doing clever things, perhaps modifying the program as it's running.

Sound scary? It needn't be. In fact, these reflection capabilities let us do some very useful things. Later in this chapter we'll look at distributed Ruby and marshaling, two reflection-based technologies that let us send objects around the world and through time.

Looking at Objects

Have you ever craved the ability to traverse allthe living objects in your program? We have! Ruby lets you perform this trick withObjectSpace::each_object . We can use it to do all sorts of neat tricks.

For example, to iterate over all objects of type Numeric, you'd write the following.

a = 102.7

b = 95.1

ObjectSpace.each_object(Numeric) {|x| p x }

produces:

95.1

102.7

2.718281828

3.141592654

Hey, where did those last two numbers come from? We didn't define them in our program. If you look on page 429, you'll see that the Mathmodule defines constants for e and PI; since we are examiningallliving objects in the system, these turn up as well.

However, there is a catch. Let's try the same example with different numbers.

a = 102

b = 95

ObjectSpace.each_object(Numeric) {|x| p x }

produces:

2.718281828

3.141592654

Neither of the Fixnumobjects we created showed up. That's becauseObjectSpacedoesn't know about objects with immediate values:Fixnum,true,false, andnil.

Looking Inside Objects

Once you've found an interesting object, you may be tempted to find out just what it can do. Unlike static languages, where a variable's type determines its class, and hence the methods it supports, Ruby supports liberated objects. You really cannot tell exactly what an object can do until you look under its hood.[Or under its bonnet, for objects created to the east of the Atlantic.]

For instance, we can get a list of all the methods to which an object will respond.

r = 1..10 # Create a Range object

list = r.methods

list.length

»

60

list[0..3]

»

["size", "exclude_end?", "to_s", "length"]

Or, we can check to see if an object supports a particular method.

r.respond_to?("frozen?")

»

true

r.respond_to?("hasKey")

»

false

"me".respond_to?("==")

»

true

We can determine our object's class and its unique object id, and test its relationship to other classes.

num = 1

num.id

»

3

num.class

»

Fixnum

num.kind_of? Fixnum

»

true

num.kind_of? Numeric

»

true

num.instance_of? Fixnum

»

true

num.instance_of? Numeric

»

false

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