lib/grape_entity/exposure/base.rb
# frozen_string_literal: true
require 'active_support'
require 'active_support/core_ext'
module Grape
class Entity
module Exposure
class Base
attr_reader :attribute, :is_safe, :documentation, :override, :conditions, :for_merge
def self.new(attribute, options, conditions, ...)
super(attribute, options, conditions).tap { |e| e.setup(...) }
end
def initialize(attribute, options, conditions)
@attribute = attribute.try(:to_sym)
@options = options
key = options[:as] || attribute
@key = key.respond_to?(:to_sym) ? key.to_sym : key
@is_safe = options[:safe]
@default_value = options[:default]
@for_merge = options[:merge]
@attr_path_proc = options[:attr_path]
@documentation = options[:documentation]
@override = options[:override]
@conditions = conditions
end
def dup(&block)
self.class.new(*dup_args, &block)
end
def dup_args
[@attribute, @options, @conditions.map(&:dup)]
end
def ==(other)
self.class == other.class &&
@attribute == other.attribute &&
@options == other.options &&
@conditions == other.conditions
end
def setup; end
def nesting?
false
end
# if we have any nesting exposures with the same name.
def deep_complex_nesting?(entity) # rubocop:disable Lint/UnusedMethodArgument
false
end
def valid?(entity)
is_delegatable = entity.delegator.delegatable?(@attribute) || entity.respond_to?(@attribute, true)
if @is_safe
is_delegatable
else
is_delegatable || raise(
NoMethodError,
"#{entity.class.name} missing attribute `#{@attribute}' on #{entity.object}"
)
end
end
def value(_entity, _options)
raise NotImplementedError
end
def serializable_value(entity, options)
partial_output = valid_value(entity, options)
if partial_output.respond_to?(:serializable_hash)
partial_output.serializable_hash
elsif partial_output.is_a?(Array) && partial_output.all? { |o| o.respond_to?(:serializable_hash) }
partial_output.map(&:serializable_hash)
elsif partial_output.is_a?(Hash)
partial_output.each do |key, value|
partial_output[key] = value.serializable_hash if value.respond_to?(:serializable_hash)
end
else
partial_output
end
end
def valid_value(entity, options)
return unless valid?(entity)
output = value(entity, options)
output.blank? && !@default_value.nil? ? @default_value : output
end
def should_return_key?(options)
options.should_return_key?(@key)
end
def conditional?
!@conditions.empty?
end
def conditions_met?(entity, options)
@conditions.all? { |condition| condition.met? entity, options }
end
def should_expose?(entity, options)
should_return_key?(options) && conditions_met?(entity, options)
end
def attr_path(entity, options)
if @attr_path_proc
entity.exec_with_object(options, &@attr_path_proc)
else
@key
end
end
def key(entity = nil)
@key.respond_to?(:call) ? entity.exec_with_object(@options, &@key) : @key
end
def with_attr_path(entity, options, &block)
path_part = attr_path(entity, options)
options.with_attr_path(path_part, &block)
end
def override?
@override
end
protected
attr_reader :options
end
end
end
end