
Сначала пара слов о картинке. По запросу «object oriented programming» к гугл.картинкам она отдается на первой странице. Так-то.
Все мы с молоком матери впитали, что «еврибади из обжект», достаточно вспомнить о «mov ax dx», который, согласно первым AI, переводится на русский язык как «двинул топором начальника штаба». Тем не менее, иногда хочется стройности. Особенно, когда твоя библиотека переживает очередной git push, и ты понимаешь, что теперь обязательно найдется кто-нибудь, жаждущий вызвать Divider.new (UndividedObject.new).
Иными словами, если вам вдруг втемяшилось повторить функциональность OOP Fops, наподобие Java/.NET в вопрсах ограничения наследования — это можно. Но, пожалуйста, не нужно так делать. Вызов .respond_to? всегда дешевле, понятнее и элегантнее мусора, который я готов вам показать:
module MyModuleSet
module MyModule
class InterfaceNotImplemented < NoMethodError
end
def self.included(clazz)
clazz.send(:include, MyModule::Methods)
clazz.send(:extend, MyModule::Methods)
clazz.send(:extend, MyModule::ClassMethods)
end
module Methods
def not_implemented(clazz, method = nil)
if method.nil?
caller.first.match(/in `(.+)'/)
method = $1
end
raise MyModule::InterfaceNotImplemented.new("#{clazz.class.name} is abstract ('#{method}' must be implemented.)")
end
end
module ClassMethods
def to_implement!(name, *args)
self.class_eval do
define_method(name) do |*args|
not_implemented(self, name)
end
end
end
end
end
class AbstractClass
include MyModule
to_implement! :method1, :method2
…
end
Это непотребство бросит исключение, если в наследнике не объявлены method1 и method2. Но.
Я настаиваю на том, что так делать не нужно. Не сто́ит тащить за собой в новую жизнь груз ошибок. Если приходится полагаться на чужой код, всегда лучше написать «respond_to?», чем городить никому не понятный и не нужный огород.
Я написал эту заметку, поскольку сам поддался соблазну сделать что-то подобное. Пусть она отдается в поиске по плохим практикам.
Автор: matiouchkine
