lib/serega/attribute.rb
# frozen_string_literal: true
class Serega
#
# Stores serialized attribute data
#
class SeregaAttribute
#
# Attribute instance methods
#
module AttributeInstanceMethods
# Attribute initial params
# @return [Hash] Attribute initial params
attr_reader :initials
# Attribute name
# @return [Symbol] Attribute name
attr_reader :name
# Attribute :many option
# @return [Boolean, nil] Attribute :many option
attr_reader :many
# Attribute :default option
# @return [Object, nil] Attribute :default option
attr_reader :default
# Attribute :hide option
# @return [Boolean, nil] Attribute :hide option
attr_reader :hide
#
# Initializes new attribute
#
# @param name [Symbol, String] Name of attribute
# @param opts [Hash] Attribute options
# @option opts [Symbol] :method Object method name to fetch attribute value
# @option opts [Hash] :delegate Allows to fetch value from nested object
# @option opts [Boolean] :hide Specify `true` to not serialize this attribute by default
# @option opts [Boolean] :many Specifies has_many relationship. By default is detected via object.is_a?(Enumerable)
# @option opts [Proc, #call] :value Custom block or callable to find attribute value
# @option opts [Serega, Proc] :serializer Relationship serializer class. Use `proc { MySerializer }` if serializers have cross references
# @param block [Proc] Custom block to find attribute value
#
def initialize(name:, opts: {}, block: nil)
serializer_class = self.class.serializer_class
serializer_class::CheckAttributeParams.new(name, opts, block).validate
@initials = SeregaUtils::EnumDeepFreeze.call(
name: name,
opts: SeregaUtils::EnumDeepDup.call(opts),
block: block
)
normalizer = serializer_class::SeregaAttributeNormalizer.new(initials)
set_normalized_vars(normalizer)
end
# Shows whether attribute has specified serializer
# @return [Boolean] Checks if attribute is relationship (if :serializer option exists)
def relation?
!@serializer.nil?
end
# Shows specified serializer class
# @return [Serega, nil] Attribute serializer if exists
def serializer
serializer = @serializer
return serializer if (serializer.is_a?(Class) && (serializer < Serega)) || !serializer
@serializer = serializer.is_a?(String) ? Object.const_get(serializer, false) : serializer.call
end
#
# Finds attribute value
#
# @param object [Object] Serialized object
# @param context [Hash, nil] Serialization context
#
# @return [Object] Serialized attribute value
#
def value(object, context)
value_block.call(object, context)
end
#
# Checks if attribute must be added to serialized response
#
# @param modifiers [Hash] Serialization modifiers
# @option modifiers [Hash] :only The only attributes to serialize
# @option modifiers [Hash] :except Attributes to hide
# @option modifiers [Hash] :with Hidden attributes to serialize additionally
#
# @return [Boolean]
#
def visible?(modifiers)
except = modifiers[:except] || FROZEN_EMPTY_HASH
only = modifiers[:only] || FROZEN_EMPTY_HASH
with = modifiers[:with] || FROZEN_EMPTY_HASH
return false if except.member?(name) && except[name].empty?
return true if only.member?(name)
return true if with.member?(name)
return false unless only.empty?
!hide
end
private
attr_reader :value_block
def set_normalized_vars(normalizer)
@name = normalizer.name
@many = normalizer.many
@default = normalizer.default
@value_block = normalizer.value_block
@hide = normalizer.hide
@serializer = normalizer.serializer
end
end
extend Serega::SeregaHelpers::SerializerClassHelper
include AttributeInstanceMethods
end
end