From 918e6853f03ba3408040aab95d3f28045fd3e6cd Mon Sep 17 00:00:00 2001 From: Nikolai Ammosov Date: Wed, 26 Sep 2018 16:54:39 +0900 Subject: [PATCH] Invoke parent serializer method instead of object method with the same name (#118) * [fix] invoke object method instead of parent serializer method (#115) * Correct rubocop offenses --- lib/surrealist/serializer.rb | 20 ++++++++++++++++++++ lib/surrealist/value_assigner.rb | 7 +++++-- spec/serializer_spec.rb | 16 ++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/lib/surrealist/serializer.rb b/lib/surrealist/serializer.rb index ab01364..7fd8951 100644 --- a/lib/surrealist/serializer.rb +++ b/lib/surrealist/serializer.rb @@ -48,6 +48,26 @@ def serializer_context(*array) # Plural form ¯\_(ツ)_/¯ alias serializer_contexts serializer_context + + # Only lookup for methods defined in Surrealist::Serializer subclasses + # to prevent invoke of Kernel methods + # + # @param [Symbol] method method to be invoked + # + # @return [Boolean] + def method_defined?(method) + return true if instance_methods(false).include?(method) + return false if superclass == Surrealist::Serializer + + super + end + + def private_method_defined?(method) + return true if private_instance_methods(false).include?(method) + return false if superclass == Surrealist::Serializer + + super + end end # NOTE: #context will work only when using serializer explicitly, diff --git a/lib/surrealist/value_assigner.rb b/lib/surrealist/value_assigner.rb index 184550c..963ba24 100644 --- a/lib/surrealist/value_assigner.rb +++ b/lib/surrealist/value_assigner.rb @@ -47,8 +47,8 @@ def raw_value(instance, schema) # @return [Object] the return value of the method def invoke_method(instance, method) object = instance.instance_variable_get(:@object) - instance_method = instance.class.instance_methods(false).include?(method) || - instance.class.private_instance_methods(false).include?(method) + instance_method = instance.class.method_defined?(method) || + instance.class.private_method_defined?(method) invoke_object = !instance_method && object && object.respond_to?(method, true) invoke_object ? object.send(method) : instance.send(method) end @@ -77,6 +77,7 @@ def coerce_value(value, schema) # @return [Array] of schemas def assign_nested_collection(instance, value) return if @skip_set.include?(value.first.class) + with_skip_set(instance.class) { Surrealist.surrealize_collection(value, raw: true) } end @@ -88,6 +89,7 @@ def assign_nested_collection(instance, value) # @return [Hash] schema def assign_nested_record(instance, value) return if @skip_set.include?(value.class) + with_skip_set(instance.class) { value.build_schema } end @@ -98,6 +100,7 @@ def assign_nested_record(instance, value) # @return [Object] block result def with_skip_set(klass) return yield if @skip_set.include?(klass) + @skip_set.add(klass) result = yield @skip_set.delete(klass) diff --git a/spec/serializer_spec.rb b/spec/serializer_spec.rb index 6f4779f..974f27e 100644 --- a/spec/serializer_spec.rb +++ b/spec/serializer_spec.rb @@ -135,6 +135,12 @@ def new_test end end +class FooChildSerializer < FooSerializer + json_schema do + { new_test: String, private_test: String } + end +end + RSpec.describe Surrealist::Serializer do describe 'Explicit surrealization through `Serializer.new`' do describe 'instance' do @@ -357,6 +363,16 @@ def new_test expect(hash[:private_test]).to eq('serializer private method') expect(hash[:another_private]).to eq('model private method') end + + context 'when serializer inherited' do + let(:instance) { FooChildSerializer.new(model) } + let(:hash) { instance.build_schema } + + it 'prefer parent serializer method before object method with the same name' do + expect(hash[:new_test]).to eq('serializer public method') + expect(hash[:private_test]).to eq('serializer private method') + end + end end end end