# Esto es un comentario=begin
Este es un comentario multilínea
Nadie los usa.
Tu tampoco deberías
=end# En primer lugar: Todo es un objeto# Los números son objetos3.class#=> Fixnum3.to_s#=> "3"# Un poco de aritmética básica1+1#=> 28-1#=> 710*2#=> 2035/5#=> 72**5#=> 325%3#=> 2# La aritmética es sólo azúcar sintáctico# para llamar un método de un objeto1.+(3)#=> 410.*5#=> 50# Los valores especiales son objetosnil# Nada que ver aquitrue# Verdaderofalse# Falsonil.class#=> NilClasstrue.class#=> TrueClassfalse.class#=> FalseClass# Igualdad1==1#=> true2==1#=> false# Desigualdad1!=1#=> false2!=1#=> true# Además de 'false', 'nil' es otro valor falso!nil#=> true!false#=> true!0#=> false# Más comparaciones1<10#=> true1>10#=> false2<=2#=> true2>=2#=> true# Operadores lógicostrue&&false#=> falsetrue||false#=> true!true#=> false# Existen versiones alternativas de los operadores lógicos con menor prioridad# Estos son usados como constructores controladores de flujo que encadenan# sentencias hasta que una de ellas retorne verdadero o falso# `haz_otra_cosa` solo se llama si `haz_algo` retorna verdadero.haz_algo()andhaz_otra_cosa()# `registra_error` solo se llama si `haz_algo` fallahaz_algo()orregistra_error()# Los strings son objetos'Soy un string'.class#=> String"Soy un string también".class#=> Stringreferente="usar interpolación de strings""Yo puedo #{referente} usando strings de comillas dobles"#=> "Yo puedo usar interpolación de strings usando strings de comillas dobles"# Imprime a la salida estándarputs"¡Estoy imprimiendo!"# Variablesx=25#=> 25x#=> 25# Nota que la asignación retorna el valor asignado# Esto significa que puedes hacer múltiples asignaciones:x=y=10#=> 10x#=> 10y#=> 10# Por convención, usa snake_case para nombres de variablessnake_case=true# Usa nombres de variables descriptivosruta_para_la_raiz_de_un_projecto='/buen/nombre/'ruta='/mal/nombre/'# Los símbolos (son objetos)# Los símbolos son inmutables, constantes reusables representadas internamente por un# valor entero. Son normalmente usados en vez de strings para expresar eficientemente# valores específicos y significativos:pendiente.class#=> Symbolstatus=:pendientestatus==:pendiente#=> truestatus=='pendiente'#=> falsestatus==:aprobado#=> false# Arreglos# Esto es un arregloarreglo=[1,2,3,4,5]#=> [1, 2, 3, 4, 5]# Arreglos pueden contener elementos de distintos tipos[1,"hola",false]#=> => [1, "hola", false]# Arreglos pueden ser indexados# Desde el frentearreglo[0]#=> 1arreglo.first#=> 1arreglo[12]#=> nil# Al igual que en aritmética, el acceso como variable[índice]# es sólo azúcar sintáctica# para llamar el método [] de un objetoarreglo.[]0#=> 1arreglo.[]12#=> nil# Desde el finalarreglo[-1]#=> 5arreglo.last#=> 5# Con un índice de inicio y longitudarreglo[2,3]#=> [3, 4, 5]# Invertir un arregloa=[1,2,3]a.reverse!#=> [3, 2, 1]# O con rangoarreglo[1..3]#=> [2, 3, 4]# Añade elementos a un arreglo asíarreglo<<6#=> [1, 2, 3, 4, 5, 6]# O asíarreglo.push(6)#=> [1, 2, 3, 4, 5, 6]#Verifica si un elemento ya existe en ese arregloarreglo.include?(1)#=> true# Hashes son los diccionarios principales de Ruby con pares llave/valor.# Hashes se denotan con llaves:hash={'color'=>'verde','numero'=>5}hash.keys#=> ['color', 'numero']# Hashes pueden buscar rápidamente una llave:hash['color']#=> 'verde'hash['numero']#=> 5# Preguntarle a un hash por una llave que no existe retorna 'nil':hash['nada aqui']#=> nil# Desde Ruby 1.9, hay una sintaxis especial cuando se usa un símbolo como llave:nuevo_hash={defcon:3,accion:true}nuevo_hash.keys#=> [:defcon, :accion]# Verifica la existencia de llaves y valores en el hashnew_hash.has_key?(:defcon)#=> truenew_hash.has_value?(3)#=> true# Tip: Tanto los arreglos como los hashes son Enumerable (enumerables)# Comparten muchos métodos útiles tales como 'each', 'map', 'count', y más# Estructuras de Controliftrue"declaracion 'if'"elsiffalse"else if, opcional"else"else, tambien opcional"endforcontadorin1..5puts"iteracion #{contador}"end#=> iteracion 1#=> iteracion 2#=> iteracion 3#=> iteracion 4#=> iteracion 5# SIN EMBARGO, nadie usa ciclos `for`# En su lugar debes usar el método "each" y pasarle un block (bloque).# Un bloque es un fragmento código que puedes pasar a métodos como `each`.# Es símilar a las funciones lambda, funciones anónimas o `closures` en otros# lenguajes de programación.## El método `each` de un Range (rango) ejecuta el bloque una vez por cada elemento.# Al bloque se le pasa un contador como parametro.# Usar el método `each` con un bloque se ve así:(1..5).eachdo|contador|puts"iteracion #{contador}"end#=> iteracion 1#=> iteracion 2#=> iteracion 3#=> iteracion 4#=> iteracion 5# También puedes envolver el bloque entre llaves:(1..5).each{|counter|puts"iteración #{contador}"}#El contenido de las estructuras de datos en ruby puede ser iterado usando `each`.arreglo.eachdo|elemento|puts"#{elemento} es parte del arreglo"endhash.eachdo|llave,valor|puts"#{llave} es #{valor}"end# Si aún necesitas un índice puedes usar "each_with_index" y definir una variable# índice.arreglo.each_with_indexdo|element,index|puts"#{element} tiene la posición #{index} en el arreglo"endcontador=1whilecontador<=5doputs"iteracion #{contador}"contador+=1end#=> iteracion 1#=> iteracion 2#=> iteracion 3#=> iteracion 4#=> iteracion 5# Hay una gran variedad de otras funciones iterativas útiles en Ruby,# por ejemplo `map`, `reduce`, `inject`, entre otras. Map, por ejemplo,# toma el arreglo sobre el cuál está iterando, le hace cambios# definidos en el bloque, y retorna un arreglo completamente nuevo.arreglo=[1,2,3,4,5]duplicado=array.mapdo|elemento|elemento*2endputsduplicado#=> [2,4,6,8,10]putsarray#=> [1,2,3,4,5]nota='B'casenotawhen'A'puts"Muy bien muchacho"when'B'puts"Mejor suerte para la proxima"when'C'puts"Puedes hacerlo mejor"when'D'puts"Sobreviviendo"when'F'puts"¡Reprobaste!"elseputs"Sistema alternativo de notas, ¿eh?"end#=> "Mejor suerte para la proxima"# Los casos también pueden usar rangosnota=82casenotawhen90..100puts'Excelente!'when80..100puts'Buen trabajo'elseputs'¡Reprobaste!'end#=> "Buen trabajo"# Manejo de excepcionesbegin# código que podría causar excepciónraiseNoMemoryError,'Se te acabó la memoria'rescueNoMemoryError=>variable_de_excepcionputs'El error NoMemoryError ocurrió',variable_de_excepcionrescueRuntimeError=>otra_variable_de_excepcionputs'El error RuntimeError ocurrió'elseputs'Esto se ejecuta si ningun error ocurrió'ensureputs'Este código siempre se ejecuta, sin importar que'end# Funcionesdefdoble(x)x*2end# Funciones (y todos los bloques) implícitamente retornan el valor de la última instruccióndoble(2)#=> 4# Paréntesis son opcionales cuando el resultado no es ambiguodoble3#=> 6dobledoble3#=> 12defsuma(x,y)x+yend# Arguméntos del método son separados por comasuma3,4#=> 7sumasuma(3,4),5#=> 12# yield# Todos los métodos tienen un parámetro bloque opcional e implícito# puede llamarse con la palabra clave 'yield'defalrededorputs"{"yieldputs"}"endalrededor{puts'hola mundo'}# {# hola mundo# }# Puedes pasar un bloque a una función# '&' representa una referencia a un bloquedefvisitantes(&bloque)bloque.callend# Puedes pasar una lista de argumentos, que serán convertidos en un arreglo# Para eso sirve el operador ('*')defvisitantes(*arreglo)arreglo.each{|visitante|putsvisitante}end# Define una clase con la palabra clave 'class'classHumano# Una variable de clase. Es compartida por todas las instancias de la clase.@@species="H. sapiens"# Inicializador Básicodefinitialize(nombre,edad=0)# Asigna el argumento a la variable de instancia 'nombre'@nombre=nombre# Si no dan edad, se usará el valor por defecto en la lista de argumentos.@edad=edadend# Método 'setter' (establecer) básicodefnombre=(nombre)@nombre=nombreend# Método 'getter' (obtener) básicodefnombre@nombreend# La funcionalidad anterior puede ser encapsulada usando el método attr_accessor# de la siguiente maneraattr_accessor:name# Los métodos de tipo getter y setter también se pueden crear de manera individual# de la siguiente maneraattr_reader:nameattr_writer:name# Un método de clase usa 'self' (sí mismo) para distinguirse de métodos de instancia.# Sólo puede ser llamado en la clase, no por una instancia.defself.decir(mensaje)putsmensajeenddefespecie@@especieendend# Instancia una clasejim=Humano.new("Jim Halpert")dwight=Humano.new("Dwight K. Schrute")# Llamemos un par de métodosjim.especie#=> "H. sapiens"jim.nombre#=> "Jim Halpert"jim.nombre="Jim Halpert II"#=> "Jim Halpert II"jim.nombre#=> "Jim Halpert II"dwight.especie#=> "H. sapiens"dwight.nombre#=> "Dwight K. Schrute"# Llama el método de claseHumano.decir("Hi")#=> "Hi"# El alcance de las variables es definido por la manera en que las nombramos.# Las variables que inician con $ tienen un alcance global$var="Soy una variable global"defined?$var#=> "global-variable"# Las variables que empiezan con @ tienen un alcance de instancia@var="Soy una variable de instancia"defined?@var#=> "instance-variable"# Variables que empiezan con @@ tienen un alcance de clase@@var="Soy una variable de clase"defined?@@var#=> "class variable"# Las variables que empiezan con letra mayuscula son constantesVar="Soy una constante"defined?Var#=> "constant"# Las clases también son un objeto en ruby. Por lo cual, las clases también pueden tener variables de instancia.# Variables de clase son compartidas a través de la clase y todos sus descendientes.# clase baseclassHumano@@foo=0defself.foo@@fooenddefself.foo=(valor)@@foo=valorendend# clase derivadaclassTrabajador<HumanoendHumano.foo# 0Trabajador.foo# 0Humano.foo=2# 2Trabajador.foo# 2# Las variables de instancia de la clase no son compartidas por los descendientes de la clase.classHumano@bar=0defself.bar@barenddefself.bar=(valor)@bar=valorendendclassDoctor<HumanoendHumano.bar# 0Doctor.bar# nilmoduleModuloEjemplodeffoo'foo'endend# Al incluir un módulo sus métodos se comparten con las instancias de la clase# Al extender un módulo sus métodos se comparten con la clase mismaclassPersonaincludeModuloEjemploendclassLibroextendModuloEjemploendPersona.foo# => NoMethodError: undefined method `foo' for Persona:ClassPersona.new.foo# => 'foo'Libro.foo# => 'foo'Libro.new.foo# => NoMethodError: undefined method `foo'# Las llamadas de retorno (callbacks) son ejecutadas cuando se incluye o# extiende un módulomoduleEjemploConcerndefself.incluido(base)base.extend(MetodosClase)base.send(:include,MetodosInstancia)endmoduleMetodosClasedefbar'bar'endendmoduleMetodosInstanciadefqux'qux'endendendclassAlgoincludeEjemploConcernendAlgo.bar#=> 'bar'Algo.qux#=> NoMethodError: undefined method `qux'Algo.new.bar# => NoMethodError: undefined method `bar'Algo.new.qux# => 'qux'