tutorial - sintaxis de lenguaje ruby
¿Cómo hacen los programadores de Ruby la comprobación de tipos? (5)
Como no hay ningún tipo en ruby, ¿cómo se aseguran los programadores de Ruby de que una función recibe los argumentos correctos? En este momento, estoy repitiendo if object.kind_of
declaraciones if object.kind_of
/ instance_of
para verificar y generar errores de tiempo de ejecución en todas partes, lo que es feo. Debe haber una mejor manera de hacer esto.
Mi forma personal, que no estoy seguro de que sea una forma recomendada en general, es verificar los tipos y realizar otras validaciones una vez que se produce un error. Pongo la rutina de verificación de tipo en un bloque de rescate. De esta manera, puedo evitar la pérdida de rendimiento cuando se dan los argumentos correctos, pero aún así devolver el mensaje de error correcto cuando se produce un error.
def foo arg1, arg2, arg3
...
main_routine
...
rescue
## check for type and other validations
raise "Expecting an array: #{arg1.inspect}" unless arg1.kind_of?(Array)
raise "The first argument must be of length 2: #{arg1.inspect}" unless arg1.length == 2
raise "Expecting a string: #{arg2.inspect}" unless arg2.kind_of?(String)
raise "The second argument must not be empty" if arg2.empty?
...
raise "This is `foo''''s bug. Something unexpected happened: #{$!.message}"
end
Supongamos que en main_routine
, usted usa el método en arg1
asumiendo que arg1
es una matriz. Si resulta que es otra cosa, a la que no se ha definido each
una, entonces el mensaje de error será algo así como un method each not defined on ...
, que, desde la perspectiva del usuario del método foo
, podría ser no es útil. En ese caso, el mensaje de error original será reemplazado por el mensaje Expecting an array: ...
, que es mucho más útil.
Puede utilizar un enfoque de Diseño por contrato , con los contracts ruby gem. Me parece bastante agradable.
Recomiendo usar el aumento al principio del método para agregar la comprobación de tipos manual, simple y eficaz:
def foo(bar)
raise TypeError, "You called foo without the bar:String needed" unless bar.is_a? String
bar.upcase
end
La mejor manera cuando no tiene muchos parámetros, también es recomendable usar los argumentos de palabras clave disponibles en ruby 2+ si tiene varios parámetros y ver sus detalles de implementación actuales / futuros, están mejorando la situación, brindándole al programador una forma Para ver si el valor es nulo.
más: puedes usar una excepción personalizada
class NotStringError < TypeError
def message
"be creative, use metaprogramming ;)"
#...
raise NotStringError
Ruby es, por supuesto, tipificado dinámicamente.
Así, la documentación del método determina el tipo de contrato; la información de tipo se traslada del sistema de tipos formal a la [especificación de tipo informal en la documentación del método]. Mezclo generalidades como "actos como una matriz" y detalles como "es una cadena". La persona que llama solo debe esperar trabajar con los tipos indicados .
Si la persona que llama viola este contrato, entonces cualquier cosa puede pasar . El método no tiene por qué preocuparse: se utilizó incorrectamente.
A la luz de lo anterior, evito buscar un tipo específico y evito tratar de crear sobrecargas con tal comportamiento.
Las pruebas unitarias pueden ayudar a garantizar que el contrato funcione para los datos esperados.
Si un método tiene una razón para existir, será llamado.
Si se escriben pruebas razonables, todo será llamado.
Y si se llama a todos los métodos, entonces todos los métodos serán revisados.
No pierda el tiempo poniendo verificaciones de tipos que pueden restringir innecesariamente a las personas que llaman y de todos modos simplemente duplicará la verificación en tiempo de ejecución. Pase ese tiempo escribiendo pruebas en su lugar.