Spec-Zone.ru › Ruby 3.3

Модули

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

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

Функциональность миксинов позволяет обмениваться общими методами между несколькими классами или модулями. 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. При вызове защищенного метода отправитель должен унаследовать Class или Module, которые определяют метод. В противном случае будет поднято исключение 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 C
end

class D < C
end

# OK
class D < C
end

# OK
class D
end

# TypeError: superclass mismatch for class D
class D < String
end

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

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

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