Категории
Самые читаемые
Лучшие книги » Компьютеры и Интернет » Программирование » Программирование на языке Ruby - Хэл Фултон

Программирование на языке Ruby - Хэл Фултон

Читать онлайн Программирование на языке Ruby - Хэл Фултон

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 88 89 90 91 92 93 94 95 96 ... 156
Перейти на страницу:

end

p Alpha::FOO # "В Alpha нет FOO"

p Beta::FOO  # "В Beta нет FOO"

p A::FOO     # "В Alpha нет FOO"

p В::FOO     # "В Beta нет FOO"

11.3.7. Удаление определений

Вследствие динамичности Ruby практически все, что можно определить, можно и уничтожить. Это может пригодиться, например, для того, чтобы «развязать» два куска кода в одной и той же области действия, избавляясь от переменных после того, как они были использованы. Другой повод — запретить вызовы некоторых потенциально опасных методов. Но по какой бы причине вы ни удаляли определение, делать это нужно крайне осторожно, чтобы не создать себе проблемы во время отладки.

Радикальный способ уничтожить определение — воспользоваться ключевым словом undef (неудивительно, что его действие противоположно действию def). Уничтожать можно определения методов, локальных переменных и констант на верхнем уровне. Хотя имя класса — тоже константа, удалить определение класса таким способом невозможно.

def asbestos

 puts "Теперь не огнеопасно"

end

tax =0.08

PI = 3

asbestos

puts "PI=#{PI}, tax=#{tax}"

undef asbestos

undef tax

undef PI

# Любое обращение к этим трем именам теперь приведет к ошибке.

Внутри определения класса можно уничтожать определения методов и констант в том же контексте, в котором они были определены. Нельзя применять undef внутри определения метода, а также к переменной экземпляра.

Существуют (определены в классе Module) также методы remove_method и undef_method. Разница между ними тонкая: remove_method удаляет текущее (или ближайшее) определение метода, a undef_method ко всему прочему удаляет его и из суперклассов, не оставляя от метода даже следа. Это различие иллюстрирует листинг 11.6.

Листинг 11.16. Методы remove_method и undef_method

class Parent

 def alpha

  puts "alpha: родитель"

 end

 def beta

  puts "beta: родитель"

 end

end

class Child < Parent

 def alpha

  puts "alpha: потомок"

 end

 def beta

  puts "beta: потомок"

 end

 remove_method :alpha # Удалить "этот" alpha.

 undef_method :beta   # Удалить все beta.

end

x = Child.new

x.alpha               # alpha: родитель

x.beta                # Ошибка!

Метод remove_const удаляет константу.

module Math

remove_const :PI

 end

# PI больше нет!

Отметим, что таким способом можно удалить и определение класса (потому что идентификатор класса — это просто константа):

class BriefCandle

 #...

end

out_out = BriefCandle.new

class Object

 remove_const :BriefCandle

end

# Создать еще один экземпляр класса BriefCandle не получится!

# (Хотя out_out все еще существует...)

Такие методы, как remove_const и remove_method, являются закрытыми (что и понятно). Поэтому во всех примерах они вызываются изнутри определения класса или модуля, а не снаружи.

11.3.8. Получение списка определенных сущностей

API отражения в Ruby позволяет опрашивать классы и объекты во время выполнения. Рассмотрим методы, имеющиеся для этой цели в Module, Class и Object.

В модуле Module есть метод constants, который возвращает массив всех констант, определенных в системе (включая имена классов и модулей). Метод nesting возвращает массив всех вложенных модулей, видимых в данной точке программы.

Метод экземпляра Module#ancestors возвращает массив всех предков указанного класса или модуля.

list = Array.ancestors

# [Array, Enumerable, Object, Kernel]

Метод constants возвращает список всех констант, доступных в данном модуле. Включаются также его предки.

list = Math.constants # ["E", "PI"]

Метод class_variables возвращает список всех переменных класса в данном классе и его суперклассах. Метод included_modules возвращает список модулей, включенных в класс.

class Parent

 @@var1 = nil

end

class Child < Parent

 @@var2 = nil

end

list1 = Parent.class_variables # ["@@var1"]

list2 = Array.included_modules # [Enumerable, Kernel]

Методы instance_methods и public_instance_methods класса Class — синонимы; они возвращают список открытых методов экземпляра, определенных в классе. Методы private_instance_methods и protected_instance_methods ведут себя аналогично. Любой из них принимает необязательный булевский параметр, по умолчанию равный true; если его значение равно false, то суперклассы не учитываются, так что список получается меньше.

n1 = Array.instance_methods.size               # 121

n2 = Array.public_instance_methods.size        # 121

n3 = Array.private_instance_methods.size       # 71

n4 = Array.protected_instance_methods.size     # 0

n5 = Array.public_instance_methods(false).size # 71

В классе Object есть аналогичные методы, применяющиеся к экземплярам (листинг 11.17). Метод methods возвращает список всех методов, которые можно вызывать для данного объекта. Метод public_methods возвращает список открытых методов и принимает параметр, равный по умолчанию true, который говорит, нужно ли включать также методы суперклассов. Методы private_methods, protected_methods и singleton_methods тоже принимают такой параметр.

Листинг 11.17. Отражение и переменные экземпляра

class SomeClass

 def initialize

  @a = 1

  @b = 2

 end

 def mymeth

  # ...

 end

 protected :mymeth

end

x = SomeClass.new

def

 x.newmeth

 # ...

end

iv = x.instance_variables       # ["@b", "@a"]

p x.methods.size                # 42

p x.public_methods.size         # 41

p x.public_methods(false).size  # 1

p x.private_methods.size        # 71

p x.private_methods(false).size # 1

p x.protected_methods.size      # 1

p x.singleton_methods.size      # 1

Если вы работаете с Ruby уже несколько лет, то заметите, что эти методы немного изменились. Теперь параметры по умолчанию равны true, а не false.

11.3.9. Просмотр стека вызовов

And you may ask yourself:Well, how did I get here?[13]

Talking Heads, «Once in a Lifetime»

Иногда необходимо знать, кто вызвал метод. Эта информация полезна, если, например, произошло неисправимое исключение. Метод caller, определенный в модуле Kernel, дает ответ на этот вопрос. Он возвращает массив строк, в котором первый элемент соответствует вызвавшему методу, следующий — методу, вызвавшему этот метод, и т.д.

def func1

 puts caller[0]

end

def func2

 func1

end

func2 # Печатается: somefile.rb:6:in 'func2'

Строка имеет формат «файл;строка» или «файл;строка в методе».

11.3.10. Мониторинг выполнения программы

Программа на Ruby может следить за собственным выполнением. У этой возможности есть много применений; интересующийся читатель может заглянуть в исходные тексты программ debug.rb, profile.rb и tracer.rb. С ее помощью можно даже создать библиотеку для «проектирования по контракту» (design-by-contract, DBC), хотя наиболее популярная в данный момент библиотека такого рода этим средством не пользуется.

Интересно, что этот фокус реализован целиком на Ruby. Мы пользуемся методом set_trace_func, который позволяет вызывать указанный блок при возникновении значимых событий в ходе исполнения программы. В справочном руководстве описывается последовательность вызова set_trace_func, поэтому здесь мы ограничимся простым примером:

def meth(n)

 sum = 0

 for i in 1..n

  sum += i

 end

 sum

end

set_trace_func(proc do |event, file, line,

 id, binding, klass, *rest|

 printf "%8s %s:%d %s/%sn", event, file, line,

  klass, id

 end)

meth(2)

Отметим, что здесь соблюдается стандартное соглашение о заключении многострочного блока в операторные скобки do-end. Круглые скобки обязательны из-за особенностей синтаксического анализатора Ruby. Можно было бы, конечно, вместо этого поставить фигурные скобки.

1 ... 88 89 90 91 92 93 94 95 96 ... 156
Перейти на страницу:
На этой странице вы можете бесплатно скачать Программирование на языке Ruby - Хэл Фултон торрент бесплатно.
Комментарии