ventajas tutorial sirve rails que para documentacion desventajas descargar ruby

tutorial - ruby wikipedia



¿Cuáles son las Ruby Gotchas que debe advertirse a un novato? (25)

Recientemente aprendí el lenguaje de programación Ruby, y en general es un buen lenguaje. Pero me sorprendió bastante ver que no era tan simple como esperaba. Más precisamente, la "regla de la mínima sorpresa" no me pareció muy respetada (por supuesto, esto es bastante subjetivo). Por ejemplo:

x = true and false puts x # displays true!

y el famoso:

puts "zero is true!" if 0 # zero is true!

¿Cuáles son los otros "errores" sobre los que advertirías a un novato de Ruby?


Presta atención a la notación de rango.

(¡Por lo menos, presta más atención de lo que inicialmente hice!)

Hay una diferencia entre 0..10 (dos puntos) y 0...10 (tres puntos).

Disfruto mucho a Ruby. Pero esta cosa de punto-punto contra punto-punto-punto me molesta. Creo que una "característica" sutil de doble sintaxis es:

  • fácil de escribir mal, y
  • fácil de perder con la vista mientras se mira el código

no debería ser capaz de causar devastadores errores "uno por uno" en mis programas.


Al llamar a super sin argumentos, el método reemplazado se llama con los mismos argumentos que el método de anulación.

class A def hello(name="Dan") puts "hello #{name}" end end class B < A def hello(name) super end end B.new.hello("Bob") #=> "hello Bob"

Para llamar realmente super sin argumentos, debes decir super() .


Comprender la diferencia entre la clase de fecha y hora. Ambos son diferentes y han creado problemas al usarlos en rieles. La clase Time a veces entra en conflicto con otras bibliotecas de clase Time presentes en la biblioteca estándar de ruby ​​/ rails. En lo personal, me llevó mucho tiempo entender lo que estaba sucediendo exactamente en mi aplicación Rails. Más tarde, pensé cuando lo hice

Time.new

Se refería a una biblioteca en un lugar del que ni siquiera era consciente.

Lo siento si no tengo claro lo que quiero decir exactamente. Si otros han enfrentado problemas similares, por favor vuelva a explicar.


Creo que " and " y " or " son guiños a Perl, que es uno de los "padres" más obvios de Ruby (el otro más destacado es Smalltalk). Ambos tienen una precedencia mucho más baja (más baja que la asignación, de hecho, que es de donde proviene el comportamiento observado) que && y || cuáles son los operadores que deberías estar usando

Otras cosas a tener en cuenta que no son inmediatamente obvias:

Realmente no llama a métodos / funciones, aunque se ve de esa manera. En cambio, como en Smalltalk, envía un mensaje a un objeto. Así que el method_missing es más como message_not_understood .

some_object.do_something(args)

es equivalente a

some_object.send(:do_something, args) # note the :

Los símbolos son muy utilizados. Esas son las cosas con las que se empieza : y no son inmediatamente obvias (bueno, no lo eran para mí), pero cuanto antes se familiarice con ellas, mejor.

Ruby es grande en el "tipado de patos", siguiendo el principio de que "si camina como un pato y grazna como un pato ..." que permite la sustitución informal de objetos con un subconjunto común de métodos sin ninguna herencia explícita o relación de mezcla.


Creo que siempre es bueno usar .length en cosas ... ya que el tamaño es compatible con casi todo y Ruby tiene tipos dinámicos, puedes obtener resultados realmente extraños llamando a .size cuando tienes el tipo incorrecto ... Preferiría obtener un NoMethodError: método indefinido `length '', por lo que generalmente nunca llamo tamaño a los objetos en Ruby.

me mordió más de una vez.

También recuerde que los objetos tienen identificadores, por lo que trato de no usar las variables call id o object_id solo para evitar confusiones. Si necesito una identificación en un objeto de los usuarios, lo mejor es llamarlo como id_usuario.

Solo mis dos centavos



El siguiente código me sorprendió. Creo que es un juego peligroso: fácil de encontrar y difícil de depurar.

(1..5).each do |number| comment = " is even" if number%2==0 puts number.to_s + comment.to_s end

Esto imprime:

1 2 is even 3 4 is even 5

Pero si solo agrego comment = anything antes del bloque ...

comment = nil (1..5).each do |number| comment = " is even" if number%2==0 puts number.to_s + comment.to_s end

Entonces obtengo:

1 2 is even 3 is even 4 is even 5 is even

Básicamente, cuando una variable solo se define dentro de un bloque, se destruye al final del bloque y luego se restablece a nil en cada iteración. Eso es generalmente lo que esperas. Pero si la variable se define antes del bloque, entonces la variable externa se usa dentro del bloque y, por lo tanto, su valor es persistente entre iteraciones.

Una solución sería escribir esto en su lugar:

comment = number%2==0 ? " is even" : nil

Creo que mucha gente (incluyéndome a mí) tiende a escribir " a = b if c " en lugar de " a = (c ? b : nil) ", porque es más fácil de leer, pero obviamente tiene efectos secundarios.


En relación con la respuesta de to_foo métodos de Ruby to_foo insinúan cuán estricta será la conversión que harán.

Los cortos como to_i , to_s dicen que es flojo, y los convierte al tipo de destino, incluso si no se pueden representar con precisión en ese formato. Por ejemplo:

"10".to_i == 10 :foo.to_s == "foo"

Las funciones explícitas más largas como to_int , to_s significan que el objeto se puede representar de forma nativa como ese tipo de datos. Por ejemplo, la clase Rational representa todos los números racionales, por lo que se puede representar directamente como un entero Fixnum (o Bignum) llamando a to_int .

Rational(20,4).to_int == 5

Si no puede llamar al método más largo, significa que el objeto no se puede representar de forma nativa en ese tipo.

Básicamente, al convertir, si eres perezoso con los nombres de los métodos, Ruby se quedará perezosa con la conversión.


Este me hizo enojar una vez:

1/2 == 0.5 #=> false 1/2 == 0 #=> true



Los bloques y métodos devuelven el valor de la última línea de forma predeterminada. Agregar sentencias puts al final para fines de depuración puede causar efectos secundarios desagradables


Los métodos se pueden redefinir y pueden convertirse en un rasguño mental hasta que descubras la causa. ( Es cierto que este error es probablemente un poco "más difícil" de detectar cuando una acción del controlador Ruby on Rails se redefine por error ).

#demo.rb class Demo def hello1 p "Hello from first definition" end # ...lots of code here... # and you forget that you have already defined hello1 def hello1 p "Hello from second definition" end end Demo.new.hello1

Correr:

$ ruby demo.rb => "Hello from second definition"

Pero llámalo con advertencias habilitadas y puedes ver el motivo:

$ ruby -w demo.rb demo.rb:10: warning: method redefined; discarding old hello1 => "Hello from second definition"


Los principiantes tendrán problemas con los métodos de igualdad :

  • a == b : verifica si a y b son iguales. Este es el más útil.
  • a.eql? b : también verifica si a y b son iguales, pero a veces es más estricto (podría verificar que a y b tienen el mismo tipo, por ejemplo). Se usa principalmente en Hashes.
  • a.equal? b : comprueba si a y b son el mismo objeto (comprobación de identidad).
  • a === b : utilizado en las declaraciones de casos (lo leí como " a coincide con b ").

Estos ejemplos deberían aclarar los primeros 3 métodos:

a = b = "joe" a==b # true a.eql? b # true a.equal? b # true (a.object_id == b.object_id) a = "joe" b = "joe" a==b # true a.eql? b # true a.equal? b # false (a.object_id != b.object_id) a = 1 b = 1.0 a==b # true a.eql? b # false (a.class != b.class) a.equal? b # false

Tenga en cuenta que == , eql? e igual? siempre debe ser simétrica: si a == b entonces b == a.

También tenga en cuenta que == y eql? Ambos se implementan en la clase Objeto como alias para igualar? , entonces si creas una nueva clase y quieres == y eql? para significar algo más que identidad simple, entonces necesitas anularlos a ambos. Por ejemplo:

class Person attr_reader name def == (rhs) rhs.name == self.name # compare person by their name end def eql? (rhs) self == rhs end # never override the equal? method! end

El método === se comporta de manera diferente. En primer lugar, no es simétrico (a === b no implica que b === a). Como dije, puedes leer a === b como "a coincide con b". Aquí están algunos ejemplos:

# === is usually simply an alias for == "joe" === "joe" # true "joe" === "bob" # false # but ranges match any value they include (1..10) === 5 # true (1..10) === 19 # false (1..10) === (1..10) # false (the range does not include itself) # arrays just match equal arrays, but they do not match included values! [1,2,3] === [1,2,3] # true [1,2,3] === 2 # false # classes match their instances and instances of derived classes String === "joe" # true String === 1.5 # false (1.5 is not a String) String === String # false (the String class is not itself a String)

La declaración de caso se basa en el método === :

case a when "joe": puts "1" when 1.0 : puts "2" when (1..10), (15..20): puts "3" else puts "4" end

es equivalente a esto:

if "joe" === a puts "1" elsif 1.0 === a puts "2" elsif (1..10) === a || (15..20) === a puts "3" else puts "4" end

Si define una nueva clase cuyas instancias representen algún tipo de contenedor o rango (si tiene algo así como un método de inclusión? O una coincidencia ), entonces puede serle útil anular el método === de esta manera:

class Subnet [...] def include? (ip_address_or_subnet) [...] end def === (rhs) self.include? rhs end end case destination_ip when white_listed_subnet: puts "the ip belongs to the white-listed subnet" when black_listed_subnet: puts "the ip belongs to the black-listed subnet" [...] end


Si declaras un setter (aka mutator) usando attr_writer o attr_accessor (o def foo= ), ten cuidado de llamarlo desde el interior de la clase. Como las variables se declaran implícitamente, el intérprete siempre debe resolver que foo = bar declare una nueva variable llamada foo, en lugar de llamar al método self.foo=(bar) .

class Thing attr_accessor :foo def initialize @foo = 1 # this sets @foo to 1 self.foo = 2 # this sets @foo to 2 foo = 3 # this does *not* set @foo end end puts Thing.new.foo #=> 2

Esto también se aplica a los objetos Rails ActiveRecord, que obtienen accesoadores definidos en función de los campos de la base de datos. Como ni siquiera son variables de instancia de estilo @, la forma correcta de establecer esos valores individualmente es con self.value = 123 o self[''value''] = 123 .


Soy nuevo en ruby, y en mi primera ronda me encontré con un problema relacionado con el cambio de flotantes / cadenas a un número entero. Empecé con las carrozas y codifiqué todo como f.to_int . Pero cuando continué y utilicé el mismo método para las cadenas, sentí una curva cuando se trataba de ejecutar el programa.

Aparentemente, una cadena no tiene un método to_int , pero los flotantes y los ints lo hacen.

irb(main):003:0* str_val = ''5.0'' => "5.0" irb(main):006:0> str_val.to_int NoMethodError: undefined method `to_int'' for "5.0":String from (irb):6 irb(main):005:0* str_val.to_i => 5 irb(main):007:0> float_val = 5.0 => 5.0 irb(main):008:0> float_val.to_int => 5 irb(main):009:0> float_val.to_i => 5 irb(main):010:0>

Los paréntesis arbitrarios también me arrojaron al principio. Vi un código con y sin él. Me tomó un tiempo darme cuenta de que cualquiera de los estilos es aceptado.


Tuve muchos problemas para comprender las variables de clase, los atributos de clase y los métodos de clase. Este código podría ayudar a un novato:

class A @@classvar = "A1" @classattr = "A2" def self.showvars puts "@@classvar => "+@@classvar puts "@classattr => "+@classattr end end A.showvars # displays: # @@classvar => A1 # @classattr => A2 class B < A @@classvar = "B1" @classattr = "B2" end B.showvars # displays: # @@classvar => B1 # @classattr => B2 A.showvars # displays: # @@classvar => B1 #Class variables are shared in a class hierarchy! # @classattr => A2 #Class attributes are not


Tuve problemas con mixins que contienen métodos de instancia y métodos de clase. Este código podría ayudar a un novato:

module Displayable # instance methods here def display puts name self.class.increment_displays end def self.included(base) # This module method will be called automatically # after this module is included in a class. # We want to add the class methods to the class. base.extend Displayable::ClassMethods end module ClassMethods # class methods here def number_of_displays @number_of_displays # this is a class attribute end def increment_displays @number_of_displays += 1 end def init_displays @number_of_displays = 0 end # this module method will be called automatically # after this module is extended by a class. # We want to perform some initialization on a # class attribute. def self.extended(base) base.init_displays end end end class Person include Displayable def name; @name; end def initialize(name); @name=name; end end puts Person.number_of_displays # => 0 john = Person.new "John" john.display # => John puts Person.number_of_displays # => 1 jack = Person.new "Jack" jack.display # => Jack puts Person.number_of_displays # => 2

Al principio, pensé que podría tener módulos con métodos de instancia y métodos de clase simplemente haciendo esto:

module Displayable def display puts name self.class.increment_displays end def self.number_of_displays # WRONG! @number_of_displays end [...] end

Lamentablemente, el método number_of_displays nunca se incluirá ni se ampliará porque es un "método de clase de módulo". Solo los "métodos de instancia de módulo" pueden incluirse en una clase (como métodos de instancia) o extenderse a una clase (como métodos de clase). Esta es la razón por la cual necesita poner los métodos de instancia de su mezcla en un módulo, y los métodos de clase de su mezcla en otro módulo (generalmente pone los métodos de clase en un submódulo "ClassMethods"). Gracias al método mágico incluido , puede hacer que sea fácil incluir métodos de instancia y métodos de clase en una sola llamada "incluir Displayable" (como se muestra en el ejemplo anterior).

Este mixin contará cada pantalla por clase . El contador es un atributo de clase, por lo que cada clase tendrá su propio (su programa probablemente fallará si obtiene una nueva clase de la clase Person ya que el contador @number_of_displays para la clase derivada nunca se inicializará). Es posible que desee reemplazar @number_of_displays por @@ number_of_displays para convertirlo en un contador global. En este caso, cada jerarquía de clases tendrá su propio contador. Si desea un contador global y exclusivo, probablemente deba convertirlo en un atributo de módulo.

Todo esto definitivamente no fue intuitivo para mí cuando comencé con Ruby.

Sin embargo, todavía no puedo entender cómo hacer que algunos de estos métodos de mixin sean privados o protegidos (solo los métodos display y number_of_displays deberían incluirse como métodos públicos).


Una cosa que aprendí fue usar el operador || = cuidadosamente. y tenga especial cuidado si se trata de booleanos. usualmente usaba un || = b como un catch all para dar ''a'' un valor predeterminado si todo lo demás fallaba y ''a'' permanecía nulo. pero si a es falso yb es verdadero, entonces a se le asignará verdadero.


Uno que me sorprendió en el pasado es que la secuencia de escape del carácter de nueva línea ( /n ), entre otros, no está respaldada por cadenas dentro de comillas simples. La barra invertida en sí se escapó. Debe usar comillas dobles para que el escapado funcione como se espera.


Wikipedia Ruby gotchas

Del artículo:

  • Los nombres que comienzan con una letra mayúscula se tratan como constantes, por lo que las variables locales deben comenzar con una letra minúscula.
  • Los caracteres $ y @ no indican el tipo de datos variables como en Perl, sino que funcionan como operadores de resolución de alcance.
  • Para indicar los números de punto flotante, uno debe seguir con un dígito cero ( 99.0 ) o una conversión explícita ( 99.to_f ). No es suficiente agregar un punto ( 99. ), porque los números son susceptibles a la sintaxis del método.
  • La evaluación booleana de datos no booleanos es estricta: 0 , "" y [] se evalúan como true . En C, la expresión 0 ? 1 : 0 0 ? 1 : 0 evalúa a 0 (es decir, falso). En Ruby, sin embargo, rinde 1 , ya que todos los números se evalúan como true ; solo nil y false evalúan a false . Un corolario de esta regla es que los métodos de Ruby por convención, por ejemplo, las búsquedas de expresiones regulares, devuelven números, cadenas, listas u otros valores no falsos en caso de éxito, pero nil en caso de error (por ejemplo, falta de coincidencia). Esta convención también se usa en Smalltalk, donde solo se pueden usar los objetos especiales true y false en una expresión booleana.
  • Las versiones anteriores a 1.9 carecen de un tipo de datos de caracteres (compárense con C, que proporciona el tipo de caracteres para los caracteres). Esto puede causar sorpresas al cortar cadenas: "abc"[0] produce 97 (un entero, que representa el código ASCII del primer carácter en la cadena); para obtener "a" use "abc"[0,1] (una subcadena de longitud 1) o "abc"[0].chr .
  • El statement until expression notación statement until expression , a diferencia de los enunciados equivalentes de otros idiomas (por ejemplo, do { statement } while (not(expression)); en C / C ++ / ...), en realidad nunca ejecuta el enunciado si la expresión ya es true . Esto se debe a que el statement until expression es en realidad azúcar sintáctico sobre

    until expression statement end

    , cuyo equivalente en C / C ++ es while (not(expression)) statement; al igual que la statement if expression es equivalente a

    if expression statement end

    Sin embargo, la notación

    begin statement end until expression

    en Ruby, de hecho, ejecutará la declaración una vez, incluso si la expresión ya es verdadera.

  • Como las constantes son referencias a objetos, cambiar a qué se refiere una constante genera una advertencia, pero modificar el objeto no lo hace. Por ejemplo, Greeting << " world!" if Greeting == "Hello" Greeting << " world!" if Greeting == "Hello" no genera un error o advertencia. Esto es similar a las variables final en Java, pero Ruby también tiene la funcionalidad de "congelar" un objeto, a diferencia de Java.

Algunas características que difieren notablemente de otros idiomas:

  • Los operadores habituales para las expresiones condicionales, yy or , no siguen las reglas de precedencia normales: and no se vinculan más estrictamente que or . Ruby también tiene operadores de expresión || y & que funcionan como se esperaba.

  • def dentro de def no hace lo que un programador de Python podría esperar:

    def a_method x = 7 def print_x; puts x end print_x end

    Esto da un error acerca de que x no está definido. Necesita usar un Proc .

Características del lenguaje

  • La omisión de paréntesis alrededor de los argumentos del método puede conducir a resultados inesperados si los métodos toman múltiples parámetros. Los desarrolladores de Ruby han declarado que la omisión de paréntesis en los métodos de múltiples parámetros puede no estar permitida en futuras versiones de Ruby; el actual (noviembre de 2007) intérprete de Ruby lanza una advertencia que alienta al escritor a no omitir () , para evitar el significado ambiguo del código. No usar () sigue siendo una práctica común, y puede ser especialmente útil usar Ruby como un lenguaje de programación específico de dominio legible para el ser humano, junto con el método llamado method_missing() .


1..5.each {|x| puts x}

no funciona Tienes que poner el rango entre paréntesis, como

(1..5).each {|x| puts x}

así que no creo que estés llamando a 5.each . Creo que este es un tema de precedencia, al igual que el x = true and false gotcha.


x = (true and false) # x is false

0 y '''' son verdaderos, como usted señaló.

Puede tener un método y un módulo / clase con el mismo nombre (lo cual tiene sentido, porque el método realmente se agrega a Object y, por lo tanto, tiene su propio espacio de nombres).

No hay herencia múltiple, pero con frecuencia los "módulos mixin" se usan para agregar métodos comunes a múltiples clases.


  • Los bloques son realmente importantes de entender, se usan en todas partes.

  • No necesita paréntesis alrededor de los parámetros del método. Si los usa o no depende de usted. Algunos dicen que siempre debes usarlos .

  • Use raise and rescue para manejo de excepciones, no throw and catch.

  • Puedes usar ; pero no tienes que hacerlo a menos que quieras poner varias cosas en una línea.


  • Monkey parches . Ruby tiene clases abiertas, por lo que su comportamiento se puede cambiar dinámicamente en el tiempo de ejecución ...

  • Los objetos pueden responder a métodos indefinidos si se ha anulado method_missing o send . Esto explota la invocación de método basada en mensajes de Ruby. El sistema ActiveRecord Rails usa esto con gran efecto.