diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb
index 7e4eb0d69..4fe428fb6 100644
--- a/lib/active_model/serializer.rb
+++ b/lib/active_model/serializer.rb
@@ -6,6 +6,7 @@ class Serializer
autoload :Configuration
autoload :ArraySerializer
autoload :Adapter
+ autoload :Lint
include Configuration
class << self
diff --git a/lib/active_model/serializer/lint.rb b/lib/active_model/serializer/lint.rb
new file mode 100644
index 000000000..1da9bc5bc
--- /dev/null
+++ b/lib/active_model/serializer/lint.rb
@@ -0,0 +1,117 @@
+module ActiveModel::Serializer::Lint
+ # == Active \Model \Serializer \Lint \Tests
+ #
+ # You can test whether an object is compliant with the Active \Model \Serializers
+ # API by including ActiveModel::Serializer::Lint::Tests in your TestCase.
+ # It will include tests that tell you whether your object is fully compliant,
+ # or if not, which aspects of the API are not implemented.
+ #
+ # Note an object is not required to implement all APIs in order to work
+ # with Active \Model \Serializers. This module only intends to provide guidance in case
+ # you want all features out of the box.
+ #
+ # These tests do not attempt to determine the semantic correctness of the
+ # returned values. For instance, you could implement serializable_hash to
+ # always return +{}+, and the tests would pass. It is up to you to ensure
+ # that the values are semantically meaningful.
+ module Tests
+
+ # Passes if the object responds to serializable_hash and if it takes
+ # zero or one arguments.
+ # Fails otherwise.
+ #
+ # serializable_hash returns a hash representation of a object's attributes.
+ # Typically, it is implemented by including ActiveModel::Serialization.
+ def test_serializable_hash
+ assert_respond_to resource, :serializable_hash, "The resource should respond to serializable_hash"
+ resource.serializable_hash
+ resource.serializable_hash(nil)
+ end
+
+ # Passes if the object responds to read_attribute_for_serialization
+ # and if it requires one argument (the attribute to be read).
+ # Fails otherwise.
+ #
+ # read_attribute_for_serialization gets the attribute value for serialization
+ # Typically, it is implemented by including ActiveModel::Serialization.
+ def test_read_attribute_for_serialization
+ assert_respond_to resource, :read_attribute_for_serialization, "The resource should respond to read_attribute_for_serialization"
+ assert_equal resource.method(:read_attribute_for_serialization).arity, 1
+ end
+
+ # Passes if the object responds to as_json and if it takes
+ # zero or one arguments.
+ # Fails otherwise.
+ #
+ # as_json returns a hash representation of a serialized object.
+ # It may delegate to serializable_hash
+ # Typically, it is implemented either by including ActiveModel::Serialization
+ # which includes ActiveModel::Serializers::JSON.
+ # or by the JSON gem when required.
+ def test_as_json
+ assert_respond_to resource, :as_json
+ resource.as_json
+ resource.as_json(nil)
+ end
+
+ # Passes if the object responds to to_json and if it takes
+ # zero or one arguments.
+ # Fails otherwise.
+ #
+ # to_json returns a string representation (JSON) of a serialized object.
+ # It may be called on the result of as_json.
+ # Typically, it is implemented on all objects when the JSON gem is required.
+ def test_to_json
+ assert_respond_to resource, :to_json
+ resource.to_json
+ resource.to_json(nil)
+ end
+
+ # Passes if the object responds to cache_key and if it takes no
+ # arguments.
+ # Fails otherwise.
+ #
+ # cache_key returns a (self-expiring) unique key for the object,
+ # which is used by the adapter.
+ # It is not required unless caching is enabled.
+ def test_cache_key
+ assert_respond_to resource, :cache_key
+ assert_equal resource.method(:cache_key).arity, 0
+ end
+
+ # Passes if the object responds to id and if it takes no
+ # arguments.
+ # Fails otherwise.
+ #
+ # id returns a unique identifier for the object.
+ # It is not required unless caching is enabled.
+ def test_id
+ assert_respond_to resource, :id
+ assert_equal resource.method(:id).arity, 0
+ end
+
+ # Passes if the object's class responds to model_name and if it
+ # is in an instance of +ActiveModel::Name+.
+ # Fails otherwise.
+ #
+ # model_name returns an ActiveModel::Name instance.
+ # It is used by the serializer to identify the object's type.
+ # It is not required unless caching is enabled.
+ def test_model_name
+ resource_class = resource.class
+ assert_respond_to resource_class, :model_name
+ assert_instance_of resource_class.model_name, ActiveModel::Name
+ end
+
+ private
+
+ def resource
+ @resource
+ end
+
+ def assert_instance_of(result, name)
+ assert result.instance_of?(name), "#{result} should be an instance of #{name}"
+ end
+
+ end
+end
diff --git a/test/lint_test.rb b/test/lint_test.rb
new file mode 100644
index 000000000..61329b247
--- /dev/null
+++ b/test/lint_test.rb
@@ -0,0 +1,44 @@
+require 'test_helper'
+
+module ActiveModel
+ class Serializer
+ class LintTest < Minitest::Test
+ include ActiveModel::Serializer::Lint::Tests
+
+ class CompliantResource
+ def serializable_hash(options = nil)
+
+ end
+
+ def read_attribute_for_serialization(name)
+
+ end
+
+ def as_json(options = nil)
+
+ end
+
+ def to_json(options = nil)
+
+ end
+
+ def cache_key
+
+ end
+
+ def id
+
+ end
+
+ def self.model_name
+ @_model_name ||= ActiveModel::Name.new(self)
+ end
+ end
+
+ def setup
+ @resource = CompliantResource.new
+ end
+
+ end
+ end
+end