Программирование на языке Ruby
Программирование на языке Ruby читать книгу онлайн
Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала
11.3.3. Динамическое создание экземпляра класса, заданного своим именем
Такой вопрос мы видели многократно. Пусть дана строка, содержащая имя класса; как можно создать экземпляр этого класса?
Правильный способ — воспользоваться методом
const_getObjectclassname = "Array"klass = Object.const_get(classname)x = klass.new(4, 1) # [1, 1, 1, 1]А если имена вложены? Как выясняется, следующий код не работает:
class Alpha class Beta class Gamma FOOBAR =237 end endendstr = "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Такой код встречается часто (и демонстрирует интересное применение
inject11.3.4. Получение и установка переменных экземпляра
Отвечая на пожелание употреблять
evalclass MyClass attr_reader :alpha, :beta def initialize(a,b,g) @alpha, @beta, @gamma = a, b, g endendx = MyClass.new(10,11,12)x.instance_variable_set("@alpha",234)p x.alpha # 234x.instance_variable_set("@gamma",345) # 345v = x.instance_variable_get("@gamma") # 345Прежде всего, отметим, что имя переменной должно начинаться со знака
@attr_accessor@Не нарушает ли существование таких методов принцип инкапсуляции? Нет. Конечно, эти методы потенциально опасны. Пользоваться ими следует с осторожностью, а не при всяком удобном случае. Но нельзя говорить, что инкапсуляция нарушена, не видя, как эти инструменты применяются в конкретном случае. Если это делается обдуманно, ради ясно осознанной цели, то все хорошо. Если же цель состоит в том, чтобы нарушить проект или обойти неудачное проектное решение, это печально. Ruby намеренно предоставляет доступ к внутренним деталям объектов тем, кому это действительно нужно; ответственный программист не станет пользоваться свободой во вред.
11.3.5. Метод define_method
Помимо ключевого слова
defdefine_methodКонечно, в Ruby практически все происходит во время выполнения. Если окружить определение метода обращениями к
putsclass MyClass puts "до" def meth #... end puts "после"endНо внутри тела метода или в другом аналогичном месте нельзя заново открыть класс (если только это не синглетный класс). В таком случае в прежних версиях Ruby приходилось прибегать к помощи
evaldefine_methodПервая (ошибочная) попытка воспользоваться этим методом могла бы выглядеть так:
# Не работает, так как метод define_method закрытый.if today =~ /Saturday | Sunday/ define_method(:activity) { puts "Отдыхаем!" }else define_method(:activity) { puts "Работаем!" }endactivityПоскольку
define_method# Работает (Object - это контекст верхнего уровня).if today =~ /Saturday | Sunday/ Object.class_eval { define_method(:activity) { puts "Отдыхаем!" } }else Object.class_eval { define_method(:activity) { puts "Работаем!" } }endactivityМожно было бы поступить так же внутри определения класса (в применении к классу
Objectclass MyClass define_method(:mymeth) { puts "Это мой метод." }endЕсть еще один трюк: включить в класс метод, который сам вызывает
define_method
