ORIENTAÇÃO A
OBJETOS
17 e 19 de Abril
marcoafilho@gmail.com
marcoafilho
@marcoafilho
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
?? ?
?
?
?
?
?
?
?
? ?
MUITO OBRIGADO!
marcoafilho@gmail.com
marcoafilho
@marcoafilho

Object Oriented Programming

  • 1.
    ORIENTAÇÃO A OBJETOS 17 e19 de Abril marcoafilho@gmail.com marcoafilho @marcoafilho
  • 2.
  • 3.
  • 4.
  • 5.
    10 COISAS SOBRERUBY #  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  +=  
  • 6.
    10 COISAS SOBRERUBY #  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  
  • 7.
    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        
  • 8.
    EXERCÍCIO OBJETIVO Criar o primeiroprograma 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
  • 9.
  • 10.
    MVC MODELS - Representam osmodelos 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
  • 11.
    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:
  • 12.
    EXERCÍCIO OBJETIVO Construir a suaarquitetura 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
  • 13.
  • 14.
    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
  • 15.
  • 16.
    CLASSES ESTÁTICAS Die sides int self.roll() Nãopode ser instanciada! Só há um dado no jogo
  • 17.
    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
  • 18.
    INTERACTIVE RUBY $  irb  -­‐Ibin  -­‐rsave_the_princess   >  Die.roll   =>  4   Ambiente interativo para desenvolvimento e teste de comandos em Ruby
  • 19.
    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!
  • 20.
    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
  • 21.
    EXERCÍCIO OBJETIVO Escrever as classesDie 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
  • 22.
    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  =  ...  
  • 23.
    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  
  • 24.
  • 25.
    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>  
  • 26.
    EXERCÍCIO OBJETIVO Escrever a classeDungeon 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  ...,  ...]  
  • 27.
    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  
  • 28.
  • 29.
  • 30.
    Battle ... start() COESÃO E ACOPLAMENTO muitasdependências == alto acoplamento Round ... start() Turn ... start()
  • 31.
    Battle ... start() ALTA COESÃO EBAIXO 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
  • 32.
    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;
  • 33.
    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  
  • 34.
    EXERCÍCIO OBJETIVO Escrever a classeBattle e todas as suas dependências; MÉTODO §  Desenvolva as classes Turn, Round e Battle nesta ordem; 30 MIN
  • 35.
    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
  • 36.
  • 37.
    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  
  • 38.
    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  
  • 39.
    Character CONVENTION OVER CONFIGURATION character.rbcharacters Nome de arquivo Nome de classe Nome de tabela §  ClassesEmCamelCase; §  variaveis_e_funcoes_sempre_minusculas; §  CONSTANTES_SEMPRE_MAIUSUCLAS;
  • 40.
    DOCUMENTE RDOC Documentar a aplicaçãoem 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  
  • 41.
    EXERCÍCIO OBJETIVO Refatorar a classeBattle 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
  • 42.
    EXERCÍCIO OBJETIVO Classe Battle deveprover 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  
  • 43.
  • 44.