Хэл Фултон - Программирование на языке Ruby
- Название:Программирование на языке Ruby
- Автор:
- Жанр:
- Издательство:ДМК Пресс
- Год:2007
- Город:Москва
- ISBN:5-94074-357-9
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Хэл Фултон - Программирование на языке Ruby краткое содержание
Ruby — относительно новый объектно-ориентированный язык, разработанный Юкихиро Мацумото в 1995 году и позаимствовавший некоторые особенности у языков LISP, Smalltalk, Perl, CLU и других. Язык активно развивается и применяется в самых разных областях: от системного администрирования до разработки сложных динамических сайтов.
Книга является полноценным руководством по Ruby — ее можно использовать и как учебник, и как справочник, и как сборник ответов на вопросы типа «как сделать то или иное в Ruby». В ней приведено свыше 400 примеров, разбитых по различным аспектам программирования, и к которым автор дает обстоятельные комментарии.
Издание предназначено для программистов самого широкого круга и самой разной квалификации, желающих научиться качественно и профессионально работать на Ruby.
Программирование на языке Ruby - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
end
Пусть на вход подаются следующие строки:
а = 1
b = 2 + 3
с = 'date'
Тогда в результате мы получим такой хэш: {"а"=>1, "b"=>5,"с"=>"Mon Apr 30 21:17:47 CDT 2001\n"}
. На этом примере демонстрируется также опасность вычисления с помощью eval
строк, содержимое которых вы не контролируете; злонамеренный пользователь может подсунуть строку d= 'rm *'
и стереть всю вашу дневную работу.
В Ruby есть еще три метода, которые интерпретируют код «на лету»: class_eval
, module_eval
и instance_eval
. Первые два — синонимы, и все они выполняют одно и то же: интерпретируют строку или блок, но при этом изменяют значение псевдопеременной self
так, что она указывает на объект, от имени которого эти методы вызваны. Наверное, чаще всего метод class_eval
применяется для добавления методов в класс, на который у вас имеется только ссылка. Мы продемонстрируем это в коде метода hook_method
в примере утилиты Trace
в разделе 11.3.13. Другие примеры вы найдете в динамических библиотечных модулях, например delegate.rb
.
Метод eval
позволяет также вычислять локальные переменные в контексте, не принадлежащем их области видимости. Мы не рекомендуем легкомысленно относиться к этой возможности, но знать, что она существует, полезно.
Ruby ассоциирует локальные переменные с блоками, с определениями высокоуровневых конструкций (класса, модуля и метода) и с верхним уровнем программы (кодом, расположенным вне любых определений). С каждой из этих областей видимости ассоциируются привязки переменных и другие внутренние детали. Наверное, самым главным потребителем информации о привязках является программа irb
— интерактивная оболочка для Ruby, которая пользуется привязками, чтобы отделить собственные переменные от тех, которые принадлежат вводимой программе.
Можно инкапсулировать текущую привязку в объект с помощью метода Kernel#binding
. Тогда вы сможете передать привязку в виде второго параметра методу eval
, установив контекст исполнения для интерпретируемого кода.
def some_method
а = "local variable"
return binding
end
the_binding = some_method
eval "a", the_binding # "local variable"
Интересно, что информация о наличии блока, ассоциированного с методом, сохраняется как часть привязки, поэтому возможны такие трюки:
def some_method
return binding
end
the_binding = some_method { puts "hello" }
eval "yield", the_binding # hello
11.3.2. Метод const_get
Метод const_get
получает значение константы с заданным именем из модуля или класса, которому она принадлежит.
str = "PI"
Math.const_get(str) # Значение равно Math::PI.
Это способ избежать обращения к методу eval
, которое иногда считается неэлегантным. Такой подход дешевле с точки зрения потребления ресурсов и безопаснее. Есть и другие аналогичные методы: instance_variable_set
, instance_variable_get
и define_method
.
Метод const_get
действительно работает быстрее, чем eval
. В неформальных тестах — на 350% быстрее, хотя у вас может получиться другой результат. Но так ли это важно? Ведь в тестовой программе на 10 миллионов итераций цикла все равно ушло менее 30 секунд.
Истинная полезность метода const_get
в том, что его проще читать, он более специфичен и лучше самодокументирован. Даже если бы он был всего лишь синонимом eval
, все равно это стало бы большим шагом вперед.
11.3.3. Динамическое создание экземпляра класса, заданного своим именем
Такой вопрос мы видели многократно. Пусть дана строка, содержащая имя класса; как можно создать экземпляр этого класса?
Правильный способ — воспользоваться методом const_get
, который мы только что рассмотрели. Имена всех классов в Ruby — константы в «глобальном» пространстве имен, то есть члены класса Object
.
classname = "Array"
klass = Object.const_get(classname)
x = klass.new(4, 1) # [1, 1, 1, 1]
А если имена вложены? Как выясняется, следующий код не работает:
class Alpha
class Beta
class Gamma
FOOBAR =237
end
end
end
str = "Alpha::Beta::Gamma::FOOBAR"
val = Object.const_get(str) # Ошибка!
Дело в том, что метод const_get
недостаточно «умен», чтобы распознать такие вложенные имена. Впрочем, в следующем примере приведена работающая идиома:
# Структура класса та же
str = "Alpha::Beta::Gamma::FOOBAR"
val = str.split("::").inject(Object) {|x,y| x.const_get(y) } # 237
Такой код встречается часто (и демонстрирует интересное применение inject
).
11.3.4. Получение и установка переменных экземпляра
Отвечая на пожелание употреблять eval
как можно реже, в Ruby теперь включены методы, которые могут получить или присвоить новое значение переменной экземпляра, имя которой задано в виде строки:
class MyClass
attr_reader :alpha, :beta
def initialize(a,b,g)
@alpha, @beta, @gamma = a, b, g
end
end
x = MyClass.new(10,11,12)
x.instance_variable_set("@alpha",234)
p x.alpha # 234
x.instance_variable_set("@gamma",345) # 345
v = x.instance_variable_get("@gamma") # 345
Прежде всего, отметим, что имя переменной должно начинаться со знака @
, иначе произойдет ошибка. Если это кажется вам неочевидным, вспомните, что метод attr_accessor
(и ему подобные) принимает для формирования имени метода символ, поэтому-то знак @
и опускается.
Не нарушает ли существование таких методов принцип инкапсуляции? Нет. Конечно, эти методы потенциально опасны. Пользоваться ими следует с осторожностью, а не при всяком удобном случае. Но нельзя говорить, что инкапсуляция нарушена, не видя, как эти инструменты применяются в конкретном случае. Если это делается обдуманно, ради ясно осознанной цели, то все хорошо. Если же цель состоит в том, чтобы нарушить проект или обойти неудачное проектное решение, это печально. Ruby намеренно предоставляет доступ к внутренним деталям объектов тем, кому это действительно нужно; ответственный программист не станет пользоваться свободой во вред.
11.3.5. Метод define_method
Помимо ключевого слова def
, единственный нормальный способ добавить метод в класс или объект — воспользоваться методом define_method
, причем он позволяет сделать это во время выполнения.
Конечно, в Ruby практически все происходит во время выполнения. Если окружить определение метода обращениями к puts
, как в примере ниже, вы это сами увидите.
class MyClass
puts "до"
def meth
#...
end
puts "после"
end
Но внутри тела метода или в другом аналогичном месте нельзя заново открыть класс (если только это не синглетный класс). В таком случае в прежних версиях Ruby приходилось прибегать к помощи eval
, теперь же у нас есть метод define_method
. Он принимает символ (имя метода) и блок (тело метода).
Интервал:
Закладка: