Я хочу создать объект, который действует как определенный класс, такой как Fixnum, но не является ни экземпляром этого класса, ни его подклассами.
Существуют различные варианты использования для этого.В случае Fixnum я хочу определить более конкретный целочисленный тип, который по сути является Fixnum, но также реализует некоторую дополнительную логику.Я не могу подклассифицировать сам Fixnum, потому что непосредственные типы, такие как Fixnum и Symbol, не могут быть разделены на подклассы.
Другой вариант использования - это насмешка в автоматических тестах: иногда вы хотите создать объект, который действует как определенный класс(обычно это экземпляр модели), но по техническим причинам не является экземпляром этого точного класса.
Вот как создать конкретный целочисленный тип, который делегирует все методы внутреннему хранимому фиксированному номеру:
require 'delegate'
require 'forwardable'
# integer representing a page number
class PageNumber < DelegateClass(Integer)
extend Forwardable
def initialize(value, name)
@name = name
super(value)
end
def inspect
"#{@name} #{to_i}"
end
alias_method :to_i, :__getobj__
def_delegators :to_i, :instance_of?, :kind_of?, :is_a?
end
Этот объект может проходить is_a?
и подобные проверки:
page = PageNumber.new(1, "page")
page.is_a? Fixnum #=> true
Но ничто из того, что я делаю, не может заставить его пройти проверку типа Module#===
:
# my problem:
Fixnum === page #=> false
Тот факт, что мой объект не прошел эту проверку, очень прискорбен, так как метод ===
используется внутри операторов case
:
case page
when Fixnum
# it will never get here
when String
# ...
else
# ...
end
Мой вопрос заключается в том, как создать ложный тип, который передает===
проверка без расширения ===
методов встроенных классов?