“Ruby is designed to make programmers happy”, en palabras de su creador, Yukihiro “Matz” Matsumoto.
Como programadores, el tema de ser felices trabajando es indudable que tiene su atractivo. Pero… ¿es eso cierto? ¿Qué tiene Ruby de particular? ¿Por qué Ruby “mola”?
3. RUBY EN UNA
FRASE➤ Ruby es un lenguaje hecho
para optimizar al programador
“Ruby is designed to make
programmers happy.”
Yukihiro “Matz” Matsumoto
4. Y POR ESO…
➤ Ruby es un lenguaje hecho
para optimizar al programador
➤ Ruby es un lenguaje
interpretado
5. Y POR ESO…
➤ Ruby es un lenguaje hecho
para optimizar al programador
➤ Ruby es un lenguaje
interpretado
➤ Ruby es dinámicamente
tipado
“With great power comes great
responsability.”
Uncle Ben
6. Y POR ESO…
➤ Ruby es un lenguaje hecho
para optimizar al programador
➤ Ruby es un lenguaje
interpretado
➤ Ruby es dinámicamente
tipado
➤ Ruby es (relativamente) lento
¿Y eso importa?
8. Y POR ESO…
➤ Ruby es un lenguaje hecho
para optimizar al programador
➤ Ruby es un lenguaje
interpretado
➤ Ruby es dinámicamente
tipado
➤ Ruby es (relativamente) lento
➤ Ruby es un lenguaje
Orientado a Objetos
9. Y POR ESO…
➤ Ruby es un lenguaje hecho
para optimizar al programador
➤ Ruby es un lenguaje
interpretado
➤ Ruby es dinámicamente
tipado
➤ Ruby es (relativamente) lento
➤ Ruby es un lenguaje
Orientado a Objetos
➤ Ruby es muy flexible
“With great power comes great
responsability.” (sí, otra vez!)
10. ¿QUE SIGNIFICA EXACTAMENTE QUE
ES FLEXIBLE?➤ Ruby tiene “formas acortadas” para escribir las cosas
tecleando menos.
11. ¿QUE SIGNIFICA EXACTAMENTE QUE
ES FLEXIBLE?➤ Ruby tiene “formas acortadas” para escribir las cosas
tecleando menos.
➤ Es frecuente tener la versión acortada para usar con trozos de
código pequeños y la “normal” para cuando hay más código.
12. ¿QUE SIGNIFICA EXACTAMENTE QUE
ES FLEXIBLE?➤ Ruby tiene “formas acortadas” para escribir las cosas
tecleando menos.
➤ Curiosamente, el beneficio no es que se escribe menos, sino
que queda más bonito y se lee mejor.
➤ Conviene seguir una “guía de estilo” para asegurar la
consistencia y que no sea un caos:
https://github.com/bbatsov/ruby-style-guide
➤ Es frecuente tener la versión acortada para usar con trozos de
código pequeños y la “normal” para cuando hay más código.
13. ➤ Una especie de “cadena corta” especialmente eficiente porque es
inmutable e internamente funciona como un entero
➤ Además de eficiente… es muy legible, y mola!
:title
SYMBOLS
14. ➤ Una especie de “cadena corta” especialmente eficiente porque es
inmutable e internamente funciona como un entero
➤ Además de eficiente… es muy legible, y mola!
➤ Hay una versión acortada para arrays de symbols
attributes = %i(title author year description)
SYMBOLS
15. ➤ Una especie de “cadena corta” especialmente eficiente porque es
inmutable e internamente funciona como un entero
➤ Además de eficiente… es muy legible, y mola!
➤ Hay una versión acortada para arrays de symbols
➤ Con frecuencia se usa para key de hashes (pares key-value), así
que… también hay una versión acortada para este caso
SYMBOLS
:key => 'My value'
key: 'My value'
16. ➤ El bucle menos rubyish del mundo (pero funciona):
for i in 0..(subscribers.length - 1)
subscribers[i].notify
end
BUCLES
17. ➤ Preferimos trabajar con instancias mejor que índices:
for i in 0..(subscribers.length - 1)
subscribers[i].notify
end
BUCLES
for suscriber in subscribers
subscriber.notify
end
18. ➤ Preferimos trabajar con instancias mejor que índices.
➤ Preferimos “each” en vez de “for” (crea un bloque: scope propio). Lo
que pasa en el “each”, se queda en el “each”:
BUCLES
for suscriber in subscribers
subscriber.notify
end
suscribers.each do |subscriber|
subscriber.notify
end
19. ➤ Preferimos trabajar con instancias mejor que índices.
➤ Preferimos “each” en vez de “for” (crea un bloque: scope propio). Lo
que pasa en el “each”, se queda en el “each”.
➤ Si se va a iterar una línea corta, se puede meter todo en una línea:
BUCLES
suscribers.each { |subscriber| subscriber.notify }
suscribers.each do |subscriber|
subscriber.notify
end
20. ➤ Preferimos trabajar con instancias mejor que índices.
➤ Preferimos “each” en vez de “for” (crea un bloque: scope propio). Lo
que pasa en el “each”, se queda en el “each”.
➤ Si se va a iterar una línea corta, se puede meter todo en una línea.
➤ Si lo único que voy a hacer es llamar un método de la instancia, ni
siquiera necesitaré el bucle:
GREAT!!!!
BUCLES
suscribers.each(&:notify)
suscribers.each { |subscriber| subscriber.notify }
21. ➤ Hay una versión acortada para usar con trozos de código pequeños
if subscriber.valid?
subscriber.notify
end
CONDICIONALES
subscriber.notify if subscriber.valid?
22. ➤ Hay una versión acortada para usar con trozos de código pequeños
➤ Se puede usar en su lugar, sin abusar, el operador ternario
timeout = if is_admin
ADMIN_TIMEOUT
else
USER_TIMEOUT
end
CONDICIONALES
timeout = is_admin ? ADMIN_TIMEOUT : USER_TIMEOUT
23. ➤ Hay una versión acortada para usar con trozos de código pequeños
➤ Se puede usar en su lugar, sin abusar, el operador ternario
➤ Preferimos unless en vez de condiciones negadas (siempre que no
haya else)
CONDICIONALES
if !subscriber.valid?
subscriber.reject
end
unless subscriber.valid?
subscriber.reject
end
24. ➤ Hay una versión acortada para usar con trozos de código pequeños
➤ Se puede usar en su lugar, sin abusar, el operador ternario
➤ Preferimos unless en vez de condiciones negadas (siempre que no
haya else)
➤ Si no se trata de condiciones “normales”, sino de tratamiento de
errores, es más expresivo usar “condiciones de salida” que partir el
flujo en dos ramas con apariencia de similar jerarquía
CONDICIONALES
(Requisito: los métodos deben devolver nil si fallan)
25. blog = Blog.find(url)
if blog
subscription = subscribe(me, blog)
if subscription
notify_subscription(subscription)
else
subscription_failed
end
else
render_404
end
CONDICIONALES
blog.find(url) or return render_404
subscription = subscribe(me, blog) or return subscription_failed
notify_subscription(subscription)
26. ➤ Similares a otros lenguajes.
➤ Muy enriquecidos con métodos útiles “de fábrica”. Consultar
documentación https://docs.ruby-lang.org/en/2.3.0/String.html
➤ Se usa interpolación "Nombre: #{user.name}" en vez de suma
"Nombre:" + user.name para evitar problemas con nil.
➤ Conversión a entero inteligente: "46-valencia".to_i => 46
➤ Al interpolar un objeto, se llamará a su método .to_s . Definiendo
este método, tendremos un magnífico “default” de cómo se
muestran las instancias de esta clase: "Nombre: #{user}"
(podremos definirlo como nombre+apellidos, o nick, o lo que sea)
STRINGS
27. ➤ Similares a otros lenguajes.
➤ Muy enriquecidos con métodos útiles “de fábrica”. Consultar
documentación https://docs.ruby-lang.org/en/2.3.0/Array.html &
https://docs.ruby-lang.org/en/2.3.0/Enumerable.html
ARRAYS
28. ➤ Pares de key + value, en los que se busca usando la key para
obtener el value asociado
HASHES
{
nil => "No se encuentra",
'A' => "Opción A",
'X' => AMOUNT * RATE
}
(Explicación de informático a jefe de proyecto: correcto pero no muy útil)
¿Para qué sirven los hashes?
29. ➤ Pares de key + value, en los que se busca usando la key para
obtener el value asociado
➤ Útiles para implementar diccionarios de traducción
HASHES
ORDER_TO_BD = {
'cheap' => 'price',
'expensive' => 'price DESC',
'popular' => 'likes_count DESC'
}
order = ORDER_TO_BD[param_order] || 'created_at DESC'
PROVINCIA_API = {
'La Coruña' => 'A Coruña',
'Gerona' => 'Girona'
}
provincia = PROVINCIA_API[provincia_api] || provincia_api
30. ➤ Pares de key + value, en los que se busca usando la key para
obtener el value asociado
➤ Útiles para implementar diccionarios de traducción
➤ O para convención sobre configuración
HASHES
DEFAULT_PAGINATE = {
page: 1,
per_page: 25,
order: 'created_at'
}
def pagination(custom_pagination = {})
options = DEFAULT_PAGINATE.merge(custom_pagination)
first = 1 + (options[:page] - 1) * options[:per_page]
...
end
31. ➤ Pares de key + value, en los que se busca usando la key para
obtener el value asociado
➤ Útiles para implementar diccionarios de traducción
➤ O para convención sobre configuración
➤ Fácil de convertir desde/hacia JSON, YAML, atributos de un
modelo, campos de la tabla en BD…
HASHES
32. ➤ Se pueden enviar llamadas a atributos o métodos de una instancia
componiendo dinámicamente su método
MÉTODOS
DINÁMICOS
user.phone_1 = '963112233'
user.phone_4 = '666111000'
user.phone_2 = '678111000'
phones = (1..4).map do |i|
user.send("phone_#{i}")
end
=> ['963112233', '678111000', nil, '666111000']
33. ➤ Se pueden enviar llamadas a atributos o métodos de una instancia
componiendo dinámicamente su método
➤ Cuidado con la seguridad: si no son constantes, sino parámetros o
valores de la BD, hay que usar whitelists
MÉTODOS
DINÁMICOS
VALID_SECTIONS = %w(banca bolsa fondos)
def filter_by_section(param_section)
return unless param_section.in?(VALID_SECTIONS)
Message.send("in_#{param_section}")
end
34. ➤ Se pueden enviar llamadas a atributos o métodos de una instancia
componiendo dinámicamente su método
➤ Cuidado con la seguridad: si no son constantes, sino parámetros o
valores de la BD, hay que usar whitelists
➤ Útil para manejar items con gran cantidad de campos que siguen
patrones en su nombre o que se comportan igual
MÉTODOS
DINÁMICOS
35. ➤ Se pueden enviar llamadas a atributos o métodos de una instancia
componiendo dinámicamente su método
➤ Cuidado con la seguridad: si no son constantes, sino parámetros o
valores de la BD, hay que usar whitelists
➤ Útil para manejar items con gran cantidad de campos que siguen
patrones en su nombre o que se comportan igual
➤ En ocasiones es un smell: si muchos atributos se comportan de
forma repetitiva, quizá se resuelva mejor usando atributos de tipo
array, o una tabla con una relación 1-n
MÉTODOS
DINÁMICOS
36. ➤ Los métodos en Ruby retornan el valor de la última operación que
se hizo
MÉTODOS
Asignación: el valor asignado a la variable
return unless admin?: nil (default)
return “No way!” unless admin?: “No way!”
Llamada a otro método: el valor de retorno del
otro método
37. ➤ Los métodos en Ruby retornan el valor de la última operación que
se hizo
➤ Se pueden pasar parámetros opcionales (al final) poniendo un
default
MÉTODOS
def pictures(format, order = 'created_at desc', limit = nil)
"Bring #{format} files sort #{order} max #{limit || 'all'}"
end
item.pictures('jpg')
item.pictures('jpg', 'likes_count desc')
item.pictures('jpg', 'created_at desc', 20)
38. ➤ Los métodos en Ruby retornan el valor de la última operación que
se hizo
➤ Se pueden pasar parámetros opcionales (al final) poniendo un
default
➤ Se puede reducir el acoplamiento (Connascence) con named
parameters (aka keyword arguments)
MÉTODOS
def pictures(format:, order: 'created_at desc', limit: nil)
"Bring #{format} files sort #{order} max #{limit || 'all'}"
end
item.pictures(format: 'jpg')
item.pictures(format: 'jpg', order: 'likes_count desc')
item.pictures(format: 'jpg', limit: 20)