2009-05-10 9 views
9

¿Cómo puedo hacer mi propia clase que se puede sustituir por IO para, p. Ej., redirigir/capturar entrada/salida para algún código que acepte un parámetro IO-like? IO en sí parece estar acoplado a los descriptores de archivos del sistema operativo y la única clase que conozco que lo imita sin subclasificarlo es StringIO, que parece simplemente reimplementar toda la interfaz.¿Cómo se crea una subclase personalizada de IO en Ruby?

Creo que el lenguaje proporcionaría una manera directa de hacerlo, pero no puedo encontrar ninguna información sobre el tema. ¿Hay algún mixin que implemente la interfaz sobre algunas primitivas, como lo hace Enumerable?

Respuesta

4

sospecho que me falta algo, pero suponiendo que no es el caso ...

¿Por qué habría de subclases no ser una opción? ¿No podría anular las partes de IO que necesitan comportarse de manera diferente?

class MyIO < IO 
    # your modified methods go here. e.g. 
    def some_io_method(args) 
    do_some_preprocessing 
    super(args) 
    do_some_post_processing 
    end 
end 

Si no puede sustituir a la subclase de vinos locales, lo que acerca de cómo modificar IO sí mismo ("mono-parches") algo como:

class IO 
    alias_method :original_some_io_method, :some_io_method 
    def some_io_method(args) 
    do_some_preprocessing 
    original_some_io_method(args) 
    do_some_post_processing 
    end 
end 
+3

El problema es que hay un montón de métodos que leen/escriben datos y volver a implementarlos es tedioso. Enumerable implementa explícitamente todo en términos de #each, por lo tanto anulando #each, obtiene todo lo demás "gratis". No entiendo por qué IO no funciona de la misma manera o por qué los mixins que ahora estoy escribiendo para lograr esto todavía no existen. La otra cosa extraña es que IO es tan especializado, con métodos como sys * que no pertenecen a otras implementaciones. Esto se puede solucionar, pero no es ideal. – jedediah

1

que han utilizado con éxito este truco para hacer StringIO una IO "real":

# make mechanize believe our address xml actually is an IO so it will be uploaded as a file: 
    address_io = StringIO.new(address_xml) 
    class << address_io 
     alias is_a_old is_a? 
     def is_a?(stuff) 
     stuff == IO || is_a_old(stuff) 
     end 
     def path 
     'address.xml' 
     end 
    end 
+0

Intenté esto con la biblioteca en la que estoy trabajando y causó que algunos códigos nativos en el intérprete se volvieran locos, en algunos casos. Usar con precaución. Además, dado que << address_io es una subclase de StringIO, el aliasing no es necesario. Simplemente anule el método y llame a super. – jedediah

Cuestiones relacionadas