Extending Objects
Part of the Object Oriented Programming section of Coddy's Ruby journey. Lesson 28 of 57.
extend adds a module's methods to one object instead of to all instances. Extending a class adds them to the class object, so they become class methods:
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.describeOutput:
Dog has 2 methodsA module used with extend can keep state in instance variables of the class. Each class that extends it gets its own copy, as class instance variables:
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}"Output:
2 1extend also works on a single object. Only that object gains the methods; other instances of its class stay unchanged, and is_a? is true for the extended object only:
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)Output:
car is shining
true
falseThe two keywords put the same module's methods in different places. include makes them instance methods of a class, extend makes them methods of the one object that is extended:
class Order
include Printable # order.print_me (every instance)
extend Counted # Order.record (the class itself)
end
item.extend(Shiny) # item.polish (only this object)Challenge
EasyComplete the module Registry, which classes use with extend. register(name) adds a name to the class's own list, kept in @entries (created on first use), and returns Plugin registered x; a name that is already there returns Plugin already has x. entries returns the list and count its size. Plugin and Theme both extend Registry and keep separate lists.
The supplied code reads lines plugin name or theme name, calls register on the matching class and prints the reply. Finally it prints plugins: a, b (2) and themes: ..., or none (0) for an empty list.
Your code goes in registry.rb, plugin.rb and theme.rb. main.rb holds the supplied input/output code and cannot be edited.
Try it yourself
require_relative 'registry'
require_relative 'plugin'
require_relative 'theme'
# Supplied input/output code: keep it as it is
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
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Classes and Objects
Working With FilesDefining ClassesInstance VariablesMethods and selfto_s and inspectRecap - Library Card7Polymorphism and Duck Typing
PolymorphismDuck TypingAbstract Methodscase and ClassesRecap - Payment Methods2Accessors and Self
Readers and WritersCustom Settersself in MethodsIdentity and EqualityRecap - Contact List8Special Methods
Equality and hashOperator MethodsIndexing and AppendingCustom CollectionsRecap - Fractions11Project: Library Management
Books and MembersBorrowing Books3Class Methods and Variables
Class MethodsClass Instance VariablesConstantsFactory MethodsRecap - Coupon Codes6Modules and Mixins
Modules and includeExtending ObjectsThe Comparable ModuleThe Enumerable ModuleRecap - Sports LeaguePractice on your own: Online Ruby compiler