cheap_ams 0.10.8 → 0.10.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +33 -0
  4. data/.simplecov +1 -1
  5. data/CHANGELOG.md +1 -0
  6. data/Gemfile +4 -0
  7. data/README.md +22 -5
  8. data/docs/general/adapters.md +55 -2
  9. data/lib/action_controller/serialization.rb +3 -0
  10. data/lib/active_model/serializable_resource.rb +1 -1
  11. data/lib/active_model/serializer.rb +3 -12
  12. data/lib/active_model/serializer/adapter.rb +67 -6
  13. data/lib/active_model/serializer/adapter/flatten_json.rb +2 -9
  14. data/lib/active_model/serializer/adapter/fragment_cache.rb +1 -7
  15. data/lib/active_model/serializer/adapter/json.rb +11 -16
  16. data/lib/active_model/serializer/adapter/json/fragment_cache.rb +1 -10
  17. data/lib/active_model/serializer/adapter/json_api.rb +36 -49
  18. data/lib/active_model/serializer/adapter/json_api/fragment_cache.rb +1 -10
  19. data/lib/active_model/serializer/adapter/json_api/pagination_links.rb +1 -9
  20. data/lib/active_model/serializer/adapter/null.rb +1 -7
  21. data/lib/active_model/serializer/fieldset.rb +2 -2
  22. data/lib/active_model/serializer/utils.rb +35 -0
  23. data/lib/active_model/serializer/version.rb +1 -1
  24. data/test/action_controller/json_api/linked_test.rb +7 -8
  25. data/test/action_controller/serialization_scope_name_test.rb +1 -1
  26. data/test/active_record_test.rb +9 -0
  27. data/test/adapter/json_api/belongs_to_test.rb +3 -3
  28. data/test/adapter/json_api/has_many_explicit_serializer_test.rb +1 -1
  29. data/test/adapter/json_api/has_many_test.rb +2 -2
  30. data/test/adapter/json_api/has_one_test.rb +2 -2
  31. data/test/adapter/json_api/linked_test.rb +6 -6
  32. data/test/adapter_test.rb +0 -10
  33. data/test/serializers/adapter_for_test.rb +123 -2
  34. data/test/utils/include_args_to_hash_test.rb +79 -0
  35. metadata +7 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c11a7633ccf053404efecf2697bfd9752aae2c9f
4
- data.tar.gz: bd233c341599ef68b1675006e377f2c42c324d59
3
+ metadata.gz: 95422216cd4811b37e7e9943fc97c1f8e1984e08
4
+ data.tar.gz: 18bb09e6ba28642242e1e75092ed5250ed9456f3
5
5
  SHA512:
6
- metadata.gz: d0490358ba5efc8a4b511ed881e2a4e1b7eec74fe9718fdeaec1439715a934ed60e4131725a05fc5ce2b8486ebb0a4fad7899ea8c544cc32933d6f7f8eb09a16
7
- data.tar.gz: 4ea5b8af5728285995945cdd8095f25ecadb444cd6919c0ad846865e1e44e849fa4216cd704b2880a404155839efbfdd185b8b901616a2c41f86b2363334a854
6
+ metadata.gz: c05c8d9b94ae34f70e5e4e3a017a1871da8497b9ecf281e967d73f0fc8033b39fc486e726c059b870935c52de544cc633d87979423f1241b9df9d4c2c0df4bf4
7
+ data.tar.gz: 9514e1203f2ccefe5b917538c47238d4e19687dd89ce4f6ebb6a9e03c4a83bb0c9f0c6c141f6a26086f2853d2445bb15912b308892a52bba6d1ff030de2d2aae
data/.gitignore CHANGED
@@ -4,6 +4,7 @@
4
4
  .config
5
5
  .yardoc
6
6
  Gemfile.lock
7
+ Gemfile.local
7
8
  InstalledFiles
8
9
  _yardoc
9
10
  coverage
@@ -8,6 +8,39 @@ AllCops:
8
8
  DisplayCopNames: true
9
9
  DisplayStyleGuide: true
10
10
 
11
+ Style/IndentationConsistency:
12
+ Exclude:
13
+ - lib/active_model/serializer/adapter/flatten_json.rb
14
+ - lib/active_model/serializer/adapter/fragment_cache.rb
15
+ - lib/active_model/serializer/adapter/json.rb
16
+ - lib/active_model/serializer/adapter/json/fragment_cache.rb
17
+ - lib/active_model/serializer/adapter/json_api.rb
18
+ - lib/active_model/serializer/adapter/json_api/fragment_cache.rb
19
+ - lib/active_model/serializer/adapter/json_api/pagination_links.rb
20
+ - lib/active_model/serializer/adapter/null.rb
21
+
22
+ Style/IndentationWidth:
23
+ Exclude:
24
+ - lib/active_model/serializer/adapter/flatten_json.rb
25
+ - lib/active_model/serializer/adapter/fragment_cache.rb
26
+ - lib/active_model/serializer/adapter/json.rb
27
+ - lib/active_model/serializer/adapter/json/fragment_cache.rb
28
+ - lib/active_model/serializer/adapter/json_api.rb
29
+ - lib/active_model/serializer/adapter/json_api/fragment_cache.rb
30
+ - lib/active_model/serializer/adapter/json_api/pagination_links.rb
31
+ - lib/active_model/serializer/adapter/null.rb
32
+
33
+ Style/AccessModifierIndentation:
34
+ Exclude:
35
+ - lib/active_model/serializer/adapter/flatten_json.rb
36
+ - lib/active_model/serializer/adapter/fragment_cache.rb
37
+ - lib/active_model/serializer/adapter/json.rb
38
+ - lib/active_model/serializer/adapter/json/fragment_cache.rb
39
+ - lib/active_model/serializer/adapter/json_api.rb
40
+ - lib/active_model/serializer/adapter/json_api/fragment_cache.rb
41
+ - lib/active_model/serializer/adapter/json_api/pagination_links.rb
42
+ - lib/active_model/serializer/adapter/null.rb
43
+
11
44
  Lint/NestedMethodDefinition:
12
45
  Enabled: false
13
46
  Exclude:
data/.simplecov CHANGED
@@ -8,7 +8,7 @@
8
8
  when 'jruby', 'rbx'
9
9
  96.0
10
10
  else
11
- 98.3
11
+ 98.1
12
12
  end
13
13
  }.to_f.round(2)
14
14
  # rubocop:disable Style/DoubleNegation
@@ -11,3 +11,4 @@
11
11
  * remove root key option and split JSON adapter [@joaomdmoura]
12
12
  * adds FlattenJSON as default adapter [@joaomdmoura]
13
13
  * adds support for `pagination links` at top level of JsonApi adapter [@bacarini]
14
+ * adds extended format for `include` option to JSONAPI adapter [@beauby]
data/Gemfile CHANGED
@@ -1,4 +1,8 @@
1
1
  source 'https://rubygems.org'
2
+ #
3
+ # Add a Gemfile.local to locally bundle gems outside of version control
4
+ local_gemfile = File.join(File.expand_path('..', __FILE__), 'Gemfile.local')
5
+ eval_gemfile local_gemfile if File.readable?(local_gemfile)
2
6
 
3
7
  # Specify your gem's dependencies in active_model_serializers.gemspec
4
8
  gemspec
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # ActiveModel::Serializer
2
2
 
3
- [![Build Status](https://travis-ci.org/rails-api/active_model_serializers.svg)](https://travis-ci.org/rails-api/active_model_serializers)
3
+ [![Build Status](https://travis-ci.org/rails-api/active_model_serializers.svg)](https://travis-ci.org/rails-api/active_model_serializers)
4
4
  <a href="https://codeclimate.com/github/rails-api/active_model_serializers"><img src="https://codeclimate.com/github/rails-api/active_model_serializers/badges/gpa.svg" /></a>
5
5
  <a href="https://codeclimate.com/github/rails-api/active_model_serializers/coverage"><img src="https://codeclimate.com/github/rails-api/active_model_serializers/badges/coverage.svg" /></a>
6
6
 
@@ -138,6 +138,23 @@ render json: @post, meta: { total: 10 }, meta_key: "custom_meta"
138
138
 
139
139
  `meta` will only be included in your response if you are using an Adapter that supports `root`, as JsonAPI and Json adapters, the default adapter (FlattenJson) doesn't have `root`.
140
140
 
141
+ ### Using a serializer without `render`
142
+
143
+ At times, you might want to use a serializer without rendering it to the view. For those cases, you can create an instance of `ActiveModel::SerializableResource` with
144
+ the resource you want to be serialized and call `.serializable_hash`.
145
+
146
+ ```ruby
147
+ def create
148
+ @message = current_user.messages.create!(message_params)
149
+ MessageCreationWorker.perform(serialized_message)
150
+ head 204
151
+ end
152
+
153
+ def serialized_message
154
+ ActiveModel::SerializableResource.new(@message).serializable_hash
155
+ end
156
+ ```
157
+
141
158
  ### Overriding association methods
142
159
 
143
160
  If you want to override any association, you can use:
@@ -187,12 +204,12 @@ Doesn't follow any specifc convention.
187
204
  This adapter follows 1.0 of the format specified in
188
205
  [jsonapi.org/format](http://jsonapi.org/format). It will include the associated
189
206
  resources in the `"included"` member when the resource names are included in the
190
- `include` option.
207
+ `include` option. Including nested associated resources is also supported.
191
208
 
192
209
  ```ruby
193
- render @posts, include: ['authors', 'comments']
210
+ render @posts, include: ['author', 'comments', 'comments.author']
194
211
  # or
195
- render @posts, include: 'authors,comments'
212
+ render @posts, include: 'author,comments,comments.author'
196
213
  ```
197
214
 
198
215
  ## Installation
@@ -283,7 +300,7 @@ The cache support is optimized to use the cached object in multiple request. An
283
300
 
284
301
  **[NOTE] Every object is individually cached.**
285
302
 
286
- **[NOTE] The cache is automatically expired after update an object but it's not deleted.**
303
+ **[NOTE] The cache is automatically expired after an object is updated, but it's not deleted.**
287
304
 
288
305
  ```ruby
289
306
  cache(options = nil) # options: ```{key, expires_in, compress, force, race_condition_ttl}```
@@ -30,9 +30,11 @@ resources in the `"included"` member when the resource names are included in the
30
30
  render @posts, include: 'authors,comments'
31
31
  ```
32
32
 
33
+ The format of the `include` option can be either a String composed of a comma-separated list of [relationship paths](http://jsonapi.org/format/#fetching-includes), an Array of Symbols and Hashes, or a mix of both.
34
+
33
35
  ## Choosing an adapter
34
36
 
35
- If you want to use a different adapter, such as JsonApi, you can change this in an initializer:
37
+ If you want to use a specify a default adapter, such as JsonApi, you can change this in an initializer:
36
38
 
37
39
  ```ruby
38
40
  ActiveModel::Serializer.config.adapter = ActiveModel::Serializer::Adapter::JsonApi
@@ -44,8 +46,59 @@ or
44
46
  ActiveModel::Serializer.config.adapter = :json_api
45
47
  ```
46
48
 
47
- If you want to have a root key in your responses you should use the Json adapter, instead of the default FlattenJson:
49
+ If you want to have a root key for each resource in your responses, you should use the Json or
50
+ JsonApi adapters instead of the default FlattenJson:
48
51
 
49
52
  ```ruby
50
53
  ActiveModel::Serializer.config.adapter = :json
51
54
  ```
55
+
56
+ ## Advanced adapter configuration
57
+
58
+ ### Registering an adapter
59
+
60
+ The default adapter can be configured, as above, to use any class given to it.
61
+
62
+ An adapter may also be specified, e.g. when rendering, as a class or as a symbol.
63
+ If a symbol, then the adapter must be, e.g. `:great_example`,
64
+ `ActiveModel::Serializer::Adapter::GreatExample`, or registered.
65
+
66
+ There are two ways to register an adapter:
67
+
68
+ 1) The simplest, is to subclass `ActiveModel::Serializer::Adapter`, e.g. the below will
69
+ register the `Example::UsefulAdapter` as `:useful_adapter`.
70
+
71
+ ```ruby
72
+ module Example
73
+ class UsefulAdapter < ActiveModel::Serializer::Adapter
74
+ end
75
+ end
76
+ ```
77
+
78
+ You'll notice that the name it registers is the class name underscored, not the full namespace.
79
+
80
+ Under the covers, when the `ActiveModel::Serializer::Adapter` is subclassed, it registers
81
+ the subclass as `register(:useful_adapter, Example::UsefulAdapter)`
82
+
83
+ 2) Any class can be registered as an adapter by calling `register` directly on the
84
+ `ActiveModel::Serializer::Adapter` class. e.g., the below registers `MyAdapter` as
85
+ `:special_adapter`.
86
+
87
+ ```ruby
88
+ class MyAdapter; end
89
+ ActiveModel::Serializer::Adapter.register(:special_adapter, MyAdapter)
90
+ ```
91
+
92
+ ### Looking up an adapter
93
+
94
+ | `ActiveModel::Serializer::Adapter.adapter_map` | A Hash of all known adapters { adapter_name => adapter_class } |
95
+ | `ActiveModel::Serializer::Adapter.adapters` | A (sorted) Array of all known adapter_names |
96
+ | `ActiveModel::Serializer::Adapter.lookup(name_or_klass)` | The adapter_class, else raises an `ActiveModel::Serializer::Adapter::UnknownAdapter` error |
97
+ | `ActiveModel::Serializer::Adapter.adapter_class(adapter)` | delegates to `ActiveModel::Serializer::Adapter.lookup(adapter)` |
98
+ | `ActiveModel::Serializer.adapter` | a convenience method for `ActiveModel::Serializer::Adapter.lookup(config.adapter)` |
99
+
100
+ The registered adapter name is always a String, but may be looked up as a Symbol or String.
101
+ Helpfully, the Symbol or String is underscored, so that `get(:my_adapter)` and `get("MyAdapter")`
102
+ may both be used.
103
+
104
+ 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)
@@ -6,6 +6,9 @@ module ActionController
6
6
 
7
7
  include ActionController::Renderers
8
8
 
9
+ # Deprecated
10
+ ADAPTER_OPTION_KEYS = ActiveModel::SerializableResource::ADAPTER_OPTION_KEYS
11
+
9
12
  included do
10
13
  class_attribute :_serialization_scope
11
14
  self._serialization_scope = :current_user
@@ -76,7 +76,7 @@ module ActiveModel
76
76
  private
77
77
 
78
78
  ActiveModelSerializers.silence_warnings do
79
- attr_reader :resource, :adapter_opts, :serializer_opts
79
+ attr_reader :resource, :adapter_opts, :serializer_opts
80
80
  end
81
81
  end
82
82
  end
@@ -10,6 +10,7 @@ module ActiveModel
10
10
  autoload :Lint
11
11
  autoload :Associations
12
12
  autoload :Fieldset
13
+ autoload :Utils
13
14
  include Configuration
14
15
  include Associations
15
16
 
@@ -94,19 +95,9 @@ module ActiveModel
94
95
  end
95
96
  end
96
97
 
98
+ # @see ActiveModel::Serializer::Adapter.lookup
97
99
  def self.adapter
98
- adapter_class = case config.adapter
99
- when Symbol
100
- ActiveModel::Serializer::Adapter.adapter_class(config.adapter)
101
- when Class
102
- config.adapter
103
- end
104
- unless adapter_class
105
- valid_adapters = Adapter.constants.map { |klass| ":#{klass.to_s.downcase}" }
106
- raise ArgumentError, "Unknown adapter: #{config.adapter}. Valid adapters are: #{valid_adapters}"
107
- end
108
-
109
- adapter_class
100
+ ActiveModel::Serializer::Adapter.lookup(config.adapter)
110
101
  end
111
102
 
112
103
  def self.root_name
@@ -1,12 +1,15 @@
1
1
  module ActiveModel
2
2
  class Serializer
3
3
  class Adapter
4
+ UnknownAdapterError = Class.new(ArgumentError)
5
+ ADAPTER_MAP = {}
6
+ private_constant :ADAPTER_MAP if defined?(private_constant)
4
7
  extend ActiveSupport::Autoload
5
- require 'active_model/serializer/adapter/json'
6
- require 'active_model/serializer/adapter/json_api'
7
- autoload :FlattenJson
8
- autoload :Null
9
8
  autoload :FragmentCache
9
+ autoload :Json
10
+ autoload :JsonApi
11
+ autoload :Null
12
+ autoload :FlattenJson
10
13
 
11
14
  def self.create(resource, options = {})
12
15
  override = options.delete(:adapter)
@@ -14,9 +17,67 @@ module ActiveModel
14
17
  klass.new(resource, options)
15
18
  end
16
19
 
20
+ # @see ActiveModel::Serializer::Adapter.lookup
17
21
  def self.adapter_class(adapter)
18
- adapter_name = adapter.to_s.classify.sub('API', 'Api')
19
- "ActiveModel::Serializer::Adapter::#{adapter_name}".safe_constantize
22
+ ActiveModel::Serializer::Adapter.lookup(adapter)
23
+ end
24
+
25
+ # Only the Adapter class has these methods.
26
+ # None of the sublasses have them.
27
+ class << ActiveModel::Serializer::Adapter
28
+ # @return Hash<adapter_name, adapter_class>
29
+ def adapter_map
30
+ ADAPTER_MAP
31
+ end
32
+
33
+ # @return [Array<Symbol>] list of adapter names
34
+ def adapters
35
+ adapter_map.keys.sort
36
+ end
37
+
38
+ # Adds an adapter 'klass' with 'name' to the 'adapter_map'
39
+ # Names are stringified and underscored
40
+ # @param [Symbol, String] name of the registered adapter
41
+ # @param [Class] klass - adapter class itself
42
+ # @example
43
+ # AMS::Adapter.register(:my_adapter, MyAdapter)
44
+ def register(name, klass)
45
+ adapter_map.update(name.to_s.underscore => klass)
46
+ self
47
+ end
48
+
49
+ # @param adapter [String, Symbol, Class] name to fetch adapter by
50
+ # @return [ActiveModel::Serializer::Adapter] subclass of Adapter
51
+ # @raise [UnknownAdapterError]
52
+ def lookup(adapter)
53
+ # 1. return if is a class
54
+ return adapter if adapter.is_a?(Class)
55
+ adapter_name = adapter.to_s.underscore
56
+ # 2. return if registered
57
+ adapter_map.fetch(adapter_name) {
58
+ # 3. try to find adapter class from environment
59
+ adapter_class = find_by_name(adapter_name)
60
+ register(adapter_name, adapter_class)
61
+ adapter_class
62
+ }
63
+ rescue NameError, ArgumentError => e
64
+ failure_message =
65
+ "NameError: #{e.message}. Unknown adapter: #{adapter.inspect}. Valid adapters are: #{adapters}"
66
+ raise UnknownAdapterError, failure_message, e.backtrace
67
+ end
68
+
69
+ # @api private
70
+ def find_by_name(adapter_name)
71
+ adapter_name = adapter_name.to_s.classify.tr('API', 'Api')
72
+ ActiveModel::Serializer::Adapter.const_get(adapter_name.to_sym) or # rubocop:disable Style/AndOr
73
+ fail UnknownAdapterError
74
+ end
75
+ private :find_by_name
76
+ end
77
+
78
+ # Automatically register adapters when subclassing
79
+ def self.inherited(subclass)
80
+ ActiveModel::Serializer::Adapter.register(subclass.to_s.demodulize, subclass)
20
81
  end
21
82
 
22
83
  attr_reader :serializer
@@ -1,10 +1,6 @@
1
- module ActiveModel
2
- class Serializer
3
- class Adapter
4
- class FlattenJson < Json
1
+ class ActiveModel::Serializer::Adapter::FlattenJson < ActiveModel::Serializer::Adapter::Json
5
2
  def serializable_hash(options = {})
6
- super
7
- @result
3
+ super.each_value.first
8
4
  end
9
5
 
10
6
  private
@@ -13,7 +9,4 @@ module ActiveModel
13
9
  def include_meta(json)
14
10
  json
15
11
  end
16
- end
17
- end
18
- end
19
12
  end
@@ -1,7 +1,4 @@
1
- module ActiveModel
2
- class Serializer
3
- class Adapter
4
- class FragmentCache
1
+ class ActiveModel::Serializer::Adapter::FragmentCache
5
2
  attr_reader :serializer
6
3
 
7
4
  def initialize(adapter, serializer, options)
@@ -75,7 +72,4 @@ module ActiveModel
75
72
  def to_valid_const_name(name)
76
73
  name.gsub('::', '_')
77
74
  end
78
- end
79
- end
80
- end
81
75
  end
@@ -1,17 +1,15 @@
1
- require 'active_model/serializer/adapter/json/fragment_cache'
1
+ class ActiveModel::Serializer::Adapter::Json < ActiveModel::Serializer::Adapter
2
+ extend ActiveSupport::Autoload
3
+ autoload :FragmentCache
2
4
 
3
- module ActiveModel
4
- class Serializer
5
- class Adapter
6
- class Json < Adapter
7
5
  def serializable_hash(options = nil)
8
6
  options ||= {}
9
7
  if serializer.respond_to?(:each)
10
- @result = serializer.map { |s| FlattenJson.new(s).serializable_hash(options) }
8
+ result = serializer.map { |s| FlattenJson.new(s).serializable_hash(options) }
11
9
  else
12
- @hash = {}
10
+ hash = {}
13
11
 
14
- @core = cache_check(serializer) do
12
+ core = cache_check(serializer) do
15
13
  serializer.attributes(options)
16
14
  end
17
15
 
@@ -21,13 +19,13 @@ module ActiveModel
21
19
 
22
20
  if serializer.respond_to?(:each)
23
21
  array_serializer = serializer
24
- @hash[association.key] = array_serializer.map do |item|
22
+ hash[association.key] = array_serializer.map do |item|
25
23
  cache_check(item) do
26
24
  item.attributes(opts)
27
25
  end
28
26
  end
29
27
  else
30
- @hash[association.key] =
28
+ hash[association.key] =
31
29
  if serializer && serializer.object
32
30
  cache_check(serializer) do
33
31
  serializer.attributes(options)
@@ -37,16 +35,13 @@ module ActiveModel
37
35
  end
38
36
  end
39
37
  end
40
- @result = @core.merge @hash
38
+ result = core.merge hash
41
39
  end
42
40
 
43
- { root => @result }
41
+ { root => result }
44
42
  end
45
43
 
46
44
  def fragment_cache(cached_hash, non_cached_hash)
47
- Json::FragmentCache.new().fragment_cache(cached_hash, non_cached_hash)
45
+ ActiveModel::Serializer::Adapter::Json::FragmentCache.new().fragment_cache(cached_hash, non_cached_hash)
48
46
  end
49
- end
50
- end
51
- end
52
47
  end
@@ -1,14 +1,5 @@
1
- require 'active_model/serializer/adapter/fragment_cache'
2
- module ActiveModel
3
- class Serializer
4
- class Adapter
5
- class Json < Adapter
6
- class FragmentCache
1
+ class ActiveModel::Serializer::Adapter::Json::FragmentCache
7
2
  def fragment_cache(cached_hash, non_cached_hash)
8
3
  non_cached_hash.merge cached_hash
9
4
  end
10
- end
11
- end
12
- end
13
- end
14
5
  end
@@ -1,19 +1,13 @@
1
- require 'active_model/serializer/adapter/json_api/fragment_cache'
2
- require 'active_model/serializer/adapter/json_api/pagination_links'
1
+ class ActiveModel::Serializer::Adapter::JsonApi < ActiveModel::Serializer::Adapter
2
+ extend ActiveSupport::Autoload
3
+ autoload :PaginationLinks
4
+ autoload :FragmentCache
3
5
 
4
- module ActiveModel
5
- class Serializer
6
- class Adapter
7
- class JsonApi < Adapter
8
6
  def initialize(serializer, options = {})
9
7
  super
10
8
  @hash = { data: [] }
11
9
 
12
- @options[:include] ||= []
13
- if @options[:include].is_a?(String)
14
- @options[:include] = @options[:include].split(',')
15
- end
16
-
10
+ @included = ActiveModel::Serializer::Utils.include_args_to_hash(@options[:include])
17
11
  fields = options.delete(:fields)
18
12
  if fields
19
13
  @fieldset = ActiveModel::Serializer::Fieldset.new(fields, serializer.json_key)
@@ -49,7 +43,7 @@ module ActiveModel
49
43
 
50
44
  def fragment_cache(cached_hash, non_cached_hash)
51
45
  root = false if @options.include?(:include)
52
- JsonApi::FragmentCache.new.fragment_cache(root, cached_hash, non_cached_hash)
46
+ ActiveModel::Serializer::Adapter::JsonApi::FragmentCache.new().fragment_cache(root, cached_hash, non_cached_hash)
53
47
  end
54
48
 
55
49
  private
@@ -62,6 +56,12 @@ module ActiveModel
62
56
  end
63
57
  end
64
58
 
59
+ def add_relationships(resource, name, serializers)
60
+ resource[:relationships] ||= {}
61
+ resource[:relationships][name] ||= { data: [] }
62
+ resource[:relationships][name][:data] += serializers.map { |serializer| { type: serializer.json_api_type, id: serializer.id.to_s } }
63
+ end
64
+
65
65
  def resource_identifier_id_for(serializer)
66
66
  if serializer.respond_to?(:id)
67
67
  serializer.id
@@ -113,56 +113,46 @@ module ActiveModel
113
113
  end
114
114
 
115
115
  def included_for(serializer)
116
- serializer.associations.flat_map { |assoc| _included_for(assoc.key, assoc.serializer) }.uniq
116
+ included = @included.flat_map do |inc|
117
+ association = serializer.associations.find { |assoc| assoc.key == inc.first }
118
+ _included_for(association.serializer, inc.second) if association
119
+ end
120
+
121
+ included.uniq
117
122
  end
118
123
 
119
- def _included_for(resource_name, serializer, parent = nil)
124
+ def _included_for(serializer, includes)
120
125
  if serializer.respond_to?(:each)
121
- serializer.flat_map { |s| _included_for(resource_name, s, parent) }.uniq
126
+ serializer.flat_map { |s| _included_for(s, includes) }.uniq
122
127
  else
123
128
  return [] unless serializer && serializer.object
124
- result = []
125
- resource_path = [parent, resource_name].compact.join('.')
126
-
127
- if include_assoc?(resource_path)
128
- primary_data = primary_data_for(serializer, @options)
129
- relationships = relationships_for(serializer)
130
- primary_data[:relationships] = relationships if relationships.any?
131
- result.push(primary_data)
132
- end
133
129
 
134
- if include_nested_assoc?(resource_path)
135
- non_empty_associations = serializer.associations.select(&:serializer)
130
+ primary_data = primary_data_for(serializer, @options)
131
+ relationships = relationships_for(serializer)
132
+ primary_data[:relationships] = relationships if relationships.any?
133
+
134
+ included = [primary_data]
136
135
 
137
- non_empty_associations.each do |association|
138
- result.concat(_included_for(association.key, association.serializer, resource_path))
139
- result.uniq!
136
+ includes.each do |inc|
137
+ association = serializer.associations.find { |assoc| assoc.key == inc.first }
138
+ if association
139
+ included.concat(_included_for(association.serializer, inc.second))
140
+ included.uniq!
140
141
  end
141
142
  end
142
- result
143
- end
144
- end
145
-
146
- def include_assoc?(assoc)
147
- check_assoc("#{assoc}$")
148
- end
149
-
150
- def include_nested_assoc?(assoc)
151
- check_assoc("#{assoc}.")
152
- end
153
143
 
154
- def check_assoc(assoc)
155
- @options[:include].any? { |s| s.match(/^#{assoc.gsub('.', '\.')}/) }
144
+ included
145
+ end
156
146
  end
157
147
 
158
148
  def add_links(options)
159
- links = @hash.fetch(:meta) { {} }
149
+ links = @hash.fetch(:links) { {} }
160
150
  collection = serializer.object
161
- @hash[:meta] = add_pagination_links(links, collection, options) if paginated?(collection)
151
+ @hash[:links] = add_pagination_links(links, collection, options) if paginated?(collection)
162
152
  end
163
153
 
164
- def add_pagination_links(links, collection, options)
165
- pagination_links = JsonApi::PaginationLinks.new(collection, options[:context]).serializable_hash(options)
154
+ def add_pagination_links(links, resources, options)
155
+ pagination_links = ActiveModel::Serializer::Adapter::JsonApi::PaginationLinks.new(resources, options[:context]).serializable_hash(options)
166
156
  links.update(pagination_links)
167
157
  end
168
158
 
@@ -171,7 +161,4 @@ module ActiveModel
171
161
  collection.respond_to?(:total_pages) &&
172
162
  collection.respond_to?(:size)
173
163
  end
174
- end
175
- end
176
- end
177
164
  end
@@ -1,9 +1,4 @@
1
- require 'active_model/serializer/adapter/fragment_cache'
2
- module ActiveModel
3
- class Serializer
4
- class Adapter
5
- class JsonApi < Adapter
6
- class FragmentCache
1
+ class ActiveModel::Serializer::Adapter::JsonApi::FragmentCache
7
2
  def fragment_cache(root, cached_hash, non_cached_hash)
8
3
  hash = {}
9
4
  core_cached = cached_hash.first
@@ -15,8 +10,4 @@ module ActiveModel
15
10
 
16
11
  hash.deep_merge no_root_non_cache.deep_merge no_root_cache
17
12
  end
18
- end
19
- end
20
- end
21
- end
22
13
  end
@@ -1,8 +1,4 @@
1
- module ActiveModel
2
- class Serializer
3
- class Adapter
4
- class JsonApi < Adapter
5
- class PaginationLinks
1
+ class ActiveModel::Serializer::Adapter::JsonApi::PaginationLinks
6
2
  FIRST_PAGE = 1
7
3
 
8
4
  attr_reader :collection, :context
@@ -51,8 +47,4 @@ module ActiveModel
51
47
  def query_parameters
52
48
  @query_parameters ||= context.query_parameters
53
49
  end
54
- end
55
- end
56
- end
57
- end
58
50
  end
@@ -1,11 +1,5 @@
1
- module ActiveModel
2
- class Serializer
3
- class Adapter
4
- class Null < Adapter
1
+ class ActiveModel::Serializer::Adapter::Null < ActiveModel::Serializer::Adapter
5
2
  def serializable_hash(options = nil)
6
3
  {}
7
4
  end
8
- end
9
- end
10
- end
11
5
  end
@@ -18,7 +18,7 @@ module ActiveModel
18
18
  private
19
19
 
20
20
  ActiveModelSerializers.silence_warnings do
21
- attr_reader :raw_fields, :root
21
+ attr_reader :raw_fields, :root
22
22
  end
23
23
 
24
24
  def parsed_fields
@@ -26,7 +26,7 @@ module ActiveModel
26
26
  raw_fields.inject({}) { |h, (k, v)| h[k.to_sym] = v.map(&:to_sym); h }
27
27
  elsif raw_fields.is_a?(Array)
28
28
  if root.nil?
29
- raise ArgumentError, 'The root argument must be specified if the fileds argument is an array.'
29
+ raise ArgumentError, 'The root argument must be specified if the fields argument is an array.'
30
30
  end
31
31
  hash = {}
32
32
  hash[root.to_sym] = raw_fields.map(&:to_sym)
@@ -0,0 +1,35 @@
1
+ module ActiveModel::Serializer::Utils
2
+ module_function
3
+
4
+ # Translates a comma separated list of dot separated paths (JSONAPI format) into a Hash.
5
+ # Example: `'posts.author, posts.comments.upvotes, posts.comments.author'` would become `{ posts: { author: {}, comments: { author: {}, upvotes: {} } } }`.
6
+ #
7
+ # @param [String] included
8
+ # @return [Hash] a Hash representing the same tree structure
9
+ def include_string_to_hash(included)
10
+ included.delete(' ').split(',').inject({}) do |hash, path|
11
+ hash.deep_merge!(path.split('.').reverse_each.inject({}) { |a, e| { e.to_sym => a } })
12
+ end
13
+ end
14
+
15
+ # Translates the arguments passed to the include option into a Hash. The format can be either
16
+ # a String (see #include_string_to_hash), an Array of Symbols and Hashes, or a mix of both.
17
+ # Example: `posts: [:author, comments: [:author, :upvotes]]` would become `{ posts: { author: {}, comments: { author: {}, upvotes: {} } } }`.
18
+ #
19
+ # @param [Symbol, Hash, Array, String] included
20
+ # @return [Hash] a Hash representing the same tree structure
21
+ def include_args_to_hash(included)
22
+ case included
23
+ when Symbol
24
+ { included => {} }
25
+ when Hash
26
+ included.each_with_object({}) { |(key, value), hash| hash[key] = include_args_to_hash(value) }
27
+ when Array
28
+ included.inject({}) { |a, e| a.merge!(include_args_to_hash(e)) }
29
+ when String
30
+ include_string_to_hash(included)
31
+ else
32
+ {}
33
+ end
34
+ end
35
+ end
@@ -1,5 +1,5 @@
1
1
  module ActiveModel
2
2
  class Serializer
3
- VERSION = "0.10.8"
3
+ VERSION = "0.10.10"
4
4
  end
5
5
  end
@@ -43,29 +43,29 @@ module ActionController
43
43
 
44
44
  def render_resource_with_include
45
45
  setup_post
46
- render json: @post, include: 'author', adapter: :json_api
46
+ render json: @post, include: [:author], adapter: :json_api
47
47
  end
48
48
 
49
49
  def render_resource_with_nested_include
50
50
  setup_post
51
- render json: @post, include: 'comments.author', adapter: :json_api
51
+ render json: @post, include: [comments: [:author]], adapter: :json_api
52
52
  end
53
53
 
54
54
  def render_resource_with_nested_has_many_include
55
55
  setup_post
56
- render json: @post, include: ['author', 'author.roles'], adapter: :json_api
56
+ render json: @post, include: 'author.roles', adapter: :json_api
57
57
  end
58
58
 
59
59
  def render_resource_with_missing_nested_has_many_include
60
60
  setup_post
61
61
  @post.author = @author2 # author2 has no roles.
62
- render json: @post, include: 'author,author.roles', adapter: :json_api
62
+ render json: @post, include: [author: [:roles]], adapter: :json_api
63
63
  end
64
64
 
65
65
  def render_collection_with_missing_nested_has_many_include
66
66
  setup_post
67
67
  @post.author = @author2
68
- render json: [@post, @post2], include: 'author,author.roles', adapter: :json_api
68
+ render json: [@post, @post2], include: [author: [:roles]], adapter: :json_api
69
69
  end
70
70
 
71
71
  def render_collection_without_include
@@ -75,7 +75,7 @@ module ActionController
75
75
 
76
76
  def render_collection_with_include
77
77
  setup_post
78
- render json: [@post], include: %w(author comments), adapter: :json_api
78
+ render json: [@post], include: 'author, comments', adapter: :json_api
79
79
  end
80
80
  end
81
81
 
@@ -141,8 +141,7 @@ module ActionController
141
141
  get :render_resource_with_nested_include
142
142
  response = JSON.parse(@response.body)
143
143
  assert response.key? 'included'
144
- assert_equal 1, response['included'].size
145
- assert_equal 'Anonymous', response['included'].first['attributes']['name']
144
+ assert_equal 3, response['included'].size
146
145
  end
147
146
 
148
147
  def test_render_collection_without_include
@@ -25,7 +25,7 @@ class DefaultScopeNameTest < ActionController::TestCase
25
25
  end
26
26
  end
27
27
 
28
- tests UserTestController
28
+ tests UserTestController
29
29
 
30
30
  def test_default_scope_name
31
31
  get :render_new_user
@@ -0,0 +1,9 @@
1
+ require 'test_helper'
2
+
3
+ class ActiveRecordTest < Minitest::Test
4
+ include ActiveModel::Serializer::Lint::Tests
5
+
6
+ def setup
7
+ @resource = ARModels::Post.new
8
+ end
9
+ end
@@ -38,7 +38,7 @@ module ActiveModel
38
38
  end
39
39
 
40
40
  def test_includes_linked_post
41
- @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer, include: 'post')
41
+ @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer, include: [:post])
42
42
  expected = [{
43
43
  id: '42',
44
44
  type: 'posts',
@@ -56,7 +56,7 @@ module ActiveModel
56
56
  end
57
57
 
58
58
  def test_limiting_linked_post_fields
59
- @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer, include: 'post', fields: { post: [:title] })
59
+ @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer, include: [:post], fields: { post: [:title] })
60
60
  expected = [{
61
61
  id: '42',
62
62
  type: 'posts',
@@ -108,7 +108,7 @@ module ActiveModel
108
108
 
109
109
  def test_include_linked_resources_with_type_name
110
110
  serializer = BlogSerializer.new(@blog)
111
- adapter = ActiveModel::Serializer::Adapter::JsonApi.new(serializer, include: %w(writer articles))
111
+ adapter = ActiveModel::Serializer::Adapter::JsonApi.new(serializer, include: [:writer, :articles])
112
112
  linked = adapter.serializable_hash[:included]
113
113
  expected = [
114
114
  {
@@ -24,7 +24,7 @@ module ActiveModel
24
24
  @serializer = PostPreviewSerializer.new(@post)
25
25
  @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(
26
26
  @serializer,
27
- include: %w(comments author)
27
+ include: [:comments, :author]
28
28
  )
29
29
  end
30
30
 
@@ -42,7 +42,7 @@ module ActiveModel
42
42
  end
43
43
 
44
44
  def test_includes_linked_comments
45
- @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer, include: 'comments')
45
+ @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer, include: [:comments])
46
46
  expected = [{
47
47
  id: '1',
48
48
  type: 'comments',
@@ -68,7 +68,7 @@ module ActiveModel
68
68
  end
69
69
 
70
70
  def test_limit_fields_of_linked_comments
71
- @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer, include: 'comments', fields: { comment: [:id] })
71
+ @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer, include: [:comments], fields: { comment: [:id] })
72
72
  expected = [{
73
73
  id: '1',
74
74
  type: 'comments',
@@ -28,7 +28,7 @@ module ActiveModel
28
28
  @virtual_value = VirtualValue.new(id: 1)
29
29
 
30
30
  @serializer = AuthorSerializer.new(@author)
31
- @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer, include: 'bio,posts')
31
+ @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer, include: [:bio, :posts])
32
32
  end
33
33
 
34
34
  def test_includes_bio_id
@@ -38,7 +38,7 @@ module ActiveModel
38
38
  end
39
39
 
40
40
  def test_includes_linked_bio
41
- @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer, include: 'bio')
41
+ @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer, include: [:bio])
42
42
 
43
43
  expected = [
44
44
  {
@@ -43,11 +43,11 @@ module ActiveModel
43
43
  serializer = ArraySerializer.new([@first_post, @second_post])
44
44
  adapter = ActiveModel::Serializer::Adapter::JsonApi.new(
45
45
  serializer,
46
- include: ['author', 'author.bio', 'comments']
46
+ include: [:comments, author: [:bio]]
47
47
  )
48
48
  alt_adapter = ActiveModel::Serializer::Adapter::JsonApi.new(
49
49
  serializer,
50
- include: 'author,author.bio,comments'
50
+ include: [:comments, author: [:bio]]
51
51
  )
52
52
 
53
53
  expected = {
@@ -153,11 +153,11 @@ module ActiveModel
153
153
  serializer = BioSerializer.new @bio1
154
154
  adapter = ActiveModel::Serializer::Adapter::JsonApi.new(
155
155
  serializer,
156
- include: ['author', 'author.posts']
156
+ include: [author: [:posts]]
157
157
  )
158
158
  alt_adapter = ActiveModel::Serializer::Adapter::JsonApi.new(
159
159
  serializer,
160
- include: 'author,author.posts'
160
+ include: [author: [:posts]]
161
161
  )
162
162
 
163
163
  expected = [
@@ -224,7 +224,7 @@ module ActiveModel
224
224
  serializer = ArraySerializer.new([@first_comment, @second_comment])
225
225
  adapter = ActiveModel::Serializer::Adapter::JsonApi.new(
226
226
  serializer,
227
- include: ['post']
227
+ include: [:post]
228
228
  )
229
229
 
230
230
  expected = [
@@ -257,7 +257,7 @@ module ActiveModel
257
257
  serializer = PostPreviewSerializer.new(@first_post)
258
258
  adapter = ActiveModel::Serializer::Adapter::JsonApi.new(
259
259
  serializer,
260
- include: ['author']
260
+ include: [:author]
261
261
  )
262
262
 
263
263
  expected = {
@@ -19,16 +19,6 @@ module ActiveModel
19
19
  assert_equal @serializer, @adapter.serializer
20
20
  end
21
21
 
22
- def test_adapter_class_for_known_adapter
23
- klass = ActiveModel::Serializer::Adapter.adapter_class(:json_api)
24
- assert_equal ActiveModel::Serializer::Adapter::JsonApi, klass
25
- end
26
-
27
- def test_adapter_class_for_unknown_adapter
28
- klass = ActiveModel::Serializer::Adapter.adapter_class(:json_simple)
29
- assert_nil klass
30
- end
31
-
32
22
  def test_create_adapter
33
23
  adapter = ActiveModel::Serializer::Adapter.create(@serializer)
34
24
  assert_equal ActiveModel::Serializer::Adapter::FlattenJson, adapter.class
@@ -1,8 +1,15 @@
1
1
  module ActiveModel
2
2
  class Serializer
3
3
  class AdapterForTest < Minitest::Test
4
+ UnknownAdapterError = ::ActiveModel::Serializer::Adapter::UnknownAdapterError
5
+
4
6
  def setup
5
7
  @previous_adapter = ActiveModel::Serializer.config.adapter
8
+ # Eager load adapters
9
+ ActiveModel::Serializer::Adapter.eager_load!
10
+ [:json_api, :flatten_json, :null, :json].each do |adapter_name|
11
+ ActiveModel::Serializer::Adapter.lookup(adapter_name)
12
+ end
6
13
  end
7
14
 
8
15
  def teardown
@@ -20,6 +27,7 @@ module ActiveModel
20
27
  adapter = ActiveModel::Serializer.adapter
21
28
  assert_equal ActiveModel::Serializer::Adapter::Null, adapter
22
29
  ensure
30
+ ActiveModel::Serializer.config.adapter = @previous_adapter
23
31
  end
24
32
 
25
33
  def test_overwrite_adapter_with_class
@@ -32,7 +40,7 @@ module ActiveModel
32
40
  def test_raises_exception_if_invalid_symbol_given
33
41
  ActiveModel::Serializer.config.adapter = :unknown
34
42
 
35
- assert_raises ArgumentError do
43
+ assert_raises UnknownAdapterError do
36
44
  ActiveModel::Serializer.adapter
37
45
  end
38
46
  end
@@ -40,10 +48,123 @@ module ActiveModel
40
48
  def test_raises_exception_if_it_does_not_know_hot_to_infer_adapter
41
49
  ActiveModel::Serializer.config.adapter = 42
42
50
 
43
- assert_raises ArgumentError do
51
+ assert_raises UnknownAdapterError do
44
52
  ActiveModel::Serializer.adapter
45
53
  end
46
54
  end
55
+
56
+ def test_adapter_class_for_known_adapter
57
+ klass = ActiveModel::Serializer::Adapter.adapter_class(:json_api)
58
+ assert_equal ActiveModel::Serializer::Adapter::JsonApi, klass
59
+ end
60
+
61
+ def test_adapter_class_for_unknown_adapter
62
+ assert_raises UnknownAdapterError do
63
+ ActiveModel::Serializer::Adapter.adapter_class(:json_simple)
64
+ end
65
+ end
66
+
67
+ def test_adapter_map
68
+ expected_adapter_map = {
69
+ 'json'.freeze => ActiveModel::Serializer::Adapter::Json,
70
+ 'json_api'.freeze => ActiveModel::Serializer::Adapter::JsonApi,
71
+ 'flatten_json'.freeze => ActiveModel::Serializer::Adapter::FlattenJson,
72
+ 'null'.freeze => ActiveModel::Serializer::Adapter::Null
73
+ }
74
+ assert_equal ActiveModel::Serializer::Adapter.adapter_map, expected_adapter_map
75
+ end
76
+
77
+ def test_adapters
78
+ assert_equal ActiveModel::Serializer::Adapter.adapters.sort, [
79
+ 'flatten_json'.freeze,
80
+ 'json'.freeze,
81
+ 'json_api'.freeze,
82
+ 'null'.freeze
83
+ ]
84
+ end
85
+
86
+ def test_lookup_adapter_by_string_name
87
+ assert_equal ActiveModel::Serializer::Adapter.lookup('json'.freeze), ActiveModel::Serializer::Adapter::Json
88
+ end
89
+
90
+ def test_lookup_adapter_by_symbol_name
91
+ assert_equal ActiveModel::Serializer::Adapter.lookup(:json), ActiveModel::Serializer::Adapter::Json
92
+ end
93
+
94
+ def test_lookup_adapter_by_class
95
+ klass = ActiveModel::Serializer::Adapter::Json
96
+ assert_equal ActiveModel::Serializer::Adapter.lookup(klass), klass
97
+ end
98
+
99
+ def test_lookup_adapter_from_environment_registers_adapter
100
+ ActiveModel::Serializer::Adapter.const_set(:AdapterFromEnvironment, Class.new)
101
+ klass = ::ActiveModel::Serializer::Adapter::AdapterFromEnvironment
102
+ name = 'adapter_from_environment'.freeze
103
+ assert_equal ActiveModel::Serializer::Adapter.lookup(name), klass
104
+ assert ActiveModel::Serializer::Adapter.adapters.include?(name)
105
+ ensure
106
+ ActiveModel::Serializer::Adapter.adapter_map.delete(name)
107
+ ActiveModel::Serializer::Adapter.send(:remove_const, :AdapterFromEnvironment)
108
+ end
109
+
110
+ def test_lookup_adapter_for_unknown_name
111
+ assert_raises UnknownAdapterError do
112
+ ActiveModel::Serializer::Adapter.lookup(:json_simple)
113
+ end
114
+ end
115
+
116
+ def test_adapter
117
+ assert_equal ActiveModel::Serializer.config.adapter, :flatten_json
118
+ assert_equal ActiveModel::Serializer.adapter, ActiveModel::Serializer::Adapter::FlattenJson
119
+ end
120
+
121
+ def test_register_adapter
122
+ new_adapter_name = :foo
123
+ new_adapter_klass = Class.new
124
+ ActiveModel::Serializer::Adapter.register(new_adapter_name, new_adapter_klass)
125
+ assert ActiveModel::Serializer::Adapter.adapters.include?('foo'.freeze)
126
+ assert ActiveModel::Serializer::Adapter.lookup(:foo), new_adapter_klass
127
+ ensure
128
+ ActiveModel::Serializer::Adapter.adapter_map.delete(new_adapter_name.to_s)
129
+ end
130
+
131
+ def test_inherited_adapter_hooks_register_adapter
132
+ Object.const_set(:MyAdapter, Class.new)
133
+ my_adapter = MyAdapter
134
+ ActiveModel::Serializer::Adapter.inherited(my_adapter)
135
+ assert_equal ActiveModel::Serializer::Adapter.lookup(:my_adapter), my_adapter
136
+ ensure
137
+ ActiveModel::Serializer::Adapter.adapter_map.delete('my_adapter'.freeze)
138
+ Object.send(:remove_const, :MyAdapter)
139
+ end
140
+
141
+ def test_inherited_adapter_hooks_register_demodulized_adapter
142
+ Object.const_set(:MyNamespace, Module.new)
143
+ MyNamespace.const_set(:MyAdapter, Class.new)
144
+ my_adapter = MyNamespace::MyAdapter
145
+ ActiveModel::Serializer::Adapter.inherited(my_adapter)
146
+ assert_equal ActiveModel::Serializer::Adapter.lookup(:my_adapter), my_adapter
147
+ ensure
148
+ ActiveModel::Serializer::Adapter.adapter_map.delete('my_adapter'.freeze)
149
+ MyNamespace.send(:remove_const, :MyAdapter)
150
+ Object.send(:remove_const, :MyNamespace)
151
+ end
152
+
153
+ def test_inherited_adapter_hooks_register_subclass_of_registered_adapter
154
+ Object.const_set(:MyAdapter, Class.new)
155
+ my_adapter = MyAdapter
156
+ Object.const_set(:MySubclassedAdapter, Class.new(MyAdapter))
157
+ my_subclassed_adapter = MySubclassedAdapter
158
+ ActiveModel::Serializer::Adapter.inherited(my_adapter)
159
+ ActiveModel::Serializer::Adapter.inherited(my_subclassed_adapter)
160
+ assert_equal ActiveModel::Serializer::Adapter.lookup(:my_adapter), my_adapter
161
+ assert_equal ActiveModel::Serializer::Adapter.lookup(:my_subclassed_adapter), my_subclassed_adapter
162
+ ensure
163
+ ActiveModel::Serializer::Adapter.adapter_map.delete('my_adapter'.freeze)
164
+ ActiveModel::Serializer::Adapter.adapter_map.delete('my_subclassed_adapter'.freeze)
165
+ Object.send(:remove_const, :MyAdapter)
166
+ Object.send(:remove_const, :MySubclassedAdapter)
167
+ end
47
168
  end
48
169
  end
49
170
  end
@@ -0,0 +1,79 @@
1
+ require 'test_helper'
2
+
3
+ module ActiveModel
4
+ class Serializer
5
+ module Utils
6
+ class IncludeArgsToHashTest < Minitest::Test
7
+ def test_nil
8
+ input = nil
9
+ expected = {}
10
+ actual = ActiveModel::Serializer::Utils.include_args_to_hash(input)
11
+ assert_equal(expected, actual)
12
+ end
13
+
14
+ def test_empty_string
15
+ input = ''
16
+ expected = {}
17
+ actual = ActiveModel::Serializer::Utils.include_args_to_hash(input)
18
+ assert_equal(expected, actual)
19
+ end
20
+
21
+ def test_single_string
22
+ input = 'author'
23
+ expected = { author: {} }
24
+ actual = ActiveModel::Serializer::Utils.include_args_to_hash(input)
25
+ assert_equal(expected, actual)
26
+ end
27
+
28
+ def test_multiple_strings
29
+ input = 'author,comments'
30
+ expected = { author: {}, comments: {} }
31
+ actual = ActiveModel::Serializer::Utils.include_args_to_hash(input)
32
+ assert_equal(expected, actual)
33
+ end
34
+
35
+ def test_multiple_strings_with_space
36
+ input = 'author, comments'
37
+ expected = { author: {}, comments: {} }
38
+ actual = ActiveModel::Serializer::Utils.include_args_to_hash(input)
39
+ assert_equal(expected, actual)
40
+ end
41
+
42
+ def test_nested_string
43
+ input = 'posts.author'
44
+ expected = { posts: { author: {} } }
45
+ actual = ActiveModel::Serializer::Utils.include_args_to_hash(input)
46
+ assert_equal(expected, actual)
47
+ end
48
+
49
+ def test_multiple_nested_string
50
+ input = 'posts.author,posts.comments.author,comments'
51
+ expected = { posts: { author: {}, comments: { author: {} } }, comments: {} }
52
+ actual = ActiveModel::Serializer::Utils.include_args_to_hash(input)
53
+ assert_equal(expected, actual)
54
+ end
55
+
56
+ def test_empty_array
57
+ input = []
58
+ expected = {}
59
+ actual = ActiveModel::Serializer::Utils.include_args_to_hash(input)
60
+ assert_equal(expected, actual)
61
+ end
62
+
63
+ def test_simple_array
64
+ input = [:comments, :author]
65
+ expected = { author: {}, comments: {} }
66
+ actual = ActiveModel::Serializer::Utils.include_args_to_hash(input)
67
+ assert_equal(expected, actual)
68
+ end
69
+
70
+ def test_nested_array
71
+ input = [:comments, posts: [:author, comments: [:author]]]
72
+ expected = { posts: { author: {}, comments: { author: {} } }, comments: {} }
73
+ actual = ActiveModel::Serializer::Utils.include_args_to_hash(input)
74
+ assert_equal(expected, actual)
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cheap_ams
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.8
4
+ version: 0.10.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Klabnik
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-09-10 00:00:00.000000000 Z
11
+ date: 2015-09-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -160,6 +160,7 @@ files:
160
160
  - lib/active_model/serializer/railtie.rb
161
161
  - lib/active_model/serializer/reflection.rb
162
162
  - lib/active_model/serializer/singular_reflection.rb
163
+ - lib/active_model/serializer/utils.rb
163
164
  - lib/active_model/serializer/version.rb
164
165
  - lib/active_model_serializers.rb
165
166
  - lib/generators/serializer/USAGE
@@ -173,6 +174,7 @@ files:
173
174
  - test/action_controller/json_api/pagination_test.rb
174
175
  - test/action_controller/serialization_scope_name_test.rb
175
176
  - test/action_controller/serialization_test.rb
177
+ - test/active_record_test.rb
176
178
  - test/adapter/fragment_cache_test.rb
177
179
  - test/adapter/json/belongs_to_test.rb
178
180
  - test/adapter/json/collection_test.rb
@@ -217,6 +219,7 @@ files:
217
219
  - test/support/stream_capture.rb
218
220
  - test/support/test_case.rb
219
221
  - test/test_helper.rb
222
+ - test/utils/include_args_to_hash_test.rb
220
223
  homepage: https://github.com/rails-api/active_model_serializers
221
224
  licenses:
222
225
  - MIT
@@ -248,6 +251,7 @@ test_files:
248
251
  - test/action_controller/json_api/pagination_test.rb
249
252
  - test/action_controller/serialization_scope_name_test.rb
250
253
  - test/action_controller/serialization_test.rb
254
+ - test/active_record_test.rb
251
255
  - test/adapter/fragment_cache_test.rb
252
256
  - test/adapter/json/belongs_to_test.rb
253
257
  - test/adapter/json/collection_test.rb
@@ -292,3 +296,4 @@ test_files:
292
296
  - test/support/stream_capture.rb
293
297
  - test/support/test_case.rb
294
298
  - test/test_helper.rb
299
+ - test/utils/include_args_to_hash_test.rb