Menu
Coddy logo textTech

Extender objetos

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

extend añade los métodos de un módulo a un objeto en lugar de a todas las instancias. Extender una clase los añade al objeto de la clase, por lo que se convierten en métodos de clase:

module Describable
  def describe
    "#{name} has #{instance_methods(false).size} methods"
  end
end

class Dog
  extend Describable

  def bark
    "Woof"
  end

  def sit
    "sits"
  end
end

puts Dog.describe

Salida:

Dog has 2 methods

Un módulo utilizado con extend puede mantener el estado en variables de instancia de la clase. Cada clase que lo extiende obtiene su propia copia, como variables de instancia de clase:

module Counted
  def created
    @created ||= 0
  end

  def record
    @created = created + 1
  end
end

class Order
  extend Counted
end

class Invoice
  extend Counted
end

Order.record
Order.record
Invoice.record
puts "#{Order.created} #{Invoice.created}"

Salida:

2 1

extend también funciona en un solo objeto. Solo ese objeto obtiene los métodos; las demás instancias de su clase permanecen sin cambios, y is_a? es true únicamente para el objeto extendido:

module Shiny
  def polish
    "#{self} is shining"
  end
end

a = "car"
b = "bike"
a.extend(Shiny)
puts a.polish
puts a.is_a?(Shiny)
puts b.respond_to?(:polish)

Salida:

car is shining
true
false

Las dos palabras clave colocan los métodos del mismo módulo en lugares diferentes. include los convierte en métodos de instancia de una clase, mientras que extend los convierte en métodos del único objeto que se extiende:

class Order
  include Printable    # order.print_me       (cada instancia)
  extend Counted       # Order.record         (la clase misma)
end

item.extend(Shiny)     # item.polish          (solo este objeto)
challenge icon

Desafío

Fácil

Completa el módulo Registry, que las clases usan con extend. register(name) añade un nombre a la lista propia de la clase, almacenada en @entries (creada en el primer uso), y devuelve Plugin registered x; un nombre que ya está allí devuelve Plugin already has x. entries devuelve la lista y count, su tamaño. Tanto Plugin como Theme extienden Registry y mantienen listas separadas.

El código proporcionado lee líneas plugin name o theme name, llama a register en la clase correspondiente e imprime la respuesta. Finalmente, imprime plugins: a, b (2) y themes: ..., o none (0) para una lista vacía.

Tu código va en registry.rb, plugin.rb y theme.rb. main.rb contiene el código proporcionado de entrada/salida y no se puede editar.

Pruébalo tú mismo

require_relative 'registry'
require_relative 'plugin'
require_relative 'theme'

# Código de entrada/salida suministrado: déjalo tal como está
input = []
while (line = gets)
  input << line.chomp
end
input.each do |line|
  kind, name = line.split
  target = kind == "plugin" ? Plugin : Theme
  puts target.register(name)
end
[["plugins", Plugin], ["themes", Theme]].each do |label, klass|
  list = klass.entries.empty? ? "none" : klass.entries.join(", ")
  puts "#{label}: #{list} (#{klass.count})"
end
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