module Roar::JSON::JSONAPI::Declarative

Declarative API for JSON API Representers.

@since 0.1.0

Public Instance Methods

attributes(&block) click to toggle source

Define attributes for this resource.

@example

attributes do
  property :name
end

@param [#call] block

@see jsonapi.org/format/#document-resource-object-attributes @api public

# File lib/roar/json/json_api/declarative.rb, line 36
def attributes(&block)
  nested(:attributes, inherit: true, &block)
end
has_many(name, options = {}, &block) click to toggle source

Define a to-many relationship for this resource.

@param (see has_one) @option options (see has_one)

@api public

# File lib/roar/json/json_api/declarative.rb, line 129
def has_many(name, options = {}, &block)
  has_relationship(name, options.merge(collection: true), &block)
end
has_one(name, options = {}, &block) click to toggle source
Define a to-one relationship for this resource.

@param [String] name name of the relationship @option options [Class,Module,Proc] :extend Representer to use for parsing or rendering @option options [Proc] :prepare Decorate the represented object @option options [Class,Proc] :class Class to instantiate when parsing nested fragment @option options [Proc] :instance Instantiate object directly when parsing nested fragment @param [#call] block Stuff

@see trailblazer.to/gems/representable/3.0/function-api.html#options @api public

# File lib/roar/json/json_api/declarative.rb, line 119
def has_one(name, options = {}, &block)
  has_relationship(name, options.merge(collection: false), &block)
end
meta(options = {}, &block) click to toggle source

Define meta information.

@example Meta information for a resource

meta do
  collection :reviewers
end

@example Top-level meta information

meta toplevel: true do
  property :copyright
end

@param (see Meta::ClassMethods#meta) @option options [Boolean] :toplevel place meta information at top-level of document.

@see Meta::ClassMethods#meta @see jsonapi.org/format/#document-meta @api public

Calls superclass method
# File lib/roar/json/json_api/declarative.rb, line 83
def meta(options = {}, &block)
  return super(&block) unless options[:toplevel]
  for_collection.meta(&block)
end
relationship(&block) click to toggle source

Define links and meta information for a given relationship.

@example

has_one :author, extend: AuthorDecorator do
  relationship do
    link(:self)     { "/articles/#{represented.id}/relationships/author" }
    link(:related)  { "/articles/#{represented.id}/author" }
  end
end

@param [#call] block

@api public

# File lib/roar/json/json_api/declarative.rb, line 101
def relationship(&block)
  return (@relationship ||= -> {}) unless block

  heritage.record(:relationship, &block)
  @relationship = block
end
type(name = nil) click to toggle source

Defjne a type for this resource.

@example

type :articles

@param [Symbol, String] name type name of this resource @return [String] type name of this resource

@see jsonapi.org/format/#document-resource-object-identification @api public

# File lib/roar/json/json_api/declarative.rb, line 18
def type(name = nil)
  return @type unless name # original name.

  heritage.record(:type, name)
  @type = name.to_s
end

Private Instance Methods

has_relationship(name, options = {}, &block) click to toggle source
# File lib/roar/json/json_api/declarative.rb, line 135
def has_relationship(name, options = {}, &block)
  resource_decorator = options[:decorator] || options[:extends] ||
                       Class.new(Roar::Decorator).tap { |decorator|
                         decorator.send(:include, JSONAPI::Resource.new(
                                                    name,
                                                    id_key: options.fetch(:id_key, :id)
                         ))
                       }
  resource_decorator.instance_exec(&block) if block

  resource_identifier_representer = Class.new(resource_decorator)
  resource_identifier_representer.class_eval do
    def to_hash(_options = {})
      super(fields: { self.class.type.to_sym => [] }, include: [], wrap: false)
    end
  end

  nested(:included, inherit: true) do
    property(name, collection: options[:collection],
                   decorator:  resource_decorator,
                   wrap:       false)
  end

  nested(:relationships, inherit: true) do
    nested(:"#{name}_relationship", as: MemberName.(name)) do
      property name, options.merge(as:           :data,
                                   getter:       ->(opts) {
                                     object = opts[:binding].send(:exec_context, opts)
                                     value  = object.public_send(opts[:binding].getter)
                                     # do not blow up on nil collections
                                     if options[:collection] && value.nil?
                                       []
                                     else
                                       value
                                     end
                                   },
                                   render_nil:   true,
                                   render_empty: true,
                                   decorator:    resource_identifier_representer,
                                   wrap:         false)

      instance_exec(&resource_identifier_representer.relationship)

      # rubocop:disable Lint/NestedMethodDefinition
      def to_hash(*)
        hash  = super
        links = Renderer::Links.new.(hash, {})
        meta  = render_meta({})

        HashUtils.store_if_any(hash, 'links', links)
        HashUtils.store_if_any(hash, 'meta',  meta)

        hash
      end
      # rubocop:enable Lint/NestedMethodDefinition
    end
  end
end
to_hash(_options = {}) click to toggle source
Calls superclass method
# File lib/roar/json/json_api/declarative.rb, line 147
def to_hash(_options = {})
  super(fields: { self.class.type.to_sym => [] }, include: [], wrap: false)
end