Spec-Zone.ru › Ruby 3.1

Модули

Модули в Ruby служат двум целям: именованное пространство и возможность миксина.

Именованное пространство может использоваться для организации кода по пакетам или функциям, которые отделяют общие имена от конфликтов с другими пакетами. Например, именованное пространство IRB предоставляет функциональность для irb, предотвращая коллизии с общим именем «Контекст».

Функциональность миксина позволяет совместно использовать общие методы между несколькими классами или модулями. Ruby поставляется с модулем миксина Enumerable, который предоставляет множество методов перечисления, основанных на методе each и Comparable позволяет сравнивать объекты на основе метода сравнения <=>.

Обратите внимание, что между модулями и классами существует много сходства. Помимо возможности смешивания модуля, описание модулей ниже также относится к классам.

Module Определение

Модуль создаётся с помощью ключевого слова module:

module MyModule
  # ...
end

Модуль можно повторно открывать любое количество раз, чтобы добавить, изменить или удалить функциональность:

module MyModule
  def my_method
  end
end

module MyModule
  alias my_alias my_method
end

module MyModule
  remove_method :my_method
end

Повторное открытие классов — очень мощная функция Ruby, но лучше всего повторно открывать только свои классы. Повторное открытие чужих классов может привести к конфликтам имён или трудно диагностируемым ошибкам.

Вложение

Модули могут быть вложены:

module Outer
  module Inner
  end
end

Многие пакеты создают один внешний модуль (или класс), чтобы предоставить именованное пространство для своей функциональности.

Вы также можете определить внутренние модули с использованием :: при условии, что внешние модули (или классы) уже определены:

module Outer::Inner::GrandChild
end

Обратите внимание, что это вызовет NameError если Outer и Outer::Inner ещё не определены.

Этот стиль имеет преимущество, позволяющее автору уменьшить количество отступов. Вместо 3 уровней отступа необходим только один. Однако область поиска констант отличается при создании именованного пространства с использованием этого синтаксиса вместо более подробного синтаксиса.

Область видимости

self

self относится к объекту, определяющему текущую область видимости. self изменится при переходе к другому методу или при определении нового модуля.

Константы

Доступные константы зависят от вложенности модулей (какой синтаксис был использован для определения модуля). В следующем примере константа A::Z доступна из B, так как A является частью вложенности:

module A
  Z = 1

  module B
    p Module.nesting #=> [A::B, A]
    p Z #=> 1
  end
end

Однако, если вы используете :: для определения A::B без вложения внутрь A, будет выброшено исключение NameError, потому что вложенность не включает A:

module A
  Z = 1
end

module A::B
  p Module.nesting #=> [A::B]
  p Z #=> raises NameError
end

Если константа определена на верхнем уровне, вы можете использовать :: для ее ссылки:

Z = 0

module A
  Z = 1

  module B
    p ::Z #=> 0
  end
end

Методы

Для получения документации по определению методов см. документацию по синтаксису методов.

Class методы могут быть вызваны напрямую. (Это немного запутанно, но метод в модуле часто называют «методом класса», а не «методом модуля». См. также Module#module_function, который может преобразовать метод экземпляра в метод класса.)

Когда метод класса ссылается на константу, он использует те же правила, что и при обращении к ней вне метода, так как область видимости одинакова.

Методы экземпляров, определенные в модуле, могут вызываться только при включении. Эти методы имеют доступ к константам, определённым при включении, через список предков:

module A
  Z = 1

  def z
    Z
  end
end

include A

p self.class.ancestors #=> [Object, A, Kernel, BasicObject]
p z #=> 1

Видимость

Ruby имеет три типа видимости. По умолчанию — public. Публичный метод может вызываться из любого другого объекта.

Вторая видимость — protected. При вызове защищенного метода отправитель должен быть подклассом получателя или получатель должен быть подклассом отправителя. В противном случае будет возбуждено исключение NoMethodError.

Защищённая видимость чаще всего используется для определения == и других методов сравнения, где автор не хочет раскрывать состояние объекта любому вызывающему объекту и хочет ограничить его только унаследованными классами.

Вот пример:

class A
  def n(other)
    other.m
  end
end

class B < A
  def m
    1
  end

  protected :m

end

class C < B
end

a = A.new
b = B.new
c = C.new

c.n b #=> 1 -- C is a subclass of B
b.n b #=> 1 -- m called on defining class
a.n b # raises NoMethodError A is not a subclass of B

Третья видимость — private. Приватный метод может быть вызван только изнутри класса-владельца без получателя или с литералом self в качестве получателя. Если приватный метод вызывается с получателем, отличным от литерала self, будет возбуждено исключение NoMethodError.

class A
  def without
    m
  end

  def with_self
    self.m
  end

  def with_other
    A.new.m
  end

  def with_renamed
    copy = self
    copy.m
  end

  def m
    1
  end

  private :m
end

a = A.new
a.without      #=> 1
a.with_self    #=> 1
a.with_other   # NoMethodError (private method `m' called for #<A:0x0000559c287f27d0>)
a.with_renamed # NoMethodError (private method `m' called for #<A:0x0000559c285f8330>)

alias и undef

Вы также можете алиасить или удалять методы, но эти операции не ограничиваются модулями или классами. См. раздел раздел синтаксиса для прочих операций для документации.

Классы

Каждый класс также является модулем, но в отличие от модулей, класс нельзя смешать с другим модулем (или классом). Как и модуль, класс может использоваться в качестве именованного пространства. Класс также наследует методы и константы от своего суперкласса.

Определение класса

Используйте ключевое слово class для создания класса:

class MyClass
  # ...
end

Если вы не укажете суперкласс, ваш новый класс будет наследовать от Object. Вы можете унаследовать от другого класса, используя < за которым следует имя класса:

class MySubclass < MyClass
  # ...
end

Существует специальный класс BasicObject, который разработан как пустой класс и содержит минимум встроенных методов. Вы можете использовать BasicObject для создания независимой структуры наследования. См. документацию BasicObject для получения дополнительной информации.

Наследование

Любой метод, определенный в классе, доступен для вызова в его подклассе:

class A
  Z = 1

  def z
    Z
  end
end

class B < A
end

p B.new.z #=> 1

То же самое верно для констант:

class A
  Z = 1
end

class B < A
  def z
    Z
  end
end

p B.new.z #=> 1

Вы можете переопределить функциональность метода суперкласса, переопределяя метод:

class A
  def m
    1
  end
end

class B < A
  def m
    2
  end
end

p B.new.m #=> 2

Если вы хотите вызвать функциональность суперкласса из метода, используйте super:

class A
  def m
    1
  end
end

class B < A
  def m
    2 + super
  end
end

p B.new.m #=> 3

Когда super используется без аргументов, он использует аргументы, переданные методу подкласса. Чтобы не передавать аргументы методу суперкласса, используйте super(). Чтобы передать конкретные аргументы методу суперкласса, укажите их вручную, как в super(2).

super может вызываться любое количество раз в методе подкласса.

Singleton Классы

Класс одиночного объекта (также известный как метакласс или собственный класс) — это класс, который содержит методы только для данного экземпляра. Вы можете получить доступ к классу одиночного объекта объекта, используя class << object следующим образом:

class C
end

class << C
  # self is the singleton class here
end

Чаще всего вы увидите доступ к классу одиночного объекта следующим образом:

class C
  class << self
    # ...
  end
end

Это позволяет определять методы и атрибуты в классе (или модуле) без необходимости писать def self.my_method.

Поскольку вы можете открыть класс одиночного объекта любого объекта, это означает, что данный блок кода:

o = Object.new

def o.my_method
  1 + 1
end

эквивалентен этому блоку кода:

o = Object.new

class << o
  def my_method
    1 + 1
  end
end

Оба объекта будут иметь метод my_method, который возвращает 2.

Ruby Core © 1993–2022 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API