如何检查对象是否可以在Ruby中迭代?

时间:2012-05-25 14:56:37

标签: ruby

如何检查对象是否可以在Ruby中迭代?

也就是说,我想要一个干净地检查对象是否可迭代的方法,如下所示:

def is_iterable(my_object)
  ..
end

我真的不确定从这个方法中明确命名类的这一短暂开始。

修改: 为了我的目的,让我们说可迭代是你可以做的事情。每次。

6 个答案:

答案 0 :(得分:43)

  

就我的目的而言,我们假设您可以.each来执行迭代。

您可以询问此对象是否具有此方法

def iterable?(object)
  object.respond_to? :each
end

答案 1 :(得分:43)

您已经有了一些答案,但还有两种方法,Object#is_a?/Object#kind_of?Module#===

  [].is_a? Enumerable #=> true
  "".is_a? Enumerable #=> false

  Enumerable === [] #=> true
  Enumerable === "" #=> false

答案 2 :(得分:9)

有很多方法可以做到这一点,具体取决于你的更大目标以及你需要对结果做些什么。

  1. 如果您只想使用duck typing来查看对象是否响应 #each ,那么您可以询问对象是否有这样的方法。

    my_object.respond_to? :each
    
  2. 如果要查看对象是否在Enumerable类中混合,可以检查该类是否包含在内。

    my_object.class.include? Enumerable
    
  3. 如果你想要一个包含所有祖先和mixin的列表,你需要#ancestors方法。例如,要查看 my_object 是否继承自Enumerable类,您可以调用:

    my_object = []
    my_object.class.ancestors
    => [Array, Enumerable, Object, PP::ObjectMixin, Kernel, BasicObject]
    
    my_object.class.ancestors.include? Enumerable
    => true
    

答案 3 :(得分:1)

一般情况下,您可以检查是否定义了each方法,或者对象的类中是否包含Enumerable模块:

my_object.class.include? Enumerable

答案 4 :(得分:1)

因为Range响应each即使它不可迭代,您需要专门检查Range的元素是否响应succ

def iterable?(object)
  return object.begin.respond_to? :succ if object.kind_of? Range
  object.respond_to? :each
end

答案 5 :(得分:0)

Minitest组成对象的ActiveRecord风格的测试用例:

def test_iterates_over_invoice_items
  invoice = Invoice.new(items: [InvoiceItem.new(description: 'test')])

  iteration_count = 0
  invoice.each do |invoice_item|
    assert_equal 'test', invoice_item.description
    iteration_count += 1
  end

  assert_equal 1, iteration_count
end