Имитируйте другой класс Ruby, чтобы объект передавал = == проверка типа

Я хочу создать объект, который действует как определенный класс, например 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

Мой вопрос в том, как создать фиктивный тип, который проходит проверку === без дополнения методов === во встроенных классах?

10
задан mislav 7 August 2011 в 14:06
поделиться