cheap_ams 0.10.8 → 0.10.10

Sign up to get free protection for your applications and to get access to all the features.
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