stringtranslate.com

Sintaxis de Ruby

La sintaxis del lenguaje de programación Ruby es muy similar a la de Perl y Python . Las definiciones de clases y métodos se indican mediante palabras clave, mientras que los bloques de código pueden definirse mediante palabras clave o llaves. A diferencia de Perl, las variables no tienen obligatoriamente como prefijo un sigilo . Cuando se utiliza, el sigilo cambia la semántica del alcance de la variable. Para fines prácticos, no hay distinción entre expresiones y declaraciones . [1] [2] Los saltos de línea son significativos y se toman como el final de una declaración; se puede utilizar un punto y coma de forma equivalente. A diferencia de Python, la sangría no es significativa.

Una de las diferencias con Python y Perl es que Ruby mantiene todas sus variables de instancia completamente privadas para la clase y solo las expone a través de métodos de acceso ( attr_writer, attr_reader, etc.). A diferencia de los métodos "getter" y "setter" de otros lenguajes como C++ o Java , los métodos de acceso en Ruby se pueden crear con una sola línea de código a través de metaprogramación ; sin embargo, los métodos de acceso también se pueden crear de la manera tradicional de C++ y Java. Como la invocación de estos métodos no requiere el uso de paréntesis, es trivial cambiar una variable de instancia en una función completa sin modificar una sola línea de código de llamada o tener que hacer ninguna refactorización logrando una funcionalidad similar a los miembros de propiedad de C# y VB.NET .

Los descriptores de propiedades de Python son similares, pero tienen una desventaja en el proceso de desarrollo. Si uno comienza en Python usando una variable de instancia expuesta públicamente y luego cambia la implementación para usar una variable de instancia privada expuesta a través de un descriptor de propiedad, es posible que sea necesario ajustar el código interno de la clase para usar la variable privada en lugar de la propiedad pública. El diseño de Ruby obliga a que todas las variables de instancia sean privadas, pero también proporciona una forma sencilla de declarar sety getusar métodos. Esto está en consonancia con la idea de que en Ruby uno nunca accede directamente a los miembros internos de una clase desde fuera de la clase; en cambio, uno pasa un mensaje a la clase y recibe una respuesta.

Sesiones interactivas

Los siguientes ejemplos se pueden ejecutar en un shell Ruby como Interactive Ruby Shell , o guardar en un archivo y ejecutar desde la línea de comandos escribiendo .ruby <filename>

Ejemplo clásico de Hola mundo :

pone '¡Hola mundo!' 

Algunos códigos básicos de Ruby:

# Todo, incluso un literal, es un objeto, por lo que esto funciona: - 199 . abs # => 199 'el hielo es agradable' . length # => 11 'ruby es genial.' . index ( 'u' ) # => 1 "Bonito día, ¿no?" . downcase . split ( '' ) . uniq . sort . join # => " '? acdeinsty"   

Aporte:

print 'Por favor escriba nombre >' nombre = gets . chomp puts "Hola #{ nombre } ."    

Conversiones:

puts 'Dame un número' numero = gets . chomp puts número . to_i número_salida = number . to_i + 1 puts número_salida . to_s + ' es un número mayor.'           

Instrumentos de cuerda

Hay una variedad de formas de definir cadenas en Ruby.

Las siguientes tareas son equivalentes:

a = " \n Esta es una cadena entre comillas dobles \n " a = %Q{ \n Esta es una cadena entre comillas dobles \n } a = %{ \n Esta es una cadena entre comillas dobles \n } a = %/\nEsta es una cadena entre comillas dobles\n/ a = <<- BLOQUE          Esta es una cadena BLOQUE entre comillas dobles

Las cadenas admiten la interpolación de variables :

var = 3 . 14159 "pi es #{ var } " => "pi es 3,14159"   

Las siguientes asignaciones son equivalentes y producen cadenas sin formato :

a = 'Esta es una cadena entre comillas simples' a = %q{Esta es una cadena entre comillas simples}    

Colecciones

Construir y utilizar una matriz :

a = [ 3 , 'hola' , 14 . 5 , 1 , 2 , [ 6 , 15 ]]        a [ 2 ] # => 14.5 a . [] ( 2 ) # => 14.5 a . reverse # => [[6, 15], 2, 1, 14.5, 'hola', 3] a . flatten . uniq # => [3, 'hola', 14.5, 1, 2, 6, 15]    

Construcción y uso de una matriz asociativa (en Ruby, llamada hash ):

hash = Hash . new # equivalente a hash = {} hash = { water : 'wet' , fire : 'hot' } # hace que la línea anterior sea redundante ya que ahora # asignando hash a un nuevo objeto hash separado puts hash [ :fire ] # imprime "hot"              hash .each_pair do | key , value | # o: hash.each do |key, value| pone " # { key } es #{ value } " fin # devuelve {:water=>"wet", :fire=>"hot"} e imprime: # el agua está mojada # el fuego está caliente      hash . delete :water # elimina el par :water => 'wet' y devuelve "wet" hash . delete_if { | key , value | value == 'hot' } # elimina el par :fire => 'hot' y devuelve {}       

Estructuras de control

Declaración if:

# Genera un número aleatorio e imprime si es par o impar. if rand ( 100 ) . even? puts "Es par" else puts "Es impar" end     

Bloques e iteradores

Las dos sintaxis para crear un bloque de código:

{ puts 'Hola, mundo!' } # note las llaves # o: do puts 'Hola, mundo!' end      

Se puede pasar un bloque de código a un método como argumento de bloque opcional. Muchos métodos integrados tienen argumentos como estos:

Archivo . open ( 'archivo.txt' , 'w' ) do | archivo | # 'w' denota "modo de escritura" archivo . puts 'Escribió algún texto'. fin # el archivo se cierra automáticamente aquí       Archivo . readlines ( 'file.txt' ) . each do | line | puts line end # => Escribí algún texto.    

Pasar parámetros a un bloque para que sea un cierre :

# En una variable de instancia de objeto (indicada con '@'), recuerda un bloque. def remember ( & a_block ) @block = a_block end    # Invoca el método anterior, dándole un bloque que toma un nombre. remember { | name | puts "Hola, #{ name } !" }   # Llamar al cierre (tenga en cuenta que esto no se cierra sobre ninguna variable libre): @block . call ( 'Jon' ) # => "¡Hola, Jon!" 

Creando una función anónima :

proc { | arg | puts arg } Proc . new { | arg | puts arg } lambda { | arg | puts arg } -> ( arg ) { puts arg } # introducido en Ruby 1.9            

Devolver cierres desde un método:

def create_set_and_get ( valor_inicial = 0 ) # tenga en cuenta el valor predeterminado de 0 valor_de_cierre = valor_inicial [ Proc . new { | x | valor_de_cierre = x }, Proc . new { valor_de_cierre } ] fin                setter , getter = create_set_and_get # devuelve dos valores setter.call ( 21 ) getter.call # = > 21     # Las variables de parámetros también se pueden utilizar como enlace para el cierre, # por lo que lo anterior se puede reescribir como:def crear_establecer_y_obtener ( valor_de_cierre = 0 ) [ proc { | x | valor_de_cierre = x } , proc { valor_de_cierre } ] fin              

Ceder el flujo de control del programa a un bloque que se proporcionó en el momento de la llamada:

def use_hello yield "hola" fin   # Invoca el método anterior, pasándole un bloque. use_hello { | string | puts string } # => 'hello'    

Iteración sobre enumeraciones y matrices utilizando bloques:

matriz = [ 1 , 'hola' , 3 . 14 ] matriz . each { | elemento | pone elemento } # imprime: # 1 # 'hola' # 3.14        array . each_index { | index | puts " #{ índice } : #{ array [ índice ] } " } # imprime: # 0: 1 # 1: 'hola' # 2: 3.14    # Lo siguiente utiliza un rango (a..b) ( 3..6 ) . cada { | num | pone num } # imprime: # 3 # 4 # 5 # 6    # Lo siguiente utiliza un rango (a...b) ( 3 ... 6 ) . cada { | num | pone num } # imprime: # 3 # 4 # 5    

Un método como injectpuede aceptar tanto un parámetro como un bloque. El injectmétodo itera sobre cada miembro de una lista, realizando alguna función en él mientras retiene un agregado. Esto es análogo a la foldlfunción en los lenguajes de programación funcional . Por ejemplo:

[ 1 , 3 , 5 ]. inyectar ( 10 ) { | suma , elemento | suma + elemento } # => 19      

En la primera pasada, el bloque recibe 10 (el argumento a inyectar) como sum, y 1 (el primer elemento de la matriz) como element. Esto devuelve 11, que luego se convierte sumen en la siguiente pasada. Se suma a 3 para obtener 14, que luego se suma a 5 en la tercera pasada, para finalmente devolver 19.

Usando una enumeración y un bloque para elevar al cuadrado los números del 1 al 10 (usando un rango ):

( 1 .. 10 ) . recolectar { | x | x * x } # => [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]   

O invocar un método en cada elemento ( mapes un sinónimo de collect):

( 1 .. 5 ) . mapa ( & :to_f ) # => [1.0, 2.0, 3.0, 4.0, 5.0] 

Clases

El siguiente código define una clase llamada Person. Además de initialize, el constructor habitual para crear nuevos objetos, tiene dos métodos: uno para anular el <=>operador de comparación (para Array#sortpoder ordenar por edad) y el otro para anular el to_smétodo (para Kernel#putspoder formatear su salida). Aquí attr_readerhay un ejemplo de metaprogramación en Ruby: attr_accessordefine métodos getter y setter de variables de instancia, pero attr_readersolo métodos getter. La última declaración evaluada en un método es su valor de retorno, lo que permite la omisión de una returndeclaración explícita.

clase Persona attr_reader :nombre , :edad def initialize ( nombre , edad ) @nombre , @edad = nombre , edad end def <=> ( persona ) # el operador de comparación para ordenar @edad <=> persona . edad end def to_s " #{ @nombre } ( #{ @edad } )" end end                        grupo = [ Persona . nueva ( "Bob" , 33 ), Persona . nueva ( "Chris" , 16 ), Persona . nueva ( "Ash" , 23 ) ]        pone grupo . ordenar . invertir 

El código anterior imprime tres nombres en orden de edad inverso:

Bob (33)Ceniza (23)Cristóbal (16)

Persones una constante y es una referencia a un Classobjeto.

Clases abiertas

En Ruby, las clases nunca se cierran: siempre se pueden agregar métodos a una clase existente. Esto se aplica a todas las clases, incluidas las clases estándar integradas. Todo lo que se necesita hacer es abrir una definición de clase para una clase existente y el nuevo contenido especificado se agregará al contenido existente. Un ejemplo simple de cómo agregar un nuevo método a la Timeclase de la biblioteca estándar:

# volver a abrir la clase Time de Ruby class Time def yesterday self - 86400 end end       hoy = Hora . ahora # => 2013-09-03 16:09:37 +0300 ayer = hoy . ayer # => 2013-09-02 16:09:37 +0300      

Agregar métodos a clases previamente definidas suele denominarse "parcheo de mono" . Si se realiza de forma imprudente, esta práctica puede provocar colisiones de comportamiento con resultados inesperados posteriores y problemas de escalabilidad del código.

Desde Ruby 2.0 es posible utilizar mejoras para reducir las consecuencias potencialmente negativas de la aplicación de parches, limitando el alcance del parche a áreas particulares de la base del código.

# volver a abrir el módulo de clase Time de Ruby RelativeTimeExtensions refine Time do def half_a_day_ago self - 43200 end end end           módulo MyModule clase MyClass # Permitir que se use el refinamiento mediante RelativeTimeExtensions       def ventana Tiempo . ahora . hace medio día fin fin fin    

Excepciones

Se genera una excepción con una raisellamada:

aumentar

Se puede agregar un mensaje opcional a la excepción:

plantear "Este es un mensaje" 

El programador también puede especificar excepciones:

generar ArgumentError , "¡Argumentos ilegales!"  

Alternativamente, se puede pasar una instancia de excepción al raisemétodo:

generar ArgumentError.new ( " ¡ Argumentos ilegales!" ) 

Esta última construcción es útil cuando se genera una instancia de una clase de excepción personalizada que presenta un constructor que toma más de un argumento:

clase ParseError < Exception def initialize ( input , line , pos ) super "No se pudo analizar ' #{ input } ' en la línea #{ line } , posición #{ pos } " end end          generar ParseError . new ( "Foo" , 3 , 9 )   

Las excepciones se manejan mediante la rescuecláusula . Una cláusula de este tipo puede capturar excepciones que heredan de StandardError. Otras palabras clave de control de flujo que se pueden usar al manejar excepciones son elsey ensure:

comenzar # hacer algo rescatar # manejar excepción else # hacer esto si no se generó ninguna excepción asegurar # hacer esto sin importar si se generó o no una excepción fin    

Es un error común intentar capturar todas las excepciones con una simple cláusula de rescate. Para capturar todas las excepciones, se debe escribir:

comenzar # hacer algo rescate Excepción # Código de manejo de excepciones aquí. # No escriba solo "rescate"; eso solo captura StandardError, una subclase de Exception. fin    

O detectar excepciones particulares:

comenzar # hacer algo rescatar RuntimeError # manejar solo RuntimeError y sus subclases fin   

También es posible especificar que el objeto de excepción esté disponible para la cláusula del controlador:

comenzar # hacer algo rescate RuntimeError => e # manejo, posiblemente involucrando e, como "puts e.to_s" fin     

Alternativamente, la excepción más reciente se almacena en el global mágico $!.

También se pueden encontrar varias excepciones:

comenzar # hacer algo rescate RuntimeError , Timeout :: Error => e # manejo, posiblemente involucrando e fin      

Metaprogramación

El código Ruby puede modificar programáticamente, en tiempo de ejecución , aspectos de su propia estructura que serían fijos en lenguajes más rígidos, como las definiciones de clases y métodos. Este tipo de metaprogramación se puede utilizar para escribir código más conciso y extender eficazmente el lenguaje.

Por ejemplo, el siguiente código Ruby genera nuevos métodos para la clase incorporada String, basándose en una lista de colores. Los métodos envuelven el contenido de la cadena con una etiqueta HTML con el estilo del color respectivo.

COLORES = { negro : "000" , rojo : "f00" , verde : "0f0" , amarillo : "ff0 " , azul : "00f" , magenta : "f0f" , cian : "0ff" , blanco : "fff" }                   clase String COLORES . cada uno hacer | color , código | define_método "en_ #{ color } " hacer "<span style= \" color: # #{ código } \" > #{ self } </span>" fin fin fin          

Los métodos generados podrían entonces usarse de la siguiente manera:

"¡Hola, mundo!" . in_blue => "<span style= \" color: #00f \" >¡Hola, mundo!</span>"  

Para implementar el equivalente en muchos otros lenguajes, el programador tendría que escribir cada método ( in_black, in_red, in_green, etc.) por separado.

Algunos otros posibles usos para la metaprogramación de Ruby incluyen:

Referencias

  1. ^ "[ruby-talk:01120] Re: El valor de while..." En la sintaxis de Ruby, la declaración es solo un caso especial de una expresión que no puede aparecer como argumento (por ejemplo, asignación múltiple).
  2. ^ "[ruby-talk:02460] Re: Pregunta de precedencia". La declaración [...] no puede ser parte de una expresión a menos que esté agrupada entre paréntesis.