Я думаю, что проблема сводится к тому, что вы пытаетесь сделать. Похоже, вы пытаетесь реализовать интерфейс на Ruby, что имеет смысл, если вы работаете с Java или .NET, но на самом деле это не то, как обычно работают разработчики Ruby.
Вот некоторая информация о типичных представлениях об интерфейсах в Ruby: Что такое интерфейс Java эквивалент в Ruby?
Тем не менее, я понимаю, что вы пытаетесь сделать. Если вы не хотите, чтобы ваш AbstractClass был реализован напрямую, но вы хотите определить методы, которые можно использовать в классе, который ведет себя так, как это предусмотрено в AbstractClass (как в Design by Contract), то вы, вероятно, захотите использовать модуль. Модули очень хорошо помогают сохранить ваш код DRY, но они не совсем решают вашу проблему. проблема, связанная с документированием переопределенных методов. Итак, на данный момент, я думаю, вы можете пересмотреть свой подход к документации или, по крайней мере, подойти к ней более рубиново.
Наследование в Ruby действительно (вообще говоря, исходя из моего собственного опыта) используется только по нескольким причинам:
- Повторно используемый код и атрибуты
- Поведение по умолчанию
- Специализация
Очевидно, есть и другие пограничные случаи, но, честно говоря, именно для этого обычно используется наследование в Ruby. Это не означает, что то, что вы делаете, не будет работать или нарушает какое-то правило, просто это нетипично для Ruby (или большинства языков с динамической типизацией). Это нетипичное поведение, вероятно, является причиной того, что YARD (и другие генераторы документов Ruby) не делают то, что вы ожидаете. Тем не менее, создание абстрактного класса, который определяет только методы, которые должны существовать в подклассе, на самом деле очень мало дает вам с точки зрения кода. Неопределенные методы в любом случае приведут к возникновению исключения NoMethodError, и вы можете программно проверить, будет ли объект реагировать на вызов метода (или любое сообщение, если на то пошло) из того, что вызывает метод, используя #respond_to?(:some_method)
(или другие отражающие инструменты для получения метаматериал). Все это возвращается к тому, что Ruby использует Duck Typing.
Для чистой документации, зачем документировать метод, который вы на самом деле не используете? На самом деле вас не должен волновать класс объекта, отправляемого или получаемого при вызове метода, а только то, на что эти объекты отвечают. Так что не утруждайте себя созданием вашего AbstractClass в первую очередь, если он не добавляет здесь реальной ценности. Если он содержит методы, которые вы действительно будете вызывать напрямую без переопределения, то создайте модуль, задокументируйте их там и запустите $ yardoc --embed-mixins
, чтобы включить методы (и их описания), определенные в смешанных модулях. В противном случае задокументируйте методы там, где вы их фактически реализуете, поскольку каждая реализация должна отличаться (иначе зачем реализовывать ее заново).
Вот как я хотел бы что-то похожее на то, что вы делаете:
# An awesome Module chock-full of reusable code
module Stuff
# A powerful method for doing things with stuff, mostly turning stuff into a Symbol
def do_stuff(thing)
if thing.kind_of?(String)
return thing.to_sym
else
return thing.to_s.to_sym
end
end
end
# Some description of the class
class ConcreteClass
include Stuff
# real (and only implementation)
def do_something
puts "Real implementation here"
return :foo
end
end
an_instance = ConcreteClass.new
an_instance.do_somthing # => :foo
# > Real implementation here
an_instance.do_stuff("bar") # => :bar
Запуск YARD (с --embed-mixins) будет включать смешанные методы из модуля Stuff (вместе с их описаниями), и теперь вы знаете, что любой объект, включая модуль Stuff, будет иметь метод, который вы ожидаете.
Вы также можете ознакомиться с Ruby Contracts, так как он может быть ближе к тому, что вы ищу, чтобы абсолютно заставить методы принимать и возвращать только те типы объектов, которые вам нужны, но я не уверен, как это будет работать с YARD.
person
jgnagy
schedule
23.10.2013