2012-05-25 22 views
29

¿Cómo verifico si un objeto es iterable en Ruby?¿Cómo comprobar si un objeto es iterable en Ruby?

Es decir, quiero un método que comprueba limpiamente si un objeto es iterable, así:

def is_iterable(my_object) 
    .. 
end 

Realmente no estoy seguro de por dónde empezar en este corto de clases de nombres de forma explícita desde dentro del método .

Edit: Para mis propósitos, digamos iterable es algo que puede hacer .each.

+2

Definir "iterable". –

+0

@SergioTulentsev compruebe la actualización. – varatis

+0

Compruebe mi respuesta :) –

Respuesta

40

For my purposes, let's say iterable is something you can do .each to.

simplemente puede preguntar si este objeto tiene este método

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

Esto no funciona en todos los casos. 'nil..nil' es un objeto Range y responde a' each', pero no es iterable y arroja 'TypeError: no puede iterar desde NilClass' cuando intenta iterar. Acabo de toparme con esto en un proyecto con un rango de fechas de entrada que lo prueba contra las entradas de usuario falsas como nada o cadenas aleatorias, etc. –

+0

Eso es interesante, gracias por mencionar :) –

+0

Otros objetos podrían tener el método # cada uno, la mejor respuesta (a continuación) sería ver si es Enumerable. – saneshark

9

Hay un número de maneras de hacer esto, dependiendo de sus objetivos más grandes y lo que tiene que ver con el resultado.

  1. Si lo que desea es utilizar la tipificación de pato para ver si el objeto responde a #each, entonces usted puede simplemente hacer que el objeto si se dispone de un procedimiento de este tipo.

    my_object.respond_to? :each 
    
  2. Si desea averiguar si el objeto se mezcla en la clase Enumerable, se puede comprobar la clase de inclusión.

    my_object.class.include? Enumerable 
    
  3. Si desea una lista de todos los antepasados ​​y mixins, desea que el método #ancestors. Por ejemplo, para ver si mi_objeto hereda de la clase Enumerable, que podrían invocar:

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

¿Por qué usar 'my_object.class.include? Enumerable' en lugar de 'my_object.is_a? Enumerable'? – dbenhur

+0

@dbenhur Claridad semántica. Los resultados son generalmente los mismos. –

+0

En lugar de mirar a los antepasados, también puede marcar esto: 'my_object.class mbillard

1

En caso general se puede comprobar si se define each método, o si Enumerable módulo está incluido en la clase de objeto :

my_object.class.include? Enumerable 
41

ya tienes algunas respuestas, pero aquí hay dos formas más, Object#is_a?/Object#kind_of? y Module#===:

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

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

¡buen punto! 432 – fl00r

1

Debido Range responde a each incluso cuando no se Iterable es necesario comprobar específicamente que los elementos de la gama responden a succ

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