ruby idioms

Expresiones de Ruby comunes



idioms (15)

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

Sin embargo, inspirado por esta pregunta: Ruby Code explicó y la descripción de cómo funciona ||= en rubí, estaba pensando en los modismos de rubí que no uso, como francamente, no los asimilo completamente.

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í verdaderamente competente?

Por cierto, de la pregunta a la que se hace referencia

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. La expansión correcta es de hecho

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

Vea estos enlaces para saber por qué:

Gracias a Jörg W Mittag por señalar esto.


Por cierto, de la pregunta a la que se hace referencia

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.

Como ambos (y solo) nil y false evalúan a booleano falso, a ||= b es en realidad (casi *) equivalente a:

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

O, para reescribirlo con otro idioma Ruby:

a = b unless a

(* Debido a que cada enunciado tiene un valor, estos no son técnicamente equivalentes a a ||= b . Pero si no está confiando en el valor de la declaración, no verá una diferencia).


¡Buena pregunta!

Como creo, cuanto más intuitivo y rápido sea el código, mejor será el software que estamos creando. Te mostraré cómo expreso mis pensamientos usando Ruby en pequeños fragmentos de código. Leer 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 manera idiomática, simple y fácil ... ¡muestra!

[1, 2, 3].sample

Equivalencia / Memocion de doble tubo

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

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, siento que es una forma realmente idiomática de crear y usar clases:

GetSearchResult.call(params)

Sencillo. Hermosa. 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 para escribir el código de Ruby idiomático, lea aquí


Algunos modismos más:

Uso de %w , %r y %( delimitadores

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

Tipo de comparación 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 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 Rubyistas, pero tal vez no para las personas que provienen de otros idiomas: el uso de each a favor de for .. in

some_iterable_object.each{|item| ... }

En Ruby 1.9+, Rails, o al aplicar el parche al método Symbol # to_proc, this 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 (bang)

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 splat implícitos

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


Aquí hay algunos, seleccionados de varias fuentes:

utilice "a menos" y "hasta" en lugar de "si no" y "mientras no". Sin embargo, intente no utilizar "a menos" cuando exista una condición de "else".

Recuerde que puede asignar múltiples variables a la vez:

a,b,c = 1,2,3

e incluso cambiar variable sin una temperatura:

a,b = b,a

Utilice los condicionales finales cuando sea apropiado, por ejemplo

do_something_interesting unless want_to_be_bored?

Tenga en cuenta una forma comúnmente utilizada pero no obvia al instante (al menos para mí) de definir los métodos de clase:

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

Algunas referencias:


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

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


Esta slideshow es bastante completa en los principales modismos de Ruby, como en:

  • Cambiar dos valores:

    x, y = y, x

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

    def somemethod(x, y=nil)

  • Combina parámetros extraños en una matriz

    def substitute(re, str, *rest)

Y así...


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

if __FILE__ == $0 # this library may be run as a standalone script end

Paquetes de embalaje y desempaquetado:

# 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'' ]

El azúcar sintáctico para hashes como argumentos de método

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

Iniciales de hash:

# 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]}

sintaxis de metaclase

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

variables de instancia de clase

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"

Bloques, procs y lambdas. Vive y respira.

# 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'' ]



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

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

podría ser reescrito

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

Lo mismo podría aplicarse a caso-cuando:

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


Me gusta esto:

str = "Something evil this way comes!" regexp = /(/w[aeiou])/ str[regexp, 1] # <- This

Que es (aproximadamente) equivalente a:

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

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


Puede hacer una copia profunda con el objeto Marshaling fácilmente. - tomado de The Ruby Programming Language

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

Tenga en cuenta que los archivos y las secuencias de E / S, así como los objetos de Método y Enlace, son demasiado dinámicos para ser calculados; no habría una manera confiable de restaurar su estado.


Siempre me olvido de la sintaxis exacta de esta abreviatura if else statement (y el nombre del operador ¿comenta alguien?) Creo que es ampliamente utilizado 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

actualizar

llamado el operador ternario:

devolver myvar? myvar.size: 0


Sugiero leer el código de plugins o gemas populares y bien diseñados de personas que admiras y respetas.

Algunos ejemplos que me 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ía refactorizado para

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


método falta magia

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 de ruby ​​llamará al método llamado ''method_missing'' si está definido, puede usar esto para algunos trucos, como escribir api wrappers, o dsl, donde no conoce todos los métodos y parámetros nombres


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

es aproximadamente:

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 haber sido encontrado, y necesito obtener uno de sus atributos.