モジュールとinclude
CoddyのRubyジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 27/57。
モジュールは、名前付きのメソッドのグループです。オブジェクトを作成することはできませんが、クラスでincludeすると、クラスが定義したかのように、すべてのインスタンスがそのモジュールのメソッドを持つようになります。これをミックスインと呼びます。
module Greetable
def greet
"Hello, I am #{name}"
end
end
class Person
include Greetable
attr_reader :name
def initialize(name)
@name = name
end
end
puts Person.new("Ada").greet出力:
Hello, I am Adaモジュールのメソッドは、上記のnameのように、クラスが提供するメソッドを呼び出せます。そのため、モジュールが使うメソッドを各クラスが提供していれば、1つのモジュールをまったく異なるクラスで利用できます。
module Greetable
def greet
"Hello, I am #{name}"
end
end
class Robot
include Greetable
def name
"R2"
end
end
class City
include Greetable
def name
"Paris"
end
end
puts Robot.new.greet
puts City.new.greet出力:
Hello, I am R2
Hello, I am Parisクラスが持てるスーパークラスは1つだけですが、任意の数のモジュールを含めることができます。include?は、クラスがモジュールを含んでいるかどうかを調べます。モジュールはancestorsにクラスの直後に現れます。これは、Rubyがメソッドを探す場所です。
module Swimmer
def swim
"swimming"
end
end
module Flyer
def fly
"flying"
end
end
class Duck
include Swimmer
include Flyer
end
d = Duck.new
puts "#{d.swim}, #{d.fly}"
puts Duck.include?(Flyer)
p Duck.ancestors.take(3)出力:
swimming, flying
true
[Duck, Flyer, Swimmer]モジュールは、名前が衝突しないように、関連するクラスや定数も1つの名前、名前空間の下にまとめます。Shop::ItemとGame::Itemは異なるクラスです。
module Shop
TAX = 0.2
class Item
def label
"shop item, tax #{TAX}"
end
end
end
puts Shop::Item.new.label
puts Shop::TAX出力:
shop item, tax 0.2
0.2チャレンジ
簡単モジュールとクラスを完成させてください。Greetable#greetは、オブジェクトのnameを使ってHello, I am Adaを返します。Walkable#walk(steps)は、@stepsに保持されているカウンター(最初はnil)に歩数を加算し、累計のAda walked 30 stepsを返します。Personは両方のモジュールをインクルードし、RobotはGreetableのみをインクルードします。ロボットの名前はR-の後にシリアル番号が続きます。
与えられたコードは、最初の行(Ada 7)から人とロボットを作成し、その後、コマンドgreet p、greet r、または(人に対する)walk 10を実行して各結果を出力し、最後にrobot walks: falseを出力します。
コードはgreetable.rb、walkable.rb、person.rb、robot.rbに記述します。main.rbには与えられた入出力コードがあり、編集できません。
自分で試してみよう
require_relative 'greetable'
require_relative 'walkable'
require_relative 'person'
require_relative 'robot'
# 提供された入出力コード:そのままにしてください
input = []
while (line = gets)
input << line.chomp
end
name, serial = input[0].split
person = Person.new(name)
robot = Robot.new(serial)
input.drop(1).each do |line|
command, arg = line.split
if command == "walk"
puts person.walk(arg.to_i)
else
target = arg == "p" ? person : robot
puts target.greet
end
end
puts "robot walks: #{Robot.include?(Walkable)}"
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: Rubyオンラインコンパイラ