From 4bac9aedd74c67ca48ddbf017fb21b4e5268e603 Mon Sep 17 00:00:00 2001 From: Rustam Ibragimov Date: Thu, 26 Dec 2019 10:13:29 +0300 Subject: [PATCH 1/5] [validation-messages] begins... --- lib/qonfig/dsl.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/qonfig/dsl.rb b/lib/qonfig/dsl.rb index 54d8e183..1378cefb 100644 --- a/lib/qonfig/dsl.rb +++ b/lib/qonfig/dsl.rb @@ -72,7 +72,8 @@ def validators # @param predefined [String, Symbol] # @option by [String, Symbol, NilClass] # @option stict [Boolean] - # @param custom_validation [Proc] + # @option error_message [NilClass, String, Proc] + # @param custom_validation [Block] # @return [void] # # @see Qonfig::Validation::Building::InstanceBuilder @@ -84,6 +85,7 @@ def validate( predefined = nil, strict: false, by: nil, + error_message: nil, &custom_validation ) validators << Qonfig::Validation::Building::InstanceBuilder.build( From 2fa0ff82a4ae30791c4be0494662f50a79aa54d7 Mon Sep 17 00:00:00 2001 From: BigForceGun Date: Mon, 9 Nov 2020 11:25:54 +0300 Subject: [PATCH 2/5] add custom error messages --- .rubocop.yml | 5 ++ bin/{rspec => _rspec} | 0 lib/qonfig/dsl.rb | 1 + .../validation/building/instance_builder.rb | 24 +++++- lib/qonfig/validation/validators/basic.rb | 28 ++++++- .../validation/validators/method_based.rb | 19 ++++- .../validation/validators/predefined.rb | 16 +++- .../validation/validators/proc_based.rb | 22 +++-- spec/features/validation_spec.rb | 82 +++++++++++++++++++ 9 files changed, 181 insertions(+), 16 deletions(-) rename bin/{rspec => _rspec} (100%) diff --git a/.rubocop.yml b/.rubocop.yml index 861ed612..35db7b3b 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -26,3 +26,8 @@ Style/RedundantBegin: # NOTE: too situative Metrics/ParameterLists: Enabled: false + +# Conflicts with current project style +Style/NilComparison: + Enabled: true + EnforcedStyle: predicate \ No newline at end of file diff --git a/bin/rspec b/bin/_rspec similarity index 100% rename from bin/rspec rename to bin/_rspec diff --git a/lib/qonfig/dsl.rb b/lib/qonfig/dsl.rb index 2598b0a6..8ba34ced 100644 --- a/lib/qonfig/dsl.rb +++ b/lib/qonfig/dsl.rb @@ -93,6 +93,7 @@ def validate( setting_key_pattern: setting_key_pattern, predefined_validator: predefined, runtime_validation_method: by, + error_message: error_message, strict: strict, validation_logic: custom_validation ) diff --git a/lib/qonfig/validation/building/instance_builder.rb b/lib/qonfig/validation/building/instance_builder.rb index 54691e31..05fd87b8 100644 --- a/lib/qonfig/validation/building/instance_builder.rb +++ b/lib/qonfig/validation/building/instance_builder.rb @@ -35,11 +35,18 @@ class Qonfig::Validation::Building::InstanceBuilder # @since 0.17.0 DEFAULT_STRICT_BEHAVIOUR = false + # @return [Boolean] + # + # @api private + # @since 0.26.0 + DEFAULT_ERROR_MESSAGE = nil + class << self # @param data_set_klass [Class] # @option setting_key_pattern [String, Symbol, NilClass] # @option predefined_validator [String, Symbol, NilClass] # @option runtime_validation_method [String, Symbol, NilClass] + # @option error_message [NilClass, String, Proc] # @option validation_logic [Proc, NilClass] # @option strict [Boolean] # @return [Qonfig::Validator::MethodBased, Qonfig::Validator::ProcBased] @@ -50,6 +57,7 @@ def build( data_set_klass, setting_key_pattern: EMPTY_SETTING_KEY_PATTERN, runtime_validation_method: NO_RUNTIME_VALIDATION_METHOD, + error_message: DEFAULT_ERROR_MESSAGE, validation_logic: NO_VALIDATION_LOGIC, strict: DEFAULT_STRICT_BEHAVIOUR, predefined_validator: NO_PREDEFINED_VALIDATOR @@ -59,6 +67,7 @@ def build( setting_key_pattern, predefined_validator, runtime_validation_method, + error_message, strict, validation_logic ).build @@ -69,6 +78,7 @@ def build( # @param setting_key_pattern [String, Symbol, NilClass] # @param predefined_validator_name [String, Symbol, NilClass] # @param runtime_validation_method [String, Symbol, NilClass] + # @param error_message [NilClass, String, Proc] # @param strict [Boolean] # @param validation_logic [Proc, NilClass] # @return [void] @@ -80,6 +90,7 @@ def initialize( setting_key_pattern, predefined_validator_name, runtime_validation_method, + error_message, strict, validation_logic ) @@ -87,6 +98,7 @@ def initialize( @setting_key_pattern = setting_key_pattern @predefined_validator_name = predefined_validator_name @runtime_validation_method = runtime_validation_method + @error_message = error_message @strict = strict @validation_logic = validation_logic end @@ -140,6 +152,12 @@ def build # @since 0.20.0 attr_reader :validation_logic + # @return [NilClass, String, Proc] + # + # @api private + # @since 0.26.0 + attr_reader :error_message + # @return [void] # # @raise [Qonfig::ArgumentError] @@ -184,7 +202,7 @@ def build_setting_key_matcher # @since 0.20.0 def build_method_based_validator Qonfig::Validation::Validators::MethodBased.new( - build_setting_key_matcher, strict, runtime_validation_method + build_setting_key_matcher, strict, runtime_validation_method, error_message ) end @@ -194,7 +212,7 @@ def build_method_based_validator # @since 0.20.0 def build_proc_based_validator Qonfig::Validation::Validators::ProcBased.new( - build_setting_key_matcher, strict, validation_logic + build_setting_key_matcher, strict, validation_logic, error_message ) end @@ -213,7 +231,7 @@ def build_predefined_validator end Qonfig::Validation::Validators::Predefined.new( - build_setting_key_matcher, strict, predefined_validation_logic + build_setting_key_matcher, strict, predefined_validation_logic, error_message ) end end diff --git a/lib/qonfig/validation/validators/basic.rb b/lib/qonfig/validation/validators/basic.rb index b1787233..525e1755 100644 --- a/lib/qonfig/validation/validators/basic.rb +++ b/lib/qonfig/validation/validators/basic.rb @@ -15,15 +15,23 @@ class Qonfig::Validation::Validators::Basic # @since 0.20.0 attr_reader :strict + # @return [NilClass, String, Proc] + # + # @api private + # @since 0.20.0 + attr_reader :error_message + # @param setting_key_matcher [Qonfig::Settings::KeyMatcher, NilClass] # @param strict [Boolean] + # @param error_message [NilClass, String, Proc] # @return [void] # # @api private # @since 0.20.0 - def initialize(setting_key_matcher, strict) + def initialize(setting_key_matcher, strict, error_message = nil) @setting_key_matcher = setting_key_matcher @strict = strict + @error_message = error_message end # @param data_set [Qonfig::DataSet] @@ -58,4 +66,22 @@ def validate_full(data_set); end # @api private # @since 0.20.0 def validate_concrete(data_set); end + + # @param context [Object, NilClass] + # @return [String] + # + # @api private + # @since 0.26.0 + def default_error_message(context); end + + # @param context [Object, NilClass] + # @return [String] + # + # @api private + # @since 0.26.0 + def build_error_message(context = nil) + return error_message.to_s if error_message.is_a?(String) + return error_message.call(context).to_s if error_message.respond_to?(:call) + default_error_message(context) + end end diff --git a/lib/qonfig/validation/validators/method_based.rb b/lib/qonfig/validation/validators/method_based.rb index 636dba6a..c70eb8e9 100644 --- a/lib/qonfig/validation/validators/method_based.rb +++ b/lib/qonfig/validation/validators/method_based.rb @@ -12,12 +12,13 @@ class Qonfig::Validation::Validators::MethodBased < Qonfig::Validation::Validato # @param setting_key_matcher [Qonfig::Settings::KeyMatcher, NilClass] # @param strict [Boolean] # @param runtime_validation_method [String, Symbol] + # @param error_message [NilClass, String, Proc] # @return [void] # # @api private # @since 0.20.0 - def initialize(setting_key_matcher, strict, runtime_validation_method) - super(setting_key_matcher, strict) + def initialize(setting_key_matcher, strict, runtime_validation_method, error_message = nil) + super(setting_key_matcher, strict, error_message) @runtime_validation_method = runtime_validation_method end @@ -33,7 +34,7 @@ def validate_concrete(data_set) raise( Qonfig::ValidationError, - "Invalid value of setting <#{setting_key}> (#{setting_value})" + build_error_message(setting_key: setting_key, setting_value: setting_value) ) unless data_set.__send__(runtime_validation_method, setting_value) end end @@ -45,7 +46,17 @@ def validate_concrete(data_set) # @since 0.20.0 def validate_full(data_set) unless data_set.__send__(runtime_validation_method) - raise(Qonfig::ValidationError, 'Invalid config object') + raise(Qonfig::ValidationError, build_error_message) end end + + # @param context [Object, NilClass] + # @return [String] + # + # @api private + # @since 0.26.0 + def default_error_message(context = nil) + return 'Invalid config object' if context.nil? + "Invalid value of setting <#{context[:setting_key]}> (#{context[:setting_value]})" + end end diff --git a/lib/qonfig/validation/validators/predefined.rb b/lib/qonfig/validation/validators/predefined.rb index ea092255..3bc69c2b 100644 --- a/lib/qonfig/validation/validators/predefined.rb +++ b/lib/qonfig/validation/validators/predefined.rb @@ -12,12 +12,13 @@ class Qonfig::Validation::Validators::Predefined < Qonfig::Validation::Validator # @param setting_key_matcher [Qonfig::Settings::KeyMatcher] # @param strict [Boolean] # @param validation [Proc] + # @param error_message [NilClass, String, Proc] # @return [void] # # @api private # @since 0.20.0 - def initialize(setting_key_matcher, strict, validation) - super(setting_key_matcher, strict) + def initialize(setting_key_matcher, strict, validation, error_message = nil) + super(setting_key_matcher, strict, error_message) @validation = validation end @@ -35,7 +36,7 @@ def validate_concrete(data_set) raise( Qonfig::ValidationError, - "Invalid value of setting <#{setting_key}> (#{setting_value})" + build_error_message(setting_key: setting_key, setting_value: setting_value) ) unless validation.call(setting_value) end end @@ -52,4 +53,13 @@ def validate_full(data_set) raise Qonfig::Error, 'Predefined validator can be used with a setting key only' # :nocov: end + + # @param context [Object, NilClass] + # @return [String] + # + # @api private + # @since 0.26.0 + def default_error_message(context = nil) + "Invalid value of setting <#{context[:setting_key]}> (#{context[:setting_value]})" + end end diff --git a/lib/qonfig/validation/validators/proc_based.rb b/lib/qonfig/validation/validators/proc_based.rb index 62c8cde2..5e060e63 100644 --- a/lib/qonfig/validation/validators/proc_based.rb +++ b/lib/qonfig/validation/validators/proc_based.rb @@ -11,13 +11,14 @@ class Qonfig::Validation::Validators::ProcBased < Qonfig::Validation::Validators # @param setting_key_matcher [Qonfig::Settings::KeyMatcher, NilClass] # @param strict [Boolean] - # @param vaidation [Proc] + # @param validation [Proc] + # @param error_message [NilClass, String, Proc] # @return [void] # # @api private # @since 0.20.0 - def initialize(setting_key_matcher, strict, validation) - super(setting_key_matcher, strict) + def initialize(setting_key_matcher, strict, validation, error_message = nil) + super(setting_key_matcher, strict, error_message) @validation = validation end @@ -35,9 +36,10 @@ def validate_concrete(data_set) raise( Qonfig::ValidationError, - "Invalid value of setting <#{setting_key}> (#{setting_value})" + build_error_message(setting_key: setting_key, setting_value: setting_value) ) unless data_set.instance_exec(setting_value, &validation) end + false end # @param data_set [Qonfig::DataSet] @@ -49,7 +51,17 @@ def validate_concrete(data_set) # @since 0.20.0 def validate_full(data_set) unless data_set.instance_eval(&validation) - raise(Qonfig::ValidationError, 'Invalid config object') + raise(Qonfig::ValidationError, build_error_message) end end + + # @param context [Object, NilClass] + # @return [String] + # + # @api private + # @since 0.26.0 + def default_error_message(context = nil) + return 'Invalid config object' if context.nil? + "Invalid value of setting <#{context[:setting_key]}> (#{context[:setting_value]})" + end end diff --git a/spec/features/validation_spec.rb b/spec/features/validation_spec.rb index 96b07797..8e8321a6 100644 --- a/spec/features/validation_spec.rb +++ b/spec/features/validation_spec.rb @@ -913,4 +913,86 @@ def check_level end.not_to raise_error end end + + describe 'Custom error messages' do + specify 'instnation with string' do + config_klass = Class.new(Qonfig::DataSet) do + setting :telegraf_url, 12345 # NOTE: should be a string + validate 'telegraf_url', error_message: 'My awesome error' do |value| + value.is_a?(String) + end + end + + expect { config_klass.new }.to raise_error(Qonfig::ValidationError, 'My awesome error') + end + + specify 'instnation with proc' do + message_proc = proc { |context| "Bad key = #{context[:setting_key]}" } + + config_klass = Class.new(Qonfig::DataSet) do + setting :telegraf_url, 12345 # NOTE: should be a string + validate 'telegraf_url', error_message: message_proc do |value| + value.is_a?(String) + end + end + + expect { config_klass.new }.to raise_error(Qonfig::ValidationError, 'Bad key = telegraf_url') + end + + specify '`validate` works right' do + config_klass = Class.new(Qonfig::DataSet) do + setting :namespace do + setting :enabled, :true + end + + setting :go_for_cybersport, 'NO' + + # NOTE: no setting key pattern => full dataset object validation + validate error_message: 'Error Message - global block' do + settings.namespace.enabled.is_a?(Symbol) + end + + # NOTE: no setting key pattern => full dataset object validation + validate by: :check_all, error_message: 'Error message - method call' + + def check_all + settings.go_for_cybersport == 'NO' + end + end + expect { config_klass.new }.not_to raise_error + + expect do + config_klass.new.settings.namespace.enabled = 123 + end.to raise_error(Qonfig::ValidationError, 'Error Message - global block') + + expect do + config_klass.new.settings.go_for_cybersport = 'YES' + end.to raise_error(Qonfig::ValidationError, 'Error message - method call') + end + + specify 'predefined validators messages change' do + config_klass = Class.new(Qonfig::DataSet) do + setting :enabled, false + setting :count, 123 + validate :enabled, :boolean, strict: true, error_message: 'You must use boolean types' + validate :count, :integer, strict: true, error_message: proc { |context| + "Error with context key #{context[:setting_key]}" + } + end + + # NOTE: all right (originally) + expect { config_klass.new }.not_to raise_error + + # NOTE: invalid values + # NOTE: invalid values + expect do + config_klass.new.settings.enabled = nil + end.to raise_error(Qonfig::ValidationError, + 'You must use boolean types') + expect do + config_klass.new.settings.count = '5' + end.to raise_error(Qonfig::ValidationError, + 'Error with context key count') + end + end end From 2d565520a954be0a04ca47fa3cecbe2f1b651eb9 Mon Sep 17 00:00:00 2001 From: BigForceGun Date: Mon, 9 Nov 2020 11:34:50 +0300 Subject: [PATCH 3/5] fix rubocop issues --- spec/features/validation_spec.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/spec/features/validation_spec.rb b/spec/features/validation_spec.rb index 8e8321a6..e16ad678 100644 --- a/spec/features/validation_spec.rb +++ b/spec/features/validation_spec.rb @@ -975,9 +975,12 @@ def check_all setting :enabled, false setting :count, 123 validate :enabled, :boolean, strict: true, error_message: 'You must use boolean types' - validate :count, :integer, strict: true, error_message: proc { |context| - "Error with context key #{context[:setting_key]}" - } + validate :count, + :integer, + strict: true, + error_message: proc { |context| + "Error with context key #{context[:setting_key]}" + } end # NOTE: all right (originally) From eb0ba2e068cb7918e4ea07550904a2f4c2477748 Mon Sep 17 00:00:00 2001 From: BigForceGun Date: Mon, 9 Nov 2020 11:43:29 +0300 Subject: [PATCH 4/5] return custom binstub back --- bin/{_rspec => rspec} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename bin/{_rspec => rspec} (100%) diff --git a/bin/_rspec b/bin/rspec similarity index 100% rename from bin/_rspec rename to bin/rspec From 82a03f036dccfece5c415e15eaf6bd9f6422bd40 Mon Sep 17 00:00:00 2001 From: BigForceGun Date: Mon, 9 Nov 2020 11:56:20 +0300 Subject: [PATCH 5/5] fix spelling and copypaste --- .rubocop.yml | 2 +- lib/qonfig/validation/validators/basic.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 35db7b3b..37e60741 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -30,4 +30,4 @@ Metrics/ParameterLists: # Conflicts with current project style Style/NilComparison: Enabled: true - EnforcedStyle: predicate \ No newline at end of file + EnforcedStyle: predicate diff --git a/lib/qonfig/validation/validators/basic.rb b/lib/qonfig/validation/validators/basic.rb index 525e1755..9e8dedf2 100644 --- a/lib/qonfig/validation/validators/basic.rb +++ b/lib/qonfig/validation/validators/basic.rb @@ -18,7 +18,7 @@ class Qonfig::Validation::Validators::Basic # @return [NilClass, String, Proc] # # @api private - # @since 0.20.0 + # @since 0.26.0 attr_reader :error_message # @param setting_key_matcher [Qonfig::Settings::KeyMatcher, NilClass]