class Module - activesupport-4.2.4 Documentation

# class Module

Extends the module object with class/module and instance accessors for class/module attributes, just like the native attr* accessors for instance attributes.

Extends the API for constants to be able to deal with qualified names. Arguments are assumed to be relative to the receiver.

### Constants

RUBY_RESERVED_WORDS

### Attributes

attr_internal_naming_format[RW]

### Public Instance Methods

alias_attribute(new_name, old_name) click to toggle source

Allows you to make aliases for attributes, which includes getter, setter, and query methods.

    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"

    # File 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

alias_method_chain(target, feature) { |aliased_target, punctuation| ... } click to toggle source

Encapsulates the common pattern of:

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

With this, you simply do:

    alias_method_chain :foo, :feature

And both aliases are set up for you.

Query and bang methods (foo?, foo!) keep the same punctuation:

    alias_method_chain :foo?, :feature

is equivalent to

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

so you can safely chain foo, foo?, foo! and/or foo= with the same feature.

    # File 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

anonymous?() click to toggle source

A module may or may not have a name.

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

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

A module gets a name when it is first assigned to a constant. Either via the `module` or `class` keyword or by an explicit assignment:

    m = Module.new # creates an anonymous module
    M = m          # => m gets a name here as a side-effect
    m.name         # => "M"

    # File lib/active_support/core_ext/module/anonymous.rb, line 16
    def anonymous?
      name.nil?
    end

attr_internal(*attrs)
Alias for: attr_internal_accessor
attr_internal_accessor(*attrs) click to toggle source

Declares an attribute reader and writer backed by an internally-named instance variable.

    # File 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

Also aliased as: attr_internal
attr_internal_reader(*attrs) click to toggle source

Declares an attribute reader backed by an internally-named instance variable.

    # File 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) click to toggle source

Declares an attribute writer backed by an internally-named instance variable.

    # File 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)
Alias for: mattr_accessor
cattr_reader(*syms)
Alias for: mattr_reader
cattr_writer(*syms)
Alias for: mattr_writer
delegate(*methods) click to toggle source

Provides a `delegate` class method to easily expose contained objects' public methods as your own.

#### Options¶ ↑

- `:to` - Specifies the target object

- `:prefix` - Prefixes the new method with the target name or a custom prefix

- `:allow_nil` - if set to true, prevents a `NoMethodError` to be raised

The macro receives one or more method names (specified as symbols or strings) and the name of the target object via the `:to` option (also a symbol or string).

Delegation is particularly useful with Active Record associations:

    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>

Multiple delegates to the same target are allowed:

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

    Foo.new.goodbye # => "goodbye"

Methods can be delegated to instance variables, class variables, or constants by providing them as a symbols:

    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

It's also possible to delegate a method to the class by using `:class`:

    class Foo
      def self.hello
        "world"
      end

      delegate :hello, to: :class
    end

    Foo.new.hello # => "world"

Delegates can optionally be prefixed using the `:prefix` option. If the value is `true`, the delegate methods are prefixed with the name of the object being delegated to.

    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"

It is also possible to supply a custom prefix.

    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'

If the target is `nil` and does not respond to the delegated method a `NoMethodError` is raised, as with any other value. Sometimes, however, it makes sense to be robust to that situation and that is the purpose of the `:allow_nil` option: If the target is not `nil`, or it is and responds to the method, everything works as usual. But if it is `nil` and does not respond to the delegated method, `nil` is returned.

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

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

But if not having a profile yet is fine and should not be an error condition:

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

    User.new.age # nil

Note that if the target is not `nil` then the call is attempted regardless of the `:allow_nil` option, and thus an exception is still raised if said object does not respond to the method:

    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'

The target method must be public, otherwise it will raise `NoMethodError`.

    # File 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

deprecate(*method_names) click to toggle source

    deprecate :foo
    deprecate bar: 'message'
    deprecate :foo, :bar, baz: 'warning!', qux: 'gone!'

You can also use custom deprecator instance:

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

Custom deprecators must respond to `deprecation_warning(deprecated_method_name, message, caller_backtrace)` method where you can implement your custom warning behavior.

    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

    # File lib/active_support/core_ext/module/deprecation.rb, line 20
    def deprecate(*method_names)
      ActiveSupport::Deprecation.deprecate_methods(self, *method_names)
    end

foo() click to toggle source

    # File lib/active_support/core_ext/module/method_transplanting.rb, line 5
    def foo; end

mattr_accessor(*syms, &blk) click to toggle source

Defines both class and instance accessors for class attributes.

    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]

If a subclass changes the value then that would also change the value for parent class. Similarly if parent class changes the value then that would change the value of subclasses too.

    class Male < Person
    end

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

To opt out of the instance writer method, pass `instance_writer: false`. To opt out of the instance reader method, pass `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

Or pass `instance_accessor: false`, to opt out both instance methods.

    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

Also you can pass a block to set up the attribute with a default value.

    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]

    # File 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

Also aliased as: cattr_accessor
mattr_reader(*syms) { || ... } click to toggle source

Defines a class attribute and creates a class and instance reader methods. The underlying the class variable is set to `nil`, if it is not previously defined.

    module HairColors
      mattr_reader :hair_colors
    end

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

The attribute name must be a valid method name in Ruby.

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

If you want to opt out the creation on the instance reader method, pass `instance_reader: false` or `instance_accessor: false`.

    module HairColors
      mattr_writer :hair_colors, instance_reader: false
    end

    class Person
      include HairColors
    end

    Person.new.hair_colors # => NoMethodError

Also, you can pass a block to set up the attribute with a default value.

    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]

    # File 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

Also aliased as: cattr_reader
mattr_writer(*syms) { || ... } click to toggle source

Defines a class attribute and creates a class and instance writer methods to allow assignment to the attribute.

    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]

If you want to opt out the instance writer method, pass `instance_writer: false` or `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

Also, you can pass a block to set up the attribute with a default value.

    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]

    # File 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

Also aliased as: cattr_writer
parent() click to toggle source

Returns the module which contains this one according to its name.

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

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

The parent of top-level and anonymous modules is Object.

    M.parent          # => Object
    Module.new.parent # => Object

    # File lib/active_support/core_ext/module/introspection.rb, line 30
    def parent
      parent_name ? ActiveSupport::Inflector.constantize(parent_name) : Object
    end

parent_name() click to toggle source

Returns the name of the module containing this one.

    M::N.parent_name # => "M"

    # File 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

parents() click to toggle source

Returns all the parents of this module according to its name, ordered from nested outwards. The receiver is not contained within the result.

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

    M.parents    # => [Object]
    M::N.parents # => [M, Object]
    X.parents    # => [M, Object]

    # File 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

qualified_const_defined?(path, search_parents=true) click to toggle source

    # File 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) click to toggle source

    # File 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) click to toggle source

    # File 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) click to toggle source

    # File 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) click to toggle source

    # File 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

### Private Instance Methods

attr_internal_define(attr_name, type) click to toggle source

    # File lib/active_support/core_ext/module/attr_internal.rb, line 28
    def attr_internal_define(attr_name, type)
      internal_name = attr_internal_ivar_name(attr_name).sub(/\A@/, '')
      # class_eval is necessary on 1.9 or else the methods are made private
      class_eval do
        # use native attr_* methods as they are faster on some Ruby implementations
        send("attr_#{type}", internal_name)
      end
      attr_name, internal_name = "#{attr_name}=", "#{internal_name}=" if type == :writer
      alias_method attr_name, internal_name
      remove_method internal_name
    end

attr_internal_ivar_name(attr) click to toggle source

    # File lib/active_support/core_ext/module/attr_internal.rb, line 24
    def attr_internal_ivar_name(attr)
      Module.attr_internal_naming_format % attr
    end