Skip to content
Rodrigo Fontoura edited this page Sep 23, 2015 · 1 revision

Exercicio 8:

  • Não é necessário o capitalize dentro do método to_s(). Já estamos usando ele nos métodos name= e initialize, dessa forma ele sempre vai chegar formatado na hora do to_s().
  • Podemos reaproveitar o método name= e utilizar ele também no initialize, dessa forma, se amanhã a gente quiser colocar um padrão de upcase ao invés de capitalize é só alterar no método name= que já vai funcionar para o restante da classe.
  • Podemos remover o @ nos casos de leitura do valor da variável também, uma vez que health é um attr_reader e name um attr_accessor. No caso de name não podemos remover o @ da escrita pois estamos sobreescrevendo esse método (name=) e no caso de health não podemos remover pois o attr_reader só da acesso a leitura e não a escrita.
  class Player
  	attr_reader :health
  	attr_accessor :name

  	def initialize(new_name, health)
      self.name = new_name
  		@health = health
  	end

  	def to_s()
  		"I'm #{name} with a health of #{health} and socre of #{score}."
  	end

  	def blam
  		@health -= 10
  	end

  	def w00t
  		@health += 15
  		puts "Player got w00ted"
  	end

  	def score
  		@health + name.length
  	end

  	def name=(new_name)
  		@name = new_name.capitalize
  	end
  end

Exercicio 11:

  • Você inicializou um game e não usou ele: chipmunks = Game.new("Chipmunks"). Só tomar cuidado para não criarmos N instancias e não usa-las.

Exercicio 12:

  • Cuidado ao copiar as mensagens de retorno. No spec has a string representation você valida se a string é igual a que você retorna no método to_s() e esse retorno tem um erro de gramatica. Se você tivesse feito o spec sem copiar o texto de retorno (pelo erro, imagino que foi o que ocorreu), você teria visto que teria que colocar score e não socre no retorno da mensagem e iria corrigir no código. Esse é o principal motivo de usarmos o rspec. Ele tem que nos ajudar a achar erros no nosso código desenvolvido.
  • O teste has an initial target funding amount você está usando o valor 200 na mão. Poderia usar a variável @target_funding para garantir que se mudar o valor dessa variável o spec não quebra.

Exercicio 13:

  • Seu spec is fully funded não faz sentido. Ele deveria retornar que o projeto está fully funded e está retornando o oposto. Nesse caso temos um spec que não serve para muita coisa. Deveriamos ter um spec que iria retornar expect(@project).to be_fully_funded.
  • O método fully_funded? poderia usar outro método já existente para saber se já completou ou não o valor que espera cada projeto. Por exemplo:
  class Project
  	attr_reader :funding, :target_funding
  	attr_accessor :name

  	def initialize( name, funding = 0, target_funding = 1000 )
  		@name = name.capitalize
  		@funding = funding
  		@target_funding = target_funding
  	end

  	def to_s
  		"O projeto #{@name.upcase} tem investimento acumulado de R$ #{@funding} de R$ #{@target_funding} desejados. Faltam R$ #{funding_left} para o objetivo ser alcancado!"
  	end

  	def add_fund
  		@funding += 25
  		puts "O projeto #{@name.upcase} recebeu mais fundos =D."
  	end

  	def remove_fund
  		@funding -= 15
  		puts "O projeto #{@name.upcase} perdeu alguns fundos =(."
  	end

  	def funding_left
  		target_funding - funding
  	end

  	def name=(new_name)
  		@name = new_name.capitalize
  	end

  	def fully_funded?
  		funding_left <= 0
  	end
  end

Dessa forma, se amanhã tiver um novo fator que altera no valor do fundo, mudamos apenas o método funding_left e o método fully_funded? continua funcionando normalmente.

  • Dentro do método Die#request_funding não temos necessidade de ter a variável number_rolled pois não usamos ela em nenhum outro lugar. Poderia chamar diretamente case die.roll dentro do when.
  • Seu spec passa bunitinho porque você criou o stub dele, porém seu código não está implementado. Se nesse momento rodar o código na mão, você iria ver que não funcionaria.

Exercicio 14

  • Mesmas observação da variável que não é utilizada em mais de um local dentro do método take_turn.
  • Você implementou a classe Die do fundraising porém ela foi criada sem usar o attr number que está na classe sem utilidade nenhuma. Temos que ter muita atenção ao adicionar qualquer coisa em uma clsse. Temos que ter certeza que precisamos ou não daquilo, senão vira uma bola de neve que só cresce e a gente perde o controle. Poderia implementar essa classe igual a de cima que eu dei uma ideia diferente.

Exercicio 15

  • Você poderia ter feito um método para imprimir os valores dos strings players e dos wimpies players. Repare que o puts é exatamente igual. Você poderia ter abstraido isso para um método apenas. Por exemplo:
  require_relative 'player'
  require_relative 'die'
  require_relative 'game_turn'

  class Game
  	attr_reader :title

  	def initialize(title)
  		@title = title
  		@players = []
  	end

  	def add_player(player)
  		@players << player
  	end

  	def play(rounds)
  		print_message("\n\n#{@title}'s game")
  		1.upto(rounds) do |round|
  			print_message("\nNew round: #{round}")
  			@players.each do |player|
  				GameTurn.take_turn(player)
  				print_message(player)
  			end
  		end
  	end

  	def print_stats
  		print_message("\n\n#{@title}'s Stats")
  		strongs, wimpies = get_strong_and_wimpies_players

  		print_name_and_health(strongs, 'strong')
      print_name_and_health(wimpies, 'wimpy')
  	    print_name_and_health_sorted
  	end
    
    def get_strong_and_wimpies_players
      @players.partition{ |player| player.strong? }
    end
    
    def print_name_and_health(players, player_type)
  		print_message("\n#{players.length} #{player_type} player:")
  		players.each { |player| print_message("#{player.name} (#{player.health})") }
    end
    
  	def print_name_and_health_sorted
		  print_message("\n\n#{@title}'s High Scores")
      @players.sort.each do |player|
			  print_message("#{player.name}".ljust(20, '.') + "#{player.score}")
		  end
  	end
    
    def print_message(message)
      puts(message)
    end
  end

Você fez algo parecido no projeto fundraising, mudei apenas algumas coisas. Coloquei o puts dentro do método responsável por printar na tela os dados pois é ele que sabe se vai usar o método puts ou se amanha vai usar algum outro, então se for mudar, muda em um método apenas. Você vai perceber que todos puts dessa classe sumiram e temos apenas 1 em apenas 1 método. Se no futuro isso começar a se repetir em várias classes, podemos criar uma classe responsável por printar os dados na tela e usar apenas 1 método em todo o projeto para printar os dados na tela. Dessa forma, se um dia a gente mudar o método que imprime na tela, mudamos apenas em um local.

Exercicio 19

  • Pequena observação: podemos usar o health.to_i ao inves de Integer(health). É mais comum usar com to_i. Mas não está errado!

Exercicio 20

  • Quando você coloca variáveis como funding1 fica díficil de entender o código rapidamente. Vamos sempre tentar sermos o mais claro possível na hora de dar um nome a uma variável.
  • O método add_fund e add_pledge só muda 1 linha de código e o resto está igual. Dava para refatorar e abstrair para outro método algumas coisas né? O que acha? Algo do tipo:
  require_relative 'project'

  class HalfWayProject < Project 

    def initialize(name, funding, target_funding, extra_funding=500)
      super(name,funding,target_funding)
      @extra_funding = extra_funding
    end

    def half_way_reached?(old_funding, new_funding)
      !old_funding_reached_half_way?(old_funding) && new_funding_reached_half_way?(new_funding)
    end

    def add_fund
      old_funding = total_funds
      super
      give_extra_funding(old_funding)
    end

    def add_pledge(pledge)
      old_funding = total_funds
      super(pledge)
      give_extra_funding(old_funding)
    end
    
    private
    
    def give_extra_funding(old_funding)
      new_funding = total_funds
      if half_way_reached?(old_funding, new_funding)
        @funding += @extra_funding
      end
    end
    
    def old_funding_reached_half_way?(old_funding)
      (old_funding >= target_funding / 2)
    end
    
    def new_funding_reached_half_way?(new_funding)
      (new_funding >= target_funding/2)
    end

  end

Quanto mais claro ficar nosso código e quanto mais a gente não repetir o mesmo código varias e varias vezes, melhor é para todos nós!

  • Sempre que a gente tiver algum método que usamos apenas dentro da classe, ou seja, não vai ser um método aberto para qualquer interface usar, vamos colocar ele dentro dos métodos privados da forma que fiz acima. Esse conceito é claro para você? Caso não seja me pergunte!

Exercicio 21

  • Faltou o spec do loaded_die heim :(
  • Faltou o spec do game_turn heim :(

Clone this wiki locally