![]() |
|
|
![]()
|
|
| fell |
|
|||
|
Новичок Профиль Группа: Участник Сообщений: 41 Регистрация: 17.12.2008 Где: Санкт-Петербург Репутация: нет Всего: нет |
Добрый день
Изучаю ror и ruby потихоньку и недавно натолкнулся на такой вот код. Конкретно отсюда ссылка. Sinatra microframework. Если еще конкретней, то эта функция используется в Padrino framework. Уже вторая строчка поставила в тупик. По идее функция работать не должна, но работает. В данном случае self должен быть объектом класса, метод вызывается в классе class Admin. Если говорить в общем и целом функция должна брать метод, который определяется символом, и параметры, но дело в том, что метод login_page не принимает параметры. Кажется все очень сложно и навернуто.... вызов функции выглядит так: set :login_page "app/controller/new" сама функция def set(option, value=self, &block) raise ArgumentError if block && value != self # Если блок =nil и value не self, тогда ArgumentError и выходим из функции, но в вызове функции блока нет, есть option =:login_page и value ="app/controller/new" value = block if block if value.kind_of?(Proc) metadef(option, &value) metadef("#{option}?") { !!__send__(option) } metadef("#{option}=") { |val| metadef(option, &Proc.new{val}) } elsif value == self && option.respond_to?(:to_hash) option.to_hash.each { |k,v| set(k, v) } elsif respond_to?("#{option}=") __send__ "#{option}=", value else set option, Proc.new{value} end self end # в этом методе создается синглетон класс, и в нем определяется метод. Название метода = message, а тело метода &block def metadef(message, &block) (class << self; self; end). send :define_method, message, &block end Это сообщение отредактировал(а) fell - 17.7.2010, 16:32 |
|||
|
||||
| source777 |
|
||||||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1878 Регистрация: 12.3.2007 Репутация: 6 Всего: 56 |
fell, это конечно очень занятно, но в чём вопрос то?
Уже неверный пересказ кода своими словами... Исключение будет как раз в противоположной ситуации - только если блок передан и value не self. А раз блок не передан, то исключения эта строка сгенерировать не может.
Ну правильно, именно поэтому value оборачивается в простейший блок с помощью строки
после чего на следующем вызове set будет value.kind_of?(Proc) == true. И в результате имеем 3 метода:
Ясно? -------------------- Если бы программистам платили за то, чтобы убирать код из программы вместо того, чтобы добавлять его, программы были бы намного лучше © Николас Негропонте |
||||||||
|
|||||||||
| fell |
|
|||
|
Новичок Профиль Группа: Участник Сообщений: 41 Регистрация: 17.12.2008 Где: Санкт-Петербург Репутация: нет Всего: нет |
да видимо чего то попутал
raise ArgumentError if block && value != self если рассмотреть все случаи raise ArgumentError if true # true = true && true, если true&&false = false, false&&true=false - block = nil -> false, значит общее false дальше value = block if block # поскольку блок =nil, то присвоения не будет if value.kind_of?(Proc) пропускаем ибо оно не Proc elsif value == self # value не self, пропускаем elsif respond_to?("#{option}=") # тоже нет ибо нету option= set option, Proc.new{value} # set :login_page, Proc.new{"app/controller/new"} ага тут как бы рекурсия получается, то есть идет вызов метода уже с блоком потом выполняется этот кусок if value.kind_of?(Proc) metadef(option, &value) metadef("#{option}?") { !!__send__(option) } metadef("#{option}=") { |val| metadef(option, &Proc.new{val}) } и в последней строке возвращается self а self у нас = Admin то есть функция возвращает класс ? объект типа класс, с именем Admin, наверно так правильней а зачем эти методы отправлять в синглетон класс ? в этой обертке, чтобы сделать их классовыми методами ? def metadef(message, &block) (class << self; self; end). send :define_method, message, &block end и последнее !!login_page какое то двойное отрицание ?это ! я знаю не, а там получается не, не ? !true=false -> !false =true, тогда какой смысл .. Это сообщение отредактировал(а) fell - 17.7.2010, 20:56 |
|||
|
||||
| source777 |
|
||||||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1878 Регистрация: 12.3.2007 Репутация: 6 Всего: 56 |
И что с того? Хотя правильнее сказать, что функция возвращает self, а что это будет по факту будет зависеть от контекста её вызова.
Смысл в том, что на выходе получиться значение булева типа, как правило такой приём используется в библиотечном коде для перестраховки, мало ли как этот код будут применять конечные пользователи, например
Проще говоря, метод с ? на конце должен возвращать либо true, либо false и ничего другого. Таково соглашение. Какой такой синглетон класс? Синглетон - это вообще паттерн проектирования и он тут абсолютно не причём. Просто такой синтаксис, чтобы динамически создать методы класса, а не методы объекта, как это было бы в случае с self.send ... Т.е. полный эквивалент этому динамическому коду будет выглядеть примерно так:
-------------------- Если бы программистам платили за то, чтобы убирать код из программы вместо того, чтобы добавлять его, программы были бы намного лучше © Николас Негропонте |
||||||||
|
|||||||||
| fell |
|
||||||||
|
Новичок Профиль Группа: Участник Сообщений: 41 Регистрация: 17.12.2008 Где: Санкт-Петербург Репутация: нет Всего: нет |
здрасти приехали, почитайте Dave Thomas, Programming ruby, страница 387, singleton class, ghost class, Eigenclasses, анонимный класс, который создается в цепочке классов. class << obj body end an anonymous (singleton) class is associated with the specific object Все тоже самое
можно было переписать так
Dave Thomas рекомендует пользоваться именно таким способом.
в данном случае метод set вызывается в классе Admin, я об этом писал уже, поэтому self = Admin login_page? - в чем смысл этой функции не очень понятно. Пока я нашел только одно объяснение. Если в функции есть строка, то !! вернет true, а если нет там ничего, то !! вернет false. То есть можно проверить возвращает что то функция или нет. Это сообщение отредактировал(а) fell - 18.7.2010, 11:42 |
||||||||
|
|||||||||
| source777 |
|
||||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1878 Регистрация: 12.3.2007 Репутация: 6 Всего: 56 |
Для данного действия есть устоявшийся термин - примесь (mix in). В случае когда примесь осуществляется в объект, действительно создаётся анонимный класс (хотя это лишь детали реализации, что не даёт права называть примесь анонимным классом), который в качестве побочного эффекта, можно с натяжкой сказать, довольно своеобразно реализует паттерн синглетон, да и то хреновато: раз можно создать ещё один независимый объект, вызвав obj.clone, у которого будет тот же набор примесей, то реализация паттерна получается косячная. Однако в твоём случае примесь осуществляется вообще в класс, а не в объект. Так что учи мат.часть внимательнее и желательно опираясь на несколько источников, а не на одного Томаса.
Нельзя, такая запись возможна только в статическом варианте, для мета-кода нужна именно та, которую я указал. Поэтому именно она и будет эквивалентна выполнению мета-кода. А раз уж ты записался в пиарщики к Dave Thomas, то не забывай писать заодно почему он что-то рекомендует и в чём разница, кроме как в синтаксисе.
И что по этому поводу думает Dave Thomas? Это сообщение отредактировал(а) source777 - 19.7.2010, 20:48 -------------------- Если бы программистам платили за то, чтобы убирать код из программы вместо того, чтобы добавлять его, программы были бы намного лучше © Николас Негропонте |
||||||
|
|||||||
| fell |
|
||||
|
Новичок Профиль Группа: Участник Сообщений: 41 Регистрация: 17.12.2008 Где: Санкт-Петербург Репутация: нет Всего: нет |
это вряд ли я узнаю, на этом форуме он явно не отметится. Хотелось бы услышать твое мнение все же... и подтвердить мою оценку или опровергнуть или что то добавить. Что касается синглетон класса, наверно лучше все же говорить о метаклассе. Мат часть я изучил хорошо и как раз вчера все стало на свои места. Mixin вызывается через методы include extend так что ,
никак не mixin. Эта запись как раз и означает вызов(конструирование) метакласса объекта. Видимо да, для динамического создания методов класса, лучше использовать метакласс. Может и есть какие то другие варианты, но пока не соображу какие. Одна из причин использования self.method описана опять же у Dave Thomas в его скринкастах о метапрограммировании. Объявление большого кол-ва методов класса через class << obj затрудняет понимание и разбор кода. И да, кстати, 90% использующих этот способ, думают что это просто синтаксический сахар |
||||
|
|||||
| source777 |
|
||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1878 Регистрация: 12.3.2007 Репутация: 6 Всего: 56 |
Если ты знаком со строго типизированными языками программирования, то тебе должно быть известно понятие "явное приведение типа", вот тут и есть явное приведение к типу Boolean, несмотря на то что в Ruby и типа такого нет. Собственно как раз из-за отсутствия такого типа нельзя написать Boolean("string") или "string".to_bool, как это происходит с другими примитивными типами, поэтому в качестве обходного пути для реализации отсутствующего в Ruby приведения к типу Boolean используется двойное отрицание. Это один из примеров программирования с использованием языка, а не на языке. Необязательно, mix-in - это подмешивание новых функций в существующие классы, модули, объекты любым способом, хоть через class_eval, хоть через метакласс, хоть через методы include, extend. Важно понимать разницу между понятием и способами его практической реализации, чтобы не отождествлять их. В данном случае, если конструкция "class << self" используется внутри определения класса, то это не mix-in, а если она используется в мета-коде для динамического подмешивания методов, то mix-in однозначно.
Ну это довольно субъективно. Если у класса куча длинных методов, то его уже на этом основании надо перепроектировать, объявление методов класса через self тут уже никак не спасёт читабельность. -------------------- Если бы программистам платили за то, чтобы убирать код из программы вместо того, чтобы добавлять его, программы были бы намного лучше © Николас Негропонте |
||||
|
|||||
![]()
|
| Правила форума "Ruby: Общие вопросы" | |
|
|
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, source777. |
| 1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | Ruby: Общие вопросы | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |