aluno: Yves Conselvan
ano/sem: 2008/2o.
data do laboratório (num. da semana) : ??/??/2008 (?)
Introdução
Neste laboratorio nossa tarefa foi fazer a conversão do segundo laboratório, escrito em Java, para Ruby.
Desenvolvimento
Na conversão removi a classe RelaQueue já que Ruby tem tipagem dinâmica. Implementei o método each na classe Queue utilizando os antigos métodos has_next e next (que renomeei para prox), os métodos agora foram tornados privados. Apresento abaixo esta parte do código da classe Queue e o código da classe QueueItem.
class QueueItem attr_accessor :prox attr_reader :item @item @prox def initialize item @item = item end end class Queue ... def each while has_next yield prox end end private def has_next ret = true if !@iterador.prox ret = false @iterador = @inicio end ret end def prox ret = @iterador.prox.item @iterador = @iterador.prox ret end end
Na implementação dos comportamentos mantive a classe Comportamento como superclasse das demais pela forma como havia implementado reutilizando o código. Nessa conversão utilizei um hash de opções para passar as definições do comportamento para o construtor da superclasse a partir do construtor de cada tipo de comportamento. Apresento abaixo o código destas classes.
class Comportamento @aluno @inteligencia @dedicacao @inteligencia_aleatoria = false @dedicacao_aleatoria = false def initialize parametros @aluno = parametros[:aluno] @inteligencia = parametros[:inteligencia] @dedicacao = parametros[:dedicacao] if parametros[:inteligencia_aleatoria] @inteligencia_aleatoria = parametros[:inteligencia_aleatoria] end if parametros[:dedicacao_aleatoria] @dedicacao_aleatoria = parametros[:dedicacao_aleatoria] end end def inteligencia if @inteligencia_aleatoria @inteligencia.to_f * rand else @inteligencia end end def dedicacao if @dedicacao_aleatoria @dedicacao * rand else @dedicacao end end end class Esforcado < Comportamento def initialize aluno options = {:aluno => aluno, :inteligencia => 0.5, :dedicacao => 1} super options end end class SafoPreguicoso < Comportamento def initialize aluno options = {:aluno => aluno, :inteligencia_aleatoria => false, :inteligencia => 1, :dedicacao_aleatoria => true, :dedicacao => 0.5} super options end end class Summa < Comportamento def initialize aluno options = {:aluno => aluno, :inteligencia => 1, :dedicacao => 1} super options end end class Burro < Comportamento def initialize aluno options = {:aluno => aluno, :inteligencia => 0, :dedicacao => 0} super options end end class Pemba < Comportamento def initialize aluno options = {:aluno => aluno, :inteligencia_aleatoria => true, :inteligencia => 0.5, :dedicacao_aleatoria => true, :dedicacao => 0.5} super options end end class Imprevisivel < Comportamento def initialize aluno options = {:aluno => aluno, :inteligencia_aleatoria => true, :inteligencia => 1, :dedicacao_aleatoria => true, :dedicacao => 1} super options end end
A classe Relatório que apenas guarda informação ficou com o corpo muito pequeno. A inicializacao é feita no construtor e o acesso através do attr_reader
class Relatorio attr_reader :qualidade, :originalidade, :aluno @qualidade @originalidade @aluno def initialize qualidade, originalidade, aluno @aluno = aluno @qualidade = qualidade @originalidade = originalidade end end
As classes Aluno e Professor que executam basicamente operações matematicas e acesso à propriedades tiveram seus códigos simplificados no acesso às usando attr_writer e attr_reader, e praticamente inalterados em relaçãos às operações.
Para a implementação do simulador criei a classe Sistema que no construtor cria as listas e o professor e chama o método menu. A partir do método menu mantive a estrutura utilizada no código do segundo laboratório. Na entrega de relatórios utilizei o método each da Queue. E ao final da definicao é instanciado um objeto sistema.
class Sistema ... def entrega_relatorios print "\nEntrega de relatorios\nAlunos na lista de alunos:\n" @alunos.each do |aluno| puts aluno.nome aluno.faz_e_entrega_relatorio end end ... end Sistema.new
A implementação dos testes ficou bastante parecida com o Java, com a maior alteração na forma de tratamento de exceções. O método de teste das restrições dos alunos exemplifica bem a utilização do tratamento.
class Teste < Test::Unit::TestCase ... def test_as_sub_classes_de_aluno_tem_restricoes queue = Queue.new() alunoITA = AlunoITA.new("John Smith", queue) alunoUSP = AlunoUSP.new("Mark Smith", queue) alunoUnicamp = AlunoUnicamp.new("Joseph Smith", queue) begin alunoITA.comportamento = SafoPreguicoso.new(alunoITA) alunoITA.comportamento = Summa.new(alunoITA) alunoUSP.comportamento = Burro.new(alunoUSP) alunoUnicamp.comportamento = Burro.new(alunoUnicamp) rescue fail("Não deveria lançar erro!") end begin alunoITA.comportamento = Burro.new(alunoITA) fail("Deveria lançar erro!") rescue end begin alunoUSP.comportamento = SafoPreguicoso.new(alunoUSP) fail("Deveria lançar erro!") rescue end begin alunoUnicamp.comportamento = Summa.new(alunoUnicamp) fail("Deveria lançar erro!") rescue end end end
Apresento abaixo a saída da execução dos testes

Conclusão
Utilizar Ruby simplifica a programação, como dá para perceber pelo tamanho que o código ficou em comparação com a versão em Java.
Eu não gosto muito de usar Ruby porque acho que essa expressabilidade da linguagem, junto com a fato de ser interpretado, acabam por utilizar mal os recursos do hardware. Apesar da abundância de recursos dos hardwares atuais eu acho que o que mais importa é que quanto menos o processador chavear menos vai dissipar.