Duck Typing
Parte da seção Programação orientada a objetos do Journey de Ruby da Coddy. Lição 33 de 57.
Ruby não verifica a classe de um objeto antes de chamar um método; ele só precisa que o objeto tenha o método. "Se anda como um pato e grasna como um pato, é um pato." Isso é tipagem pato: classes que não compartilham nenhuma superclasse ainda podem ser usadas no mesmo lugar:
class Duck
def speak
"Quack"
end
end
class Robot
def speak
"Beep"
end
end
class Radio
def speak
"...news..."
end
end
[Duck.new, Robot.new, Radio.new].each { |thing| puts thing.speak }Saída:
Quack
Beep
...news...As classes integradas também participam. Um método que usa apenas << funciona com um array, uma string ou qualquer objeto seu que defina <<:
class Tally
attr_reader :count
def initialize
@count = 0
end
def <<(_item)
@count += 1
self
end
end
def export(items, target)
items.each { |item| target << item.to_s }
target
end
p export([1, 2], [])
p export([1, 2], +"")
puts export([1, 2, 3], Tally.new).countSaída:
["1", "2"]
"12"
3respond_to?(:name) verifica se um objeto possui um método público, sem chamá-lo. Use-o quando um objeto pode ou não oferecer suporte a um recurso opcional:
class Printer
def print_page(text)
"printing #{text}"
end
end
class Scanner
end
[Printer.new, Scanner.new].each do |device|
if device.respond_to?(:print_page)
puts device.print_page("report")
else
puts "#{device.class} cannot print"
end
endSaída:
printing report
Scanner cannot printQuando o objeto não possui o método, a chamada gera NoMethodError, cuja mensagem nomeia o método e o objeto. A tipagem pato depende de que todo objeto passado responda aos métodos que lhe são enviados:
def loudest(things)
things.map(&:speak).max_by(&:size)
end
class Cat
def speak
"Meow"
end
end
puts loudest([Cat.new, Cat.new])
begin
loudest([Cat.new, 42])
rescue NoMethodError => e
puts e.message
endSaída:
Meow
undefined method `speak' for an instance of IntegerDesafio
FácilComplete as classes Printer e LineCounter e o auxiliar export(items, target) em functions.rb. export envia cada item ao destino com target << item.to_s e retorna o destino. Printer#<< imprime o texto com um número de linha, 1: text, e retorna a impressora. LineCounter#<< conta linhas e caracteres e retorna o contador; seu to_s retorna 3 lines, 12 chars.
O código fornecido lê os itens, exporta-os para um array (impresso com p), para uma nova string (impressa com p), para um Printer e para um LineCounter (impresso com puts).
Seu código deve ser colocado em printer.rb, line_counter.rb e functions.rb. main.rb contém o código fornecido de entrada/saída e não pode ser editado.
Experimente você mesmo
require_relative 'printer'
require_relative 'line_counter'
require_relative 'functions'
# Código de entrada/saída fornecido: mantenha-o como está
input = []
while (line = gets)
input << line.chomp
end
p export(input, [])
p export(input, +"")
export(input, Printer.new)
puts export(input, LineCounter.new)
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação orientada a objetos
1Classes e Objetos
Trabalhando com ArquivosDefinindo ClassesVariáveis de InstânciaMétodos e selfto_s e inspectRevisão - Cartão da Biblioteca4Encapsulamento
Métodos privadosMétodos protegidosSetters privadosProtegendo o estadoRevisão - Máquina de venda automática7Polimorfismo e Duck Typing
PolimorfismoDuck TypingMétodos Abstratoscase e ClassesRevisão - Métodos de Pagamento2Acessores e self
Leitores e GravadoresSetters Personalizadosself nos MétodosIdentidade e IgualdadeRecapitulação - Lista de Contatos5Herança
SubclassesSobrescrita de métodosChamando superis_a? e ancestraisRevisão - Folha de pagamento da equipe8Métodos Especiais
Igualdade e hashMétodos de OperadoresIndexação e AdiçãoColeções PersonalizadasRevisão - Frações11Projeto: Gerenciamento de Biblioteca
Livros e MembrosEmpréstimo de LivrosPratique por conta própria: Compilador de Ruby online