lib/alba/resource.rb in alba-2.3.0 vs lib/alba/resource.rb in alba-2.4.0

- old
+ new

@@ -9,11 +9,11 @@ module Alba # This module represents what should be serialized module Resource # @!parse include InstanceMethods # @!parse extend ClassMethods - DSLS = {_attributes: {}, _key: nil, _key_for_collection: nil, _meta: nil, _transform_type: :none, _transforming_root_key: false, _key_transformation_cascade: true, _on_error: nil, _on_nil: nil, _layout: nil, _collection_key: nil}.freeze # rubocop:disable Layout/LineLength + DSLS = {_attributes: {}, _key: nil, _key_for_collection: nil, _meta: nil, _transform_type: :none, _transforming_root_key: false, _key_transformation_cascade: true, _on_error: nil, _on_nil: nil, _layout: nil, _collection_key: nil, _helper: nil}.freeze # rubocop:disable Layout/LineLength private_constant :DSLS WITHIN_DEFAULT = Object.new.freeze private_constant :WITHIN_DEFAULT @@ -78,11 +78,11 @@ def to_json(options = {}, root_key: nil, meta: {}) _to_json(root_key, meta, options) end end - # Returns a Hash correspondng {Resource#serialize} + # Returns a Hash correspondng {#serialize} # # @param root_key [Symbol, nil, true] # @param meta [Hash] metadata for this seialization # @return [Hash] def as_json(root_key: nil, meta: {}) @@ -258,22 +258,32 @@ 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 then attribute.value(obj) when NestedAttribute then attribute.value(object: obj, params: params) 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}" + else raise ::Alba::Error, "Unsupported type of attribute: #{attribute.class}" end value.nil? && nil_handler ? instance_exec(obj, key, attribute, &nil_handler) : value end + # TODO: from version 3, `_fetch_attribute_from_resource_first` is default def fetch_attribute_from_object_and_resource(obj, attribute) + _fetch_attribute_from_object_first(obj, attribute) + end + + def _fetch_attribute_from_object_first(obj, attribute) obj.__send__(attribute) rescue NoMethodError __send__(attribute, obj) end + def _fetch_attribute_from_resource_first(obj, attribute) + __send__(attribute, obj) + rescue NoMethodError + obj.__send__(attribute) + end + def nil_handler @_on_nil end def yield_if_within(association_name) @@ -372,12 +382,11 @@ # @return [void] # @see Alba::Association#initialize def association(name, condition = nil, resource: nil, key: nil, params: {}, **options, &block) key_transformation = @_key_transformation_cascade ? @_transform_type : :none assoc = Association.new( - name: name, condition: condition, resource: resource, params: params, nesting: nesting, key_transformation: key_transformation, -&block + name: name, condition: condition, resource: resource, params: params, nesting: nesting, key_transformation: key_transformation, helper: @_helper, &block ) @_attributes[key&.to_sym || name.to_sym] = options[:if] ? ConditionalAttribute.new(body: assoc, condition: options[:if]) : assoc end alias one association alias many association @@ -386,11 +395,11 @@ def nesting if name.nil? nil else - name.rpartition('::').first.tap { |n| n.empty? ? nil : n } + name.rpartition('::').first.then { |n| n.empty? ? nil : n } end end private :nesting # Set a nested attribute with the given block @@ -500,9 +509,28 @@ # Set nil handler # # @param block [Block] def on_nil(&block) @_on_nil = block + end + + # Define helper methods + # + # @param mod [Module] a module to extend + def helper(mod = @_helper || Module.new, &block) + mod.module_eval(&block) if block + extend mod + @_helper = mod + end + + # DSL for alias, purely for readability + def prefer_resource_method! + alias_method :fetch_attribute_from_object_and_resource, :_fetch_attribute_from_resource_first + end + + # DSL for alias, purely for readability + def prefer_object_method! + alias_method :fetch_attribute_from_object_and_resource, :_fetch_attribute_from_object_first end end end end