2011-07-20 22 views
2

我有一个接受参数的方法,该参数可以是数组/类似对象或哈希。该方法的要点是一样的东西:如何检测类似数组或类似的值,同时避免类型检查

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

的方法将接受一组ID的对象,并把它变成了MongoDB的哈希条件。

两个问题上面的代码:

  1. 如果“设置”未从标准库需要它将会失败。我不想仅仅依靠执行检查。
  2. 我不想做严格的类型比较。我想接受任何数组或类似值,并将其转换为to_a的值数组。

您将如何执行此检查?一些注意事项有记:

  1. 我可以检查to_ary方法,但设置并不to_ary回应。实现这个方法的对象应该基本上是数组,我同意Set不是一个基本的数组。见Consequences of implementing to_int and to_str in Ruby
  2. 我无法检查to_a因为哈希响应它
  3. 的方法是共同的阵列和设置,而不是哈希是:

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

我决定去像这样:

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

因为相交可能是一个集合类对象将具有的运算符。但我不确定这一点。

+0

基本上你说的是鸭子打字。如果它可以像数组一样操作,则不关心对象是什么。因此,将'.to_a'添加到对象并查看它是否可以转换为数组。如果你想要一个散列,你可能想转换为一个数组,然后构造一个散列:'Hash [* array.to_a.flatten]'。那时,呼叫者的工作就是要求适当的班级,而不是你。 –

回答

1

如何试图找出查询是否哈希什么样的?

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

如果对象响应has_key,那么期望该对象是散列或哈希是合理的。

+1

这似乎是这个具体问题最优雅的解决方案,但并没有回答原始的一般问题:“如何检测数组或类似值”。好吧 – mislav

0

检查以查看Set是否定义将解决您的第一个问题。对于第二种情况,您可能会检查查询类的祖先以查看数组是否在其中,但这可能不会捕获所有“类似数组”的对象。我可能不会检查是否存在用于测试数组的方法,因为您正在测试名称而不是行为。 Arel特别响应(或者在它被弃用之前)&,但是这种类型的对象不会像你想要的那样工作。

4

这是我的看法:

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

我只是检查to_a,这是我感兴趣的,而且确保它不是一个Hash对象的唯一方法。我使用严格的哈希类型检查,但只是因为这是最不可能的对象被传递为一个完全独立的类,它基本上是一个哈希。

0

个人而言,我在想......

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