Module: TinyDecorator::CompositeDecorator

Defined in:
lib/tiny_decorator/composite_decorator.rb

Overview

Passing only decorator name, object will be decorated

“‘

extend TinyDecorator::CompositeDecorator
decorated_by :default, 'DefaultDecorator'

“‘

Passing only 1 block param to #decorated_by Execute block to get decorator name. “‘

extend TinyDecorator::CompositeDecorator
decorated_by :default, ->(record) { record.nil? ? 'NilDecorator' : 'DefaultDecorator' }
decorated_by :default, ->(record, context) { record.in(context).nil? ? 'NilDecorator' : 'DefaultDecorator' }

“‘

Passing decorator name and 1 block param to #decorated_by Execute block to determine should we decorate it or not “‘

extend TinyDecorator::CompositeDecorator
decorated_by :default, ->(record) { record.valid? ? 'ValidDecorator' : 'InvalidDecorator' }
decorated_by :default, ->(record, context) { record.in(context).valid? ? 'ValidDecorator' : 'InvalidDecorator' }

“‘

For now, :name is redundant, but it’s nice to have a friendly name for readbility and later usage

Block may receive

1 parameter is record to decorate OR
2 parameters are record to decorate and context

CompositeDecorator introduces a central conditional decorator manager. It answer the questions: which decorater will be used in which conditions. The decorator is a sub class of TinyDecorator::BaseDelegator (or draper decorator, but not recommend) TinyDecorator::BaseDelegator will answer the question which attributes are decorated.

In case we don’t have eager loading or rails’ eager loading doesn’t match,

preload block could be used to manually load data to avoid N+1.
Then access through 3rd param of decorator

“‘ruby

preload :count_all, ->(all_records, context, preloaded) { Group(all_records).count }

“‘

all_records - all the records to decorate
context     - The context passed to collection decorating,
  because preload run once before all decratings, this is the only cotext we have at this time
preloaded   - all preloaded before. For perfomrance, it's mutable, please handle with care

Instance Method Summary collapse

Instance Method Details

#decorate(record, context = {}, preloaded = {}) ⇒ Object

Decorate an object by defined #decorated_by



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/tiny_decorator/composite_decorator.rb', line 67

def decorate(record, context = {}, preloaded = {})
  if instance_variable_get(:@_contexts)
    context = context.merge(instance_variable_get(:@_contexts).inject({}) do |carry, (context_name, context_block)|
      context[context_name] = context_block.call(record, context)

      carry
    end)
  end

  instance_variable_get(:@_decorators).inject(record) do |carry, (name, value)|
    decorator = decorator_resolver(name, value, record, context)
    if decorator
      carry = begin
        const_get(decorator, false)
      rescue NameError
        Object.const_get(decorator, false)
      end.decorate(carry, context, preloaded)
    end

    carry
  end
end

#decorate_collection(records, context = {}) ⇒ Object

Decorate collection of objects, each object is decorate by #decorate TODO: [AV] It’s greate if with activerecord relationship, we defer decorate until data retrieved.

Using `map` will make data retrieval executes immediately


53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/tiny_decorator/composite_decorator.rb', line 53

def decorate_collection(records, context = {})
  if instance_variable_get(:@_preloaders)
    preloaded = {}
    instance_variable_get(:@_preloaders).each do |preloader, execute_block|
      preloaded[preloader] = execute_block.call(records, context, preloaded)
    end
  end

  Array(records).map do |record|
    decorate(record, context, preloaded)
  end
end