Upload
marco-antonio-filho
View
146
Download
0
Embed Size (px)
DESCRIPTION
Second part of the Agile Development with Ruby on Rails course for the Computer's Science junior enterprise. It is shown
LICENÇA
MARCO ANTONIO FILHO
COORDENADOR DE TI INPACT.ME
UM POUCO DE RUBY
10 COISAS SOBRE RUBY # 1. Tudo eh um objeto 5.times { print "Hello World!" } # 2. Blocos sample_array.each { |element| print element } # 3. Retorno de funcao implicito def sum(a,b) a + b end # 4. Tudo eh aberto class Fixnum def previous self – 1 end end 6.previous # 5. Operadores unarios. Nao ha ++, -‐-‐; Use +=
10 COISAS SOBRE RUBY # 6. Atribuicao paralela a, b = b, a # 7. Cada string é um objeto print "hello".object_id print "hello".object_id # Um novo objeto # 8. Verdadeiro e falso em Ruby if 0 print "Hello World" end # 9. Suporte a faixa de numeros e expressoes regulares de forma nativa (1..10).each { print "Hello World" } # 10. Indicadores de metodo class Woman def loves?(thing) thing == "chocolate" ? true : false end end
APLICAÇÃO SIMPLES puts "Welcome! What do you want to be?" # Imprime na tela choice = gets.strip # Lê do teclado e remove \n if choice == "Knight" # Comparacao em if puts "Then a princess you must save" elsif choice == "Wizard" # Else if com condicao puts "Then a book you must find" else puts "Just stay at home" end puts "What is your strength?" choice = gets.to_i # Le do teclado e converte para int damage = choice.times.collect do
rand(6) + 1 end.inject(:+) puts "You did #{damage} damage" # String com interpolacao
EXERCÍCIO OBJETIVO
Criar o primeiro programa em Ruby: Calculadora de dano.
MÉTODO
§ Crie arquivo calculator.rb;
§ Leia do teclado a força e depois leia a armadura;
§ Para cada unidade de força jogue um dado de seis lados. A soma é o valor de ataque;
§ Para cada unidade de armadura jogue um dado de seis lados. A soma é o valor de defesa;
§ A subtração do ataque com a defesa é o dano total. Apresente este resultado;
§ Para executar o programa no terminal execute ruby calculator.rb
15 MIN
UM POUCO DE ARQUITETURA
MVC
MODELS - Representam os modelos do sistema CONTROLLERS - Representam as ações do sistema VIEWS - Interfaces resultantes de ações ASSETS - Arquivos auxiliares (images, js, css) BIN - Arquivo binários LIB - Módulos auxiliares
INICIALIZAÇÃO # bin/nome_da_aplicacao.rb libs = [ File.expand_path('../../lib', __FILE__), File.expand_path('../../app', __FILE__) ] $LOAD_PATH.unshift *Dir.glob(libs) require "nome_da_aplicacao"
# lib/nome_da_aplicacao.rb # inicialmente vazio
$ ruby bin/nome_da_aplicacao.rb
Para executar faça uso do seguinte comando no terminal:
EXERCÍCIO OBJETIVO
Construir a sua arquitetura
MÉTODO
§ A partir dos conceitos dados monte a sua arquitetura MVC;
§ Crie o arquivo de inicialização da aplicação;
§ Crie o arquivo de gerenciamento de dependências;
§ Para testar coloque um comando para escrita na tela no arquivo de dependências;
§ Execute;
§ Se funciona, apague a linha usada o comando de escrita na tela;
5 MIN
BATALHA DE CONCEITOS
CONCEITOS DE OO Classe
Atributos
Métodos
Character name str skill
attack() defend()
string int int
Character #2
name str skill
attack() defend()
James 3 2
Character #1 name str skill
attack() defend()
Marc 2 4
Character #3 name str skill
attack() defend()
Leon 1 3
INSTÂNCIAS
CLASSES Classe
Atributos
Métodos
Dungeon name type
string string
Dungeon #2
name type
Garlia Prison
Dungeon #1 name type
Syrus Castle
INSTÂNCIAS
CLASSES ESTÁTICAS Die
sides int
self.roll()
Não pode ser instanciada! Só há um dado no jogo
MÓDULOS EM RUBY # lib/save_the_princess/die.rb class Die @@sides = 6 # Roll the die # You can change the amount of sides. Default is 6. def self.roll(sides = @@sides) rand(6) + 1 end end
# lib/save_the_princess.rb require "save_the_princess/die.rb"
Adicionar classe à lista de dependências
INTERACTIVE RUBY
$ irb -‐Ibin -‐rsave_the_princess > Die.roll => 4
Ambiente interativo para desenvolvimento e teste de comandos em Ruby
CLASSES EM RUBY # app/models/character.rb class Character # Character profile attributes attr_accessor :name attr_accessor :strength, :skill, :resistance, :armor, :fire_power # The sum of the amount of strength die rolls. def attack strength.times.collect do Die.roll end.inject(:+) end # The sum of the amount of armor die rolls. def defend armor.times.collect do Die.roll end.inject(:+) end end
LEMBRE-SE DE ADICIONAR A DEPENDÊNCIA!
INTERACTIVE RUBY
$ irb -‐Ibin -‐rsave_the_princess > character = Character.new > character.name = "Marc" > character.name => "Marc" > character.strength = 3 > character.attack => 15 > character.defend NoMethodError: undefined method `times' for nil:NilClass
# lib/save_the_princess.rb require "save_the_princess/die.rb" require "models/character.rb"
LEMBRETE
EXERCÍCIO OBJETIVO
Escrever as classes Die e Character;
MÉTODO
§ Na classe Die deve existir o método self.roll representando um jogar de dados;
§ Na classe Character defina os seus atributos e os métodos attack e defend;
§ Execute no IRB;
§ Em Character adicione um método para calcular a vida do personagem:
§ O método calculate_health_points é baseado na resistência do usuário;
§ É necessário guardar a vida em um atributo chamado max_health_points;
30 MIN
CONSTRUTORES class Character ... attr_accessor :max_health_points # Character constructor. Sets the attributes default values. def initialize(params = {}) @name = params[:name] || "" @strength = params[:strength] || 0 @skill = params[:skill] || 0 @resistance = params[:resistance] || 0 @armor = params[:armor] || 0 @fire_power = params[:fire_power] || 0 calculate_max_health_points end end
self.name = @name = ...
INTERACTIVE RUBY
$ irb -‐Ibin -‐rsave_the_princess > c = Character.new name: "Marc", strength: 2, skill: 4, resistance: 2 => #<Character:0x007fcf2210f3d0 @name="Marc", @strength=2, @skill=4, @resistance=2, @armor=0, @fire_power=0, @max_health_points=12> > c.name => "Marc" > c.max_health_points = 200 > c.max_health_points 200
HERANÇA Character
name str skill
attack() defend()
string int int
Knight
slash()
Priest
heal()
Archer
fire_arrow()
SUB-CLASSES
INSTÂNCIAS
HERANÇA class Knight < Character # Do an attack with a bonus of 3 def slash attack + 3 end end
$ irb -‐Ibin -‐rsave_the_princess > k = Knight.new name: "Marc", strength: 2, skill: 4, resistance: 2 => #<Knight:0x007ffcf280e750 @name="Marc", @strength=2, @skill=4, @resistance=2, @armor=0, @fire_power=0, @max_health_points=8> > k.slash => 9 > c = Character.new name: "James", strength: 3, skill: 2, resistance: 1 => #<Character:0x007f93a30f90e0 @name="James", @strength=3, @skill=2, @resistance=1, @armor=0, @fire_power=0, @max_health_points=3> > c.slash NoMethodError: undefined method `slash' for #<Character:0x007f93a30f90e0>
EXERCÍCIO OBJETIVO
Escrever a classe Dungeon e as classes filhas de Character;
MÉTODO
§ Com o que já aprendeu construa a classe Dungeon, com seu nome e tipo;
§ Combine com o colega ao lado quais classes filhas cada um vai escrever;
§ Escreva as classes e partilhe com o seu colega;
§ No arquivo de inicialização carregue um array de personagens e masmorras para disponibilizar para a aplicação, sem ter a necessidade de criar toda vez que é inicializada.
50 MIN
# bin/save_the_princess.rb @characters = [Character.new ..., ...]
MODIFICADORES DE ACESSO class Character ... attr_reader :max_health_points private # Calculate max health based on resistance. def calculate_max_health_points ... end end
> c = Character.new name: "James", strength: 3, skill: 2, resistance: 1 => #<Character> > c.max_health_points = 1000 NoMethodError: undefined method `max_health_points=' for #<Character> > c.calculate_max_health_points NoMethodError: private method `calculate_max_health_points' called for #<Character> > c.max_health_points 5
QUE A BATALHA COMECE!!!
Battle
...
start() start_round() start_turn()
COESÃO E ACOPLAMENTO
fazendo mais do que deveria == baixa coesão
Battle
...
start()
COESÃO E ACOPLAMENTO
muitas dependências == alto acoplamento
Round
...
start()
Turn
...
start()
Battle
...
start()
ALTA COESÃO E BAIXO ACOPLAMENTO
Round
...
start() Turn
...
start()
Importante! Ruby não possui interfaces. É necessário implementar uma solução.
OBJETIVO Classe deve fazer o que propõe Classe deve possuir o mínimo de relacionamento possível
A BATALHA
REGRAS
1. Iniciativa: Joga-se um dado. Aquele que obtiver maior valor ataca primeiro. Caso igual joga-se de novo;
2. Ataque: Caso seja um ataque normal, seguir para 3, senão fazer um teste de habilidade;
3. Dano: A soma resultante de lances de dados equivalente à força ou poder de fogo;
4. Defesa: A soma resultante de lances de dados equivalente à defesa. Valor do dano é subtraído;
5. Pontos de vida: O dano que ultrapassa a soma da Armadura é subtraído de seus pontos de vida;
6. Retaliação: Se ainda estiver vivo, o lutador que foi atacado revida e os passos 2 a 4 são repetidos;
CLASSES DE COMBATE # app/models/battle.rb class Battle attr_accessor :challenger, :opponent # Armazena os combatentes def initialize(params = {}) end # Instancia rodadas até que # os pontos de vida de um # pesonagem chegue a zero. # Recupera os combatentes. def start end end
# app/models/battle.rb class Battle::Round attr_accessor :challenger, :opponent # Armazena os combatentes def initialize(params = {}) end # Verifica quem terá a # iniciativa e istancia # turnos. def start end end
# app/models/battle.rb class Battle::Round::Turn attr_accessor :attacker, :defender # Armazena os combatentes def initialize(params = {}) end # Calcula o dano feito em # combate. def start end end
EXERCÍCIO OBJETIVO
Escrever a classe Battle e todas as suas dependências;
MÉTODO
§ Desenvolva as classes Turn, Round e Battle nesta ordem;
30 MIN
EXERCÍCIO OBJETIVO
Adicionar class Team. Uma dungeon pode ter vários times;
MÉTODO § Desenvolver uma classe Team que tem um nome e um vetor de Characters;
§ Adicione ao método initialize da Dungeon para receber times de oponentes como parâmetro;
§ Crie um método visit para Team que receba uma Dungeon como parâmetro;
§ Nesse método os oponentes presentes naquela dungeon devem ser enfrentados;
§ O vencedor será a batalha entre o primeiro do time 1 luta contra o primeiro do time 2;
2 HORAS
BOAS PRÁTICAS
DON’T REPEAT YOURSELF (DRY) # app/models/character.rb class Character ... # The sum of the amount of strength die rolls. def attack [strength, fire_power].max.times.collect do Die.roll end.inject(:+) end # The sum of the amount of armor die rolls. def defend armor.times.collect do Die.roll end.inject(:+) end end
DON’T REPEAT YOURSELF (DRY) # app/models/character.rb class Character ... # The sum of the amount of strength die rolls. def attack roll_die_for [strength, fire_power].max end # The sum of the amount of armor die rolls. def defend roll_die_for armor end protected def roll_die_for(attribute) attribute.times.map{ Die.roll }.inject(:+) end end
Character
CONVENTION OVER CONFIGURATION character.rb characters
Nome de arquivo Nome de classe Nome de tabela
§ ClassesEmCamelCase; § variaveis_e_funcoes_sempre_minusculas; § CONSTANTES_SEMPRE_MAIUSUCLAS;
DOCUMENTE RDOC
Documentar a aplicação em Ruby é simples:
$ rdoc -‐-‐all Parsing sources... 100% [12/12] UTF-‐8 Generating Darkfish format into /Users/marco/Projects/Rails/save-‐the-‐princess/doc... Files: 12 Classes: 10 (10 undocumented) Modules: 1 ( 1 undocumented) Constants: 1 ( 1 undocumented) Attributes: 21 (20 undocumented) Methods: 38 (33 undocumented) Total: 71 (65 undocumented) 8.45% documented Elapsed: 0.8s
EXERCÍCIO OBJETIVO
Refatorar a classe Battle e seus sub-módulos;
MÉTODO § Simplificar as funções das classes criando classes mais específicas;
§ Garantir que a classe funciona da mesma forma;
§ Gere a documentação do seu projeto com RDoc;
1 HORA
EXERCÍCIO OBJETIVO
Classe Battle deve prover batalhas entre times;
MÉTODO § Alterar a classe Battle para receber dois times (ao invés de characters);
§ Para cada personagem no time desafiante (challenger) deve ser feita uma rodada escolhendo um inimigo aleatório, assim como, o time desafiado (opponent) deve ter uma rodada para cada integrante escolhendo um adversário aleatório;
§ Tente fazer o mínimo de alterações nas classes Turn e Round;
4 HORAS
# Dica @challengers.each do |challenger| Round.new challenger: challenger, opponent: @opponents.shuffle[0] end
DÚVIDAS
? ? ?
?
?
? ?
? ?
?
? ?