module Rails::Decorators::Decorator

Public Class Methods

decorate(*targets, &module_definition) click to toggle source
# File lib/rails/decorators/decorator.rb, line 14
      def self.decorate(*targets, &module_definition)
        options = targets.extract_options!

        targets.each do |target|
          unless target.is_a?(Class)
            raise(
              InvalidDecorator,
              <<-eos.strip_heredoc

                Problem:
                  You cannot decorate a Module
                Summary:
                  Decoration only works with classes. Decorating modules requires
                  managing load order, a problem that is very complicated and
                  beyond the scope of this system.
                Resolution:
                  Decorate multiple classes that include the module like so:
                  `decorate Catalog::Product, Content::Page do`
              eos
            )
          end

          if target.name.to_s.end_with?('Helper')
            raise(
              InvalidDecorator,
              <<-eos.strip_heredoc

                Problem:
                  Rails::Decorators doesn't work with helpers.
                Summary:
                  Rails does some magic with helpers which in certain cases
                  causes decoration to not work.
                Resolution:
                  Create a new helper and in a `to_prepare` block, use
                  ActionPack's `helper` method to include the helper, e.g.
                  `MyEngine::ApplicationController.helper(MyEngine::BlogsHelper)`
              eos
            )
          end

          namespace = target.to_s.remove('::')
          decorator_name = "#{options[:with].to_s.camelize}#{namespace}Decorator"

          if target.const_defined?(decorator_name)
            # We are probably reloading in Rails development env if this happens
            next if !Rails.application.config.cache_classes

            raise(
              InvalidDecorator,
              <<-eos.strip_heredoc

                Problem:
                  #{decorator_name} is already defined in #{target.name}.
                Summary:
                  When decorating a class, Rails::Decorators dynamically defines
                  a module for prepending the decorations passed in the block. In
                  this case, the name for the decoration module is already defined
                  in the namespace, so decorating would redefine the constant.
                Resolution:
                  Please specify a unique `with` option when decorating #{target.name}.
              eos
            )
          end

          mod = Module.new do
            extend Rails::Decorators::Decorator
            module_eval(&module_definition)
          end

          target.const_set(decorator_name, mod)
          mod.decorates(target)
        end
      end
loader(roots) click to toggle source
# File lib/rails/decorators/decorator.rb, line 4
def self.loader(roots)
  Proc.new do
    roots.each do |root|
      decorators = Dir.glob("#{root}/app/**/*.#{Rails::Decorators.extension}")
      decorators.sort!
      decorators.each { |d| require_dependency(d) }
    end
  end
end

Public Instance Methods

before_decorate(&block) click to toggle source
# File lib/rails/decorators/decorator.rb, line 106
def before_decorate(&block)
  instance_variable_set(:@_before_decorate_block, block)
end
class_methods(&class_methods_module_definition) click to toggle source
# File lib/rails/decorators/decorator.rb, line 114
def class_methods(&class_methods_module_definition)
  mod = const_set(:ClassMethodsDecorator, Module.new)
  mod.module_eval(&class_methods_module_definition)
end
Also aliased as: module_methods
decorated(&block) click to toggle source
# File lib/rails/decorators/decorator.rb, line 110
def decorated(&block)
  instance_variable_set(:@_decorated_block, block)
end
decorates(klass) click to toggle source
# File lib/rails/decorators/decorator.rb, line 120
def decorates(klass)
  klass.send(:prepend, self)
end
module_methods(&class_methods_module_definition)
Alias for: class_methods
prepend_features(base) click to toggle source
Calls superclass method
# File lib/rails/decorators/decorator.rb, line 88
def prepend_features(base)
  if instance_variable_defined?(:@_before_decorate_block)
    base.class_eval(&@_before_decorate_block)
  end

  super

  if const_defined?(:ClassMethodsDecorator)
    base
      .singleton_class
      .send(:prepend, const_get(:ClassMethodsDecorator))
  end

  if instance_variable_defined?(:@_decorated_block)
    base.class_eval(&@_decorated_block)
  end
end