Class: Azeroth::Decorator

Inherits:
Object
  • Object
show all
Defined in:
lib/azeroth/decorator.rb,
lib/azeroth/decorator/options.rb,
lib/azeroth/decorator/hash_builder.rb,
lib/azeroth/decorator/method_builder.rb,
lib/azeroth/decorator/key_value_extractor.rb

Overview

Class to be used when decorating outputs

Examples:

class DummyModel
  include ActiveModel::Model

  attr_accessor :id, :first_name, :last_name, :age,
                :favorite_pokemon

  class Decorator < Azeroth::Decorator
    expose :name
    expose :age
    expose :favorite_pokemon, as: :pokemon

    def name
      [object.first_name, object.last_name].join(' ')
    end
  end
end

model = DummyModel.new(
  id: 100,
  first_name: 'John',
  last_name: 'Wick',
  favorite_pokemon: 'Arcanine'
)

decorator = DummyModel::Decorator.new(model)

decorator.as_json # returns {
                  #   'name'    => 'John Wick',
                  #   'age'     => nil,
                  #   'pokemon' => 'Arcanine'
                  # }

Defined Under Namespace

Classes: HashBuilder, KeyValueExtractor, MethodBuilder, Options

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(object) ⇒ Decorator #initialize(array) ⇒ Decorator

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a new instance of Decorator.

Overloads:

  • #initialize(object) ⇒ Decorator

    Parameters:

    • object (Object)

      to be decorated

  • #initialize(array) ⇒ Decorator

    Parameters:

    • array (Array)

      array of objects to be decorated



244
245
246
# File 'lib/azeroth/decorator.rb', line 244

def initialize(object)
  @object = object
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_name, *args) ⇒ Object (private)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Method called when method is missing

This delegates method calls to the given object

Parameters:

  • method_name (Symbol)

    name of the method called

  • args (Array<Object>)

    arguments of the method called

Returns:

  • (Object)


310
311
312
313
314
315
316
# File 'lib/azeroth/decorator.rb', line 310

def method_missing(method_name, *args)
  if object.respond_to?(method_name)
    object.public_send(method_name, *args)
  else
    super
  end
end

Class Method Details

.attributes_mapHash<Symbol,Hash>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

All attributes exposed

Returns:

  • (Hash<Symbol,Hash>)


54
55
56
# File 'lib/azeroth/decorator.rb', line 54

def attributes_map
  @attributes_map ||= build_attributes_map
end

.expose(attribute, **options_hash) ⇒ Array<Symbol>

Expose attributes on json decorated

Examples:

class DummyModel
  include ActiveModel::Model

  attr_accessor :id, :first_name, :last_name, :age,
                :favorite_pokemon

  class Decorator < Azeroth::Decorator
    expose :name
    expose :age
    expose :favorite_pokemon, as: :pokemon

    def name
      [object.first_name, object.last_name].join(' ')
    end
  end
end

With relations

# pokemon/decorator.rb

class Pokemon::Decorator < Azeroth::Decorator
  expose :name
  expose :previous_form_name, as: :evolution_of, if: :evolution?

  def evolution?
    previous_form
  end

  def previous_form_name
    previous_form.name
  end
end

# pokemon/favorite_decorator.rb

class Pokemon::FavoriteDecorator < Pokemon::Decorator
  expose :nickname
end

# pokemon_master/decorator.rb

class PokemonMaster < ActiveRecord::Base
  has_one :favorite_pokemon, -> { where(favorite: true) },
          class_name: 'Pokemon'
  has_many :pokemons
end

# pokemon.rb

class Pokemon < ActiveRecord::Base
  belongs_to :pokemon_master
  has_one :previous_form,
          class_name: 'Pokemon',
          foreign_key: :previous_form_id
end

# pokemon_master.rb

class PokemonMaster::Decorator < Azeroth::Decorator
  expose :name
  expose :age
  expose :favorite_pokemon, decorator: Pokemon::FavoriteDecorator
  expose :pokemons

  def name
    [
      first_name,
      last_name
    ].compact.join(' ')
  end
end

# schema.rb

ActiveRecord::Schema.define do
  self.verbose = false

   create_table :pokemon_masters, force: true do |t|
    t.string :first_name, null: false
    t.string :last_name
    t.integer :age, null: false
  end

  create_table :pokemons, force: true do |t|
    t.string :name, null: false
    t.string :nickname
    t.integer :pokemon_master_id
    t.boolean :favorite
    t.integer :previous_form_id
    t.index %i[pokemon_master_id favorite], unique: true
  end

  add_foreign_key 'pokemons', 'pokemon_masters'
end

# test.rb

master = PokemonMaster.create(
  first_name: 'Ash',
  last_name: 'Ketchum',
  age: 10
)

master.create_favorite_pokemon(
  name: 'pikachu',
  nickname: 'Pikachu'
)

metapod = Pokemon.create(name: :metapod)

master.pokemons.create(
  name: 'butterfree', previous_form: metapod
)
master.pokemons.create(name: 'squirtle')

decorator = PokemonMaster::Decorator.new(master)

decorator.as_json
# returns
# {
#   'age' => 10,
#   'name' => 'Ash Ketchum',
#   'favorite_pokemon' => {
#     'name' => 'pikachu',
#     'nickname' => 'Pikachu'
#   },
#   'pokemons' => [{
#     'name' => 'butterfree',
#     'evolution_of' => 'metapod'
#   }, {
#     'name' => 'squirtle'
#   }, {
#     'name' => 'pikachu'
#   }]
# }

Parameters:

  • attribute (Symbol, String)

    attribute to be exposed

  • options_hash (Hash)

    exposing options

Options Hash (**options_hash):

  • as (Symbol, String)

    custom key to expose

  • if (Symbol, Proc)

    method/block to be called checking if an attribute should or should not be exposed

  • decorator (FalseClass, TrueClass, Class)

    flag to use or not a decorator or decorator class to be used

Returns:

  • (Array<Symbol>)


229
230
231
232
233
234
235
# File 'lib/azeroth/decorator.rb', line 229

def expose(attribute, **options_hash)
  options = Decorator::Options.new(options_hash)

  MethodBuilder.build_reader(self, attribute)

  attributes_map[attribute] = options
end

Instance Method Details

#as_json(*args) ⇒ Hash

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Builds hash / Json from the given object

When object is an iterator, decoration is applied to each and an array is returned

Parameters:

  • args (Hash)

    options (to be implemented)

Returns:

  • (Hash)


258
259
260
261
262
263
264
# File 'lib/azeroth/decorator.rb', line 258

def as_json(*args)
  return nil if object.nil?

  return array_as_json(*args) if enum?

  HashBuilder.new(self).as_json
end