lib/alba/resource.rb in alba-2.0.1 vs lib/alba/resource.rb in alba-2.1.0
- old
+ new
@@ -39,11 +39,10 @@
# @param within [Object, nil, false, true] determines what associations to be serialized. If not set, it serializes all associations.
def initialize(object, params: {}, within: WITHIN_DEFAULT)
@object = object
@params = params
@within = within
- @method_existence = {} # Cache for `respond_to?` result
DSLS.each_key { |name| instance_variable_set("@#{name}", self.class.__send__(name)) }
end
# Serialize object into JSON string
#
@@ -147,20 +146,20 @@
k = collection? ? _key_for_collection : _key
transforming_root_key? ? transform_key(k) : k
end
def _key_for_collection
- if Alba.inferring
+ if Alba.inflector
@_key_for_collection == true ? resource_name(pluralized: true) : @_key_for_collection.to_s
else
@_key_for_collection == true ? raise_root_key_inference_error : @_key_for_collection.to_s
end
end
# @return [String]
def _key
- if Alba.inferring
+ if Alba.inflector
@_key == true ? resource_name(pluralized: false) : @_key.to_s
else
@_key == true ? raise_root_key_inference_error : @_key.to_s
end
end
@@ -172,100 +171,108 @@
underscore_name = inflector.underscore(name)
pluralized ? inflector.pluralize(underscore_name) : underscore_name
end
def raise_root_key_inference_error
- raise Alba::Error, 'You must call Alba.enable_inference! to set root_key to true for inferring root key.'
+ raise Alba::Error, 'You must set inflector when setting root key as true.'
end
def transforming_root_key?
@_transforming_root_key
end
def converter
- lambda do |object|
- attributes_to_hash(object, {})
+ lambda do |obj|
+ attributes_to_hash(obj, {})
end
end
def collection_converter
- lambda do |object, a|
+ lambda do |obj, a|
a << {}
h = a.last
- attributes_to_hash(object, h)
+ attributes_to_hash(obj, h)
a
end
end
- def attributes_to_hash(object, hash)
+ def attributes_to_hash(obj, hash)
attributes.each do |key, attribute|
- set_key_and_attribute_body_from(object, key, attribute, hash)
+ set_key_and_attribute_body_from(obj, key, attribute, hash)
rescue ::Alba::Error, FrozenError, TypeError
raise
rescue StandardError => e
- handle_error(e, object, key, attribute, hash)
+ handle_error(e, obj, key, attribute, hash)
end
hash
end
# This is default behavior for getting attributes for serialization
# Override this method to filter certain attributes
def attributes
@_attributes
end
- def set_key_and_attribute_body_from(object, key, attribute, hash)
+ # Default implementation for selecting attributes
+ # Override this method to filter attributes based on key and value
+ def select(_key, _value)
+ true
+ end
+
+ def set_key_and_attribute_body_from(obj, key, attribute, hash)
key = transform_key(key)
- value = fetch_attribute(object, key, attribute)
+ value = fetch_attribute(obj, key, attribute)
+ return unless select(key, value)
+
hash[key] = value unless value == Alba::REMOVE_KEY
end
- def handle_error(error, object, key, attribute, hash)
+ def handle_error(error, obj, key, attribute, hash)
on_error = @_on_error || :raise
case on_error # rubocop:disable Style/MissingElse
when :raise, nil then raise(error)
when :nullify then hash[key] = nil
when :ignore then nil
when Proc
- key, value = on_error.call(error, object, key, attribute, self.class)
+ key, value = on_error.call(error, obj, key, attribute, self.class)
hash[key] = value
end
end
# @return [Symbol]
def transform_key(key) # rubocop:disable Metrics/CyclomaticComplexity
key = key.to_s
return key if @_transform_type == :none || key.empty? # We can skip transformation
inflector = Alba.inflector
- raise Alba::Error, 'Inflector is nil. You can set inflector with `Alba.enable_inference!(with: :active_support)` for example.' unless inflector
+ raise Alba::Error, 'Inflector is nil. You must set inflector before transforming keys.' unless inflector
case @_transform_type # rubocop:disable Style/MissingElse
when :camel then inflector.camelize(key)
when :lower_camel then inflector.camelize_lower(key)
when :dash then inflector.dasherize(key)
when :snake then inflector.underscore(key)
end
end
- def fetch_attribute(object, key, attribute) # rubocop:disable Metrics/CyclomaticComplexity
+ def fetch_attribute(obj, key, attribute) # rubocop:disable Metrics/CyclomaticComplexity
value = case attribute
- when Symbol then fetch_attribute_from_object_and_resource(object, attribute)
- when Proc then instance_exec(object, &attribute)
- when Alba::Association then yield_if_within(attribute.name.to_sym) { |within| attribute.to_h(object, params: params, within: within) }
- when TypedAttribute, NestedAttribute then attribute.value(object)
- when ConditionalAttribute then attribute.with_passing_condition(resource: self, object: object) { |attr| fetch_attribute(object, key, attr) }
+ when Symbol then fetch_attribute_from_object_and_resource(obj, attribute)
+ when Proc then instance_exec(obj, &attribute)
+ when Alba::Association then yield_if_within(attribute.name.to_sym) { |within| attribute.to_h(obj, params: params, within: within) }
+ when TypedAttribute, NestedAttribute then attribute.value(obj)
+ when ConditionalAttribute then attribute.with_passing_condition(resource: self, object: obj) { |attr| fetch_attribute(obj, key, attr) }
else
raise ::Alba::Error, "Unsupported type of attribute: #{attribute.class}"
end
- value.nil? && nil_handler ? instance_exec(object, key, attribute, &nil_handler) : value
+ value.nil? && nil_handler ? instance_exec(obj, key, attribute, &nil_handler) : value
end
- def fetch_attribute_from_object_and_resource(object, attribute)
- has_method = @method_existence[attribute]
- has_method = @method_existence[attribute] = object.respond_to?(attribute) if has_method.nil?
- has_method ? object.__send__(attribute) : __send__(attribute, object)
+ def fetch_attribute_from_object_and_resource(obj, attribute)
+ obj.__send__(attribute)
+ rescue NoMethodError
+ __send__(attribute, obj)
end
def nil_handler
@_on_nil
end
@@ -311,10 +318,10 @@
# @param attrs [Array<String, Symbol>]
# @param if [Proc] condition to decide if it should serialize these attributes
# @param attrs_with_types [Hash<[Symbol, String], [Array<Symbol, Proc>, Symbol]>]
# attributes with name in its key and type and optional type converter in its value
# @return [void]
- def attributes(*attrs, if: nil, **attrs_with_types) # rubocop:disable Naming/MethodParameterName
+ def attributes(*attrs, if: nil, **attrs_with_types)
if_value = binding.local_variable_get(:if)
assign_attributes(attrs, if_value)
assign_attributes_with_types(attrs_with_types, if_value)
end