Академический Документы
Профессиональный Документы
Культура Документы
1. Introduccin
2. Ruby
i. Cdigo y sintaxis
i. Nombramientos
ii. Colecciones
iii. Operadores logicos
iv. Literales
v. Idiomas
vi. Multilinea
vii. Comentarios y anotaciones
i. Anotaciones
viii. Modulos clases y variables
ix. Excepciones
x. Cadenas de caracteres
3. Ruby on Rails
i. Engines (Balloom)
ii. Assets
iii. Modelos
iv. Controladores
v. Vistas
vi. Seguridad
vii. Helpers
4. Navegadores
5. SEO
6. Bibliografia
Introduccin
Este libro es una recopilacin de buenas practicas a la hora de programar que han sido extraidos de
varios posts, libros, pginas externas y conocimientos que el autor ha tenido a lo largo de su carrera.
En la seccin de Bibliografa, podrs encontrar los enlaces de las paginas en donde se ha extraido la
mayor parte de informacin contenida en este libro asi como tambien muchos enlaces de interes.
Ruby
Ruby es un lenguaje multiplataforma, interpretado y orientado a objetos. Ruby fue diseado por
Yukihiro Matsumoto ('Matz') en 1993, con el Principio de la Menor Sorpresa: Matz dice "quera
minimizar mi frustracin mientras programo, y eso conllevaba minimizar mi esfuerzo. Este es el
principal objetivo de Ruby. Quiero divertirme mientras programo. Despus de lanzar Ruby y probarlo
mucha gente, ellos me dijeron que sentan lo mismo que yo. Ellos fueron los que acuaron el trmino
de "Principio de Menor Sorpresa".
En el ao 2004 hubo un boom en el inters por Ruby, debido a Ruby on Rails: el entorno para
desarrollo web de David Heinemeier Hansson.
El lenguaje de programacin Ruby permite la metaprogramacin, de la cual Rails hace uso, lo que
resulta en una sintaxis que muchos de sus usuarios encuentran muy legible.
Cdigo y Sintaxis
Codificacin de archivos
Todo archivo de que contenga codigo ruby debe ser guardado con codificacion UTF-8 y de preferencia
usar saltos de linea UNIX.
Argumentos
Evitar el uso de la coma despues del ltimo argumento de un mtodo o del ltimo elemento de un
array o Hash.
# bad
some_method(size, count, color, )
my_array = [1, 2, 3,]
# good
some_method(size, count, color)
my_array = [1, 2, 3]
Omitir parentesis a la hora de listar argumentos que son parte de una DSL interna (Rake, Rails,
RSpec) o de metodos con status "keyword", de lo contrario utilizar parentesis.
class Person
attr_reader :name, :age
# omitted
end
puts temperance.age
x = Math.sin(y)
array.delete(e)
bowling.score.should == 0
# ok
def initialize(options)
self.options = options
# both options and self.options are equivalent here
end
# bad
def do_something(options = {})
unless options[:when] == :later
output(self.options[:message])
end
end
# good
def do_something(params = {})
unless params[:when] == :later
output(options[:message])
end
end
end
Redireccion de salidas
Utilizar $stdout / $stderr / $stdin en vez de STDOUT / STDERR / STDIN . ya que los valors presedidos
de $ son variables globales y no constantes
Saltos de Linea
Usar salto de linea para separar deficiones de metodos y clases, asi como tambien para separar la
logica en parrafos, ademas para separar los modificadores de acceso de una clase (public,
protected private) y para terminar un archivo con una nueva linea.
class MyAwesomeClass
def some_method
data = initialize(options)
data.manipulate!
data.result
end
def some_method
result
end
protected
def some_protected_method
end
private
def some_private_method
end
end
Indentacion
Todos los metodos, bloques, condiciones, etc deben de ir correctamente indentados y dicha tabulacion
debe de ser de 2 espacios en vez de tabs.
case
when song.name == 'Misty'
puts 'Not again!'
when song.duration > 120
puts 'Too long!'
when Time.now.hour > 21
puts "It's too late"
else
song.play
end
result =
if some_cond
calc_something
else
calc_something_else
end
Espacios en blanco
Cuando usar espacios en blanco como separador?
sum = 1 + 2
a, b = 1, 2
[1, 2, 3].each { |e| puts e }
class FooError < StandardError; end
array = [1, 2, 3]
if !something
(1..10).each { |i| puts i }
end
Nombramientos
Idenficadores
# bad - identifier is a Bulgarian word, written with Latin letters (instead of Cyrillic)
zaplata = 1_000
# good
salary = 1_000
CamelCase
Deben de empezar un una letra Mayuscula y la separacin de mltiples palabras debe de ser
concatenadas pero con la primera letra de la siguiente palabra en Mayscula.
SCREAMING_SNAKE_CASE
snake_case
Hashes
Es preferible usar la sintanxis de ruby 1.9 para la declaracion de hashes { a: :b } en vez de { :a => :b
}.
# bad
{ a: 1, 'b' => 2 }
# good
{ :a => 1, 'b' => 2 }
# bad
hash.has_key?(:test)
hash.has_value?(value)
# good
hash.key?(:test)
hash.value?(value)
Puedes usar Hash#fetch cuando necesites que una llave este presene o asignarle un valor por
defecto cuando no este.
# good - fetch return a values when the hash doesnt have the key
heroes.fetch(:supermann, true)
# very good - fetch return a values when the hash doesnt have the key, blocks are lazy evaluated, so only triggered in c
heroes.fetch(:supermann) { true }
# good
email, username = data.values_at('email', 'nickname')
Arrays
Utilizar Array#join en vez de Array#* con una cadena de texto como argumento.
# bad
%w(one two three) * ', '
# => 'one, two, three'
# good
%w(one two three).join(', ')
# => 'one, two, three'
Usar [*var] or Array() en vez de una comparacion explicitar con la clase Array cuando queremos
tratar una variable como si fuera un array.
# bad
paths = [paths] unless paths.is_a? Array
paths.each { |path| do_something(path) }
# good
[*paths].each { |path| do_something(path) }
foo = :foo
bar = nil
Nota: Como regla puedes usar && y || para expresiones booleanas y and y or para control de
flujo:
# Expresion booleana
if some_condition && some_other_condition
do_something
end
# Control de flujo
document.saved? or document.save!
Tratemos de evitar la igualacion explicita de tipo y mejor utilizemos uno de los varios metodos que
ruby ya nos ofrece.
# bad
Array === something
(1..100) === 7
/something/ === some_string
# good
something.is_a?(Array)
(1..100).include?(7)
some_string =~ /something/
# good
v = array.grep(/foo/)
if v
do_something(v)
...
end
# bad
while some_condition
do_something
end
if some_condition
do_something
end
# good
do_something while some_condition
do_something if some_condition
# bad
if some_condition then
# body omitted
end
# good
if some_condition
# body omitted
end
# bad
result = if some_condition then something else something_else end
# good
result = some_condition ? something : something_else
# good
if some_condition
nested_condition ? nested_something : nested_something_else
else
something_else
end
# bad
10.times do
# multi-line body omitted
end if some_condition
# good
if some_condition
10.times do
# multi-line body omitted
end
end
# bad
unless success?
puts 'failure'
else
puts 'success'
end
# good
if success?
puts 'success'
else
puts 'failure'
end
until x > 5 do
# body omitted
end
# good
while x > 5
# body omitted
end
until x > 5
# body omitted
end
# bad
do_something while !some_condition
# good
do_something until some_condition
# bad
while true
do_something
end
until false
do_something
end
# good
loop do
do_something
end
# good
loop do
puts val
val += 1
break unless val < 0
end
# bad
do_something if x >= 1000 && x <= 2000
# good
do_something if (1000..2000).include?(x)
# good
do_something if x.between?(1000, 2000)
# bad
if x % 2 == 0
end
if x % 2 == 1
end
if x == nil
end
# good
if x.even?
end
if x.odd?
end
if x.nil?
end
if x.zero?
end
if x == 0
end
# good
[0, 1, 2, 3].each do |item|
next unless item > 1
puts item
end
Literales
Preferir el parentesis como delimitador de un literal con excepcion de %r ya que hay expresiones
regulares que hace uso de parentesis.
#bad
%Q[Joe said: "Frank said: "#{what_frank_said}""]
%Q+Joe said: "Frank said: "#{what_frank_said}""+
#good
%Q(Joe said: "Frank said: "#{what_frank_said}"")
# bad
STATES = ['draft', 'open', 'closed']
# good
STATES = %w(draft open closed)
Nota: la diferencia entre %w y %W es que el que esta en mayuscula crea un Array de string con
comillas doble (el cual permite intepolacion) mientras que el otro no.
# bad
STATES = [:draft, :open, :closed]
# good
STATES = %i(draft open closed)
Utilizar %Q para cadenas de texto de una sola linea o aun mejor utilizar su alias %()
# bad (no interpolation needed)
%(<div class="text">Some text</div>)
# should be '<div class="text">Some text</div>'
Nota: la diferencia entre %q y %Q es que el que esta en mayuscula crea un String con comillas
doble (el cual permite intepolacion) mientras que el otro no.
# bad
date = %x(date)
# good
date = `date`
echo = %x(echo `date`)
# bad
%r(\s+)
# still bad
%r(^/(.*)$)
# should be /^\/(.*)$/
# good
%r(^/blog/2011/(.*)$)
El ||= para asignaciones cortas evaluando si existe o no, asignandole el valor solo si no existe.
Smbolo a proc :
array.map(&:upcase)
Bloques
La convencion para bloques de una sola linea es usando las llaves {} y para los de multiples lineas es
usando el do / end .
Cadenas
# good
def send_mail(source)
Mailer.deliver(to: 'bob@example.com',
from: 'us@example.com',
subject: 'Important message',
body: source.text)
end
Evitar el uso de \ para indicar el salto de linea en expresiones que no sean concatenacion de cadenas
# bad
result = 1 - \
2
# good
menu_item = [
'Spam',
'Spam',
'Spam'
]
Comentarios y anotaciones
Evitar los comentarios de bloque
# bad
=begin
comment line
another comment line
=end
# good
# comment line
# another comment line
# counter
counter += 1 # Increments counter by one.
Anotaciones
Las anotaciones deben de ser escritas una linea por encima del codigo relevante y despues de la
palabra clave debe utilizarse el : seguido de un espacio de separacion. Si la anotacion abarca
multiple lineas, las lineas subsiguientes deben de ir corectamente indentadas.
TODO: se utiliza para explicar que hace falta o se agregara mas adelante
FIXME: Indica codigo que necesita ser reparado
OPTIMIZE: Indica codigo lento o ineficiente que puede causar problemas de rendimiento
HACK: Se utiliza para indicar codigo con practicas "questionables" y que deberia de ser
refactorizado
REVIEW: Se utiliza para nota que deberia de confirmarse si el codigo funciona como deberia
Se pueden usar mas palabras claves pero estas deberian estar documentada en el archivo README
Modulos clases y variables
Modulos
module MyModule
module_function
def do_something
end
end
MyModule.do_something
Clases
Estructura de clases.
class Person
# extend and include go first
extend SomeModule
include AnotherModule
# inner classes
CustomErrorKlass = Class.new(StandardError)
private
def some_private_method
end
end
Utilizar :: solamente para llamar constantes (esto incluye classes y modulos) o para llamar
contructores, ejemplo.
# bad
SomeClass::some_method
some_object::some_method
# good
SomeClass.some_method
some_object.some_method
SomeModule::SomeClass::SOME_CONST
SomeModule::SomeClass()
Mtodos
Los metodos deben definirse en minsculas , separadas por guiones bajos (snakecase) y con un
nombre claro que indica su funcin, preferiblemente incluir algn verbo.
Asi mismo utilizar parentesis en la definicion de metodo solo cuando hay argumentos de lo
contrario no utilizar parentesis
En ruby todos lo mtodos son publicos por defecto, para declarar mtodos protected o private,
estos deben de ser declarados debajo de las palabras clave protected y private ademas deben ir
correctamente identados, ejemplo:
def some_public_method
end
protected
private
def some_private_method
end
A la hora de crear metodos sin cuerpo, declararlos en una sola linea, ejemplo.
# Classes
# bad
class FooError < StandardError
end
# okish
class FooError < StandardError; end
# good
FooError = Class.new(StandardError)
# methods
# good
def no_op; end
Deprecar metodos si estos ban ya no van a ser utilizado en proximas version, ejemplo
def old_method
warn "DEPRECATED METHOD: 'old_method', please use 'new_method' instead"
end
Los nombres de los metodos que retornan un booleano deben de terminar con un signo de
interrogacion
def active?
active == 1
end
Los metodos potencialmente peligros que modifcan la instancia de la clase o que se deben utilizar
con cuidado deben de llevar el signo de admiracion cuando haya una version segura de este metodo.
# good
class Person
def update
end
end
# good
class Person
def update!
end
def update
end
end
Metodos de clase: Es preferible utilizar el bloque class << self que self.method_name para mtodos
de clase.
def self.metodo_estatico
end
# bad
def some_method(some_arr)
return some_arr.size
end
# good
def some_method(some_arr)
some_arr.size
end
Variables.
Al igual que los metodos las variables deben de ser utlizar snakecase, ademas de eso no deben ser
palabras demasiadas largas, las variables demasiada cortas o de una sola letra solo deben de ser
usadas para indicar iteradores, como por ejemplo las variable de un loop , each .
Asi mismo todas las variables internas propias de la clase deben de ser precedidas de una @ al igual
que las y las variables internas estticas (no utilizar @@ para las variables estaticas).
Ejemplo de variables de clase ( @@ ) y del por que no usarlas ya que producen efectos no deseados.
class Shared
@@name = "Shared"
end
end
Brother.name
=> "Shared"
Sister.name = "Sister"
=> "Sister"
Brother.name
=> "Sister"
class MyAwesomeClass
# variable de clase
@@shared = ""
def initialize
# variable de instancia
@name = ""
end
def self.foo
$foo
end
def config
# variable local
cfg = YAML::load(File.open("#{Rails.root.to_s}/config/application.yml"))
if cfg
do_something_with_config(cfg)
end
end
end
# bad
def ready?
if self.last_reviewed_at > self.last_updated_at
self.worker.update(self.content, self.options)
self.status = :in_progress
end
self.status == :verified
end
# good
def ready?
if last_reviewed_at > last_updated_at
worker.update(content, options)
self.status = :in_progress
end
status == :verified
end
No usar punto y coma para separar definicion de multiples variables o para imprimirlas.
# bad
puts 'foobar';
# good
puts 'foobar'
puts 'foo'
puts 'bar'
Excepciones
No utilizar el rescue con la clase Exception, ya que esto podria rescatar errores que no son
recuperables como: SyntaxError, LoadError, Interrupt, etc.
#bad
begin
foo
rescue Exception => e
logger.warn "Unable to foo, will ignore: #{e}"
end
#good
begin
foo
rescue => e
logger.warn "Unable to foo, will ignore: #{e}"
end
# also good
begin
# an exception occurs here
def foo
begin
fail
ensure
return 'very bad idea'
end
end
# bad
def foo
begin
# main logic goes here
rescue
# failure handling goes here
end
end
# good
def foo
# main logic goes here
rescue
# failure handling goes here
end
Evitar la proliferacion de declaracione begin , usando metodos de contingencia.
# bad
begin
something_that_might_fail
rescue IOError
# handle IOError
end
begin
something_else_that_might_fail
rescue IOError
# handle IOError
end
# good
def with_io_error_handling
yield
rescue IOError
# handle IOError
end
with_io_error_handling { something_that_might_fail }
with_io_error_handling { something_else_that_might_fail }
f = File.open('testfile')
begin
# .. process
rescue
# .. handle error
ensure
f.close if f
end
Cadenas de caracteres
Formato
Utilizar sprintf y su alias format en vez String#% para darle formato a una cadena
# bad
'%d %d' % [20, 10]
# => '20 10'
# good
sprintf('%d %d', 20, 10)
# => '20 10'
# good
sprintf('%{first} %{second}', first: 20, second: 10)
# => '20 10'
# good
format('%{first} %{second}', first: 20, second: 10)
# => '20 10'
class Person
attr_reader :first_name, :last_name
# good
def to_s
"#{@first_name} #{@last_name}"
end
end
$global = 0
# bad
puts "$global = #$global"
# good
puts "$global = #{$global}"
A la hora de interpolar grandes cantidades de datos hay que utilizar String#<< en vez de String#+
la cual crea muchas instancias de la clase string haciendo la asignacion mas lenta, mientras que
String#<< muta la instancia de clase string que toma lugar haciendo la asignacion mas rapida
paragraphs.each do |paragraph|
html << "<p>#{paragraph}</p>"
end
first_quatrain = <<-EOT
My mistress' eyes are nothing like the sun;
Coral is far more red than her lips' red;
If snow be white, why then her breasts are dun;
If hairs be wires, black wires grow on her head.
EOT
def second_quatrain
x = <<-HTML
<blockquote>
I have seen roses damask'd, red and white,
But no such roses see I in her cheeks;
And in some perfumes is there more delight
Than in the breath that from my mistress reeks.
</blockquote>
HTML
x
end
Ruby on Rails
Ruby on Rails, tambin conocido como RoR o Rails, es un framework de aplicaciones web de cdigo
abierto escrito en el lenguaje de programacin Ruby, siguiendo el paradigma de la arquitectura
Modelo Vista Controlador (MVC).
Trata de combinar la simplicidad con la posibilidad de desarrollar aplicaciones del mundo real
escribiendo menos cdigo que con otros frameworks y con un mnimo de configuracin.
Rails se distribuye a travs de RubyGems, que es el formato oficial de paquete y canal de distribucin
de bibliotecas y aplicaciones Ruby.
Balloom
Para sobreescribir correctamente un modelo del balloom se debe de crear dicho modelo en la misma
ruta que posee el engine y agregarle _decorator al nombre del archivo. Ejemplo.
En app/models/balloom/order_decorator.rb
Balloom::Order.class_eval do
def my_awesome_method
puts "Gotcha!"
end
end
Quedando asi:
Javascripts
Utilizar solo archivos coffeescript para escribir javascript y nombrarlo con extension .coffee.js
Si se necesita interactuar bastante con elementos HTML, crear clase en coffescript o crear plugins
de jquery utilizando el Widget Factory
Stylesheets
Utilizar solo archivos sass para escribir css y nombrarlo con extension .sass.css
Hacer uso de la gema de compass-rails y de los mixings que nos proporciona compass sass
Modelos
Nunca ocupar default scopes
No dejar consultas en ninguna parte que no sea un modelo, en vez de esto utilizar scopes
declarados en el modelo y anidar estos,
# good
@recent_books = Book.recent.published_desc # 'recent' and 'published_desc' are scopes defined in Book model
end
end
Controladores
No modificar el objeto params
#bad
def search
params.except!(:action, :controller)
@search = User.search(params)
render "search"
end
# good
def search
filter = params.except(:action, :controller)
@search = User.search(filter)
render "search"
end
# better
def search
@search = User.search(search_params)
render "search"
end
private
def search_params
# params.except(:action, :controller)
params.permit(:user_id, :name)
end
def create
@user = User.new(params[:user])
@user.save
end
def edit
@user = User.find(params[:id]) rescue nil
end
def update
@user = User.find(params[:id]) rescue nil
@user.update_attributes(params[:user])
end
# good
helper_method :user
def create
user.save
end
def update
user.update_attributes(params[:user])
end
def user
@user ||=
case action_name
when "new", "create"
User.new(params[:user])
else
User.find(params[:id]) rescue nil
end
end
Vistas
TODO
Seguridad
El Cross Frame Scripting o Clickjacking es una vulnerabilidad la cual permite el atacante capturar los
clicks y otros eventos mediante javascript a traves de un iframe
Si se va imprimir html simple hacer uso de los helpers que nos otroga rails para tratar con html:
concat , raw , capture , content_tag , sanitize , etc.
Compatibiladad
Browser update
https://browser-update.org/
<script type="text/javascript">
var $buoop = {vs:{i:9,f:10,o:15,s:4.1}};
$buoop.ol = window.onload;
window.onload=function(){
try {if ($buoop.ol) $buoop.ol();}catch (e) {}
var e = document.createElement("script");
e.setAttribute("type", "text/javascript");
e.setAttribute("src", "//browser-update.org/update.js");
document.body.appendChild(e);
}
</script>
while (length--) {
method = methods[length];
humans.txt
Un archivo TXT que contiene la informacin sobre las personas que han intervenido en la web.
Dnde se pone?
En la raz del site. Al lado de robots.txt. Y (siempre que sea posible) en el aade en el Tag author
Ejemplo de humans.txt.
# humanstxt.org/
# The humans responsible & technology colophon
/* TEAM */
Chef:Juanjo Bernabeu
Contact: hello [at] humanstxt.org
Twitter: @juanjobernabeu
From:Barcelona, Catalonia, Spain
/* THANKS */
CA Translator: Eva AC
Twitter: @evaac
From:Barcelona, Catalonia, Spain
Media Queries by: Marta Armada (@martuishere) and Javier Usobiaga (@htmlboy)
/* SITE */
Last update:2012/02/04
Language: Catal / Czech / Deutsch / English / Castellano / Japanese / Dutch / Russian / Chinese
Doctype:HTML5
IDE: Sublime Text, Notepad++, FileZilla, Photoshop
/* TECHNOLOGY COLOPHON */
HTML5, CSS3
jQuery, Modernizr
Bibliografia
https://github.com/bbatsov/ruby-style-guide
https://github.com/bbatsov/rails-style-guide
http://www.elabs.se/blog/36-working-with-time-zones-in-ruby-on-rails
http://javascript.info/tutorial/clickjacking
https://browser-update.org/
http://simpleror.wordpress.com/2009/03/15/q-q-w-w-x-r-s/
http://ruby-doc.org/core-2.0/doc/syntax/literals_rdoc.html
http://rubytutorial.wikidot.com/introduccion
http://phrogz.net/programmingruby/language.html#table_18.4
http://www.adobe.com/devnet/articles/crossdomain_policy_file_spec.html