Menu
Coddy logo textTech

Модули и include

Часть раздела Объектно-ориентированное программирование путешествия по Ruby на Coddy. Урок 27 из 57.

Модуль — это именованная группа методов. Он не может создавать объекты, но класс может использовать его с помощью include, и тогда каждый экземпляр получает методы модуля, как если бы они были определены в классе. Это называется примесью (mixin):

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. Поэтому один модуль может использоваться совершенно разными классами, если каждый из них предоставляет всё, что использует модуль:

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

У класса может быть только один суперкласс, но он может включать любое количество модулей. 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]

Модули также объединяют связанные классы и константы под одним именем — пространством имён, — чтобы имена не конфликтовали. 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
challenge icon

Задание

Легко

Завершите модули и классы. Greetable#greet возвращает Hello, I am Ada, используя name объекта. 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)}"
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор Ruby