Spec-Zone.ru › Ruby on Rails 4.2

класс Module

Родитель:
Объект
Включенные модули:
Модуль::Concerning

Расширяет объект модуля с помощью аксессоров для доступа к классам/модулям и экземплярам для атрибутов классов/модулей, точно так же, как родные аксессоры attr* для атрибутов экземпляров.

Расширяет API для констант, чтобы иметь возможность работать с квалифицированными именами. Аргументы предполагаются относительными к получателю.

Константы

RUBY_RESERVED_WORDS

Атрибуты

attr_internal_naming_format[RW]

Методы публичного экземпляра

alias_attribute(new_name, old_name) Показать исходный код
# File activesupport/lib/active_support/core_ext/module/aliasing.rb, line 62
  def alias_attribute(new_name, old_name)
    module_eval "      def #{new_name}; self.#{old_name}; end          # def subject; self.title; end
      def #{new_name}?; self.#{old_name}?; end        # def subject?; self.title?; end
      def #{new_name}=(v); self.#{old_name} = v; end  # def subject=(v); self.title = v; end
", __FILE__, __LINE__ + 1
  end

Позволяет создавать псевдонимы для атрибутов, что включает методы получения, установки и запроса.

class Content < ActiveRecord::Base
  # has a title attribute
end

class Email < Content
  alias_attribute :subject, :title
end

e = Email.find(1)
e.title    # => "Superstars"
e.subject  # => "Superstars"
e.subject? # => true
e.subject = "Megastars"
e.title    # => "Megastars"
alias_method_chain(target, feature) { |aliased_target, punctuation| ... } Показать исходный код
# File activesupport/lib/active_support/core_ext/module/aliasing.rb, line 23
def alias_method_chain(target, feature)
  # Strip out punctuation on predicates, bang or writer methods since
  # e.g. target?_without_feature is not a valid method name.
  aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
  yield(aliased_target, punctuation) if block_given?

  with_method = "#{aliased_target}_with_#{feature}#{punctuation}"
  without_method = "#{aliased_target}_without_#{feature}#{punctuation}"

  alias_method without_method, target
  alias_method target, with_method

  case
  when public_method_defined?(without_method)
    public target
  when protected_method_defined?(without_method)
    protected target
  when private_method_defined?(without_method)
    private target
  end
end

Капсулирует распространенный шаблон:

alias_method :foo_without_feature, :foo
alias_method :foo, :foo_with_feature

С помощью этого вы просто делаете:

alias_method_chain :foo, :feature

И оба псевдонима создаются для вас.

Методы запроса и с восклицательным знаком (foo?, foo!) сохраняют те же знаки препинания:

alias_method_chain :foo?, :feature

равносильно

alias_method :foo_without_feature?, :foo?
alias_method :foo?, :foo_with_feature?

чтобы вы могли безопасно использовать цепочки foo, foo?, foo! и/или foo= с той же функцией.

anonymous?() Показать исходный код
# File activesupport/lib/active_support/core_ext/module/anonymous.rb, line 16
def anonymous?
  name.nil?
end

Модуль может иметь или не иметь имя.

module M; end
M.name # => "M"

m = Module.new
m.name # => nil

Модуль получает имя, когда он впервые присваивается константе. Либо через ключевое слово module или class, или явным присваиванием:

m = Module.new # creates an anonymous module
M = m          # => m gets a name here as a side-effect
m.name         # => "M"
attr_internal(*attrs)
Псевдоним для: attr_internal_accessor
attr_internal_accessor(*attrs) Показать исходный код
# File activesupport/lib/active_support/core_ext/module/attr_internal.rb, line 14
def attr_internal_accessor(*attrs)
  attr_internal_reader(*attrs)
  attr_internal_writer(*attrs)
end

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

Также псевдоним для: attr_internal
attr_internal_reader(*attrs) Показать исходный код
# File activesupport/lib/active_support/core_ext/module/attr_internal.rb, line 3
def attr_internal_reader(*attrs)
  attrs.each {|attr_name| attr_internal_define(attr_name, :reader)}
end

Объявляет метод чтения атрибута, поддерживаемый внутренним именем экземпляра переменной.

attr_internal_writer(*attrs) Показать исходный код
# File activesupport/lib/active_support/core_ext/module/attr_internal.rb, line 8
def attr_internal_writer(*attrs)
  attrs.each {|attr_name| attr_internal_define(attr_name, :writer)}
end

Объявляет метод записи атрибута, поддерживаемый внутренним именем экземпляра переменной.

cattr_accessor(*syms, &blk)
Псевдоним для: mattr_accessor
cattr_reader(*syms)
Псевдоним для: mattr_reader
cattr_writer(*syms)
Псевдоним для: mattr_writer
delegate(*methods) Показать исходный код
# File activesupport/lib/active_support/core_ext/module/delegation.rb, line 151
def delegate(*methods)
  options = methods.pop
  unless options.is_a?(Hash) && to = options[:to]
    raise ArgumentError, 'Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, to: :greeter).'
  end

  prefix, allow_nil = options.values_at(:prefix, :allow_nil)

  if prefix == true && to =~ /^[^a-z_]/
    raise ArgumentError, 'Can only automatically set the delegation prefix when delegating to a method.'
  end

  method_prefix =        if prefix
      "#{prefix == true ? to : prefix}_"
    else
      ''
    end

  file, line = caller.first.split(':', 2)
  line = line.to_i

  to = to.to_s
  to = "self.#{to}" if RUBY_RESERVED_WORDS.include?(to)

  methods.each do |method|
    # Attribute writer methods only accept one argument. Makes sure []=
    # methods still accept two arguments.
    definition = (method =~ /[^\]]=$/) ? 'arg' : '*args, &block'

    # The following generated method calls the target exactly once, storing
    # the returned value in a dummy variable.
    #
    # Reason is twofold: On one hand doing less calls is in general better.
    # On the other hand it could be that the target has side-effects,
    # whereas conceptually, from the user point of view, the delegator should
    # be doing one call.
    if allow_nil
      method_def = [
        "def #{method_prefix}#{method}(#{definition})",
        "_ = #{to}",
        "if !_.nil? || nil.respond_to?(:#{method})",
        "  _.#{method}(#{definition})",
        "end",
      "end"
      ].join ';'
    else
      exception = %Q(raise DelegationError, "#{self}##{method_prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}")

      method_def = [
        "def #{method_prefix}#{method}(#{definition})",
        " _ = #{to}",
        "  _.#{method}(#{definition})",
        "rescue NoMethodError => e",
        "  if _.nil? && e.name == :#{method}",
        "    #{exception}",
        "  else",
        "    raise",
        "  end",
        "end"
      ].join ';'
    end

    module_eval(method_def, file, line)
  end
end

Предоставляет delegate метод класса для простого экспорта общедоступных методов содержащихся объектов в качестве собственных.

Параметры

  • :to - Указывает целевой объект

  • :prefix - Добавляет префикс к новому методу с именем целевого объекта или пользовательским префиксом

  • :allow_nil - Если установлено в true, предотвращает поднятие NoMethodError

Макрос получает одно или несколько имён методов (указанных как символы или строки) и имя целевого объекта через параметр :to (также символ или строка).

Делегирование особенно полезно с ассоциациями Active Record:

class Greeter < ActiveRecord::Base
  def hello
    'hello'
  end

  def goodbye
    'goodbye'
  end
end

class Foo < ActiveRecord::Base
  belongs_to :greeter
  delegate :hello, to: :greeter
end

Foo.new.hello   # => "hello"
Foo.new.goodbye # => NoMethodError: undefined method `goodbye' for #<Foo:0x1af30c>

Разрешается несколько делегатов одному и тому же целевому объекту:

class Foo < ActiveRecord::Base
  belongs_to :greeter
  delegate :hello, :goodbye, to: :greeter
end

Foo.new.goodbye # => "goodbye"

Методы могут быть делегированы переменным экземпляра, класса или константам, указав их как символы:

class Foo
  CONSTANT_ARRAY = [0,1,2,3]
  @@class_array  = [4,5,6,7]

  def initialize
    @instance_array = [8,9,10,11]
  end
  delegate :sum, to: :CONSTANT_ARRAY
  delegate :min, to: :@@class_array
  delegate :max, to: :@instance_array
end

Foo.new.sum # => 6
Foo.new.min # => 4
Foo.new.max # => 11

Также можно делегировать метод классу, используя :class:

class Foo
  def self.hello
    "world"
  end

  delegate :hello, to: :class
end

Foo.new.hello # => "world"

Делегаты могут быть необязательно префиксными с помощью параметра :prefix.

Если значение равно true, методы делегирования префиксруются именем делегируемого объекта.

Person = Struct.new(:name, :address)

class Invoice < Struct.new(:client)
  delegate :name, :address, to: :client, prefix: true
end

john_doe = Person.new('John Doe', 'Vimmersvej 13')
invoice = Invoice.new(john_doe)
invoice.client_name    # => "John Doe"
invoice.client_address # => "Vimmersvej 13"

Также можно указать пользовательский префикс.

class Invoice < Struct.new(:client)
  delegate :name, :address, to: :client, prefix: :customer
end

invoice = Invoice.new(john_doe)
invoice.customer_name    # => 'John Doe'
invoice.customer_address # => 'Vimmersvej 13'

Если целевой объект nil и не отвечает на делегированный метод, поднимается NoMethodError, как и в случае с любым другим значением. Однако иногда имеет смысл быть устойчивым к этой ситуации, и в этом цель параметра :allow_nil: Если целевой объект не nil, или он есть и отвечает на метод, всё работает как обычно. Но если он nil и не отвечает на делегированный метод, возвращается nil

class User < ActiveRecord::Base
  has_one :profile
  delegate :age, to: :profile
end

User.new.age # raises NoMethodError: undefined method `age'

Но если отсутствие профиля ещё не является проблемой и не должно быть условием ошибки:

class User < ActiveRecord::Base
  has_one :profile
  delegate :age, to: :profile, allow_nil: true
end

User.new.age # nil

Обратите внимание, что если целевой объект не nil, вызов выполняется независимо от параметра :allow_nil, и следовательно, исключение всё равно поднимается, если указанный объект не отвечает на метод:

class Foo
  def initialize(bar)
    @bar = bar
  end

  delegate :name, to: :@bar, allow_nil: true
end

Foo.new("Bar").name # raises NoMethodError: undefined method `name'

Метод целевого объекта должен быть общедоступным, в противном случае он поднимет NoMethodError.

deprecate(*method_names) Показать исходный код
# File activesupport/lib/active_support/core_ext/module/deprecation.rb, line 20
def deprecate(*method_names)
  ActiveSupport::Deprecation.deprecate_methods(self, *method_names)
end
deprecate :foo
deprecate bar: 'message'
deprecate :foo, :bar, baz: 'warning!', qux: 'gone!'

Вы также можете использовать экземпляр пользовательского деприкатора:

deprecate :foo, deprecator: MyLib::Deprecator.new
deprecate :foo, bar: "warning!", deprecator: MyLib::Deprecator.new

Пользовательские деприкаторы должны отвечать на метод deprecation_warning(deprecated_method_name, message, caller_backtrace) , где вы можете реализовать своё поведение предупреждения.

class MyLib::Deprecator
  def deprecation_warning(deprecated_method_name, message, caller_backtrace = nil)
     message = "#{deprecated_method_name} is deprecated and will be removed from MyLibrary | #{message}"
     Kernel.warn message
  end
end
mattr_accessor(*syms, &blk) Показать исходный код
# File activesupport/lib/active_support/core_ext/module/attribute_accessors.rb, line 207
def mattr_accessor(*syms, &blk)
  mattr_reader(*syms, &blk)
  mattr_writer(*syms, &blk)
end

Определяет методы доступа как к классу, так и к экземпляру для атрибутов класса.

module HairColors
  mattr_accessor :hair_colors
end

class Person
  include HairColors
end

Person.hair_colors = [:brown, :black, :blonde, :red]
Person.hair_colors     # => [:brown, :black, :blonde, :red]
Person.new.hair_colors # => [:brown, :black, :blonde, :red]

Если подкласс изменяет значение, это также изменит значение для родительского класса. Аналогично, если родительский класс изменяет значение, это также изменит значение для подклассов.

class Male < Person
end

Male.hair_colors << :blue
Person.hair_colors # => [:brown, :black, :blonde, :red, :blue]

Чтобы отказаться от метода записи экземпляра, передайте instance_writer: false. Чтобы отказаться от метода чтения экземпляра, передайте instance_reader: false.

module HairColors
  mattr_accessor :hair_colors, instance_writer: false, instance_reader: false
end

class Person
  include HairColors
end

Person.new.hair_colors = [:brown]  # => NoMethodError
Person.new.hair_colors             # => NoMethodError

Или передайте instance_accessor: false, чтобы отказаться от обоих методов экземпляра.

module HairColors
  mattr_accessor :hair_colors, instance_accessor: false
end

class Person
  include HairColors
end

Person.new.hair_colors = [:brown]  # => NoMethodError
Person.new.hair_colors             # => NoMethodError

Также можно передать блок для задания атрибута со значением по умолчанию.

module HairColors
  mattr_accessor :hair_colors do
    [:brown, :black, :blonde, :red]
  end
end

class Person
  include HairColors
end

Person.class_variable_get("@@hair_colors") #=> [:brown, :black, :blonde, :red]
Также псевдоним для: cattr_accessor
mattr_reader(*syms) { || ... } Показать исходный код
# File activesupport/lib/active_support/core_ext/module/attribute_accessors.rb, line 53
  def mattr_reader(*syms)
    options = syms.extract_options!
    syms.each do |sym|
      raise NameError.new("invalid attribute name: #{sym}") unless sym =~ /^[_A-Za-z]\w*$/
      class_eval("        @@#{sym} = nil unless defined? @@#{sym}

        def self.#{sym}
          @@#{sym}
        end
", __FILE__, __LINE__ + 1)

      unless options[:instance_reader] == false || options[:instance_accessor] == false
        class_eval("          def #{sym}
            @@#{sym}
          end
", __FILE__, __LINE__ + 1)
      end
      class_variable_set("@@#{sym}", yield) if block_given?
    end
  end

Определяет атрибут класса и создаёт методы чтения для класса и экземпляра. Базовая переменная класса устанавливается в nil, если она не была ранее определена.

module HairColors
  mattr_reader :hair_colors
end

HairColors.hair_colors # => nil
HairColors.class_variable_set("@@hair_colors", [:brown, :black])
HairColors.hair_colors # => [:brown, :black]

Имя атрибута должно быть допустимым именем метода в Ruby.

module Foo
  mattr_reader :"1_Badname "
end
# => NameError: invalid attribute name

Если вы хотите отказаться от создания метода чтения экземпляра, передайте instance_reader: false или instance_accessor: false.

module HairColors
  mattr_writer :hair_colors, instance_reader: false
end

class Person
  include HairColors
end

Person.new.hair_colors # => NoMethodError

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

module HairColors
  cattr_reader :hair_colors do
    [:brown, :black, :blonde, :red]
  end
end

class Person
  include HairColors
end

Person.hair_colors # => [:brown, :black, :blonde, :red]
Также псевдоним для: cattr_reader
mattr_writer(*syms) { || ... } Показать исходный код
# File activesupport/lib/active_support/core_ext/module/attribute_accessors.rb, line 119
  def mattr_writer(*syms)
    options = syms.extract_options!
    syms.each do |sym|
      raise NameError.new("invalid attribute name: #{sym}") unless sym =~ /^[_A-Za-z]\w*$/
      class_eval("        @@#{sym} = nil unless defined? @@#{sym}

        def self.#{sym}=(obj)
          @@#{sym} = obj
        end
", __FILE__, __LINE__ + 1)

      unless options[:instance_writer] == false || options[:instance_accessor] == false
        class_eval("          def #{sym}=(obj)
            @@#{sym} = obj
          end
", __FILE__, __LINE__ + 1)
      end
      send("#{sym}=", yield) if block_given?
    end
  end

Определяет атрибут класса и создаёт методы записи для класса и экземпляра для присваивания атрибута.

module HairColors
  mattr_writer :hair_colors
end

class Person
  include HairColors
end

HairColors.hair_colors = [:brown, :black]
Person.class_variable_get("@@hair_colors") # => [:brown, :black]
Person.new.hair_colors = [:blonde, :red]
HairColors.class_variable_get("@@hair_colors") # => [:blonde, :red]

Если вы хотите отказаться от метода записи экземпляра, передайте instance_writer: false или instance_accessor: false.

module HairColors
  mattr_writer :hair_colors, instance_writer: false
end

class Person
  include HairColors
end

Person.new.hair_colors = [:blonde, :red] # => NoMethodError

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

class HairColors
  mattr_writer :hair_colors do
    [:brown, :black, :blonde, :red]
  end
end

class Person
  include HairColors
end

Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red]
Также псевдоним для: cattr_writer
parent() Показать исходный код
# File activesupport/lib/active_support/core_ext/module/introspection.rb, line 30
def parent
  parent_name ? ActiveSupport::Inflector.constantize(parent_name) : Object
end

Возвращает модуль, который содержит этот модуль в соответствии с его именем.

module M
  module N
  end
end
X = M::N

M::N.parent # => M
X.parent    # => M

Родительским модулем для модулей верхнего уровня и анонимных модулей является Object.

M.parent          # => Object
Module.new.parent # => Object
parent_name() Показать исходный код
# File activesupport/lib/active_support/core_ext/module/introspection.rb, line 7
def parent_name
  if defined? @parent_name
    @parent_name
  else
    @parent_name = name =~ /::[^:]+\Z/ ? $`.freeze : nil
  end
end

Возвращает имя модуля, содержащего данный модуль.

M::N.parent_name # => "M"
parents() Показать исходный код
# File activesupport/lib/active_support/core_ext/module/introspection.rb, line 46
def parents
  parents = []
  if parent_name
    parts = parent_name.split('::')
    until parts.empty?
      parents << ActiveSupport::Inflector.constantize(parts * '::')
      parts.pop
    end
  end
  parents << Object unless parents.include? Object
  parents
end

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

module M
  module N
  end
end
X = M::N

M.parents    # => [Object]
M::N.parents # => [M, Object]
X.parents    # => [M, Object]
qualified_const_defined?(path, search_parents=true) Показать исходный код
# File activesupport/lib/active_support/core_ext/module/qualified_const.rb, line 26
def qualified_const_defined?(path, search_parents=true)
  QualifiedConstUtils.raise_if_absolute(path)

  QualifiedConstUtils.names(path).inject(self) do |mod, name|
    return unless mod.const_defined?(name, search_parents)
    mod.const_get(name)
  end
  return true
end
qualified_const_get(path) Показать исходный код
# File activesupport/lib/active_support/core_ext/module/qualified_const.rb, line 36
def qualified_const_get(path)
  QualifiedConstUtils.raise_if_absolute(path)

  QualifiedConstUtils.names(path).inject(self) do |mod, name|
    mod.const_get(name)
  end
end
qualified_const_set(path, value) Показать исходный код
# File activesupport/lib/active_support/core_ext/module/qualified_const.rb, line 44
def qualified_const_set(path, value)
  QualifiedConstUtils.raise_if_absolute(path)

  const_name = path.demodulize
  mod_name = path.deconstantize
  mod = mod_name.empty? ? self : qualified_const_get(mod_name)
  mod.const_set(const_name, value)
end
redefine_method(method, &block) Показать исходный код
# File activesupport/lib/active_support/core_ext/module/remove_method.rb, line 8
def redefine_method(method, &block)
  remove_possible_method(method)
  define_method(method, &block)
end
remove_possible_method(method) Показать исходный код
# File activesupport/lib/active_support/core_ext/module/remove_method.rb, line 2
def remove_possible_method(method)
  if method_defined?(method) || private_method_defined?(method)
    undef_method(method)
  end
end

© 2004–2018 David Heinemeier Hansson
Licensed under the MIT License.

Spec-Zone.ru

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