Pregunta

Una cosa que me encanta de ruby ??es que, en su mayoría, es un lenguaje muy legible (lo cual es excelente para el código de auto-documentación)

Sin embargo, inspirado por esta pregunta: Explicación del Código Ruby y la descripción de cómo || = funciona en ruby, estaba pensando en los modismos ruby ??que no uso, ya que francamente no los asimilo por completo.

Entonces, mi pregunta es, similar al ejemplo de la pregunta a la que se hace referencia, ¿qué expresiones de rubí comunes, pero no obvias, debo tener en cuenta para ser un programador de rubíes verdaderamente competente?

Por cierto, de la pregunta referenciada

a ||= b 

es equivalente a

if a == nil || a == false
  a = b
end

(Gracias a Ian Terrell por la corrección)

Editar: Resulta que este punto no es totalmente indiscutible. De hecho, la expansión correcta es

(a || (a = (b))) 

Vea estos enlaces para saber por qué:

Gracias a J & # 246; rg W Mittag por señalar esto.

¿Fue útil?

Solución

La cláusula magic if que permite que el mismo archivo sirva como biblioteca o script:

if __FILE__ == 
# put the first two words in a and b and the rest in arr
a,b,*arr = *%w{a dog was following me, but then he decided to chase bob}
# this holds for method definitions to
def catall(first, *rest)
  rest.map { |word| first + word }
end
catall( 'franken', 'stein', 'berry', 'sense' ) #=> [ 'frankenstein', 'frankenberry', 'frankensense' ]
# this library may be run as a standalone script end

Empaquetado y desempaquetado de matrices:

this(:is => :the, :same => :as)
this({:is => :the, :same => :as})

El azúcar sintético para los hashes como argumentos de método

# this
animals = Hash.new { [] }
animals[:dogs] << :Scooby
animals[:dogs] << :Scrappy
animals[:dogs] << :DynoMutt
animals[:squirrels] << :Rocket
animals[:squirrels] << :Secret
animals #=> {}
# is not the same as this
animals = Hash.new { |_animals, type| _animals[type] = [] }
animals[:dogs] << :Scooby
animals[:dogs] << :Scrappy
animals[:dogs] << :DynoMutt
animals[:squirrels] << :Rocket
animals[:squirrels] << :Secret
animals #=> {:squirrels=>[:Rocket, :Secret], :dogs=>[:Scooby, :Scrappy, :DynoMutt]}

Inicializadores de hash:

x = Array.new
y = Array.new
class << x
  # this acts like a class definition, but only applies to x
  def custom_method
     :pow
  end
end
x.custom_method #=> :pow
y.custom_method # raises NoMethodError

sintaxis de metaclase

class Ticket
  @remaining = 3
  def self.new
    if @remaining > 0
      @remaining -= 1
      super
    else
      "IOU"
    end
  end
end
Ticket.new #=> Ticket
Ticket.new #=> Ticket
Ticket.new #=> Ticket
Ticket.new #=> "IOU"

variables de instancia de clase

 # know how to pack them into an object
 block = lambda { |e| puts e }
 # unpack them for a method
 %w{ and then what? }.each(&block)
 # create them as needed
 %w{ I saw a ghost! }.each { |w| puts w.upcase }
 # and from the method side, how to call them
 def ok
   yield :ok
 end
 # or pack them into a block to give to someone else
 def ok_dokey_ok(&block)
    ok(&block)
    block[:dokey] # same as block.call(:dokey)
    ok(&block)
 end
 # know where the parentheses go when a method takes arguments and a block.
 %w{ a bunch of words }.inject(0) { |size,w| size + 1 } #=> 4
 pusher = lambda { |array, word| array.unshift(word) }
 %w{ eat more fish }.inject([], &pusher) #=> ['fish', 'more', 'eat' ]

Bloques, procs y lambdas. Vive y respira.

<*>

Otros consejos

Esta presentación de diapositivas es bastante completa en los idiomas principales de Ruby, como en:

  • Intercambia dos valores:

    x, y = y, x

  • Parámetros que, si no se especifican, adquieren algún valor predeterminado

    def algún método (x, y = nil)

  • Combina los parámetros extraños en una matriz

    def sustituto (re, str, * rest)

Y así sucesivamente ...

Algunos modismos más:

Uso de los % w , % r y % ( delimitadores

%w{ An array of strings %}
%r{ ^http:// }
%{ I don't care if the string has 'single' or "double" strings }

Comparación de tipos en declaraciones de casos

def something(x)
  case x
    when Array
      # Do something with array
    when String
      # Do something with string
    else
      # You should really teach your objects how to 'quack', don't you?
  end
end

... y abuso general del método === en las declaraciones de casos

case x
  when 'something concrete' then ...
  when SomeClass then ...
  when /matches this/ then ...
  when (10...20) then ...
  when some_condition >= some_value then ...
  else ...
end

Algo que debería parecer natural para los rubistas, pero tal vez no para las personas que vienen de otros idiomas: el uso de cada a favor de para .. en

some_iterable_object.each{|item| ... }

En Ruby 1.9+, Rails, o parcheando el método Symbol # to_proc, esto se está convirtiendo en un idioma cada vez más popular:

strings.map(&:upcase)

Método condicional / definición constante

SOME_CONSTANT = "value" unless defined?(SOME_CONSTANT)

Métodos de consulta y métodos destructivos (explosión)

def is_awesome?
  # Return some state of the object, usually a boolean
end

def make_awesome!
  # Modify the state of the object
end

Parámetros implícitos de splat

[[1, 2], [3, 4], [5, 6]].each{ |first, second| puts "(#{first}, #{second})" }

Me gusta esto:

str = "Something evil this way comes!"
regexp = /(\w[aeiou])/

str[regexp, 1] # <- This

Lo que equivale (aproximadamente) a:

str_match = str.match(regexp)
str_match[1] unless str_match.nil?

O al menos eso es lo que he usado para reemplazar tales bloques.

Sugeriría leer el código de complementos o gemas populares y bien diseñados de personas que admiras y respetas.

Algunos ejemplos que he encontrado:

if params[:controller] == 'discussions' or params[:controller] == 'account'
  # do something here
end

correspondiente a

if ['account', 'discussions'].include? params[:controller]
  # do something here
end

que luego será refactorizado a

if ALLOWED_CONTROLLERS.include? params[:controller]
  # do something here
end

Aquí hay algunos, seleccionados de varias fuentes:

utilice " a menos que " y "hasta" en lugar de " si no " y " mientras que no " ;. Trate de no usar " a menos que " cuando un " else " la condición existe, sin embargo.

Recuerda que puedes asignar múltiples variables a la vez:

a,b,c = 1,2,3

e incluso cambiar la variable sin una temperatura:

a,b = b,a

Use condicionales finales cuando sea apropiado, por ejemplo,

do_something_interesting unless want_to_be_bored?

Tenga en cuenta una forma de definición de métodos de clase comúnmente utilizada pero no instantáneamente obvia (al menos para mí):

class Animal
  class<<self
    def class_method
      puts "call me using Animal.class_method"
    end
  end
end

Algunas referencias:

  

Por cierto, de la referencia   pregunta

a ||= b 
     

es equivalente a

if a == nil   
  a = b 
end

Eso es sutilmente incorrecto, y es una fuente de errores en las aplicaciones Ruby de los recién llegados.

Dado que ambos (y solo) nil y false se evalúan como booleanos falsos, a || = b es en realidad (casi *) equivalente a:

if a == nil || a == false
  a = b
end

O, para reescribirlo con otro lenguaje Ruby:

a = b unless a

(* Como cada declaración tiene un valor, estos no son técnicamente equivalentes a a || = b . Pero si no confías en el valor de la declaración, no verás una diferencia.)

Mantengo una página wiki que cubre algunos modismos y formatos de Ruby:

https://github.com/tokland/tokland/wiki/RubyIdioms

Siempre olvido la sintaxis exacta de esta abreviatura en caso contrario (y el nombre del operador. ¿alguien comenta?) Creo que se usa ampliamente fuera de ruby, pero en caso de que alguien más quiera la sintaxis, aquí está:

refactor < 3 ? puts("No need to refactor YET") : puts("You need to refactor this into a  method")

se expande a

if refactor < 3
  puts("No need to refactor YET")
else
  puts("You need to refactor this into a  method")
end

update

llamado operador ternario:

devuelve myvar? myvar.size: 0

Puedes realizar una copia en profundidad con el objeto Marshaling fácilmente. - Tomado del lenguaje de programación Ruby

def deepcopy(o)
  Marshal.load(Marshal.dump(o))
end
  

Tenga en cuenta que los archivos y las secuencias de E / S, como   así como los objetos Método y Encuadernación,   son demasiado dinámicos para ser ordenados; ahí   no sería una forma confiable de restaurar   su estado.

a = (b && b.attribute) || "default"

es más o menos:

if ( ! b.nil? && ! b == false) && ( ! b.attribute.nil? && ! b.attribute.false) a = b
else a = "default"

Utilizo esto cuando b es un registro que puede o no haberse encontrado, y necesito obtener uno de sus atributos.

Me gusta cómo acortar If-then-else o case-when porque devuelven un valor:

if test>0
  result = "positive"
elsif test==0
  result = "zero"
else
  result = "negative"
end

podría reescribirse

result = if test>0
  "positive"
elsif test==0
  "zero"
else
  "negative"
end

Lo mismo podría aplicarse al caso cuando:

result = case test
when test>0 ; "positive"
when test==0 ; "zero"
else "negative"
end

Array.pack y String.unpack para trabajar con archivos binarios:

# extracts four binary sint32s to four Integers in an Array
data.unpack("iiii") 

Magia faltante del método

class Dummy  
  def method_missing(m, *args, &block)  
    "You just called method with name #{m} and arguments- #{args}"  
  end  
end

Dummy.new.anything(10, 20)
=> "You just called method with name anything and arguments- [10, 20]"

si llama a métodos que no existen en los objetos ruby, el intérprete ruby ??llamará a un método llamado 'method_missing' si está definido, puede usar esto para algunos trucos, como escribir envoltorios de api, o dsl, donde no sabe todos métodos y nombres de parámetros

Buena pregunta!

Como creo, el más intuitivo & amp; más rápido es el código, un mejor software que estamos construyendo. Te mostraré cómo expreso mis pensamientos usando Ruby en pequeños fragmentos de código. Lea más aquí

Mapa

Podemos usar el método de mapa de diferentes maneras:

user_ids = users.map { |user| user.id }

O:

user_ids = users.map(&:id)

Muestra

Podemos usar el método rand:

[1, 2, 3][rand(3)]

Barajar:

[1, 2, 3].shuffle.first

Y la forma idiomática, simple y fácil ... muestra!

[1, 2, 3].sample

Double Pipe Equals / Memoization

Como dijiste en la descripción, podemos usar la memoria:

some_variable ||= 10
puts some_variable # => 10

some_variable ||= 99
puts some_variable # => 10

Método estático / Método de clase

Me gusta usar métodos de clase, creo que es una forma muy idiomática de crear & amp; usar clases:

GetSearchResult.call(params)

Simple. Hermoso. Intuitivo. ¿Qué pasa en el fondo?

class GetSearchResult
  def self.call(params)
    new(params).call
  end

  def initialize(params)
    @params = params
  end

  def call
    # ... your code here ...
  end
end

Para obtener más información sobre cómo escribir código Ruby idiomático, lea aquí

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top