From 9ec61c8dcfb8e18044a229bb098a2f387a77fbe4 Mon Sep 17 00:00:00 2001 From: Ali Date: Mon, 22 Jan 2024 19:55:52 +0300 Subject: [PATCH] Add rule priority to allow rules to validate data before rules that will radically change data (#16) --- lib/mini_defender/rule.rb | 7 +++++++ lib/mini_defender/rules/array.rb | 4 ++++ lib/mini_defender/rules/hash.rb | 4 ++++ lib/mini_defender/rules_factory.rb | 13 ++++++++++--- lib/mini_defender/validator.rb | 2 +- lib/mini_defender/version.rb | 2 +- test/rules/hash_test.rb | 21 +++++++++++++++++++++ 7 files changed, 48 insertions(+), 5 deletions(-) diff --git a/lib/mini_defender/rule.rb b/lib/mini_defender/rule.rb index 64c829e..a2e887b 100644 --- a/lib/mini_defender/rule.rb +++ b/lib/mini_defender/rule.rb @@ -16,6 +16,13 @@ def self.available? true end + # Priority is used to sort rules in a rule set to allow rules to validate data + # before rules that will radically change data + # @return [Integer] + def priority + 100 + end + # @param [MiniDefender::Validator] validator # @return [Boolean] def implicit?(validator) diff --git a/lib/mini_defender/rules/array.rb b/lib/mini_defender/rules/array.rb index 5ccc413..52cf93e 100644 --- a/lib/mini_defender/rules/array.rb +++ b/lib/mini_defender/rules/array.rb @@ -13,6 +13,10 @@ def self.make(args) new(args[0] || 'none') end + def priority + 500 + end + def coerce(value) @data_mode == 'all' ? value : [] end diff --git a/lib/mini_defender/rules/hash.rb b/lib/mini_defender/rules/hash.rb index c76615c..e49a6f0 100644 --- a/lib/mini_defender/rules/hash.rb +++ b/lib/mini_defender/rules/hash.rb @@ -19,6 +19,10 @@ def self.make(args) ) end + def priority + 500 + end + def coerce(value) @data_mode == 'all' ? value : {} end diff --git a/lib/mini_defender/rules_factory.rb b/lib/mini_defender/rules_factory.rb index 39a26e7..966f9c5 100644 --- a/lib/mini_defender/rules_factory.rb +++ b/lib/mini_defender/rules_factory.rb @@ -11,16 +11,23 @@ def self.register(klass) end def init_set(rule_set) - rule_set = rule_set.split('|') if rule_set.is_a?(String) - raise ArgumentError, 'Rule set must be a string or an array' unless rule_set.is_a?(Array) + if rule_set.is_a?(String) + rule_set = rule_set.split('|') + end + + unless rule_set.is_a?(Array) + raise ArgumentError, 'Rule set must be a string or an array' + end - rule_set.map do |rule| + rule_set = rule_set.map do |rule| unless rule.is_a?(String) || rule.is_a?(Rule) raise ArgumentError, 'Rule must be a string or an instance of MiniDefender::Rule' end rule.is_a?(String) ? init_rule(rule) : rule end + + rule_set.sort_by! { |r| r.priority } end def init_rule(signature) diff --git a/lib/mini_defender/validator.rb b/lib/mini_defender/validator.rb index afa0e64..c1aff56 100644 --- a/lib/mini_defender/validator.rb +++ b/lib/mini_defender/validator.rb @@ -62,7 +62,7 @@ def validate value_included &= !rule.excluded?(self) - if rule.passes?(k, value, self) + if rule.passes?(k, coerced, self) coerced = rule.coerce(coerced) force_coerce = rule.force_coerce? else diff --git a/lib/mini_defender/version.rb b/lib/mini_defender/version.rb index b679774..aaef9d3 100644 --- a/lib/mini_defender/version.rb +++ b/lib/mini_defender/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module MiniDefender - VERSION = "0.5.1" + VERSION = "0.5.2" end diff --git a/test/rules/hash_test.rb b/test/rules/hash_test.rb index d7a4e73..77c2dd8 100644 --- a/test/rules/hash_test.rb +++ b/test/rules/hash_test.rb @@ -147,4 +147,25 @@ def test_hash_must_return_all_elements_when_all_mode_is_used_2 assert_equal 'foo', validator.coerced['metadata']['1'] assert_equal 'bar', validator.coerced['metadata']['2'] end + + def test_hash_should_be_delayed_to_all_size_rules_validation + validator = MiniDefender::Validator.new( + { + 'metadata' => 'required|hash|size:2|max:2|min:2', + 'metadata.foo' => 'required|string', + 'metadata.zee' => 'required|string' + }, + { + 'metadata' => { + 'foo' => 'bar', + 'zee' => 'mee' + } + } + ) + + assert validator.passes? + + assert_equal 2, validator.coerced['metadata'].length + assert_equal 'bar', validator.coerced['metadata']['foo'] + end end