Я хочу создать объект, который действует как определенный класс, например Fixnum, но не является экземпляром этого класса и его подклассов.
Для этого существуют различные варианты использования. В случае Fixnum я хочу определить более конкретный целочисленный тип, который по существу является Fixnum, но также реализует некоторую дополнительную логику. Я не могу подклассифицировать Fixnum, потому что немедленные типы, такие как Fixnum и Symbol, не могут быть подклассы.
Другой пример использования - насмешка в автоматизированных тестах: иногда вы хотите создать объект, который действует как определенный класс (обычно это экземпляр модели), но по техническим причинам не является экземпляром этого точного класса.
Здесь, как создать определенный целочисленный тип, который делегирует все методы встроенной памяти fixnum:
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
Мой вопрос в том, как я могу создать макет типа, который проходит проверку ===
, не увеличивая методы ===
на встроенных классах?