From fb8ca1caeeca07a3394ae150ac337c450e6a4a24 Mon Sep 17 00:00:00 2001 From: vsevolod Date: Tue, 29 May 2018 22:58:35 +0300 Subject: [PATCH 1/4] Allow hash surrealization --- lib/surrealist/helper.rb | 2 +- lib/surrealist/serializer.rb | 6 ++++- spec/build_schema_spec.rb | 45 ++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/lib/surrealist/helper.rb b/lib/surrealist/helper.rb index 57f888f..d2994f9 100644 --- a/lib/surrealist/helper.rb +++ b/lib/surrealist/helper.rb @@ -16,7 +16,7 @@ def self.collection?(object) # 4.2 AR relation object did not include Enumerable (it defined # all necessary method through ActiveRecord::Delegation module), # so we need to explicitly check for this - object.is_a?(Enumerable) || ar_relation?(object) + (object.is_a?(Enumerable) && !object.instance_of?(Hash)) || ar_relation?(object) end def self.ar_relation?(object) diff --git a/lib/surrealist/serializer.rb b/lib/surrealist/serializer.rb index 3d2f1a5..eb09983 100644 --- a/lib/surrealist/serializer.rb +++ b/lib/surrealist/serializer.rb @@ -54,7 +54,7 @@ def serializer_context(*array) # e.g `CatSerializer.new(Cat.new(3), food: CatFood.new)` # And then food will be available inside serializer via `context[:food]` def initialize(object, **context) - @object = object + @object = wrap_hash_into_struct(object) @context = context end @@ -94,5 +94,9 @@ def method_missing(method, *args, &block) def respond_to_missing?(method, include_private = false) object.respond_to?(method) || super end + + def wrap_hash_into_struct(object) + object.instance_of?(Hash) ? OpenStruct.new(object) : object + end end end diff --git a/spec/build_schema_spec.rb b/spec/build_schema_spec.rb index 7df391a..15fb58f 100644 --- a/spec/build_schema_spec.rb +++ b/spec/build_schema_spec.rb @@ -158,8 +158,53 @@ def name # expecting: Surrealist::UnknownSchemaError end +class ComplexNumber < Surrealist::Serializer + json_schema do + { + real: Integer, + imaginary: Integer, + } + end +end + +class DeepHash < Surrealist::Serializer + json_schema do + { + list: Array, + nested: { + left: String, + right: Integer, + }, + } + end +end + +class HashRoot < Surrealist::Serializer + json_schema do + { nested: ComplexNumber.defined_schema } + end +end + RSpec.describe Surrealist do describe '#build_schema' do + context 'with hash arg' do + specify do + expect(ComplexNumber.new({real: 1, imaginary: 2}).build_schema).to eq(real: 1, imaginary: 2) + end + end + + context 'deep hash arg' do + specify do + expect(DeepHash.new({list: [1, 2], nested: { right: 4, left: 'three'}}).build_schema).to eq({list: [1, 2], nested: { right: 4, left: 'three'}}) + end + end + + context 'root hash with object inside' do + specify do + expect(HashRoot.new({nested: OpenStruct.new(real: 1, imaginary: -1)}).build_schema).to eq({nested: { real: 1, imaginary: -1}}) + end + end + context 'with defined schema' do context 'with correct types' do it 'works' do From 10bfc6ab9d2f94d814fbe8fd8fb2f76b2f9f6cb5 Mon Sep 17 00:00:00 2001 From: vsevolod Date: Wed, 6 Jun 2018 20:45:34 +0300 Subject: [PATCH 2/4] Fix rubocop offences --- spec/build_schema_spec.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/spec/build_schema_spec.rb b/spec/build_schema_spec.rb index 15fb58f..5ea0e78 100644 --- a/spec/build_schema_spec.rb +++ b/spec/build_schema_spec.rb @@ -189,19 +189,22 @@ class HashRoot < Surrealist::Serializer describe '#build_schema' do context 'with hash arg' do specify do - expect(ComplexNumber.new({real: 1, imaginary: 2}).build_schema).to eq(real: 1, imaginary: 2) + expect(ComplexNumber.new(real: 1, imaginary: 2).build_schema) + .to eq(real: 1, imaginary: 2) end end context 'deep hash arg' do specify do - expect(DeepHash.new({list: [1, 2], nested: { right: 4, left: 'three'}}).build_schema).to eq({list: [1, 2], nested: { right: 4, left: 'three'}}) + expect(DeepHash.new(list: [1, 2], nested: { right: 4, left: 'three' }).build_schema) + .to eq(list: [1, 2], nested: { right: 4, left: 'three' }) end end context 'root hash with object inside' do specify do - expect(HashRoot.new({nested: OpenStruct.new(real: 1, imaginary: -1)}).build_schema).to eq({nested: { real: 1, imaginary: -1}}) + expect(HashRoot.new(nested: OpenStruct.new(real: 1, imaginary: -1)).build_schema) + .to eq(nested: { real: 1, imaginary: -1 }) end end From 9ea4efc7de4385dc44308d2ed7ef9fb59cb32f2c Mon Sep 17 00:00:00 2001 From: vsevolod Date: Wed, 6 Jun 2018 21:56:11 +0300 Subject: [PATCH 3/4] Add specs for hash with #surrealize --- spec/serializer_spec.rb | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/spec/serializer_spec.rb b/spec/serializer_spec.rb index 8137720..8b7c71c 100644 --- a/spec/serializer_spec.rb +++ b/spec/serializer_spec.rb @@ -151,6 +151,35 @@ class FooSerializer < Surrealist::Serializer it { is_expected.to eq expectation } end end + + describe 'serializing hash' do + let(:milk) { Struct.new(:amount).new(20) } + let(:flour) { Struct.new(:amount).new(40) } + let(:instance) { { color: 'yellow', amount: 60 } } + + describe "#surrealize" do + subject(:json) { PancakeSerializer.new(instance, flour: flour).surrealize } + let(:expectation) { { amount: 60, color: 'yellow' }.to_json } + + it { is_expected.to eq expectation } + end + + describe "#surrealize with include root" do + subject(:json) { PancakeSerializer.new(instance, flour: flour).surrealize(include_root: true) } + # NOTE: include root doesn't work as well when we call serializer in such way + let(:expectation) { { pancake_serializer: { amount: 60, color: 'yellow' } }.to_json } + + it { is_expected.to eq expectation } + end + + describe "#surrealize with camelize" do + let(:instance) { { name: 'Pepe' } } + subject(:json) { DogeSerializer.new(instance, flour: flour).surrealize(camelize: true) } + let(:expectation) { { name: 'Pepe', nameLength: 4 }.to_json } + + it { is_expected.to eq expectation } + end + end end describe 'collection' do From 7535a756ec9e3b367c9caa8d85a5412652aacb9b Mon Sep 17 00:00:00 2001 From: vsevolod Date: Wed, 6 Jun 2018 21:57:45 +0300 Subject: [PATCH 4/4] fix cops --- spec/serializer_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/serializer_spec.rb b/spec/serializer_spec.rb index 8b7c71c..b434c2e 100644 --- a/spec/serializer_spec.rb +++ b/spec/serializer_spec.rb @@ -157,14 +157,14 @@ class FooSerializer < Surrealist::Serializer let(:flour) { Struct.new(:amount).new(40) } let(:instance) { { color: 'yellow', amount: 60 } } - describe "#surrealize" do + describe '#surrealize' do subject(:json) { PancakeSerializer.new(instance, flour: flour).surrealize } let(:expectation) { { amount: 60, color: 'yellow' }.to_json } it { is_expected.to eq expectation } end - describe "#surrealize with include root" do + describe '#surrealize with include root' do subject(:json) { PancakeSerializer.new(instance, flour: flour).surrealize(include_root: true) } # NOTE: include root doesn't work as well when we call serializer in such way let(:expectation) { { pancake_serializer: { amount: 60, color: 'yellow' } }.to_json } @@ -172,7 +172,7 @@ class FooSerializer < Surrealist::Serializer it { is_expected.to eq expectation } end - describe "#surrealize with camelize" do + describe '#surrealize with camelize' do let(:instance) { { name: 'Pepe' } } subject(:json) { DogeSerializer.new(instance, flour: flour).surrealize(camelize: true) } let(:expectation) { { name: 'Pepe', nameLength: 4 }.to_json }