diff --git a/.gitignore b/.gitignore index ad7f37d1..43b0fba4 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ .config .yardoc Gemfile.lock +Gemfile.local InstalledFiles _yardoc coverage diff --git a/.rubocop.yml b/.rubocop.yml index e7d729cc..43ccb9f5 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -8,6 +8,39 @@ AllCops: DisplayCopNames: true DisplayStyleGuide: true +Style/IndentationConsistency: + Exclude: + - lib/active_model/serializer/adapter/flatten_json.rb + - lib/active_model/serializer/adapter/fragment_cache.rb + - lib/active_model/serializer/adapter/json.rb + - lib/active_model/serializer/adapter/json/fragment_cache.rb + - lib/active_model/serializer/adapter/json_api.rb + - lib/active_model/serializer/adapter/json_api/fragment_cache.rb + - lib/active_model/serializer/adapter/json_api/pagination_links.rb + - lib/active_model/serializer/adapter/null.rb + +Style/IndentationWidth: + Exclude: + - lib/active_model/serializer/adapter/flatten_json.rb + - lib/active_model/serializer/adapter/fragment_cache.rb + - lib/active_model/serializer/adapter/json.rb + - lib/active_model/serializer/adapter/json/fragment_cache.rb + - lib/active_model/serializer/adapter/json_api.rb + - lib/active_model/serializer/adapter/json_api/fragment_cache.rb + - lib/active_model/serializer/adapter/json_api/pagination_links.rb + - lib/active_model/serializer/adapter/null.rb + +Style/AccessModifierIndentation: + Exclude: + - lib/active_model/serializer/adapter/flatten_json.rb + - lib/active_model/serializer/adapter/fragment_cache.rb + - lib/active_model/serializer/adapter/json.rb + - lib/active_model/serializer/adapter/json/fragment_cache.rb + - lib/active_model/serializer/adapter/json_api.rb + - lib/active_model/serializer/adapter/json_api/fragment_cache.rb + - lib/active_model/serializer/adapter/json_api/pagination_links.rb + - lib/active_model/serializer/adapter/null.rb + Lint/NestedMethodDefinition: Enabled: false Exclude: diff --git a/.simplecov b/.simplecov index 31db7d88..37d037a1 100644 --- a/.simplecov +++ b/.simplecov @@ -8,7 +8,7 @@ when 'jruby', 'rbx' 96.0 else - 98.3 + 98.1 end }.to_f.round(2) # rubocop:disable Style/DoubleNegation diff --git a/Gemfile b/Gemfile index 7b93d844..7899d8df 100644 --- a/Gemfile +++ b/Gemfile @@ -1,4 +1,8 @@ source 'https://rubygems.org' +# +# Add a Gemfile.local to locally bundle gems outside of version control +local_gemfile = File.join(File.expand_path('..', __FILE__), 'Gemfile.local') +eval_gemfile local_gemfile if File.readable?(local_gemfile) # Specify your gem's dependencies in active_model_serializers.gemspec gemspec diff --git a/docs/general/adapters.md b/docs/general/adapters.md index 60dc9842..b505a7f5 100644 --- a/docs/general/adapters.md +++ b/docs/general/adapters.md @@ -32,7 +32,7 @@ resources in the `"included"` member when the resource names are included in the ## Choosing an adapter -If you want to use a different adapter, such as JsonApi, you can change this in an initializer: +If you want to use a specify a default adapter, such as JsonApi, you can change this in an initializer: ```ruby ActiveModel::Serializer.config.adapter = ActiveModel::Serializer::Adapter::JsonApi @@ -44,8 +44,59 @@ or ActiveModel::Serializer.config.adapter = :json_api ``` -If you want to have a root key in your responses you should use the Json adapter, instead of the default FlattenJson: +If you want to have a root key for each resource in your responses, you should use the Json or +JsonApi adapters instead of the default FlattenJson: ```ruby ActiveModel::Serializer.config.adapter = :json ``` + +## Advanced adapter configuration + +### Registering an adapter + +The default adapter can be configured, as above, to use any class given to it. + +An adapter may also be specified, e.g. when rendering, as a class or as a symbol. +If a symbol, then the adapter must be, e.g. `:great_example`, +`ActiveModel::Serializer::Adapter::GreatExample`, or registered. + +There are two ways to register an adapter: + +1) The simplest, is to subclass `ActiveModel::Serializer::Adapter`, e.g. the below will +register the `Example::UsefulAdapter` as `:useful_adapter`. + +```ruby +module Example + class UsefulAdapter < ActiveModel::Serializer::Adapter + end +end +``` + +You'll notice that the name it registers is the class name underscored, not the full namespace. + +Under the covers, when the `ActiveModel::Serializer::Adapter` is subclassed, it registers +the subclass as `register(:useful_adapter, Example::UsefulAdapter)` + +2) Any class can be registered as an adapter by calling `register` directly on the +`ActiveModel::Serializer::Adapter` class. e.g., the below registers `MyAdapter` as +`:special_adapter`. + +```ruby +class MyAdapter; end +ActiveModel::Serializer::Adapter.register(:special_adapter, MyAdapter) +``` + +### Looking up an adapter + +| `ActiveModel::Serializer::Adapter.adapter_map` | A Hash of all known adapters { adapter_name => adapter_class } | +| `ActiveModel::Serializer::Adapter.adapters` | A (sorted) Array of all known adapter_names | +| `ActiveModel::Serializer::Adapter.lookup(name_or_klass)` | The adapter_class, else raises an `ActiveModel::Serializer::Adapter::UnknownAdapter` error | +| `ActiveModel::Serializer::Adapter.adapter_class(adapter)` | delegates to `ActiveModel::Serializer::Adapter.lookup(adapter)` | +| `ActiveModel::Serializer.adapter` | a convenience method for `ActiveModel::Serializer::Adapter.lookup(config.adapter)` | + +The registered adapter name is always a String, but may be looked up as a Symbol or String. +Helpfully, the Symbol or String is underscored, so that `get(:my_adapter)` and `get("MyAdapter")` +may both be used. + +For more information, see [the Adapter class on GitHub](https://github.com/rails-api/active_model_serializers/blob/master/lib/active_model/serializer/adapter.rb) diff --git a/lib/active_model/serializable_resource.rb b/lib/active_model/serializable_resource.rb index feae1e8e..d3565f9a 100644 --- a/lib/active_model/serializable_resource.rb +++ b/lib/active_model/serializable_resource.rb @@ -76,7 +76,7 @@ module ActiveModel private ActiveModelSerializers.silence_warnings do - attr_reader :resource, :adapter_opts, :serializer_opts + attr_reader :resource, :adapter_opts, :serializer_opts end end end diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index 8b4f02ab..29acbabf 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -94,19 +94,9 @@ module ActiveModel end end + # @see ActiveModel::Serializer::Adapter.lookup def self.adapter - adapter_class = case config.adapter - when Symbol - ActiveModel::Serializer::Adapter.adapter_class(config.adapter) - when Class - config.adapter - end - unless adapter_class - valid_adapters = Adapter.constants.map { |klass| ":#{klass.to_s.downcase}" } - raise ArgumentError, "Unknown adapter: #{config.adapter}. Valid adapters are: #{valid_adapters}" - end - - adapter_class + ActiveModel::Serializer::Adapter.lookup(config.adapter) end def self.root_name diff --git a/lib/active_model/serializer/adapter.rb b/lib/active_model/serializer/adapter.rb index 1cbeb9b7..98987bda 100644 --- a/lib/active_model/serializer/adapter.rb +++ b/lib/active_model/serializer/adapter.rb @@ -1,12 +1,15 @@ module ActiveModel class Serializer class Adapter + UnknownAdapterError = Class.new(ArgumentError) + ADAPTER_MAP = {} + private_constant :ADAPTER_MAP if defined?(private_constant) extend ActiveSupport::Autoload - require 'active_model/serializer/adapter/json' - require 'active_model/serializer/adapter/json_api' - autoload :FlattenJson - autoload :Null autoload :FragmentCache + autoload :Json + autoload :JsonApi + autoload :Null + autoload :FlattenJson def self.create(resource, options = {}) override = options.delete(:adapter) @@ -14,9 +17,67 @@ module ActiveModel klass.new(resource, options) end + # @see ActiveModel::Serializer::Adapter.lookup def self.adapter_class(adapter) - adapter_name = adapter.to_s.classify.sub('API', 'Api') - "ActiveModel::Serializer::Adapter::#{adapter_name}".safe_constantize + ActiveModel::Serializer::Adapter.lookup(adapter) + end + + # Only the Adapter class has these methods. + # None of the sublasses have them. + class << ActiveModel::Serializer::Adapter + # @return Hash + def adapter_map + ADAPTER_MAP + end + + # @return [Array] list of adapter names + def adapters + adapter_map.keys.sort + end + + # Adds an adapter 'klass' with 'name' to the 'adapter_map' + # Names are stringified and underscored + # @param [Symbol, String] name of the registered adapter + # @param [Class] klass - adapter class itself + # @example + # AMS::Adapter.register(:my_adapter, MyAdapter) + def register(name, klass) + adapter_map.update(name.to_s.underscore => klass) + self + end + + # @param adapter [String, Symbol, Class] name to fetch adapter by + # @return [ActiveModel::Serializer::Adapter] subclass of Adapter + # @raise [UnknownAdapterError] + def lookup(adapter) + # 1. return if is a class + return adapter if adapter.is_a?(Class) + adapter_name = adapter.to_s.underscore + # 2. return if registered + adapter_map.fetch(adapter_name) { + # 3. try to find adapter class from environment + adapter_class = find_by_name(adapter_name) + register(adapter_name, adapter_class) + adapter_class + } + rescue NameError, ArgumentError => e + failure_message = + "NameError: #{e.message}. Unknown adapter: #{adapter.inspect}. Valid adapters are: #{adapters}" + raise UnknownAdapterError, failure_message, e.backtrace + end + + # @api private + def find_by_name(adapter_name) + adapter_name = adapter_name.to_s.classify.tr('API', 'Api') + ActiveModel::Serializer::Adapter.const_get(adapter_name.to_sym) or # rubocop:disable Style/AndOr + fail UnknownAdapterError + end + private :find_by_name + end + + # Automatically register adapters when subclassing + def self.inherited(subclass) + ActiveModel::Serializer::Adapter.register(subclass.to_s.demodulize, subclass) end attr_reader :serializer diff --git a/lib/active_model/serializer/adapter/flatten_json.rb b/lib/active_model/serializer/adapter/flatten_json.rb index 7ed57034..0c10f3e6 100644 --- a/lib/active_model/serializer/adapter/flatten_json.rb +++ b/lib/active_model/serializer/adapter/flatten_json.rb @@ -1,7 +1,4 @@ -module ActiveModel - class Serializer - class Adapter - class FlattenJson < Json +class ActiveModel::Serializer::Adapter::FlattenJson < ActiveModel::Serializer::Adapter::Json def serializable_hash(options = {}) super @result @@ -13,7 +10,4 @@ module ActiveModel def include_meta(json) json end - end - end - end end diff --git a/lib/active_model/serializer/adapter/fragment_cache.rb b/lib/active_model/serializer/adapter/fragment_cache.rb index 8463b5a2..13558c08 100644 --- a/lib/active_model/serializer/adapter/fragment_cache.rb +++ b/lib/active_model/serializer/adapter/fragment_cache.rb @@ -1,7 +1,4 @@ -module ActiveModel - class Serializer - class Adapter - class FragmentCache +class ActiveModel::Serializer::Adapter::FragmentCache attr_reader :serializer def initialize(adapter, serializer, options) @@ -75,7 +72,4 @@ module ActiveModel def to_valid_const_name(name) name.gsub('::', '_') end - end - end - end end diff --git a/lib/active_model/serializer/adapter/json.rb b/lib/active_model/serializer/adapter/json.rb index b3fa6e9c..2c0b6455 100644 --- a/lib/active_model/serializer/adapter/json.rb +++ b/lib/active_model/serializer/adapter/json.rb @@ -1,9 +1,7 @@ -require 'active_model/serializer/adapter/json/fragment_cache' +class ActiveModel::Serializer::Adapter::Json < ActiveModel::Serializer::Adapter + extend ActiveSupport::Autoload + autoload :FragmentCache -module ActiveModel - class Serializer - class Adapter - class Json < Adapter def serializable_hash(options = nil) options ||= {} if serializer.respond_to?(:each) @@ -44,9 +42,6 @@ module ActiveModel end def fragment_cache(cached_hash, non_cached_hash) - Json::FragmentCache.new().fragment_cache(cached_hash, non_cached_hash) + ActiveModel::Serializer::Adapter::Json::FragmentCache.new().fragment_cache(cached_hash, non_cached_hash) end - end - end - end end diff --git a/lib/active_model/serializer/adapter/json/fragment_cache.rb b/lib/active_model/serializer/adapter/json/fragment_cache.rb index 846a216f..5e687241 100644 --- a/lib/active_model/serializer/adapter/json/fragment_cache.rb +++ b/lib/active_model/serializer/adapter/json/fragment_cache.rb @@ -1,14 +1,5 @@ -require 'active_model/serializer/adapter/fragment_cache' -module ActiveModel - class Serializer - class Adapter - class Json < Adapter - class FragmentCache +class ActiveModel::Serializer::Adapter::Json::FragmentCache def fragment_cache(cached_hash, non_cached_hash) non_cached_hash.merge cached_hash end - end - end - end - end end diff --git a/lib/active_model/serializer/adapter/json_api.rb b/lib/active_model/serializer/adapter/json_api.rb index ac3bf4a1..f273fc65 100644 --- a/lib/active_model/serializer/adapter/json_api.rb +++ b/lib/active_model/serializer/adapter/json_api.rb @@ -1,10 +1,8 @@ -require 'active_model/serializer/adapter/json_api/fragment_cache' -require 'active_model/serializer/adapter/json_api/pagination_links' +class ActiveModel::Serializer::Adapter::JsonApi < ActiveModel::Serializer::Adapter + extend ActiveSupport::Autoload + autoload :PaginationLinks + autoload :FragmentCache -module ActiveModel - class Serializer - class Adapter - class JsonApi < Adapter def initialize(serializer, options = {}) super @hash = { data: [] } @@ -49,7 +47,7 @@ module ActiveModel def fragment_cache(cached_hash, non_cached_hash) root = false if @options.include?(:include) - JsonApi::FragmentCache.new.fragment_cache(root, cached_hash, non_cached_hash) + ActiveModel::Serializer::Adapter::JsonApi::FragmentCache.new().fragment_cache(root, cached_hash, non_cached_hash) end private @@ -62,6 +60,12 @@ module ActiveModel end end + def add_relationships(resource, name, serializers) + resource[:relationships] ||= {} + resource[:relationships][name] ||= { data: [] } + resource[:relationships][name][:data] += serializers.map { |serializer| { type: serializer.json_api_type, id: serializer.id.to_s } } + end + def resource_identifier_id_for(serializer) if serializer.respond_to?(:id) serializer.id @@ -161,8 +165,8 @@ module ActiveModel @hash[:links] = add_pagination_links(links, collection, options) if paginated?(collection) end - def add_pagination_links(links, collection, options) - pagination_links = JsonApi::PaginationLinks.new(collection, options[:context]).serializable_hash(options) + def add_pagination_links(links, resources, options) + pagination_links = ActiveModel::Serializer::Adapter::JsonApi::PaginationLinks.new(resources, options[:context]).serializable_hash(options) links.update(pagination_links) end @@ -171,7 +175,4 @@ module ActiveModel collection.respond_to?(:total_pages) && collection.respond_to?(:size) end - end - end - end end diff --git a/lib/active_model/serializer/adapter/json_api/fragment_cache.rb b/lib/active_model/serializer/adapter/json_api/fragment_cache.rb index 070371ac..ab348130 100644 --- a/lib/active_model/serializer/adapter/json_api/fragment_cache.rb +++ b/lib/active_model/serializer/adapter/json_api/fragment_cache.rb @@ -1,9 +1,4 @@ -require 'active_model/serializer/adapter/fragment_cache' -module ActiveModel - class Serializer - class Adapter - class JsonApi < Adapter - class FragmentCache +class ActiveModel::Serializer::Adapter::JsonApi::FragmentCache def fragment_cache(root, cached_hash, non_cached_hash) hash = {} core_cached = cached_hash.first @@ -15,8 +10,4 @@ module ActiveModel hash.deep_merge no_root_non_cache.deep_merge no_root_cache end - end - end - end - end end diff --git a/lib/active_model/serializer/adapter/json_api/pagination_links.rb b/lib/active_model/serializer/adapter/json_api/pagination_links.rb index 55e3280b..8661f3b1 100644 --- a/lib/active_model/serializer/adapter/json_api/pagination_links.rb +++ b/lib/active_model/serializer/adapter/json_api/pagination_links.rb @@ -1,8 +1,4 @@ -module ActiveModel - class Serializer - class Adapter - class JsonApi < Adapter - class PaginationLinks +class ActiveModel::Serializer::Adapter::JsonApi::PaginationLinks FIRST_PAGE = 1 attr_reader :collection, :context @@ -51,8 +47,4 @@ module ActiveModel def query_parameters @query_parameters ||= context.query_parameters end - end - end - end - end end diff --git a/lib/active_model/serializer/adapter/null.rb b/lib/active_model/serializer/adapter/null.rb index 1728f88e..78f9b8e3 100644 --- a/lib/active_model/serializer/adapter/null.rb +++ b/lib/active_model/serializer/adapter/null.rb @@ -1,11 +1,5 @@ -module ActiveModel - class Serializer - class Adapter - class Null < Adapter +class ActiveModel::Serializer::Adapter::Null < ActiveModel::Serializer::Adapter def serializable_hash(options = nil) {} end - end - end - end end diff --git a/lib/active_model/serializer/fieldset.rb b/lib/active_model/serializer/fieldset.rb index 30e68334..935aea81 100644 --- a/lib/active_model/serializer/fieldset.rb +++ b/lib/active_model/serializer/fieldset.rb @@ -18,7 +18,7 @@ module ActiveModel private ActiveModelSerializers.silence_warnings do - attr_reader :raw_fields, :root + attr_reader :raw_fields, :root end def parsed_fields diff --git a/test/action_controller/serialization_scope_name_test.rb b/test/action_controller/serialization_scope_name_test.rb index 6e2b15e6..51abf108 100644 --- a/test/action_controller/serialization_scope_name_test.rb +++ b/test/action_controller/serialization_scope_name_test.rb @@ -25,7 +25,7 @@ class DefaultScopeNameTest < ActionController::TestCase end end - tests UserTestController + tests UserTestController def test_default_scope_name get :render_new_user diff --git a/test/adapter_test.rb b/test/adapter_test.rb index 73bacdd5..75efac15 100644 --- a/test/adapter_test.rb +++ b/test/adapter_test.rb @@ -19,16 +19,6 @@ module ActiveModel assert_equal @serializer, @adapter.serializer end - def test_adapter_class_for_known_adapter - klass = ActiveModel::Serializer::Adapter.adapter_class(:json_api) - assert_equal ActiveModel::Serializer::Adapter::JsonApi, klass - end - - def test_adapter_class_for_unknown_adapter - klass = ActiveModel::Serializer::Adapter.adapter_class(:json_simple) - assert_nil klass - end - def test_create_adapter adapter = ActiveModel::Serializer::Adapter.create(@serializer) assert_equal ActiveModel::Serializer::Adapter::FlattenJson, adapter.class diff --git a/test/serializers/adapter_for_test.rb b/test/serializers/adapter_for_test.rb index 3a17cd24..5bab05ae 100644 --- a/test/serializers/adapter_for_test.rb +++ b/test/serializers/adapter_for_test.rb @@ -1,8 +1,15 @@ module ActiveModel class Serializer class AdapterForTest < Minitest::Test + UnknownAdapterError = ::ActiveModel::Serializer::Adapter::UnknownAdapterError + def setup @previous_adapter = ActiveModel::Serializer.config.adapter + # Eager load adapters + ActiveModel::Serializer::Adapter.eager_load! + [:json_api, :flatten_json, :null, :json].each do |adapter_name| + ActiveModel::Serializer::Adapter.lookup(adapter_name) + end end def teardown @@ -20,6 +27,7 @@ module ActiveModel adapter = ActiveModel::Serializer.adapter assert_equal ActiveModel::Serializer::Adapter::Null, adapter ensure + ActiveModel::Serializer.config.adapter = @previous_adapter end def test_overwrite_adapter_with_class @@ -32,7 +40,7 @@ module ActiveModel def test_raises_exception_if_invalid_symbol_given ActiveModel::Serializer.config.adapter = :unknown - assert_raises ArgumentError do + assert_raises UnknownAdapterError do ActiveModel::Serializer.adapter end end @@ -40,10 +48,123 @@ module ActiveModel def test_raises_exception_if_it_does_not_know_hot_to_infer_adapter ActiveModel::Serializer.config.adapter = 42 - assert_raises ArgumentError do + assert_raises UnknownAdapterError do ActiveModel::Serializer.adapter end end + + def test_adapter_class_for_known_adapter + klass = ActiveModel::Serializer::Adapter.adapter_class(:json_api) + assert_equal ActiveModel::Serializer::Adapter::JsonApi, klass + end + + def test_adapter_class_for_unknown_adapter + assert_raises UnknownAdapterError do + ActiveModel::Serializer::Adapter.adapter_class(:json_simple) + end + end + + def test_adapter_map + expected_adapter_map = { + 'json'.freeze => ActiveModel::Serializer::Adapter::Json, + 'json_api'.freeze => ActiveModel::Serializer::Adapter::JsonApi, + 'flatten_json'.freeze => ActiveModel::Serializer::Adapter::FlattenJson, + 'null'.freeze => ActiveModel::Serializer::Adapter::Null + } + assert_equal ActiveModel::Serializer::Adapter.adapter_map, expected_adapter_map + end + + def test_adapters + assert_equal ActiveModel::Serializer::Adapter.adapters.sort, [ + 'flatten_json'.freeze, + 'json'.freeze, + 'json_api'.freeze, + 'null'.freeze + ] + end + + def test_lookup_adapter_by_string_name + assert_equal ActiveModel::Serializer::Adapter.lookup('json'.freeze), ActiveModel::Serializer::Adapter::Json + end + + def test_lookup_adapter_by_symbol_name + assert_equal ActiveModel::Serializer::Adapter.lookup(:json), ActiveModel::Serializer::Adapter::Json + end + + def test_lookup_adapter_by_class + klass = ActiveModel::Serializer::Adapter::Json + assert_equal ActiveModel::Serializer::Adapter.lookup(klass), klass + end + + def test_lookup_adapter_from_environment_registers_adapter + ActiveModel::Serializer::Adapter.const_set(:AdapterFromEnvironment, Class.new) + klass = ::ActiveModel::Serializer::Adapter::AdapterFromEnvironment + name = 'adapter_from_environment'.freeze + assert_equal ActiveModel::Serializer::Adapter.lookup(name), klass + assert ActiveModel::Serializer::Adapter.adapters.include?(name) + ensure + ActiveModel::Serializer::Adapter.adapter_map.delete(name) + ActiveModel::Serializer::Adapter.send(:remove_const, :AdapterFromEnvironment) + end + + def test_lookup_adapter_for_unknown_name + assert_raises UnknownAdapterError do + ActiveModel::Serializer::Adapter.lookup(:json_simple) + end + end + + def test_adapter + assert_equal ActiveModel::Serializer.config.adapter, :flatten_json + assert_equal ActiveModel::Serializer.adapter, ActiveModel::Serializer::Adapter::FlattenJson + end + + def test_register_adapter + new_adapter_name = :foo + new_adapter_klass = Class.new + ActiveModel::Serializer::Adapter.register(new_adapter_name, new_adapter_klass) + assert ActiveModel::Serializer::Adapter.adapters.include?('foo'.freeze) + assert ActiveModel::Serializer::Adapter.lookup(:foo), new_adapter_klass + ensure + ActiveModel::Serializer::Adapter.adapter_map.delete(new_adapter_name.to_s) + end + + def test_inherited_adapter_hooks_register_adapter + Object.const_set(:MyAdapter, Class.new) + my_adapter = MyAdapter + ActiveModel::Serializer::Adapter.inherited(my_adapter) + assert_equal ActiveModel::Serializer::Adapter.lookup(:my_adapter), my_adapter + ensure + ActiveModel::Serializer::Adapter.adapter_map.delete('my_adapter'.freeze) + Object.send(:remove_const, :MyAdapter) + end + + def test_inherited_adapter_hooks_register_demodulized_adapter + Object.const_set(:MyNamespace, Module.new) + MyNamespace.const_set(:MyAdapter, Class.new) + my_adapter = MyNamespace::MyAdapter + ActiveModel::Serializer::Adapter.inherited(my_adapter) + assert_equal ActiveModel::Serializer::Adapter.lookup(:my_adapter), my_adapter + ensure + ActiveModel::Serializer::Adapter.adapter_map.delete('my_adapter'.freeze) + MyNamespace.send(:remove_const, :MyAdapter) + Object.send(:remove_const, :MyNamespace) + end + + def test_inherited_adapter_hooks_register_subclass_of_registered_adapter + Object.const_set(:MyAdapter, Class.new) + my_adapter = MyAdapter + Object.const_set(:MySubclassedAdapter, Class.new(MyAdapter)) + my_subclassed_adapter = MySubclassedAdapter + ActiveModel::Serializer::Adapter.inherited(my_adapter) + ActiveModel::Serializer::Adapter.inherited(my_subclassed_adapter) + assert_equal ActiveModel::Serializer::Adapter.lookup(:my_adapter), my_adapter + assert_equal ActiveModel::Serializer::Adapter.lookup(:my_subclassed_adapter), my_subclassed_adapter + ensure + ActiveModel::Serializer::Adapter.adapter_map.delete('my_adapter'.freeze) + ActiveModel::Serializer::Adapter.adapter_map.delete('my_subclassed_adapter'.freeze) + Object.send(:remove_const, :MyAdapter) + Object.send(:remove_const, :MySubclassedAdapter) + end end end end