diff --git a/lib/jsonapi-serializers.rb b/lib/jsonapi-serializers.rb index 2979585..5a7b49b 100644 --- a/lib/jsonapi-serializers.rb +++ b/lib/jsonapi-serializers.rb @@ -1,6 +1,7 @@ require "jsonapi-serializers/version" require "jsonapi-serializers/attributes" require "jsonapi-serializers/serializer" +require "jsonapi-serializers/dynamic_proxy_object" module JSONAPI module Serializer diff --git a/lib/jsonapi-serializers/dynamic_proxy_object.rb b/lib/jsonapi-serializers/dynamic_proxy_object.rb new file mode 100644 index 0000000..c0272bf --- /dev/null +++ b/lib/jsonapi-serializers/dynamic_proxy_object.rb @@ -0,0 +1,24 @@ +module JSONAPI + class DynamicProxyObject < BasicObject + + def initialize(target) + @cache = {} + @target = target + end + + def class + @target.class + end + + def cache_key(name, args) + "#{name}_#{args.hash}" + end + + def method_missing(name, *args, &block) + key = cache_key(name, args) + @cache[key] ||= @target.send(name, *args, &block) + @cache[key] + end + + end +end \ No newline at end of file diff --git a/lib/jsonapi-serializers/serializer.rb b/lib/jsonapi-serializers/serializer.rb index 3e55158..ecc04fd 100644 --- a/lib/jsonapi-serializers/serializer.rb +++ b/lib/jsonapi-serializers/serializer.rb @@ -120,7 +120,7 @@ def relationships end if @_include_linkages.include?(formatted_attribute_name) || attr_data[:options][:include_data] - object = has_one_relationship(attribute_name, attr_data) + object = JSONAPI::Serializer.proxy_objects(has_one_relationship(attribute_name, attr_data)) if object.nil? # Spec: Resource linkage MUST be represented as one of the following: # - null for empty to-one relationships. @@ -156,7 +156,7 @@ def relationships # http://jsonapi.org/format/#document-structure-resource-relationships if @_include_linkages.include?(formatted_attribute_name) || attr_data[:options][:include_data] data[formatted_attribute_name]['data'] = [] - objects = has_many_relationship(attribute_name, attr_data) || [] + objects = JSONAPI::Serializer.proxy_objects(has_many_relationship(attribute_name, attr_data) || []) objects.each do |obj| related_object_serializer = JSONAPI::Serializer.find_serializer(obj, @options) data[formatted_attribute_name]['data'] << { @@ -252,7 +252,17 @@ def self.find_serializer(object, options) find_serializer_class(object, options).new(object, options) end + def self.proxy_objects(objects) + return nil unless objects + if objects.respond_to?(:map) + objects.map { |obj| DynamicProxyObject.new(obj) } + else + DynamicProxyObject.new(objects) + end + end + def self.serialize(objects, options = {}) + objects = proxy_objects(objects) # Normalize option strings to symbols. options[:is_collection] = options.delete('is_collection') || options[:is_collection] || false options[:include] = options.delete('include') || options[:include] @@ -462,12 +472,12 @@ def self.find_recursive_relationships(root_object, root_inclusion_tree, results, if serializer.has_one_relationships.has_key?(unformatted_attr_name) is_valid_attr = true attr_data = serializer.has_one_relationships[unformatted_attr_name] - object = serializer.has_one_relationship(unformatted_attr_name, attr_data) + object = proxy_objects(serializer.has_one_relationship(unformatted_attr_name, attr_data)) elsif serializer.has_many_relationships.has_key?(unformatted_attr_name) is_valid_attr = true is_collection = true attr_data = serializer.has_many_relationships[unformatted_attr_name] - object = serializer.has_many_relationship(unformatted_attr_name, attr_data) + object = proxy_objects(serializer.has_many_relationship(unformatted_attr_name, attr_data)) end if !is_valid_attr diff --git a/spec/dynamic_proxy_object_spec.rb b/spec/dynamic_proxy_object_spec.rb new file mode 100644 index 0000000..d2ab16b --- /dev/null +++ b/spec/dynamic_proxy_object_spec.rb @@ -0,0 +1,13 @@ +describe JSONAPI::DynamicProxyObject do + it 'should delegate methods to target and cache results' do + target = double('target') + expect(target).to receive(:foo).and_return('bar') + expect(target).to receive(:foo).with(param1: '1', param2: 2).and_return('bar2') + + proxy = JSONAPI::DynamicProxyObject.new(target) + expect(proxy.foo).to eq('bar') + expect(proxy.foo).to eq('bar') + expect(proxy.foo(param1: '1', param2: 2)).to eq('bar2') + expect(proxy.foo(param1: '1', param2: 2)).to eq('bar2') + end +end \ No newline at end of file