Я не уверен в том, что вы пытаетесь сделать из вашего примера. Как правило, в Ruby вы не проверяете типы. Он динамически типизируется по причине: вы можете написать код, который работает для любых объектов, которые поддерживают методы, которые ваш код вызывает для них.
Из того, что я могу сказать из ваших комментариев, вы хотите расширить класс Array
, поэтому при вызове метода в массиве, подобном an_array.pack
, в массиве выполняется поиск экземпляра Pack
и возвращается. В Ruby есть метод, вызываемый всякий раз, когда обнаруживается, что метод не существует, и называется Module#method_missing
. Например, если я случайно решу вызвать 4.to_dragon(magic: 4, height: 700)
, интерпретатор Ruby попытается найти to_dragon
как открытый метод, определенный в некотором классе или модуле в цепочке наследования Fixnum
(тип чисел). Если вы не сделали что-то странное для этой цепочки, мы получим вызов method_missing
для объекта 4
со следующими аргументами: [:to_dragon, { magic: 4, height: 700 }]
. По сути, это имя добавляется в начало аргументов, и блок должен быть задан.
Используя эту технику, вы можете переопределить method_missing
, чтобы получить этот код как решение:
class String
def method_to_class
split('_').map(&:capitalize).join
end
end
class Array
def method_missing(method_name, *arguments, &block)
find do |element|
element.class.name == method_name.to_s.method_to_class
end || super
end
end
Вы добавляете метод в String
для преобразования имени метода в имя класса. Затем вы переопределяете method_missing
на Array
, чтобы проверить каждый элемент, чтобы увидеть, соответствует ли имя класса данному имени класса. Если он найден, он возвращается. В противном случае (и мы делаем это, используя причудливый оператор ||
Руби), значение, возвращаемое этой функцией, равно nil
, и возвращается второй операнд ||
. Это является реализацией по умолчанию для method_missing
(которую мы получаем по ключевому слову super
) и возвращает ошибку, которой заслуживает вызов.
Единственная потенциальная проблема, связанная с этим, заключается в том, что если у вас есть элементы с именами классов, идентичными именам методов, которые уже определены в массивах, то они будут вызываться вместо этого специального метода. Например, вызов an_array.hash
даст вам хеш-код массива, а не первый экземпляр хеш-функции.
Более безопасная техника в этом отношении больше похожа на то, что, я думаю, вы пытались сделать. На самом деле он использует объекты класса, и вы можете использовать его для переопределения других методов:
class Array
def add(class_object)
class << self
define_method class_object.name do
find do |element|
element.is_a? class_object
end
end
end
end
end
Это определяет новые методы непосредственно на экземпляре массива. Например:
an_array = [Array, Hash, Dragon].map &:new
an_array.add Hash
an_array.hash #=> {}
Если в этом ответе нет решения, оно должно как минимум приблизить вас!