Lab4 Alexandre Albizzati

aluno: Alexandre Couto Albizzati
ano/sem: 2008/2o.
data do laboratório (num. da semana) : 06/08/2008 (2)

Introdução

Neste laboratório houve um primeiro contato com uma linguagem de tipagem dinâmica: Ruby. A idéia deste lab foi transpor o código implementado no Lab. 02,em Java, para Ruby. Dessa forma, sem ter que se preocupar muito com o desenvolvimento da aplicação em si, foi possível "experimentar" algumas sutilezas do desenvolvimento em uma linguagem com maior "flexibilidade".

Desenvolvimento

O código foi estruturado da maneira proposta, três arquivos, um para guardar todas as classes (classes.rb), outro para o que seria a "main", onde de fato o programa será executado (simulador.rb) e um arquivo que contém os testes (test.rb).
O procedimento seguido foi basicamente trocar as estruturas padrões de declaração de classes, métodos, desvios, etc, de Java para o estilo Ruby. Ao ajustar os métodos acessores, percebi que eles realmente tornam o processo de get e set, quase como se eu estivesse acessando diretamente as variáveis, sem todavia violar o encapsulamento. (Não usei, porém os Symbols attr_reader e attr_writer, pois como ainda estou me ambientando com a linguagem, preferi escrever por extenso os métodos acessores). De qualquer forma, a linguagem se mostrou bastante mais enxuta que Java.
O código do arquivo classes.rb é mostrado abaixo:

class Aluno
    def initialize(nome,relaQueue)
    @conhecimento = 0.5
        @comportamento = Esforcado.new(self)
        @nome = nome
        @queue = relaQueue
    end
 
    def comportamento=(comport)
        @comportamento = comport
    end
 
    def fazEEntregaRelatorio()
        qualidade = (2 * self.dedicacao + 1 * self.inteligencia ) / 3 
        originalidade = (1 * self.dedicacao + 2 * self.inteligencia ) / 3 
        rela = Relatorio.new(qualidade,originalidade,self)
    @queue.queue(rela)
    end
 
    def inteligencia
        return  @comportamento.inteligencia
    end
 
    def dedicacao
        return  @comportamento.dedicacao      
    end
 
    def conhecimento
         return @conhecimento
    end
 
    def comportamento
         return @comportamento
    end
 
    def nome()
         return @nome
    end
 
end
 
class AlunoITA < Aluno
 
    def initialize(nome,relaQueue)
    super(nome,relaQueue)
    end
 
    def comportamento=(comportamento)
        if(comportamento.class==Burro) then raise Exception.new end
    @comportamento = comportamento
    end
 
end
 
class AlunoUSP < Aluno
 
    def comportamento=(comportamento) 
        if(comportamento.class==SafoPreguicoso) then raise Exception.new end
        if(comportamento.class==Summa) then raise Exception.new end
        @comportamento = comportamento
    end   
end
 
class AlunoUnicamp < Aluno
 
    def comportamento=(comportamento)
        if(comportamento.class==SafoPreguicoso) then raise Exception.new end
        if(comportamento.class==Summa) then raise Exception.new end
        @comportamento = comportamento
    end
end
 
class Esforcado
    def initialize(al)
        @aluno = al
    end
 
    def inteligencia
            return 0.5
    end
 
    def dedicacao
        dedicacao = 1
        return dedicacao
    end
 
end
 
class SafoPreguicoso
    def initialize(al)
        @aluno = al
    end
 
    def inteligencia
         inteligencia = 1
        return inteligencia
    end
 
    def dedicacao
    generator = rand()
        return generator * 0.5
    end
end
 
class Summa
    def initialize(al)
        @aluno = al
    end
 
    def inteligencia
        inteligencia = 1
        return inteligencia
    end
 
    def dedicacao
        dedicacao=1
        return dedicacao
    end
end
 
class Pemba
    def initialize(al)
        @aluno = al
    end
 
    def inteligencia
    generator = rand()
        return generator * 0.5
    end
 
    def dedicacao
    generator = rand()
        return generator * 0.5
    end
end
 
class Burro
 
    def initialize(al)
        @aluno = al
    end
 
    def inteligencia
        inteligencia = 0
        return inteligencia
    end
 
    def dedicacao
        dedicacao=0
        return dedicacao
    end
end
 
class Imprevisivel
 
    def initialize(al)
        @aluno = al
    end
 
    def inteligencia
    inteligencia = rand()
        return inteligencia
    end
 
    def dedicacao
    dedicacao = rand()
        return dedicacao
    end
end
 
class Professor
    def initialize(relaQueue)
        @queue = relaQueue
    end
 
    def corrigirRelatorio(rela)
    fatorAleatorioDe0a1 = rand()
        nota = ( rela.qualidade() + rela.originalidade() + fatorAleatorioDe0a1 ) / 3 * 10
        return nota
    end
 
    def corrigirRelatorios()
        inicio = @queue.inicio()
        fim = @queue.fim()
        while(true) do
           aux=@queue.dequeue()
           if(aux==nil) then break end
           puts("#{aux.aluno.nome} :  #{corrigirRelatorio(aux)}")
        end
    end
end
 
class Relatorio
    def initialize(qualidade,originalidade,aluno)
        @qualidade = qualidade
        @originalidade = originalidade
        @aluno = aluno
    end
 
    def qualidade
        return @qualidade
    end
 
    def originalidade
        return @originalidade
    end
 
    def aluno
        return @aluno
    end
end
 
class RelaQueue
 
    def initialize()
        @array = Array.new(10)
        @inicio=0
        @fim=0
    end    
 
    def queue(elem)
        # Maximo de 10 elementos
        if( (@fim+1)==@inicio || (@fim+1)==(@inicio+10) ) then
            print("Fila cheia!")
        else
            @array[@fim]=elem
            @fim = (@fim + 1) % 10
        end
    end
 
    def dequeue()
      valor = @array[@inicio]
      if (@inicio!=@fim) then
       @inicio = (@inicio + 1) % 10
       return valor
      else
    return nil
      end
    end
 
    def inicio
      return @inicio
    end
 
    def fim
      return @fim
    end
 
end

O arquivo simulador.rb, que tem a função de rodar o programa é mostrado abaixo:

require 'classes.rb'
 
        alunos = Array.new(20)
        relaQueue = RelaQueue.new()
        professor = Professor.new(relaQueue)
    i=0
 
            print("Vc deseja cadastrar novo aluno? (s/n)")
        var = gets()
 
    while (var=="s\n") do
            print("Entre com o nome do aluno: ")
          nome = gets()
          print("Qual a instituicao de seu aluno: 'ITA', 'USP' ou 'Unicamp?'")
      instituto = gets()
          if ( instituto=="ITA\n" ) then alunos[i] = AlunoITA.new(nome,relaQueue)             
          elsif ( instituto=="USP\n" ) then alunos[i] = AlunoUSP.new(nome,relaQueue)  
          elsif ( instituto=="Unicamp\n") then alunos[i] = AlunoUnicamp.new(nome,relaQueue)
      end    
 
          print("Qual o tipo do seu aluno? 'esforcado', 'preguicoso', 'summa', 'pemba', 'burro' ou 'imprevisivel'?")
      tipo = gets()
 
    if (tipo=="esforcado\n")
        begin        
        comp = Esforcado.new(alunos[i])
        alunos[i].comportamento=(comp)
        rescue Exception => e
        print("Nao deveria lancar erro!")
                end
        elsif (tipo=="preguicoso\n")[[code type="Ruby"]]
        begin
        comp = SafoPreguicoso.new(alunos[i])
                alunos[i].comportamento=(comp)
        rescue Exception => e
                print("Soh iteanos sao safos!")
                end
 
        elsif (tipo=="summa\n")
        begin
        comp = Summa.new(alunos[i])
                alunos[i].comportamento=(comp)
        rescue Exception => e
                print("Soh iteanos sao summas!")
                end
 
        elsif (tipo=="pemba\n")
        begin
        comp = Pemba.new(alunos[i])
                alunos[i].comportamento=(comp)
        rescue Exception => e
                print("Nao deveria dar erro!")
                end
 
        elsif (tipo=="burro\n")
        begin
        comp = Burro.new(alunos[i])
                alunos[i].comportamento=(comp)
        rescue Exception => e
                print("Iteanos nao podem ser burros!")
                end
 
        elsif (tipo=="imprevisivel\n")
        begin
        comp = Imprevisivel.new(alunos[i])
                alunos[i].comportamento=(comp)
        rescue Exception => e
                print("Nao deveria dar erro!")
                end
    end
 
    alunos[i].fazEEntregaRelatorio()
        i=i+1
    print("Vc deseja cadastrar novo aluno? (s/n)")
        var = gets
    end
 
        professor.corrigirRelatorios()

O código de testes é mostrado abaixo:

require 'classes.rb'
require 'test/unit'
 
class TestAluno < Test::Unit::TestCase
 
def testFuncionaComoOLab1
  queue = RelaQueue.new();
  prof = Professor.new(queue);
 
  # O que muda em termos de interface externa neste lab,
  # é a criação dos alunos. O que mostra que o nosso código
  # está bem desacoplado e a nossa refatoração não alterou
  # o funcionamento dos outros objetos (Professor, Relatório, etc).
    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
    fail("Não deveria lançar erro!");
  end
 
  #teste de alunoesforcado
  assert_equal(0.5, aluno1.inteligencia, 0.01);
  assert_equal(1, aluno1.dedicacao, 0.01);
 
  #teste de alunosafo
  assert_equal(1.0, aluno3.inteligencia, 0.01);
  assert(aluno3.dedicacao != aluno3.dedicacao); 
  assert(aluno3.dedicacao < 0.5);
 
  #alunos comecam 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.eql?("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 coreção dos relas dos 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 esforcado
  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 testAsSubClassesDeAlunoTemRestricoes()
    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
    fail("Não deveria lançar erro!");
  end
 begin
    alunoITA.comportamento=( Burro.new(alunoITA) );
    fail("Deveria lançar erro!");
  rescue Exception => e
  end
 begin
    alunoUSP.comportamento=( SafoPreguicoso.new(alunoUSP) );
    fail("Deveria lançar erro!");
  rescue Exception => e
  end
 begin
    alunoUnicamp.comportamento=( Summa.new(alunoUnicamp) );
    fail("Deveria lançar erro!");
  rescue Exception => e
  end
end
 
def testRelaQueueEhSubclasseDoGenericoQueue()
  q = RelaQueue.new()
end
 
end

Os resultados são mostrados abaixo:

Figura da execução de simulador.rb:
simulador.jpg

Figura da execução de test.rb:
teste.jpg

Uma peculiaridade do desenvolvimento em Ruby é a flexibilidade em se distribuir o código entre os arquivos. No desenvolvimento em Java, tínhamos que criar um arquivo para cada classe, já em Ruby, pude colocar todas as classes em um arquivo somente. Os outros arquivos, simulador.rb e test.rb apenas utilizaram "require" para saberem onde estavam as referência às classes criadas.
Uma diferença observada durante o desenvolvimento é o estilo que se pode adotar ao programar. Eu podia ir programando e verificando o código, muito antes dele estar completo. Pude verificar como o programa vinha se comportando em estágios, que se estivesse programando em Java, o programa com certeza nem compilaria. Outro aspecto que torna confortável a programação em Ruby: o programador quase pode "escolher" a sintaxe a ser adotada, já que ela é muito flexível, podendo ajustar-se ao seu próprio estilo.
Uma outra diferença bastante sensível foi a ausência da necessidade de se declarar as variáveis e seus tipos. Programar assim, embora seja mais rápido, exige mais atenção do programador, pois a qualquer momento, pode haver confusão e métodos serem chamados com parâmetros que não fazem sentido.
Assim, a tipagem dinâmica dá liberdade, mas é necessário cuidado, pois mesmo que a tipagem seja segura, pode-se cometer erros que serão executados sem nenhum aviso, gerando resultados válidos, porém sem sentido.

Conclusão

Este Lab., permitiu uma ambientação com a linguagem Ruby, que servirá de base para os próximos labs. Ao transpor o código, muito do que eu fiz foi simplesmente deletar código, retirando declarações de tipos e variáveis. O código em Ruby ficou bem mais enxuto e também mais flexível.
Finalmente, observou-se o cuidado extra que se tem que ter ao programar com tipagem dinâmica, para que não se cometa o erro de atribuir parâmetros que levem métodos a resultados sem sentido (mesmo que Ruby tente nos fornecer uma tipagem segura).

OBS.: Eu estava fazendo o lab no gedit, e só após eu terminar este rela eu tive tempo de instalar o NetBeans (porque eu estava tentando instalar e não conseguia). Agora, após ter instalado eu coloquei o código lá e percebi que alguns métodos meus deveriam estar "tradicionalmente" somente com letras minúsculas. Não tinha percebido isso antes pois o interpretador não tinha reclamado…

Add a New Comment
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License