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