Как определить значение, похожее на массив или множество, избегая проверок типов - PullRequest
2 голосов
/ 21 июля 2011

У меня есть метод, который принимает аргумент, который может быть объектом, подобным массиву / множеству, или хэшем. Суть метода в следующем:

def find(query = {})
  if Array === query or Set === query
    query = {:_id => {'$in' => query.to_a}}
  end
  mongo_collection.find(query)
end

Метод примет набор объектов ID и превратит его в условие хеширования для MongoDB.

Две проблемы с кодом выше:

  1. Не удастся, если 'set' не требуется из стандартной библиотеки. Я не хочу требовать зависимости просто для проверки.
  2. Я не хочу делать строгие сравнения типов. Я хочу принять любое значение типа массива или набора и привести его к массиву значений с помощью to_a.

Как бы вы выполнили эту проверку? Некоторые соображения, которые следует иметь в виду:

  1. Я мог бы проверить метод to_ary, но Set не отвечает на to_ary. Объекты, которые реализуют этот метод, должны быть массивами, и я согласен, что Set не является массивом. См. Последствия реализации to_int и to_str в Ruby
  2. Я не могу проверить to_a, так как Hash отвечает на него
  3. Методы, которые являются общими для Array и Set, но не для Hash:

    [:&, :+, :-, :<<, :collect!, :flatten!, :map!, :|]
    

Я решил пойти с чем-то вроде этого:

query = {:_id => {'$in' => query.to_a}} if query.respond_to? :&

поскольку пересечение, скорее всего, является оператором объекта, подобного множеству. Но я не уверен в этом.

Ответы [ 4 ]

4 голосов
/ 21 июля 2011

Вот мое мнение:

if not Hash === query and query.respond_to? :to_a

Я просто проверяю to_a, это единственный интересующий меня метод, но я также проверяю, что это не объект Hash.Я использую строгую проверку типов для Hash, но только потому, что это наименее вероятный объект, который будет передан как совершенно отдельный класс, который по сути является хешем.

1 голос
/ 21 июля 2011

Как насчет попытки выяснить, является ли запрос хеш-кодом?

def find(query = {})
  query = {:_id => {'$in' => query.to_a}} unless query.respond_to?(:has_key?)
  mongo_collection.find(query)
end

Разумно ожидать, что объект будет похож на хеш или хэш, если он отвечает на has_key?

0 голосов
/ 21 июля 2011

Лично я думаю ...

def find(query = {})      
  mongo_collection.find(query_formatter(query))
end

def query_formatter(query)
  if query.respond_to?(:to_a) && !query.kind_of?(Hash)
    {:_id => {'$in' => query.to_a}}
  else
    query
  end
end
0 голосов
/ 21 июля 2011

Проверка, определен ли Set, решит вашу первую проблему.Во-вторых, вы могли бы проверить предков класса запроса, чтобы увидеть, есть ли в них массив, но это, вероятно, не поймает все "массоподобные" объекты.Возможно, я бы не стал проверять наличие методов для проверки массивности, поскольку вы проверяете имена, а не поведение.В частности, Arel отвечает (или делал до того, как это устарело) &, но этот тип объекта не будет работать так, как вы этого хотели.

...