From 1a26a089d567d32aff91284e91ae6feb9390f77b Mon Sep 17 00:00:00 2001 From: Adrian Mugnolo and Santiago Pastorino Date: Mon, 13 Jan 2014 17:43:59 -0200 Subject: [PATCH] Split Configuration object --- lib/active_model/array_serializer.rb | 15 +- lib/active_model/default_serializer.rb | 2 +- lib/active_model/serializer.rb | 24 ++- lib/active_model/serializer/configuration.rb | 95 ++++++------ .../serializer/configuration_test.rb | 140 +++++++++++++++--- .../unit/active_model/serializer/meta_test.rb | 2 +- .../unit/active_model/serializer/root_test.rb | 4 +- 7 files changed, 190 insertions(+), 92 deletions(-) diff --git a/lib/active_model/array_serializer.rb b/lib/active_model/array_serializer.rb index 4d8b2ca1..4803dafc 100644 --- a/lib/active_model/array_serializer.rb +++ b/lib/active_model/array_serializer.rb @@ -7,13 +7,14 @@ module ActiveModel include Serializable class << self + def inherited(subclass) + subclass.configuration = Serializer::ClassConfiguration.new configuration + end + + attr_writer :configuration + def configuration - @configuration ||= - if self == ArraySerializer - Serializer::Configuration.global - else - superclass.configuration.build - end + @configuration ||= Serializer::ClassConfiguration.new Serializer::GlobalConfiguration.instance end end @@ -25,7 +26,7 @@ module ActiveModel def initialize(object, options = {}) @object = object - @configuration = self.class.configuration.build options + @configuration = Serializer::ArrayConfiguration.new self.class.configuration, options end def json_key diff --git a/lib/active_model/default_serializer.rb b/lib/active_model/default_serializer.rb index d3a00ac2..e45f9ddf 100644 --- a/lib/active_model/default_serializer.rb +++ b/lib/active_model/default_serializer.rb @@ -11,7 +11,7 @@ module ActiveModel def initialize(object, options = nil) @object = object - @configuration = Serializer::Configuration::Null.instance + @configuration = Serializer::InstanceConfiguration.new nil end def as_json(options = {}) diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index 2005b433..ff59a9e4 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -11,9 +11,10 @@ module ActiveModel include Serializable class << self - def inherited(base) - base._attributes = (_attributes || []).dup - base._associations = (_associations || {}).dup + def inherited(subclass) + subclass.configuration = ClassConfiguration.new configuration + subclass._attributes = (_attributes || []).dup + subclass._associations = (_associations || {}).dup end if RUBY_VERSION >= '2.0' @@ -38,6 +39,12 @@ module ActiveModel end end + attr_writer :configuration + + def configuration + @configuration ||= ClassConfiguration.new GlobalConfiguration.instance + end + attr_accessor :_attributes, :_associations def root_name @@ -48,15 +55,6 @@ module ActiveModel def_delegators :dsl, :attributes, :has_one, :has_many, :embed, :root - def configuration - @configuration ||= - if self == Serializer - Configuration.global - else - superclass.configuration.build - end - end - private def dsl @@ -72,7 +70,7 @@ module ActiveModel def initialize(object, options = {}) @object = object - @configuration = self.class.configuration.build options + @configuration = InstanceConfiguration.new self.class.configuration, options end def json_key diff --git a/lib/active_model/serializer/configuration.rb b/lib/active_model/serializer/configuration.rb index f581cb9b..1b61798a 100644 --- a/lib/active_model/serializer/configuration.rb +++ b/lib/active_model/serializer/configuration.rb @@ -3,77 +3,70 @@ require 'singleton' module ActiveModel class Serializer class Configuration - class Null - include Singleton + class << self + def options(*names) + names.each do |name| + attr_writer name - def method_missing(*) - nil - end - - def respond_to?(*) - true + define_method name do + option name + end + end end + alias option options end attr_accessor :parent - class << self - def global - @global ||= new default_options - end + def initialize(parent, options = {}) + self.parent = parent - def default_options - { embed: :objects, meta_key: :meta } + default_options.merge!(options).each do |name, value| + send "#{name}=", value end end - def build(options = {}) - self.class.new options, self + def default_options + {} end - attr_reader :scope, :each_serializer, :resource_name - attr_writer :root, :meta, :meta_key - attr_accessor :wrap_in_array + private - def initialize(options = {}, parent = Null.instance) - @parent = parent - @root = read_option options, :root - @embed = read_option options, :embed - @embed_in_root = read_option options, :embed_in_root - @scope = options[:scope] - @meta_key = read_option options, :meta_key - @meta = read_option options, meta_key - @wrap_in_array = options[:_wrap_in_array] - @each_serializer = options[:each_serializer] - @resource_name = options[:resource_name] + def own_option(name) + instance_variable_get "@#{name}" end - def root - return_first @root, parent.root + def parent_option(name) + parent.send name if parent.respond_to? name end - def embed - return_first @embed, parent.embed + def option(name) + value = own_option name + value.nil? ? parent_option(name) : value end + end - def embed_in_root - return_first @embed_in_root, parent.embed_in_root + class SerializerConfiguration < Configuration + options :root, :embed, :embed_in_root + + def default_options + { embed: :objects } end + end - def meta_key - return_first @meta_key, parent.meta_key + class GlobalConfiguration < SerializerConfiguration + include Singleton + + def initialize + super nil end + end - def meta - return_first @meta, parent.meta - end - - # FIXME: Get rid of this mess. + class ClassConfiguration < SerializerConfiguration def embed_objects=(value) @embed = :objects if value end - # FIXME: Get rid of this mess. def embed_ids=(value) @embed = :ids if value end @@ -85,16 +78,18 @@ module ActiveModel def embed_ids [:ids, :id].include? embed end + end - private + class InstanceConfiguration < ClassConfiguration + options :scope, :meta, :meta_key, :wrap_in_array, :serializer, :prefixes, :template, :layout - def read_option(options, name) - options[name] || false if options.has_key? name + def default_options + super.merge! meta_key: :meta end + end - def return_first(*values) - values.compact.first - end + class ArrayConfiguration < InstanceConfiguration + options :each_serializer, :resource_name end end end diff --git a/test/unit/active_model/serializer/configuration_test.rb b/test/unit/active_model/serializer/configuration_test.rb index 1d99fd2f..fe5ec633 100644 --- a/test/unit/active_model/serializer/configuration_test.rb +++ b/test/unit/active_model/serializer/configuration_test.rb @@ -3,37 +3,141 @@ require 'test_helper' module ActiveModel class Serializer class Configuration - class GlobalTest < Minitest::Test - def test_returns_global_configuration - assert_kind_of Configuration, Configuration.global - end + class Test < Minitest::Test + class ParentConfiguration < Configuration + options :root, :embed_in_root, :embed - def test_global_configuration_returns_the_same_instance - assert_equal Configuration.global.object_id, Configuration.global.object_id - end - - def test_global_configuration_has_default_options_set - assert Configuration.default_options.all? do |name, value| - Configuration.global.send(name) == value + def default_options + { embed: :objects } end end - end - class OptionsTest < Minitest::Test + class ChildConfiguration < ParentConfiguration + options :scope + end + def setup - @configuration = Configuration.global.build(root: 'root', embed: :ids, embed_in_root: false) + @parent = ParentConfiguration.new nil, root: 'root', embed_in_root: true + @child = ChildConfiguration.new @parent, root: 'other' + end + + def test_configuration_has_root_option + assert_equal 'root', @parent.root + end + + def test_parent_has_default_embed_option + assert_equal :objects, @parent.embed + end + + def test_child_returns_own_root_option + assert_equal 'other', @child.root + end + + def test_child_returns_parent_embed_in_root_option + assert_equal true, @child.embed_in_root + end + + def test_child_returns_nil_for_non_existing_parent_option + assert_equal nil, @child.scope + end + end + end + + class SerializerConfiguration + class Test < Minitest::Test + def setup + @configuration = SerializerConfiguration.new nil, root: 'root' + end + + def test_configuration_inherits_from_base_class + assert_kind_of Configuration, @configuration end def test_configuration_has_root_option assert_equal 'root', @configuration.root end - def test_configuration_has_embed_option - assert_equal :ids, @configuration.embed + def test_configuration_sets_root_option + @configuration.root = 'other' + assert_equal 'other', @configuration.root end - def test_configuration_has_embed_in_root_option - assert_equal false, @configuration.embed_in_root + def test_configuration_has_default_embed_option + assert_equal :objects, @configuration.embed + end + end + end + + class GlobalConfiguration + class Test < Minitest::Test + def setup + @configuration = GlobalConfiguration.instance + end + + def test_configuration_inherits_from_base_class + assert_kind_of Configuration, @configuration + end + + def test_returns_singleton_configuration + other = GlobalConfiguration.instance + assert @configuration == other, "instances don't match" + end + end + end + + class ClassConfiguration + class Test < Minitest::Test + def setup + @configuration = ClassConfiguration.new nil, root: 'root' + end + + def test_configuration_inherits_from_base_class + assert_kind_of Configuration, @configuration + end + + def test_configuration_has_root_option + assert_equal 'root', @configuration.root + end + + def test_configuration_sets_root_option + @configuration.root = 'other' + assert_equal 'other', @configuration.root + end + + def test_configuration_has_default_embed_option + assert_equal :objects, @configuration.embed + end + end + end + + class InstanceConfiguration + class Test < Minitest::Test + def setup + @configuration = InstanceConfiguration.new nil, scope: :current_user + end + + def test_configuration_inherits_from_base_class + assert_kind_of ClassConfiguration, @configuration + end + + def test_configuration_has_root_option + assert_equal :current_user, @configuration.scope + end + end + end + + class ArrayConfiguration + class Test < Minitest::Test + def setup + @configuration = ArrayConfiguration.new nil, resource_name: 'posts' + end + + def test_configuration_inherits_from_base_class + assert_kind_of Configuration, @configuration + end + + def test_configuration_has_resource_name_option + assert_equal 'posts', @configuration.resource_name end end end diff --git a/test/unit/active_model/serializer/meta_test.rb b/test/unit/active_model/serializer/meta_test.rb index 8f8d49c8..61a21df6 100644 --- a/test/unit/active_model/serializer/meta_test.rb +++ b/test/unit/active_model/serializer/meta_test.rb @@ -22,7 +22,7 @@ module ActiveModel end def test_meta_using_meta_key - profile_serializer = ProfileSerializer.new(@profile, root: 'profile', meta_key: :my_meta, my_meta: { total: 10 }) + profile_serializer = ProfileSerializer.new(@profile, root: 'profile', meta_key: :my_meta, meta: { total: 10 }) assert_equal({ 'profile' => { diff --git a/test/unit/active_model/serializer/root_test.rb b/test/unit/active_model/serializer/root_test.rb index 3fdcb14f..58781fc2 100644 --- a/test/unit/active_model/serializer/root_test.rb +++ b/test/unit/active_model/serializer/root_test.rb @@ -58,10 +58,10 @@ module ActiveModel def test_root_inheritance ProfileSerializer.root 'profile' - inherited_serializer_klass = Class.new(ProfileSerializer) + inherited_serializer_klass = Class.new ProfileSerializer inherited_serializer_klass.root 'inherited_profile' - another_inherited_serializer_klass = Class.new(ProfileSerializer) + another_inherited_serializer_klass = Class.new ProfileSerializer assert_equal('inherited_profile', inherited_serializer_klass.configuration.root)