Spec-Zone.ru › Ruby 3.4

Модули

Модули в 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–2024 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

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