Ejercicios de Programaci´
on con Ruby
Ingenier´ıa de Sistemas de Informaci´
on
Departamento de Sistemas Telem´
aticos y Computaci´
on (GSyC)
18 de septiembre de 2012
Notas:
1. Al lado de cada ejercicio aparecen una o m´as cruces, en funci´on de su dificultad y de la cantidad de tiempo estimado que requiere. Cuantas m´as cruces tenga un ejercicio m´as dif´ıcil es o m´as tiempo puede requerir. 2. Aparte de las transparencias que estamos usando en clase, utiliza ri y la siguiente documentaci´on de Ruby:
Documentaci´on online de Ruby: http://ruby-doc.org/core-1.9.3/ API de la biblioteca est´andar de Ruby: http://ruby-doc.org/
Libro Programming Ruby: http://ruby-doc.org/docs/ProgrammingRuby/ 3. Utiliza este resumen sobre el uso de expresiones regulares en Ruby:
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
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")
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
¿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<b
2. a==b 3. x[0] 4. x[0]=’foo’
Ejercicio 12 +
Imagina que el m´etodo foo admite dos argumentos que son dos hashes. 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
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 Fixnum
def seconds ; self ; end def minutes ; self * 60 ; end def hours ; self * 60 * 60 ; end def ago ; Time.now - self ; end def from_now ; Time.now + self ; end 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.
A˜n´adele 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? # => true "Reconocer".palindromo? # => true "Se van sus naves".palindromo? # => true "Pepe".palindromo? # => false
Utiliza ´unicamente 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 +
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 # => #<Foo:0x127e678> f.bar = 3 # => 3
f.bar = :wowzo # => :wowzo f.bar = ’boo!’ # => ’boo!’
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) # devuelve un iterador para los 6 primeros n´umeros
# de la sucesi´on de Fibonacci f.each { |s| print(s,’:’) } # => 1:1:2:3:5:8:
f.reject { |s| s.odd? } # => [2, 8]
f.map { |x| 2*x } # => [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.