aluno: Nome do Aluno
ano/sem: 2008/2o.
data do laboratório (num. da semana) : 08/11/2008 (6)
Introdução
O objetivo deste laboratório foi a aplicação da linguagem Ruby. Utilizando o código desenvolvido para o lab2, realizamos as alterações para aplicar a linguagem Ruby. Com isto, foi possível perceber como se relacionam Java e Ruby, quais suas diferenças em diversos casos e suas semelhanças.
Desenvolvimento
O código foi separado em 3 classes. A classe simulador, a classe classes e a classe de teste.
A classe classes contém todas as classes desenvolvidas para o funcionamento da aplicação: Aluno, AlunoITA, AlunoUSP, AlunoUnicamp, Professor, RelaQueue, Relatorio e os comportamentos SafoPreguicoso, Esforcado, Summa, Pemba, Burro. Ao contrário da aplicação em Java, em ruby, podemos colocar várias classes em um mesmo aquivo de classe. E para relacionar dois arquivos, basta colocarmos o comando "require 'classe_necessaria' " no início da classe Ruby que utilizará a classe_necessária. Em Java, arquivos do mesmo pacote já estão relacionados.
O código da classe classes é:
Alunos:
class Aluno attr_accessor :comportamento attr_reader :conhecimento, :nome def initialize(nome,queue) @nome=nome @queue=queue @comportamento= Esforcado.new(self) @conhecimento = 0 end def fazeentregarelatorio rela = Relatorio.new(self.qualidade ,self.originalidade,self) @queue.queue(rela) @conhecimento+=1 end def qualidade @qualidade=(2*@comportamento.dedicacao+ @comportamento.inteligencia )/3 end def originalidade @originalidade= (@comportamento.dedicacao+ 2*@comportamento.inteligencia)/3 end def inteligencia @comportamento.inteligencia end def dedicacao @comportamento.dedicacao end end class AlunoITA < Aluno def initialize(nome,queue) super(nome,queue) end def comportamento= (comportamento) raise "Iteanos nao sao burros!" if comportamento.class == Burro super end end class AlunoUSP < Aluno def initialize(nome,queue) super(nome,queue) end def comportamento= (comportamento) raise "Alunos da USP não são Summa." if comportamento.class == Summa raise "Alunos da USP não são Safos Preguiçosos." if comportamento.class ==SafoPreguicoso super end end class AlunoUnicamp < Aluno def initialize(nome,queue) super(nome,queue) end def comportamento= (comportamento) raise "Alunos da UNICAMP não são Summa." if comportamento.class == Summa raise "Alunos da UNICAMP não são Safos Preguiçosos." if comportamento.class == SafoPreguicoso super end end
Comportamentos:
class Esforcado attr_reader :inteligencia , :dedicacao def initialize(aluno) @inteligencia=0.5 @dedicacao=1 @aluno=aluno end end class Burro attr_reader :inteligencia, :dedicacao def initialize(aluno) @inteligencia = 0 @dedicacao = 0 @aluno = aluno end end class Imprevisivel def initialize(aluno) @aluno = aluno end def inteligencia return random0a1 end def dedicacao return random0a1 end def random0a1 rand end end class Pemba def initialize(aluno) @aluno = aluno @inteligencia = self.random0ameio end def inteligencia return random0ameio end def dedicacao return random0ameio end def random0ameio rand*0.5 end end class SafoPreguicoso attr_reader :inteligencia def initialize(aluno) @aluno = aluno @inteligencia = 1 end def dedicacao return random0ameio end def random0ameio rand*0.5 end end class Summa attr_reader :inteligencia, :dedicacao def initialize(aluno) @aluno = aluno @inteligencia = 1 @dedicacao = 1 end end
Rela:
class Relatorio attr_reader :aluno, :originalidade, :qualidade def initialize(qualidade,originalidade,aluno) @originalidade=originalidade; @qualidade=qualidade; @aluno=aluno; end end class RelaQueue def initialize @array =[] @inicio = 0 @fim = 0 end def queue(rela) @array[@fim] = rela @fim = (@fim + 1) % 10; end def dequeue @valor = @array[@inicio] if(@inicio==@fim) valor=nil end @inicio = (@inicio + 1) % 10 @valor end end
Professor:
class Professor def initialize(queue) @queue=queue; end def corrigirrelatorios while(true) rela=@queue.dequeue if(rela==nil) break end puts("#{rela.aluno.nome.to_s}"+ ": "); puts("#{corrigirrelatorio(rela)}"); end end private def corrigirrelatorio(rela) nota = (rela.qualidade + rela.originalidade + fatoraleatoriode0a1)/3 nota *=10 return nota end def fatoraleatoriode0a1 rand end end
A classe simulador é equivalente à classe simulador desenvolvida em Java, sendo utilizada para a interação entre a aplicação e o usuário. Aqui, uma diferença é que em Java, temos a classe Simulador com o método main dentro dela para a execução do arquivo. Em ruby, não precisamos declarar nenhuma classe ou método. Apenas desenvolvemos a forma como o usuário deve interagir com a aplicação.
A implementação da classe simulador segue abaixo:
require 'classes' puts("Deseja adicionar um aluno (s/n): ") string = gets() while(string!="n") queue = RelaQueue.new professor = Professor.new(queue) puts "Digite o nome do aluno - " nome = gets().strip puts "Escolha a faculdade do aluno: (ITA, USP, UNICAMP) - " facul = gets().strip if(facul=="ITA") alunos=AlunoITA.new(nome,queue) elsif(facul=="USP") alunos=AlunoUSP.new(nome,queue) else alunos=AlunoUnicamp.new(nome,queue) end puts alunos.class puts"Escolha o tipo do aluno: (summa, safo, esforcado, pemba, imprevisivel, burro) - " tipo = gets().strip if(tipo=="summa") alunos.comportamento = Summa.new(alunos) elsif(tipo=="safo") alunos.comportamento = SafoPreguicoso.new(alunos) elsif(tipo=="esforcado") alunos.comportamento = Esforcado.new(alunos) elsif(tipo=="pemba") alunos.comportamento = Pemba.new(alunos) elsif(tipo=="imprevisivel") alunos.comportamento = Imprevisivel.new(alunos) else alunos.comportamento = Burro.new(alunos) end puts alunos.comportamento.class alunos.fazeentregarelatorio professor.corrigirrelatorios puts "Deseja adicionar outro aluno (s/n): " string=gets().strip end
Com a classe de simulação acima, obtivemos os seguintes resultados:
A classe de testes é a mesma que a desenvolvida em Java, apenas alterando a sintaxe de seus comandos para que a aplicação rodasse em Ruby. A classe de testes portada para Ruby é:
require 'classes' require 'test/unit' class TestInteressante < Test::Unit::TestCase def test_meu_teste queue = RelaQueue.new aluno = AlunoITA.new("John Smith", queue) aluno.comportamento = SafoPreguicoso.new(aluno) assert_equal(1.0, aluno.inteligencia(), 0.01) assert(aluno.dedicacao() < 0.5) assert_raise(RuntimeError) { aluno.comportamento = Burro.new(aluno) } end end class Teste < Test::Unit::TestCase def test_funciona_como_o_lab1 queue = RelaQueue.new prof = Professor.new(queue) aluno1 = Aluno.new("John Smith", queue) aluno2 = Aluno.new("Mark Smith", queue) aluno3 = Aluno.new("Joseph Smith", queue) aluno4 = Aluno.new("Robert Smith", queue) begin aluno3.comportamento = (SafoPreguicoso.new(aluno3)) aluno4.comportamento = (SafoPreguicoso.new(aluno4)) rescue Exception=> e puts "Não deveria lançar erro!" end #teste de aluno_esforçado assert_equal(0.5, aluno1.inteligencia , 0.01) assert_equal(1, aluno1.dedicacao, 0.01) #teste de aluno_safo assert_equal(1.0, aluno3.inteligencia, 0.01) assert(aluno3.dedicacao != aluno3.dedicacao) assert(aluno3.dedicacao < 0.5) #alunos começam a fazer os relas aluno1.fazeentregarelatorio #roubamos o relatório do primeiro aluno para investigá-lo rela1 = queue.dequeue assert_equal(aluno1, rela1.aluno) assert(rela1.aluno.nome == "John Smith") assert(rela1.qualidade < 0.9) assert(rela1.qualidade > 0.8) assert(rela1.originalidade < 0.7) assert(rela1.originalidade > 0.6) #os outros continuam a fazer os relas aluno2.fazeentregarelatorio aluno3.fazeentregarelatorio aluno4.fazeentregarelatorio #deve exibir a correção dos relas dos alunos aluno2, aluno3 e aluno4, nesta ordem #pois "roubamos" o relatório do aluno1 prof.corrigirrelatorios end def testoscomportamentosfuncionamcomoespecificado queue = RelaQueue.new aluno1 = Aluno.new("John", queue) summa = Summa.new(aluno1) pemba = Pemba.new(aluno1) imprevisivel = Imprevisivel.new(aluno1) safo = SafoPreguicoso.new(aluno1) esforcado = Esforcado.new(aluno1) burro = Burro.new(aluno1) #teste de esforçado assert_equal(0.5, esforcado.inteligencia, 0.01) assert_equal(1, esforcado.dedicacao, 0.01) #teste de burro assert_equal(0.0, burro.inteligencia, 0.01) assert_equal(0.0, burro.dedicacao, 0.01) #teste de summa assert_equal(1.0, summa.inteligencia, 0.01) assert_equal(1.0, summa.dedicacao, 0.01) #teste de safo assert_equal(1.0, safo.inteligencia, 0.01) assert(safo.dedicacao != safo.dedicacao) assert(safo.dedicacao() < 0.5) #teste de imprevisivel assert(imprevisivel.inteligencia != imprevisivel.inteligencia) assert(imprevisivel.inteligencia < 1.0) assert(imprevisivel.dedicacao != imprevisivel.dedicacao); assert(imprevisivel.dedicacao() < 1.0) #teste de pemba assert(pemba.inteligencia != pemba.inteligencia) assert(pemba.inteligencia < 0.5) assert(pemba.dedicacao != pemba.dedicacao) assert(pemba.dedicacao < 0.5) end def test_as_subclasses_de_aluno_tem_restricoes queue = RelaQueue.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 Exception => e puts "Não deveria lançar erro!" end begin alunoita.comportamento = Burro.new(alunoita) puts "Deveria lançar erro!" rescue Exception => e end begin alunousp.comportamento = SafoPreguicoso.new(alunousp) puts "Deveria lançar erro!" rescue Exception => e end begin alunounicamp.comportamento = Summa.new(alunounicamp) puts "Deveria lançar erro!" rescue Exception => e end end end
Com a classe de testes acima, obtivemos os seguintes resultados:
Conclusão
Utilizando como base um projeto em Java, foi possível perceber as diferenças entre Java e Ruby em cada parte do projeto. Por exemplo, em Java utilizamos uma classe abstrata Comportamento e subclasses que definiam cada tipo de comportamento. Em Ruby não é necessário o desenvolvimento da classe Comportamento. Contudo, poderíamos desenvolver a classe Comportamento, do mesmo modo como feito no lab2. Teríamos uma classe Comportamento e os métodos seriam sobrescritos em suas subclasses, que extenderiam a classe comportamento (ex: class Burro < Comportamento).
Além disso, foi possível perceber que a linguagem Ruby simplifica muito o código, ou seja, a quantidade de linhas necessárias para realizar a mesma operação é muito menor em diversas situações, sem prejudicar a legibilidade do código.
Outra diferença é que em Ruby, pelo fato de termos uma tipagem dinâmica, temos uma liberdade maior para implementação. Alem de ser possível testar todas as idéias antes de realmente implementar-las no projeto. Utilizando o irb, podemos criar a classe ou o método que estamos pensando e podemos ver se funciona antes de colocar-las no projeto. Isto facilita e otimiza muito o desenvolvimento do projeto, pois reduz a quantidade de erros.
A principal dificuldade encontrada foi que, por estarmos desenvolvendo a primeira aplicação em Ruby, cometemos muitos erros pequenos e simples de se corrigir, mas que pela falta de prática com a linguagem, tornam-se motivos para ficarmos travados no mesmo lugar por muito tempo.





