active_model_serializers_custom 0.10.90

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 (215) hide show
  1. checksums.yaml +7 -0
  2. data/.github/ISSUE_TEMPLATE.md +29 -0
  3. data/.github/PULL_REQUEST_TEMPLATE.md +15 -0
  4. data/.gitignore +35 -0
  5. data/.rubocop.yml +109 -0
  6. data/.simplecov +110 -0
  7. data/.travis.yml +63 -0
  8. data/CHANGELOG.md +727 -0
  9. data/CODE_OF_CONDUCT.md +74 -0
  10. data/CONTRIBUTING.md +105 -0
  11. data/Gemfile +74 -0
  12. data/MIT-LICENSE +22 -0
  13. data/README.md +305 -0
  14. data/Rakefile +76 -0
  15. data/active_model_serializers.gemspec +64 -0
  16. data/appveyor.yml +28 -0
  17. data/bin/bench +171 -0
  18. data/bin/bench_regression +316 -0
  19. data/bin/rubocop +38 -0
  20. data/bin/serve_benchmark +39 -0
  21. data/docs/README.md +41 -0
  22. data/docs/STYLE.md +58 -0
  23. data/docs/general/adapters.md +269 -0
  24. data/docs/general/caching.md +58 -0
  25. data/docs/general/configuration_options.md +185 -0
  26. data/docs/general/deserialization.md +100 -0
  27. data/docs/general/fields.md +31 -0
  28. data/docs/general/getting_started.md +133 -0
  29. data/docs/general/instrumentation.md +40 -0
  30. data/docs/general/key_transforms.md +40 -0
  31. data/docs/general/logging.md +21 -0
  32. data/docs/general/rendering.md +293 -0
  33. data/docs/general/serializers.md +495 -0
  34. data/docs/how-open-source-maintained.jpg +0 -0
  35. data/docs/howto/add_pagination_links.md +138 -0
  36. data/docs/howto/add_relationship_links.md +140 -0
  37. data/docs/howto/add_root_key.md +62 -0
  38. data/docs/howto/grape_integration.md +42 -0
  39. data/docs/howto/outside_controller_use.md +66 -0
  40. data/docs/howto/passing_arbitrary_options.md +27 -0
  41. data/docs/howto/serialize_poro.md +73 -0
  42. data/docs/howto/test.md +154 -0
  43. data/docs/howto/upgrade_from_0_8_to_0_10.md +265 -0
  44. data/docs/integrations/ember-and-json-api.md +147 -0
  45. data/docs/integrations/grape.md +19 -0
  46. data/docs/jsonapi/errors.md +56 -0
  47. data/docs/jsonapi/schema.md +151 -0
  48. data/docs/jsonapi/schema/schema.json +366 -0
  49. data/docs/rfcs/0000-namespace.md +106 -0
  50. data/docs/rfcs/template.md +15 -0
  51. data/lib/action_controller/serialization.rb +76 -0
  52. data/lib/active_model/serializable_resource.rb +13 -0
  53. data/lib/active_model/serializer.rb +418 -0
  54. data/lib/active_model/serializer/adapter.rb +26 -0
  55. data/lib/active_model/serializer/adapter/attributes.rb +17 -0
  56. data/lib/active_model/serializer/adapter/base.rb +20 -0
  57. data/lib/active_model/serializer/adapter/json.rb +17 -0
  58. data/lib/active_model/serializer/adapter/json_api.rb +17 -0
  59. data/lib/active_model/serializer/adapter/null.rb +17 -0
  60. data/lib/active_model/serializer/array_serializer.rb +14 -0
  61. data/lib/active_model/serializer/association.rb +91 -0
  62. data/lib/active_model/serializer/attribute.rb +27 -0
  63. data/lib/active_model/serializer/belongs_to_reflection.rb +13 -0
  64. data/lib/active_model/serializer/collection_serializer.rb +90 -0
  65. data/lib/active_model/serializer/concerns/caching.rb +304 -0
  66. data/lib/active_model/serializer/error_serializer.rb +16 -0
  67. data/lib/active_model/serializer/errors_serializer.rb +34 -0
  68. data/lib/active_model/serializer/field.rb +92 -0
  69. data/lib/active_model/serializer/fieldset.rb +33 -0
  70. data/lib/active_model/serializer/has_many_reflection.rb +12 -0
  71. data/lib/active_model/serializer/has_one_reflection.rb +9 -0
  72. data/lib/active_model/serializer/lazy_association.rb +99 -0
  73. data/lib/active_model/serializer/link.rb +23 -0
  74. data/lib/active_model/serializer/lint.rb +152 -0
  75. data/lib/active_model/serializer/null.rb +19 -0
  76. data/lib/active_model/serializer/reflection.rb +212 -0
  77. data/lib/active_model/serializer/version.rb +7 -0
  78. data/lib/active_model_serializers.rb +63 -0
  79. data/lib/active_model_serializers/adapter.rb +100 -0
  80. data/lib/active_model_serializers/adapter/attributes.rb +15 -0
  81. data/lib/active_model_serializers/adapter/base.rb +85 -0
  82. data/lib/active_model_serializers/adapter/json.rb +23 -0
  83. data/lib/active_model_serializers/adapter/json_api.rb +535 -0
  84. data/lib/active_model_serializers/adapter/json_api/deserialization.rb +215 -0
  85. data/lib/active_model_serializers/adapter/json_api/error.rb +98 -0
  86. data/lib/active_model_serializers/adapter/json_api/jsonapi.rb +51 -0
  87. data/lib/active_model_serializers/adapter/json_api/link.rb +85 -0
  88. data/lib/active_model_serializers/adapter/json_api/meta.rb +39 -0
  89. data/lib/active_model_serializers/adapter/json_api/pagination_links.rb +90 -0
  90. data/lib/active_model_serializers/adapter/json_api/relationship.rb +106 -0
  91. data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +68 -0
  92. data/lib/active_model_serializers/adapter/null.rb +11 -0
  93. data/lib/active_model_serializers/callbacks.rb +57 -0
  94. data/lib/active_model_serializers/deprecate.rb +56 -0
  95. data/lib/active_model_serializers/deserialization.rb +17 -0
  96. data/lib/active_model_serializers/json_pointer.rb +16 -0
  97. data/lib/active_model_serializers/logging.rb +124 -0
  98. data/lib/active_model_serializers/lookup_chain.rb +82 -0
  99. data/lib/active_model_serializers/model.rb +132 -0
  100. data/lib/active_model_serializers/railtie.rb +52 -0
  101. data/lib/active_model_serializers/register_jsonapi_renderer.rb +80 -0
  102. data/lib/active_model_serializers/serializable_resource.rb +84 -0
  103. data/lib/active_model_serializers/serialization_context.rb +41 -0
  104. data/lib/active_model_serializers/test.rb +9 -0
  105. data/lib/active_model_serializers/test/schema.rb +140 -0
  106. data/lib/active_model_serializers/test/serializer.rb +127 -0
  107. data/lib/generators/rails/USAGE +6 -0
  108. data/lib/generators/rails/resource_override.rb +12 -0
  109. data/lib/generators/rails/serializer_generator.rb +38 -0
  110. data/lib/generators/rails/templates/serializer.rb.erb +8 -0
  111. data/lib/grape/active_model_serializers.rb +18 -0
  112. data/lib/grape/formatters/active_model_serializers.rb +34 -0
  113. data/lib/grape/helpers/active_model_serializers.rb +19 -0
  114. data/lib/tasks/rubocop.rake +55 -0
  115. data/test/action_controller/adapter_selector_test.rb +64 -0
  116. data/test/action_controller/explicit_serializer_test.rb +137 -0
  117. data/test/action_controller/json/include_test.rb +248 -0
  118. data/test/action_controller/json_api/deserialization_test.rb +114 -0
  119. data/test/action_controller/json_api/errors_test.rb +42 -0
  120. data/test/action_controller/json_api/fields_test.rb +68 -0
  121. data/test/action_controller/json_api/linked_test.rb +204 -0
  122. data/test/action_controller/json_api/pagination_test.rb +126 -0
  123. data/test/action_controller/json_api/transform_test.rb +191 -0
  124. data/test/action_controller/lookup_proc_test.rb +51 -0
  125. data/test/action_controller/namespace_lookup_test.rb +239 -0
  126. data/test/action_controller/serialization_scope_name_test.rb +237 -0
  127. data/test/action_controller/serialization_test.rb +480 -0
  128. data/test/active_model_serializers/adapter_for_test.rb +210 -0
  129. data/test/active_model_serializers/json_pointer_test.rb +24 -0
  130. data/test/active_model_serializers/logging_test.rb +79 -0
  131. data/test/active_model_serializers/model_test.rb +144 -0
  132. data/test/active_model_serializers/railtie_test_isolated.rb +70 -0
  133. data/test/active_model_serializers/register_jsonapi_renderer_test_isolated.rb +163 -0
  134. data/test/active_model_serializers/serialization_context_test_isolated.rb +73 -0
  135. data/test/active_model_serializers/test/schema_test.rb +133 -0
  136. data/test/active_model_serializers/test/serializer_test.rb +64 -0
  137. data/test/active_record_test.rb +11 -0
  138. data/test/adapter/attributes_test.rb +42 -0
  139. data/test/adapter/deprecation_test.rb +102 -0
  140. data/test/adapter/json/belongs_to_test.rb +47 -0
  141. data/test/adapter/json/collection_test.rb +106 -0
  142. data/test/adapter/json/has_many_test.rb +55 -0
  143. data/test/adapter/json/transform_test.rb +95 -0
  144. data/test/adapter/json_api/belongs_to_test.rb +157 -0
  145. data/test/adapter/json_api/collection_test.rb +98 -0
  146. data/test/adapter/json_api/errors_test.rb +78 -0
  147. data/test/adapter/json_api/fields_test.rb +98 -0
  148. data/test/adapter/json_api/has_many_explicit_serializer_test.rb +98 -0
  149. data/test/adapter/json_api/has_many_test.rb +175 -0
  150. data/test/adapter/json_api/has_one_test.rb +82 -0
  151. data/test/adapter/json_api/include_data_if_sideloaded_test.rb +215 -0
  152. data/test/adapter/json_api/json_api_test.rb +35 -0
  153. data/test/adapter/json_api/linked_test.rb +415 -0
  154. data/test/adapter/json_api/links_test.rb +112 -0
  155. data/test/adapter/json_api/pagination_links_test.rb +208 -0
  156. data/test/adapter/json_api/parse_test.rb +139 -0
  157. data/test/adapter/json_api/relationship_test.rb +399 -0
  158. data/test/adapter/json_api/resource_meta_test.rb +102 -0
  159. data/test/adapter/json_api/toplevel_jsonapi_test.rb +84 -0
  160. data/test/adapter/json_api/transform_test.rb +514 -0
  161. data/test/adapter/json_api/type_test.rb +195 -0
  162. data/test/adapter/json_test.rb +48 -0
  163. data/test/adapter/null_test.rb +24 -0
  164. data/test/adapter/polymorphic_test.rb +220 -0
  165. data/test/adapter_test.rb +69 -0
  166. data/test/array_serializer_test.rb +24 -0
  167. data/test/benchmark/app.rb +67 -0
  168. data/test/benchmark/benchmarking_support.rb +69 -0
  169. data/test/benchmark/bm_active_record.rb +83 -0
  170. data/test/benchmark/bm_adapter.rb +40 -0
  171. data/test/benchmark/bm_caching.rb +121 -0
  172. data/test/benchmark/bm_lookup_chain.rb +85 -0
  173. data/test/benchmark/bm_transform.rb +47 -0
  174. data/test/benchmark/config.ru +3 -0
  175. data/test/benchmark/controllers.rb +85 -0
  176. data/test/benchmark/fixtures.rb +221 -0
  177. data/test/cache_test.rb +717 -0
  178. data/test/collection_serializer_test.rb +129 -0
  179. data/test/fixtures/active_record.rb +115 -0
  180. data/test/fixtures/poro.rb +227 -0
  181. data/test/generators/scaffold_controller_generator_test.rb +26 -0
  182. data/test/generators/serializer_generator_test.rb +77 -0
  183. data/test/grape_test.rb +198 -0
  184. data/test/lint_test.rb +51 -0
  185. data/test/logger_test.rb +22 -0
  186. data/test/poro_test.rb +11 -0
  187. data/test/serializable_resource_test.rb +81 -0
  188. data/test/serializers/association_macros_test.rb +39 -0
  189. data/test/serializers/associations_test.rb +520 -0
  190. data/test/serializers/attribute_test.rb +155 -0
  191. data/test/serializers/attributes_test.rb +54 -0
  192. data/test/serializers/caching_configuration_test_isolated.rb +172 -0
  193. data/test/serializers/configuration_test.rb +34 -0
  194. data/test/serializers/fieldset_test.rb +16 -0
  195. data/test/serializers/meta_test.rb +204 -0
  196. data/test/serializers/options_test.rb +34 -0
  197. data/test/serializers/read_attribute_for_serialization_test.rb +81 -0
  198. data/test/serializers/reflection_test.rb +481 -0
  199. data/test/serializers/root_test.rb +23 -0
  200. data/test/serializers/serialization_test.rb +57 -0
  201. data/test/serializers/serializer_for_test.rb +138 -0
  202. data/test/serializers/serializer_for_with_namespace_test.rb +90 -0
  203. data/test/support/custom_schemas/active_model_serializers/test/schema_test/my/index.json +6 -0
  204. data/test/support/isolated_unit.rb +86 -0
  205. data/test/support/rails5_shims.rb +55 -0
  206. data/test/support/rails_app.rb +40 -0
  207. data/test/support/schemas/active_model_serializers/test/schema_test/my/index.json +6 -0
  208. data/test/support/schemas/active_model_serializers/test/schema_test/my/show.json +6 -0
  209. data/test/support/schemas/custom/show.json +7 -0
  210. data/test/support/schemas/hyper_schema.json +93 -0
  211. data/test/support/schemas/render_using_json_api.json +43 -0
  212. data/test/support/schemas/simple_json_pointers.json +10 -0
  213. data/test/support/serialization_testing.rb +81 -0
  214. data/test/test_helper.rb +72 -0
  215. metadata +622 -0
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveModel
4
+ class Serializer
5
+ class ErrorSerializer < ActiveModel::Serializer
6
+ # @return [Hash<field_name,Array<error_message>>]
7
+ def as_json
8
+ object.errors.messages
9
+ end
10
+
11
+ def success?
12
+ false
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_model/serializer/error_serializer'
4
+
5
+ module ActiveModel
6
+ class Serializer
7
+ class ErrorsSerializer
8
+ include Enumerable
9
+ delegate :each, to: :@serializers
10
+ attr_reader :object, :root
11
+
12
+ def initialize(resources, options = {})
13
+ @root = options[:root]
14
+ @object = resources
15
+ @serializers = resources.map do |resource|
16
+ serializer_class = options.fetch(:serializer) { ActiveModel::Serializer::ErrorSerializer }
17
+ serializer_class.new(resource, options.except(:serializer))
18
+ end
19
+ end
20
+
21
+ def success?
22
+ false
23
+ end
24
+
25
+ def json_key
26
+ nil
27
+ end
28
+
29
+ protected
30
+
31
+ attr_reader :serializers
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveModel
4
+ class Serializer
5
+ # Holds all the meta-data about a field (i.e. attribute or association) as it was
6
+ # specified in the ActiveModel::Serializer class.
7
+ # Notice that the field block is evaluated in the context of the serializer.
8
+ Field = Struct.new(:name, :options, :block) do
9
+ def initialize(*)
10
+ super
11
+
12
+ validate_condition!
13
+ end
14
+
15
+ # Compute the actual value of a field for a given serializer instance.
16
+ # @param [Serializer] The serializer instance for which the value is computed.
17
+ # @return [Object] value
18
+ #
19
+ # @api private
20
+ #
21
+ def value(serializer)
22
+ if block
23
+ serializer.instance_eval(&block)
24
+ else
25
+ serializer.read_attribute_for_serialization(name)
26
+ end
27
+ end
28
+
29
+ # Decide whether the field should be serialized by the given serializer instance.
30
+ # @param [Serializer] The serializer instance
31
+ # @return [Bool]
32
+ #
33
+ # @api private
34
+ #
35
+ def excluded?(serializer)
36
+ case condition_type
37
+ when :if
38
+ !evaluate_condition(serializer)
39
+ when :unless
40
+ evaluate_condition(serializer)
41
+ else
42
+ false
43
+ end
44
+ end
45
+
46
+ private
47
+
48
+ def validate_condition!
49
+ return if condition_type == :none
50
+
51
+ case condition
52
+ when Symbol, String, Proc
53
+ # noop
54
+ else
55
+ fail TypeError, "#{condition_type.inspect} should be a Symbol, String or Proc"
56
+ end
57
+ end
58
+
59
+ def evaluate_condition(serializer)
60
+ case condition
61
+ when Symbol
62
+ serializer.public_send(condition)
63
+ when String
64
+ serializer.instance_eval(condition)
65
+ when Proc
66
+ if condition.arity.zero?
67
+ serializer.instance_exec(&condition)
68
+ else
69
+ serializer.instance_exec(serializer, &condition)
70
+ end
71
+ else
72
+ nil
73
+ end
74
+ end
75
+
76
+ def condition_type
77
+ @condition_type ||=
78
+ if options.key?(:if)
79
+ :if
80
+ elsif options.key?(:unless)
81
+ :unless
82
+ else
83
+ :none
84
+ end
85
+ end
86
+
87
+ def condition
88
+ options[condition_type]
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveModel
4
+ class Serializer
5
+ class Fieldset
6
+ def initialize(fields)
7
+ @raw_fields = fields || {}
8
+ end
9
+
10
+ def fields
11
+ @fields ||= parsed_fields
12
+ end
13
+
14
+ def fields_for(type)
15
+ fields[type.singularize.to_sym] || fields[type.pluralize.to_sym]
16
+ end
17
+
18
+ protected
19
+
20
+ attr_reader :raw_fields
21
+
22
+ private
23
+
24
+ def parsed_fields
25
+ if raw_fields.is_a?(Hash)
26
+ raw_fields.each_with_object({}) { |(k, v), h| h[k.to_sym] = v.map(&:to_sym) }
27
+ else
28
+ {}
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveModel
4
+ class Serializer
5
+ # @api private
6
+ class HasManyReflection < Reflection
7
+ def collection?
8
+ true
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveModel
4
+ class Serializer
5
+ # @api private
6
+ class HasOneReflection < Reflection
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveModel
4
+ class Serializer
5
+ # @api private
6
+ LazyAssociation = Struct.new(:reflection, :association_options) do
7
+ REFLECTION_OPTIONS = %i(key links polymorphic meta serializer virtual_value namespace).freeze
8
+
9
+ delegate :collection?, to: :reflection
10
+
11
+ def reflection_options
12
+ @reflection_options ||= reflection.options.select { |k, _| REFLECTION_OPTIONS.include?(k) }
13
+ end
14
+
15
+ def object
16
+ return @object if defined?(@object)
17
+ @object = reflection.value(
18
+ association_options.fetch(:parent_serializer),
19
+ association_options.fetch(:include_slice)
20
+ )
21
+ end
22
+ alias_method :eval_reflection_block, :object
23
+
24
+ def include_data?
25
+ eval_reflection_block if reflection.block
26
+ reflection.include_data?(
27
+ association_options.fetch(:include_slice)
28
+ )
29
+ end
30
+
31
+ # @return [ActiveModel::Serializer, nil]
32
+ def serializer
33
+ return @serializer if defined?(@serializer)
34
+ if serializer_class
35
+ serialize_object!(object)
36
+ elsif !object.nil? && !object.instance_of?(Object)
37
+ cached_result[:virtual_value] = object
38
+ end
39
+ @serializer = cached_result[:serializer]
40
+ end
41
+
42
+ def virtual_value
43
+ cached_result[:virtual_value] || reflection_options[:virtual_value]
44
+ end
45
+
46
+ def serializer_class
47
+ return @serializer_class if defined?(@serializer_class)
48
+ serializer_for_options = { namespace: namespace }
49
+ serializer_for_options[:serializer] = reflection_options[:serializer] if reflection_options.key?(:serializer)
50
+ @serializer_class = association_options.fetch(:parent_serializer).class.serializer_for(object, serializer_for_options)
51
+ end
52
+
53
+ private
54
+
55
+ def cached_result
56
+ @cached_result ||= {}
57
+ end
58
+
59
+ def serialize_object!(object)
60
+ if collection?
61
+ if (serializer = instantiate_collection_serializer(object)).nil?
62
+ # BUG: per #2027, JSON API resource relationships are only id and type, and hence either
63
+ # *require* a serializer or we need to be a little clever about figuring out the id/type.
64
+ # In either case, returning the raw virtual value will almost always be incorrect.
65
+ #
66
+ # Should be reflection_options[:virtual_value] or adapter needs to figure out what to do
67
+ # with an object that is non-nil and has no defined serializer.
68
+ cached_result[:virtual_value] = object.try(:as_json) || object
69
+ else
70
+ cached_result[:serializer] = serializer
71
+ end
72
+ else
73
+ cached_result[:serializer] = instantiate_serializer(object)
74
+ end
75
+ end
76
+
77
+ def instantiate_serializer(object)
78
+ serializer_options = association_options.fetch(:parent_serializer_options).except(:serializer)
79
+ serializer_options[:serializer_context_class] = association_options.fetch(:parent_serializer).class
80
+ serializer = reflection_options.fetch(:serializer, nil)
81
+ serializer_options[:serializer] = serializer if serializer
82
+ serializer_options[:namespace] = reflection_options[:namespace] if reflection_options[:namespace]
83
+ serializer_class.new(object, serializer_options)
84
+ end
85
+
86
+ def instantiate_collection_serializer(object)
87
+ serializer = catch(:no_serializer) do
88
+ instantiate_serializer(object)
89
+ end
90
+ serializer
91
+ end
92
+
93
+ def namespace
94
+ reflection_options[:namespace] ||
95
+ association_options.fetch(:parent_serializer_options)[:namespace]
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_model/serializer/field'
4
+
5
+ module ActiveModel
6
+ class Serializer
7
+ # Holds all the data about a serializer link
8
+ #
9
+ # @example
10
+ # class PostSerializer < ActiveModel::Serializer
11
+ # link :callback, if: :internal? do
12
+ # object.callback_link
13
+ # end
14
+ #
15
+ # def internal?
16
+ # instance_options[:internal] == true
17
+ # end
18
+ # end
19
+ #
20
+ class Link < Field
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,152 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveModel
4
+ class Serializer
5
+ module Lint
6
+ # == Active \Model \Serializer \Lint \Tests
7
+ #
8
+ # You can test whether an object is compliant with the Active \Model \Serializers
9
+ # API by including <tt>ActiveModel::Serializer::Lint::Tests</tt> in your TestCase.
10
+ # It will include tests that tell you whether your object is fully compliant,
11
+ # or if not, which aspects of the API are not implemented.
12
+ #
13
+ # Note an object is not required to implement all APIs in order to work
14
+ # with Active \Model \Serializers. This module only intends to provide guidance in case
15
+ # you want all features out of the box.
16
+ #
17
+ # These tests do not attempt to determine the semantic correctness of the
18
+ # returned values. For instance, you could implement <tt>serializable_hash</tt> to
19
+ # always return +{}+, and the tests would pass. It is up to you to ensure
20
+ # that the values are semantically meaningful.
21
+ module Tests
22
+ # Passes if the object responds to <tt>serializable_hash</tt> and if it takes
23
+ # zero or one arguments.
24
+ # Fails otherwise.
25
+ #
26
+ # <tt>serializable_hash</tt> returns a hash representation of a object's attributes.
27
+ # Typically, it is implemented by including ActiveModel::Serialization.
28
+ def test_serializable_hash
29
+ assert_respond_to resource, :serializable_hash, 'The resource should respond to serializable_hash'
30
+ resource.serializable_hash
31
+ resource.serializable_hash(nil)
32
+ end
33
+
34
+ # Passes if the object responds to <tt>read_attribute_for_serialization</tt>
35
+ # and if it requires one argument (the attribute to be read).
36
+ # Fails otherwise.
37
+ #
38
+ # <tt>read_attribute_for_serialization</tt> gets the attribute value for serialization
39
+ # Typically, it is implemented by including ActiveModel::Serialization.
40
+ def test_read_attribute_for_serialization
41
+ assert_respond_to resource, :read_attribute_for_serialization, 'The resource should respond to read_attribute_for_serialization'
42
+ actual_arity = resource.method(:read_attribute_for_serialization).arity
43
+ # using absolute value since arity is:
44
+ # 1 for def read_attribute_for_serialization(name); end
45
+ # -1 for alias :read_attribute_for_serialization :send
46
+ assert_equal 1, actual_arity.abs, "expected #{actual_arity.inspect}.abs to be 1 or -1"
47
+ end
48
+
49
+ # Passes if the object responds to <tt>as_json</tt> and if it takes
50
+ # zero or one arguments.
51
+ # Fails otherwise.
52
+ #
53
+ # <tt>as_json</tt> returns a hash representation of a serialized object.
54
+ # It may delegate to <tt>serializable_hash</tt>
55
+ # Typically, it is implemented either by including ActiveModel::Serialization
56
+ # which includes ActiveModel::Serializers::JSON.
57
+ # or by the JSON gem when required.
58
+ def test_as_json
59
+ assert_respond_to resource, :as_json
60
+ resource.as_json
61
+ resource.as_json(nil)
62
+ end
63
+
64
+ # Passes if the object responds to <tt>to_json</tt> and if it takes
65
+ # zero or one arguments.
66
+ # Fails otherwise.
67
+ #
68
+ # <tt>to_json</tt> returns a string representation (JSON) of a serialized object.
69
+ # It may be called on the result of <tt>as_json</tt>.
70
+ # Typically, it is implemented on all objects when the JSON gem is required.
71
+ def test_to_json
72
+ assert_respond_to resource, :to_json
73
+ resource.to_json
74
+ resource.to_json(nil)
75
+ end
76
+
77
+ # Passes if the object responds to <tt>cache_key</tt>
78
+ # Fails otherwise.
79
+ #
80
+ # <tt>cache_key</tt> returns a (self-expiring) unique key for the object,
81
+ # and is part of the (self-expiring) cache_key, which is used by the
82
+ # adapter. It is not required unless caching is enabled.
83
+ def test_cache_key
84
+ assert_respond_to resource, :cache_key
85
+ actual_arity = resource.method(:cache_key).arity
86
+ assert_includes [-1, 0], actual_arity, "expected #{actual_arity.inspect} to be 0 or -1"
87
+ end
88
+
89
+ # Passes if the object responds to <tt>updated_at</tt> and if it takes no
90
+ # arguments.
91
+ # Fails otherwise.
92
+ #
93
+ # <tt>updated_at</tt> returns a Time object or iso8601 string and
94
+ # is part of the (self-expiring) cache_key, which is used by the adapter.
95
+ # It is not required unless caching is enabled.
96
+ def test_updated_at
97
+ assert_respond_to resource, :updated_at
98
+ actual_arity = resource.method(:updated_at).arity
99
+ assert_equal 0, actual_arity
100
+ end
101
+
102
+ # Passes if the object responds to <tt>id</tt> and if it takes no
103
+ # arguments.
104
+ # Fails otherwise.
105
+ #
106
+ # <tt>id</tt> returns a unique identifier for the object.
107
+ # It is not required unless caching is enabled.
108
+ def test_id
109
+ assert_respond_to resource, :id
110
+ assert_equal 0, resource.method(:id).arity
111
+ end
112
+
113
+ # Passes if the object's class responds to <tt>model_name</tt> and if it
114
+ # is in an instance of +ActiveModel::Name+.
115
+ # Fails otherwise.
116
+ #
117
+ # <tt>model_name</tt> returns an ActiveModel::Name instance.
118
+ # It is used by the serializer to identify the object's type.
119
+ # It is not required unless caching is enabled.
120
+ def test_model_name
121
+ resource_class = resource.class
122
+ assert_respond_to resource_class, :model_name
123
+ assert_instance_of resource_class.model_name, ActiveModel::Name
124
+ end
125
+
126
+ def test_active_model_errors
127
+ assert_respond_to resource, :errors
128
+ end
129
+
130
+ def test_active_model_errors_human_attribute_name
131
+ assert_respond_to resource.class, :human_attribute_name
132
+ assert_equal(-2, resource.class.method(:human_attribute_name).arity)
133
+ end
134
+
135
+ def test_active_model_errors_lookup_ancestors
136
+ assert_respond_to resource.class, :lookup_ancestors
137
+ assert_equal 0, resource.class.method(:lookup_ancestors).arity
138
+ end
139
+
140
+ private
141
+
142
+ def resource
143
+ @resource or fail "'@resource' must be set as the linted object"
144
+ end
145
+
146
+ def assert_instance_of(result, name)
147
+ assert result.instance_of?(name), "#{result} should be an instance of #{name}"
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end