モジュールと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-を付けたものになります。
提供されたコードは、1行目(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オンラインコンパイラ