Lab4 Pedro Cau

aluno: Pedro de Sousa Cau Ramos Salles
ano/sem: 2008/2o.
04/08/2008

Introdução

Este laboratorio teve como objetivo a familiarização com a linguagem Ruby. Para tanto foi realizada a converção do laboratorio 2, que era em Java, para Ruby.

Desenvolvimento

Para realizar a conversão entre as linguagens,foram necessarias algumas alterações na logica do lab2.
A classe Comportamento, em java, devia ser extendida por varias outras classes, afim de, por polimorfismo, definir diversos comportamentos ao aluno. Como em ruby nao se define os tipos das variaveis, entao não há mais a necessidade da classe Comportamento, que foi excluida na versao ruby. A logica da classe Aluno e suas subclasses foi mantida, alterando somente a sintaxe. Todas as classes relativas a aluno ficaram reunidas no arquivo Aluno.rb . O codigo resultante está mostrado a seguir:

require 'Outros'
 
class Burro
  def initialize 
    @inteligencia = 0 #sempre zero
    @dedicacao = 0 #sempre zero
  end 
  attr_reader :inteligencia
  attr_reader :dedicacao
end
 
class SafoPreguicoso
  def initialize 
    @inteligencia = 1 #sempre um
  end 
  attr_reader :inteligencia
  def dedicacao
    0.5*rand
  end
end
 
class Summa
  def initialize 
    @inteligencia = 1 #sempre um
    @dedicacao = 1 #sempre um
  end 
  attr_reader :inteligencia
  attr_reader :dedicacao
end
 
class Pemba
  def inteligencia 
    0.5*rand #inteligencia aleatoria
  end
  def dedicacao 
    0.5*rand #dedicacao aleatoria
  end
end
 
class Imprevisivel
  def inteligencia 
    rand #inteligencia aleatoria
  end
  def dedicacao 
    rand #dedicacao aleatoria
  end
end
 
class Esforcado
  def initialize 
    @inteligencia = 0.5 #aleatorio
    @dedicacao = 1.0 #aleatorio
  end 
  attr_reader :inteligencia
  attr_reader :dedicacao
end
 
class Aluno
  def initialize (nome,queue)
    @nome,@queue,@conhecimento = nome,queue,0
    @comportamento = Esforcado.new
  end
  attr_reader :conhecimento, :nome
  attr_writer :comportamento
  def inteligencia
    @comportamento.inteligencia
  end
  def dedicacao
    @comportamento.dedicacao
  end
  def faz_e_entrega_relatorio
    qualidade = (2.0 * dedicacao + 1.0* inteligencia)/3.0
    originalidade = (1.0 * dedicacao + 2.0* inteligencia)/3.0
    @queue.queue(Relatorio.new(qualidade,originalidade,self))
    @conhecimento = @conhecimento + 1
  end
end
 
class AlunoUnicamp < Aluno
  def initialize(nome,queue)
    super(nome, queue)
  end
  def comportamento=(value)
    if value.class != Summa && value.class != SafoPreguicoso
      @comportamento = value 
    else raise 'Comportamento impossivel'
    end
  end
end
 
class AlunoITA < Aluno
  def initialize(nome,queue)
    super(nome, queue)
  end
  def comportamento=(value)
    if value.class != Burro
      @comportamento = value 
    else raise 'Comportamento impossivel'
    end
  end
end
 
class AlunoUSP < Aluno
  def initialize(nome,queue)
    super(nome, queue)
  end
  def comportamento=(value)
    if value.class != Summa && value.class != SafoPreguicoso
      @comportamento = value 
    else raise 'Comportamento impossivel'
    end
  end
end

O codigo mostrado acima possui as mesmas funções que o codigo em java, porém ficou mais conciso. Um detalhe que foi alterado é que no programa em Java as subclasses de comportamento recebem o aluno como parametro no construtor, porém como ele não é utilizado em nada foi retirado dessa versão.

Também devido ao fato da tipagem dinamica de Ruby, não foi necessario a criação de uma Queue usando generics para depois ser extendida para relatorio, pois ela já é generica naturalmente. A classe relatorio manteve a mesma logica, somente ficou mais concisa devido a atribuição em paralelo e os atribute readers. O mesmo com a classe Professor. Estas classes descritas ficaram reunidas em Outros.rb, mostrado a seguir:

class Queue 
  def initialize
    @lista = Array.new
    @inicio,@fim = 0,0 
  end
 
  def queue(item)
    @lista[@fim]= item
    @fim = (@fim+1)%10
  end
 
  def dequeue
    if @fim!=@inicio
      a = @lista[@inicio]
      @inicio = (@inicio+1)%10
      return a
    else
      nil
    end
  end
end
 
class Relatorio
  def initialize(qualidade,originalidade,aluno)
    @qualidade,@originalidade,@aluno = qualidade,originalidade,aluno
  end
  attr_reader :qualidade
  attr_reader :originalidade
  attr_reader :aluno
end
 
class Professor
  def initialize(queue)
    @queue = queue
  end
 
  def corrigir_relatorios
    while rela = @queue.dequeue 
      corrigir_relatorio(rela)
    end
  end
 
  private
  def corrigir_relatorio(rela)
    nota = (rela.qualidade + rela.originalidade + rand)*10/3
    puts "#{rela.aluno.nome}: #{nota}" 
    return nota
  end
end

No arquivo main.rb temos o simulador. O simulador foi basicamente comandos em sequencia com algumas funções definidas. O seu funcionamento é identido ao da versao em Java.

require 'Aluno'
require 'Outros'
require 'test'
 
$queue = Queue.new
$alunos = Array.new
$num_alunos = 0
$teacher = Professor.new($queue)
 
def criar_aluno
 
  puts "Nome do aluno: "
  str = gets
  ok = false
 
  while !ok
    ok=true
    puts "\nEscolha a Instituicao do aluno: \n"
    puts "1 : Ita"
    puts "2 : Usp"
    puts "3 : Unicamp\n"
    puts "Opcao: "
    str2 = gets
    case str2[0]
      when 49
        novo_aluno = AlunoITA.new(str,$queue);
      when 50
        novo_aluno = AlunoUSP.new(str,$queue);
      when 51
        novo_aluno = AlunoUnicamp.new(str,$queue);
      else
        puts "Opcao invalida, tente denovo"
        ok = false
    end
  end
 
  ok = false
  while !ok
    ok = true
    puts "\nEscolha do tipo de aluno: \n"
    puts "1 : Safo Preguiçoso"
    puts "2 : Esforçado"
    puts "3 : Summa"
    puts "4 : Pemba"
    puts "5 : Imprevisivel"
    puts "6 : Burro"
    puts "Opo: "
    str2 = gets
    begin
      case str2[0]
        when 49; novo_aluno.comportamento = SafoPreguicoso.new
        when 50; novo_aluno.comportamento = Esforcado.new
        when 51; novo_aluno.comportamento = Summa.new
        when 52; novo_aluno.comportamento = Pemba.new
        when 53; novo_aluno.comportamento = Imprevisivel.new
        when 54; novo_aluno.comportamento = Burro.new
        else
          puts "Opcao invalida, tente denovo"
          ok = false
      end
 
    rescue Exception => e  
       puts e.message
       ok = false
    end
  end
 
  $alunos[$num_alunos] = novo_aluno
  $num_alunos = $num_alunos + 1
 
  puts "Alunos criados: "
  for aluno in $alunos
    puts aluno.nome
  end
end
 
def fazer_relas
  puts "De o nome do aluno a fazer o rela: "
  nome = gets
 
  for aluno in $alunos
    if aluno.nome == nome 
      get_aluno = aluno
    end     
  end
  if !get_aluno
    puts "Aluno com nome #{nome} nao existe, tente novamente."
  else
    get_aluno.faz_e_entrega_relatorio
    puts "Relatorio de #{nome} entregue."
  end
end
 
def corrigir_relas
   puts "Relatorios corrigidos. Notas:"
   $teacher.corrigir_relatorios
end
 
puts "Simulador"
 
quit = false
 
while !quit
  puts "\n"           
  puts "Escolha uma opcao:\n"
  puts "1-Criar Novo Aluno"
  puts "2-Entregar Relatorio"
  puts "3-Corrigir Relatorios"
  puts "4-Sair\n"
  puts "Opcao: "
 
  str = gets
 
  case str[0]
    when 49
      criar_aluno
    when 50
      fazer_relas
    when 51
      corrigir_relas
    when 52  
      quit = true
    else
      puts "Opcao invalida, tente denovo"
  end
end
 
puts "Fim do programa"

Por ultimo temos o porte da classe de testes, onde foi necessaria poucas alterações e ficou bem parecido com a versão em Java:

require 'Aluno' 
require 'Outros' 
require 'test/unit'
 
class Testes < Test::Unit::TestCase
  def test_funciona_como_lab1
    queue = Queue.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
      aluno4.comportamento = SafoPreguicoso.new
    rescue
      puts "Erro: Nao deveria lancar 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,aluno3.inteligencia,0.01)
    assert(aluno3.dedicacao != aluno3.dedicacao)#deve ser randomica
    assert(aluno3.dedicacao < 0.5)
 
    #alunos comecam a fazer os relas
    aluno1.faz_e_entrega_relatorio
 
    #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.faz_e_entrega_relatorio
    aluno3.faz_e_entrega_relatorio
    aluno4.faz_e_entrega_relatorio
 
    #deve exibir a coreção dos relas dos aluno2, aluno3, e aluno4, nesta ordem
    #pois "roubamos" o relatório do aluno1
    prof.corrigir_relatorios
  end
 
  def test_os_comportamentos_funcionam_como_especificado
    summa = Summa.new
    pemba = Pemba.new
    imprevisivel = Imprevisivel.new
    safo = SafoPreguicoso.new
    esforcado = Esforcado.new
    burro = Burro.new
 
    #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); #deve ser randomica
    assert(safo.dedicacao < 0.5);
 
    #teste de imprevisivel
    assert(imprevisivel.inteligencia != imprevisivel.inteligencia); #deve ser randomica
    assert(imprevisivel.inteligencia < 1.0);
    assert(imprevisivel.dedicacao != imprevisivel.dedicacao); #deve ser randomica
    assert(imprevisivel.dedicacao < 1.0);
 
    #teste de pemba
    assert(pemba.inteligencia != pemba.inteligencia) #deve ser randomica
    assert(pemba.inteligencia < 0.5);
    assert(pemba.dedicacao != pemba.dedicacao); #deve ser randomica
    assert(pemba.dedicacao < 0.5);
  end
 
  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.comportamento = Summa.new
      alunoUSP.comportamento = Burro.new
      alunoUnicamp.comportamento = Burro.new 
    rescue Exception => e
      fail "Não deveria lançar erro!"
    end
    begin
      alunoITA.comportamento = Burro.new
      fail "Deveria lançar erro!"
    rescue Exception => e
    end
    begin
      alunoUSP.comportamento = SafoPreguicoso.new
      fail "Deveria lançar erro!"
    rescue Exception => e
    end
    begin
      alunoUnicamp.comportamento = Summa.new
      fail "Deveria lançar erro!"
    rescue Exception => e
    end
  end
end

Ao executar a classe de testes, foi obtido o seguinte resultado:

tests.JPG

Temos que o programa passou em todos os testes, oque mostra que ele esta funcionando corretamente.

Conclusão

A linguagem Ruby se mostrou uma linguagem bastante pratica, pois é possivel fazer logicas equivalentes a java porém com poucas linhas de codigo. O fato de ser de tipagem dinamica também se mostrou algo interessante pois elimina a necessidade de polimorfismo, alem de eliminar varias linhas de declaração de variaveis.
De inicio levou um tempo para se acostumar com a linguagem, mas uma vez familiarizado, a conversão do Lab2 de Java para Ruby se tornou facil.

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