Ejercicios de Programaci´on on con Ruby Ingenier´ Ingenier´ıa de Sistemas Sistema s de Informaci´ Informa ci´ on on Departamento de Sistemas Telem´aticos aticos y Computaci´ Computaci´ on on (GSyC) 18 de septiembre de 2012 Notas:
1. Al lado de cada ejercicio aparecen una o m´as cruces, en funci´on on de su dificultad y de la cantidad de tiempo estimado que requiere. Cuantas m´as as cruces tenga un ejercicio m´as dif´ dif´ıcil es o m´as as tiempo puede requerir. 2. Aparte Aparte de las transparenc transparencias ias que estamos estamos usando en clase, clase, utiliza ri y la siguiente documentaci´on de Ruby: http://ruby-doc.org/core-1.9.3/ 1.9.3/ Documentaci´ on on online de Ruby: http://ruby-doc.org/corehttp://ruby-doc.org/ API de la biblioteca est´andar andar de Ruby: http://ruby-doc.org/ http://ruby-doc.org/docs/ProgrammingRuby ogrammingRuby/ / Libro Programming Ruby : http://ruby-doc.org/docs/Pr
3. Utiliza Utiliza este resumen sobre el uso de expresiones expresiones regulares regulares en Ruby: Ruby:
Figura 1: Fuente: Engineering Long-Lasting Software . Armando Fox, David Patterson
1
Ejercicio 1 + Dada esta definici´on de un m´etodo: def foo(arg, hash1, hash2) end
¿Cu´ al de las siguientes NO es una llamada legal al m´ etodo foo ? 1. foo a, {:x=>1, :y=>2}, :z=>3 2. foo(a, :x=>1, :y=>2, :z=>3) 3. foo(a, {:x=>1, :y=>2}, {:z=>3}) 4. foo(a, {:x=>1}, {:y=>2, :z=>3})
Ejercicio 2 + Dada la siguiente declaraci´on de la clase SavingsAccount : class SavingsAccount < Account def initialize(starting_balance=0) @balance = starting_balance end def balance @balance end def balance=(new_amount) @balance = new_amount end def deposit(amount) @balance += amount end @@bank_name = "MyBank.com" def self.bank_name @@bank_name end end
Indica cu´ales de las siguientes l´ıneas son correctas: 1. SavingsAccount.new.@balance 2. SavingsAccount.new.balance 3. SavingsAccount.new.balance()
2
Ejercicio 3 + Dada esta asignaci´on: rx = {:primero=>/^rub/, ’primero’=>[/RA(IL)$/, /ra(il)/i]}
¿Cu´ al de las siguientes expresiones se evaluar´a correctamente, devolviendo algo que no sea nil? 1. "rubyonrails" =~ rx{:primero} 2. rx[:primero][1] =~ "RUBYONRAILS" 3. rx[’primero’][1] =~ "RUBYONRAIL" 4. "rubyonrails" =~ rx[’primero’, 1] 5. "rubyonrails" =~ rx[’primero’][0]
Ejercicio 4 + Dada esta extensi´on de la clase String : class String def curvy? !("AEFHIKLMNTVWXYZ".include?(self.upcase)) end end
¿Cu´ al de las siguientes l´ıneas es correcta?: 1. String.curvy?("foo") 2. "foo".curvy? 3. self.curvy?("foo") 4. curvy?("foo")
3
Ejercicio 5 + Se ha extendido la clase Numeric de la siguiente forma: class Numeric def euros self * 1.292 end end
Ahora se desea poder ejecutar esta l´ınea: 5.euros.in(:rupias)
¿Cu´ al de los siguientes mecanismos ser´ıa m´as apropiado? 1. Cambiar Numeric.method_missing para que detecte llamadas al m´etodo in 2. Cambiar Numeric#method_missing para que detecte llamadas al m´etodo in 3. Definir un m´etodo Numeric#in 4. Definir un m´etodo Numeric.in
Ejercicio 6 + ¿Cu´ al de los siguientes string NO aparecer´a como resultado de ejecutar este c´odigo?: [’banana’, ’anana’, ’naan’].map do |food| food.reverse end.select { |f| f.match /^a/ }
1. "naan" 2. "ananab" 3. "anana" 4. El c´odigo no funcionar´a debido a errores de sintaxis
Ejercicio 7 + ¿Cu´ ales de las siguientes expresiones de Ruby son equivalentes entre s´ı?: A) :foo B) %q{foo} C) %Q{foo} D) ’foo’.to_sym E) :foo.to_s
4
Ejercicio 8 + ¿Qu´e se captura en $1 buscando en el string ”25 to 1” las siguientes expresiones regulares?: /(\d+)$/ /^\d+([^0-9]+)/
Ejercicio 9 + ¿Cu´ ando es correcto utilizar la siguiente l´ınea en Ruby?: Fixnum num=3
Ejercicio 10 + ¿Por qu´e al ejecutar 5.superclass se eleva una excepci´on “undefined method”?.
Ejercicio 11 + Escribe utilizando send las siguientes expresiones: 1. a
Ejercicio 12 + Imagina que el m´etodo foo admite dos argumentos que son dos hash es. Explica por qu´ e no podemos utilizar el modo po´etico para escribir esta llamada: foo :a =>1, :b => 2
Ejercicio 13 + ¿Por qu´e esta expresi´on es incorrecta en Ruby?: movie.@year=1998
5
Ejercicio 14 ++ Time.now devuelve el n´ umero de segundos que han pasado desde las 00:00 GMT del 1/1/1970, que es la forma en que se representa una hora en Unix. Se ha extendido la clase Fixnum para poder hacer aritm´ etica con las horas
utilizando expresiones como las siguientes: Time.now # => Mon Nov 07 10:18:10 -0800 2011 5.minutes.ago # => Mon Nov 07 10:13:15 -0800 2011 5.minutes - 4.minutes # => 60 3.hours.from_now # => Mon Nov 07 13:18:15 -0800 2011
A continuaci´on se muestra la extensi´on del c´odigo de la clase Fixnum que permite hacer este tipo de operaciones: class def def def def def end
Fixnum seconds minutes hours ago from_now
; ; ; ; ;
self ; end self * 60 ; end self * 60 * 60 ; end Time.now - self ; end Time.now + self ; end
Sin embargo, esta sentencia no se puede ejecutar: 1.minute.ago La raz´on es que no existe el m´etodo minute. El siguiente c´odigo soluciona este problema: class Fixnum def method_missing(method_id, *args) name = method_id.to_s if name =~ /^(second|minute|hour)$/ self.send(name + ’s’) else super # se llama al mismo m´etodo (method_missing) de clases ancestro end end end
Explica por qu´e son necesarios $ y ^ en la expresi´on regular de la l´ınea 4. Una pista: piensa qu´e ocurrir´ıa si omitimos alguno de estos dos caracteres e intentamos hacer la siguiente llamada: 5.milliseconds o 5.secondary .
6
Ejercicio 15 ++ A˜ na´dele a la clase String un m´etodo palindromo? que devuelva true si la cadena es un pal´ındromo (se lee igual del derecho que del rev´es), y false si no lo es. Ejemplos: "reconocer".palindromo? "Reconocer".palindromo? "Se van sus naves".palindromo? "Pepe".palindromo?
# # # #
=> => => =>
true true true false
Utiliza u ´ nicamente m´ etodos de la siguiente lista (consulta la documentaci´on para saber qu´e hacen): map, select, reject, uniq reverse, compact, flatten, partition sort, sort_by, max, min, downcase
Ejercicio 16 + Explica qu´e ocurre cuando se ejecuta el siguiente c´odigo: class Foo include Enumerable end Foo.new.map { |e| puts e }
Ejercicio 17 ++ Explica para qu´e sirve el siguiente c´odigo: module Enumerable def every_nth(count) index = 0 self.each do |elt| yield elt if index % count == 0 index += 1 end end end
Ejercicio 18 + ¿Cu´ antas clases ancestro tiene el ob jeto 5? Los siguientes m´etodos te ayudar´an: class, superclass .
7
Ejercicio 19 + Sabiendo que el m´etodo superclass devuelve nil cuando se le manda a BasicObject , escribe el c´odigo del m´etodo ancestros que reciba como argumento cualquier objeto y muestre en pantalla la clase del objeto y sus clases ancestro hasta BasicObject.
Ejercicio 20 +++ Escribe c´odigo que permita que se puedan ejecutar sentencias como la siguiente: Time.now.at_beginning_of_year + 1.day # => 2012-01-02 00:00:00 -0800
Estudia antes el c´odigo que se proporciona en el ejercicio 14, no siendo necesario que resuelvas aquel ejercicio antes de resolver este. Te vendr´a bien consultar la documentaci´on de Time.local y utilizar este m´etodo de clase.
Ejercicio 21 +++ Define un m´etodo attr_accessor_with_history que proporcione la misma funcionalidad que attr_accessor pero que lleve guarde la lista de valores que el atributo ha ido adoptando. Ejemplo de uso: class Foo attr_accessor_with_history :bar end f = Foo.new # => # f.bar = 3 # => 3 f.bar = :wowzo # => :wowzo f.bar = ’boo!’ # => ’boo!’ f.history(:bar) # => [3, :wowzo, ’boo!’]
8
Ejercicio 22 ++ El m´odulo Enumerable define el iterador each_with_index que devuelve cada uno de los elementos enumerable junto a un ´ındice que empieza en cero. Veamos un ejemplo de su uso: %w(alice bob carol).each_with_index do |person,index| puts ">> #{person} is number #{index}" end >> alice is number 0 >> bob is number 1 >> carol is number 2
Escribe un iterador each_with_custom_index en el m´odulo Enumerable que permita fijar el valor inicial del ´ındice que devolver´a para el primer elemento, y el n´umero de saltos que debe ir dando el ´ındice al ir iterando. Ejemplo de uso: include Enumerable %w(alice bob carol).each_with_custom_index(3,2) do |person,index| puts ">> #{person} is number #{index}" end >> alice is number 3 >> bob is number 5 >> carol is number 7
Ejercicio 23 ++ En la sucesi´on de Fibonacci los dos primeros enteros son 1 y 1, y cada n´umero sucesivo es la suma de los dos previos. Crea una clase FibSequence que devuelva un iterador para los n primeros n´umeros de Fibonacci. Ejemplo de uso: f = FibSequence.new(6) f.each { |s| print(s,’:’) } f.reject { |s| s.odd? } f.map { |x| 2*x }
# # # # #
devuelve un iterador para los 6 primeros n´umeros de la sucesi´on de Fibonacci => 1:1:2:3:5:8: => [2, 8] => [2, 2, 4, 6, 10, 16]
Recuerda que si la clase FibSequence implementa each, al incluir el m´odulo mix-in Enumerable se a˜ naden los m´etodos definidos en este m´odulo como reject , map ,...
Ejercicio 24 +++ Implementa un iterador each_with_flattening que se comporte del siguiente modo: [1, [2, 3], 4, [[5, 6], 7]].each_with_flattening { |s| print "#{s}," } >> 1, 2, 3, 4, 5, 6, 7
Ejercicio 25 + A˜ nade al m´odulo Enumerable un nuevo iterador, each_permuted que devuelva los elementos de una colecci´on en orden aleatorio. El iterador puede asumir que la colecci´on responde al m´etodo each pero no debe esperar nada de cada elemento. Utiliza el m´etodo rand. 9