オブジェクトの拡張
CoddyのRubyジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 28/57。
extendは、モジュールのメソッドをすべてのインスタンスではなく、1つのオブジェクトに追加します。クラスを拡張すると、それらはクラスオブジェクトに追加されるため、クラスメソッドになります:
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出力:
Dog has 2 methodsextendとともに使用するモジュールは、クラスのインスタンス変数に状態を保持できます。それを拡張する各クラスは、クラスのインスタンス変数として、それぞれ独自のコピーを持ちます。
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}"出力:
2 1extendは単一のオブジェクトにも作用します。メソッドを取得するのはそのオブジェクトだけであり、同じクラスの他のインスタンスは変更されません。また、拡張されたオブジェクトに対してのみis_a?はtrueになります。
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)出力:
car is shining
true
falseこの2つのキーワードは、同じモジュールのメソッドを異なる場所に配置します。includeはクラスのインスタンスメソッドにし、extendは拡張された1つのオブジェクトのメソッドにします。
class Order
include Printable # order.print_me (すべてのインスタンス)
extend Counted # Order.record (クラス自体)
end
item.extend(Shiny) # item.polish (このオブジェクトのみ)チャレンジ
簡単クラスがextendで使用するRegistryモジュールを完成させてください。register(name)はクラス独自のリストに名前を追加します。このリストは@entriesに保持され、初回使用時に作成されます。そしてPlugin registered xを返します。すでに存在する名前の場合はPlugin already has xを返します。entriesはリストを返し、countはそのサイズを返します。PluginとThemeはどちらもRegistryを拡張し、それぞれ別々のリストを保持します。
提供されたコードはplugin nameまたはtheme nameの形式で行を読み取り、該当するクラスでregisterを呼び出して、その結果を出力します。最後にplugins: a, b (2)とthemes: ...を出力し、リストが空の場合はnone (0)を出力します。
コードはregistry.rb、plugin.rb、theme.rbに記述してください。main.rbには提供された入出力コードが含まれており、編集できません。
自分で試してみよう
require_relative 'registry'
require_relative 'plugin'
require_relative 'theme'
# 提供された入出力コード: そのままにしておく
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
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: Rubyオンラインコンパイラ