Menu
Coddy logo textTech

Tipado pato

Parte de la sección Programación orientada a objetos del Journey de Ruby de Coddy. Lección 33 de 57.

Ruby no comprueba la clase de un objeto antes de llamar a un método; solo necesita que el objeto tenga el método. «Si camina como un pato y grazna como un pato, es un pato». Esto es la tipificación pato: las clases que no comparten ninguna superclase aún pueden usarse en el mismo 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 }

Salida:

Quack
Beep
...news...

Las clases integradas también participan. Un método que solo usa << funciona con un array, una cadena o cualquier objeto tuyo 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).count

Salida:

["1", "2"]
"12"
3

respond_to?(:name) pregunta si un objeto tiene un método público, sin llamarlo. Úsalo cuando un objeto pueda admitir o no una función 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
end

Salida:

printing report
Scanner cannot print

Cuando el objeto no tiene el método, la llamada genera NoMethodError, cuyo mensaje indica el nombre del método y el objeto. La tipificación pato se basa en que cada objeto que se pasa responda a los métodos que se le envían:

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
end

Salida:

Meow
undefined method `speak' for an instance of Integer
challenge icon

Desafío

Fácil

Completa las clases Printer y LineCounter y el auxiliar export(items, target) en functions.rb. export envía cada elemento al destino con target << item.to_s y devuelve el destino. Printer#<< muestra el texto con un número de línea, 1: text, y devuelve la impresora. LineCounter#<< cuenta las líneas y los caracteres y devuelve el contador; su to_s devuelve 3 lines, 12 chars.

El código proporcionado lee los elementos, los exporta a un arreglo (mostrado con p), a una cadena nueva (mostrada con p), a un Printer y a un LineCounter (mostrado con puts).

Tu código debe ir en printer.rb, line_counter.rb y functions.rb. main.rb contiene el código proporcionado de entrada/salida y no se puede editar.

Pruébalo tú mismo

require_relative 'printer'
require_relative 'line_counter'
require_relative 'functions'

# Código de entrada/salida suministrado: déjalo 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)
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación orientada a objetos

Practica por tu cuenta: Compilador de Ruby online