From e7a8e6b9895c6f5d9d79a9ee811350e73e672957 Mon Sep 17 00:00:00 2001 From: George Dietrich Date: Mon, 27 Dec 2021 10:20:52 -0500 Subject: [PATCH] Ensure callback constraint methods are not added as getters (#132) * Bump versions --- shard.yml | 2 +- spec/validatable_spec.cr | 30 +++++++++++++++++++++++++++++- src/athena-validator.cr | 2 +- src/constraints/callback.cr | 4 ++-- src/metadata/class_metadata.cr | 2 +- 5 files changed, 34 insertions(+), 6 deletions(-) diff --git a/shard.yml b/shard.yml index 1eb1bcc..72ecb12 100644 --- a/shard.yml +++ b/shard.yml @@ -1,6 +1,6 @@ name: athena-validator -version: 0.1.6 +version: 0.1.7 crystal: '>= 0.35.0' diff --git a/spec/validatable_spec.cr b/spec/validatable_spec.cr index 09391fb..2229af0 100644 --- a/spec/validatable_spec.cr +++ b/spec/validatable_spec.cr @@ -26,6 +26,22 @@ private class Obj property name : String = "" end +private class InstanceCallbackClass + include AVD::Validatable + + @[Assert::Callback] + def validate(context : AVD::ExecutionContextInterface, payload : Hash(String, String)?) : Nil + end +end + +private class ClassCallbackClass + include AVD::Validatable + + @[Assert::Callback] + def self.validate(value : AVD::Constraints::Callback::ValueContainer, context : AVD::ExecutionContextInterface, payload : Hash(String, String)?) : Nil + end +end + describe AVD::Validatable do describe ".load_metadata" do it "should manually add constraints to the metadata object" do @@ -34,7 +50,7 @@ describe AVD::Validatable do end describe ".validation_class_metadata" do - it "is inheritted when included in parent type" do + it "is inherited when included in parent type" do Child.validation_class_metadata.constrained_properties.should eq ["name"] end @@ -45,5 +61,17 @@ describe AVD::Validatable do it "is defined when included directly into non-abstract types" do Obj.validation_class_metadata.constrained_properties.should eq ["name"] end + + it "properly registers instance method callback constraints" do + constraints = InstanceCallbackClass.validation_class_metadata.constraints + constraints.size.should eq 1 + constraints.first.should be_a AVD::Constraints::Callback + end + + it "properly registers class method callback constraints" do + constraints = ClassCallbackClass.validation_class_metadata.constraints + constraints.size.should eq 1 + constraints.first.should be_a AVD::Constraints::Callback + end end end diff --git a/src/athena-validator.cr b/src/athena-validator.cr index 558f9b0..5cd1be7 100644 --- a/src/athena-validator.cr +++ b/src/athena-validator.cr @@ -383,7 +383,7 @@ alias Assert = AVD::Annotations # # NOTE: See the related types for more detailed information. module Athena::Validator - VERSION = "0.1.6" + VERSION = "0.1.7" # :nodoc: # diff --git a/src/constraints/callback.cr b/src/constraints/callback.cr index 1da01ad..3d623fb 100644 --- a/src/constraints/callback.cr +++ b/src/constraints/callback.cr @@ -80,7 +80,7 @@ # The callback method can also be defined as a class method. # Since class methods do not have access to the related object instance, it is passed in as an argument. # -# That argument is typed as `AVD::Constraints::Callback::Value` which exposes a `AVD::Constraints::Callback::Value#get` +# That argument is typed as `AVD::Constraints::Callback::Value` instance which exposes a `AVD::Constraints::Callback::Value#get` # method that can be used as an easier syntax than `.as`. # # ``` @@ -90,7 +90,7 @@ # SPAM_DOMAINS = ["fake.com", "spam.net"] # # @[Assert::Callback] -# def self.validate(value : AVD::Constraints::Callback::Value, context : AVD::ExecutionContextInterface, payload : Hash(String, String)?) : Nil +# def self.validate(value : AVD::Constraints::Callback::ValueContainer, context : AVD::ExecutionContextInterface, payload : Hash(String, String)?) : Nil # # Get the object from the value, typed as our `Example` class. # object = value.get self # diff --git a/src/metadata/class_metadata.cr b/src/metadata/class_metadata.cr index 28ee9fc..95f1f64 100644 --- a/src/metadata/class_metadata.cr +++ b/src/metadata/class_metadata.cr @@ -76,7 +76,7 @@ class Athena::Validator::Metadata::ClassMetadata(T) {% for constraint in AVD::Constraint.all_subclasses.reject &.abstract? %} {% ann_name = constraint.name(generic_args: false).split("::").last.id %} - {% if ann = m.annotation Assert.constant(ann_name).resolve %} + {% if ann_name != "Callback" && (ann = m.annotation Assert.constant(ann_name).resolve) %} {% default_arg = ann.args.empty? ? nil : ann.args.first %} class_metadata.add_getter_constraint(