usecasing_validations 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +19 -0
  3. data/.rspec +3 -0
  4. data/.rvmrc +1 -0
  5. data/Gemfile +4 -0
  6. data/Gemfile.lock +40 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +1 -0
  9. data/Rakefile +6 -0
  10. data/lib/usecasing/depends_all.rb +21 -0
  11. data/lib/usecasing/validator.rb +31 -0
  12. data/lib/usecasing_validations/custom_validator.rb +21 -0
  13. data/lib/usecasing_validations/each_validator.rb +32 -0
  14. data/lib/usecasing_validations/errors.rb +364 -0
  15. data/lib/usecasing_validations/helpers.rb +50 -0
  16. data/lib/usecasing_validations/target.rb +44 -0
  17. data/lib/usecasing_validations/validations/format.rb +116 -0
  18. data/lib/usecasing_validations/validations/helper_methods.rb +16 -0
  19. data/lib/usecasing_validations/validations/length.rb +126 -0
  20. data/lib/usecasing_validations/validations/presence.rb +17 -0
  21. data/lib/usecasing_validations/validations/uniqueness.rb +56 -0
  22. data/lib/usecasing_validations/validator.rb +20 -0
  23. data/lib/usecasing_validations/version.rb +3 -0
  24. data/lib/usecasing_validations.rb +122 -0
  25. data/spec/spec_helper.rb +17 -0
  26. data/spec/support/models/ruby_post.rb +9 -0
  27. data/spec/support/models/ruby_post_with_comments.rb +28 -0
  28. data/spec/support/usecases/validate_comments.rb +34 -0
  29. data/spec/support/usecases/validate_comments_custom_target.rb +14 -0
  30. data/spec/support/usecases/validate_depends_all.rb +24 -0
  31. data/spec/support/usecases/validate_post.rb +18 -0
  32. data/spec/support/usecases/validate_post_clear_errors.rb +9 -0
  33. data/spec/support/usecases/validate_uniq_comments.rb +77 -0
  34. data/spec/usecasing/validate_comments_custom_target_spec.rb +36 -0
  35. data/spec/usecasing/validate_comments_spec.rb +77 -0
  36. data/spec/usecasing/validate_depends_all_spec.rb +22 -0
  37. data/spec/usecasing/validate_post_clear_errors_spec.rb +48 -0
  38. data/spec/usecasing/validates_uniqueness_of_spec.rb +124 -0
  39. data/usecasing_validations.gemspec +29 -0
  40. metadata +166 -0
@@ -0,0 +1,116 @@
1
+ module UseCaseValidations
2
+ module Validations
3
+
4
+ class FormatValidator < EachValidator # :nodoc:
5
+ def validate_each(record, attribute, value)
6
+ if options[:with]
7
+ regexp = option_call(record, :with)
8
+ record_error(record, attribute, :with, value) if value.to_s !~ regexp
9
+ elsif options[:without]
10
+ regexp = option_call(record, :without)
11
+ record_error(record, attribute, :without, value) if value.to_s =~ regexp
12
+ end
13
+ end
14
+
15
+ def check_validity!
16
+ unless options.include?(:with) ^ options.include?(:without) # ^ == xor, or "exclusive or"
17
+ raise ArgumentError, "Either :with or :without must be supplied (but not both)"
18
+ end
19
+
20
+ check_options_validity(options, :with)
21
+ check_options_validity(options, :without)
22
+ end
23
+
24
+ private
25
+
26
+ def option_call(record, name)
27
+ option = options[name]
28
+ option.respond_to?(:call) ? option.call(record) : option
29
+ end
30
+
31
+ def record_error(record, attribute, name, value)
32
+ record.errors.add(attribute, :invalid, Helpers._except(options, name).merge!(value: value))
33
+ end
34
+
35
+ def regexp_using_multiline_anchors?(regexp)
36
+ regexp.source.start_with?("^") ||
37
+ (regexp.source.end_with?("$") && !regexp.source.end_with?("\\$"))
38
+ end
39
+
40
+ def check_options_validity(options, name)
41
+ option = options[name]
42
+ if option && !option.is_a?(Regexp) && !option.respond_to?(:call)
43
+ raise ArgumentError, "A regular expression or a proc or lambda must be supplied as :#{name}"
44
+ elsif option && option.is_a?(Regexp) &&
45
+ regexp_using_multiline_anchors?(option) && options[:multiline] != true
46
+ raise ArgumentError, "The provided regular expression is using multiline anchors (^ or $), " \
47
+ "which may present a security risk. Did you mean to use \\A and \\z, or forgot to add the " \
48
+ ":multiline => true option?"
49
+ end
50
+ end
51
+ end
52
+
53
+ module HelperMethods
54
+ # Validates whether the value of the specified attribute is of the correct
55
+ # form, going by the regular expression provided.You can require that the
56
+ # attribute matches the regular expression:
57
+ #
58
+ # class Person < ActiveRecord::Base
59
+ # validates_format_of :email, with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, on: :create
60
+ # end
61
+ #
62
+ # Alternatively, you can require that the specified attribute does _not_
63
+ # match the regular expression:
64
+ #
65
+ # class Person < ActiveRecord::Base
66
+ # validates_format_of :email, without: /NOSPAM/
67
+ # end
68
+ #
69
+ # You can also provide a proc or lambda which will determine the regular
70
+ # expression that will be used to validate the attribute.
71
+ #
72
+ # class Person < ActiveRecord::Base
73
+ # # Admin can have number as a first letter in their screen name
74
+ # validates_format_of :screen_name,
75
+ # with: ->(person) { person.admin? ? /\A[a-z0-9][a-z0-9_\-]*\z/i : /\A[a-z][a-z0-9_\-]*\z/i }
76
+ # end
77
+ #
78
+ # Note: use <tt>\A</tt> and <tt>\Z</tt> to match the start and end of the
79
+ # string, <tt>^</tt> and <tt>$</tt> match the start/end of a line.
80
+ #
81
+ # Due to frequent misuse of <tt>^</tt> and <tt>$</tt>, you need to pass
82
+ # the <tt>multiline: true</tt> option in case you use any of these two
83
+ # anchors in the provided regular expression. In most cases, you should be
84
+ # using <tt>\A</tt> and <tt>\z</tt>.
85
+ #
86
+ # You must pass either <tt>:with</tt> or <tt>:without</tt> as an option.
87
+ # In addition, both must be a regular expression or a proc or lambda, or
88
+ # else an exception will be raised.
89
+ #
90
+ # Configuration options:
91
+ # * <tt>:message</tt> - A custom error message (default is: "is invalid").
92
+ # * <tt>:allow_nil</tt> - If set to true, skips this validation if the
93
+ # attribute is +nil+ (default is +false+).
94
+ # * <tt>:allow_blank</tt> - If set to true, skips this validation if the
95
+ # attribute is blank (default is +false+).
96
+ # * <tt>:with</tt> - Regular expression that if the attribute matches will
97
+ # result in a successful validation. This can be provided as a proc or
98
+ # lambda returning regular expression which will be called at runtime.
99
+ # * <tt>:without</tt> - Regular expression that if the attribute does not
100
+ # match will result in a successful validation. This can be provided as
101
+ # a proc or lambda returning regular expression which will be called at
102
+ # runtime.
103
+ # * <tt>:multiline</tt> - Set to true if your regular expression contains
104
+ # anchors that match the beginning or end of lines as opposed to the
105
+ # beginning or end of the string. These anchors are <tt>^</tt> and <tt>$</tt>.
106
+ #
107
+ # There is also a list of default options supported by every validator:
108
+ # +:if+, +:unless+, +:on+ and +:strict+.
109
+ # See <tt>ActiveModel::Validation#validates</tt> for more information
110
+ def validates_format_of(*attr_names)
111
+ validates_with FormatValidator, _merge_attributes(attr_names)
112
+ end
113
+ end
114
+
115
+ end
116
+ end
@@ -0,0 +1,16 @@
1
+ module UseCaseValidations
2
+ module Validations
3
+
4
+ module HelperMethods
5
+
6
+ def _merge_attributes(attr_names)
7
+ options = Helpers._symbolyze_keys(Helpers._extract_options!(attr_names))
8
+ attr_names.flatten!
9
+ options[:attributes] = attr_names
10
+ options
11
+ end
12
+
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,126 @@
1
+ module UseCaseValidations
2
+
3
+ # == Active \Model Length \Validator
4
+ module Validations
5
+ class LengthValidator < EachValidator # :nodoc:
6
+ MESSAGES = { is: :wrong_length, minimum: :too_short, maximum: :too_long }.freeze
7
+ CHECKS = { is: :==, minimum: :>=, maximum: :<= }.freeze
8
+
9
+ RESERVED_OPTIONS = [:minimum, :maximum, :within, :is, :tokenizer, :too_short, :too_long]
10
+
11
+ def initialize(options)
12
+ if range = (options.delete(:in) || options.delete(:within))
13
+ raise ArgumentError, ":in and :within must be a Range" unless range.is_a?(Range)
14
+ options[:minimum], options[:maximum] = range.min, range.max
15
+ end
16
+
17
+ if options[:allow_blank] == false && options[:minimum].nil? && options[:is].nil?
18
+ options[:minimum] = 1
19
+ end
20
+
21
+ super
22
+ end
23
+
24
+ def check_validity!
25
+ keys = CHECKS.keys & options.keys
26
+
27
+ if keys.empty?
28
+ raise ArgumentError, 'Range unspecified. Specify the :in, :within, :maximum, :minimum, or :is option.'
29
+ end
30
+
31
+ keys.each do |key|
32
+ value = options[key]
33
+
34
+ unless (value.is_a?(Integer) && value >= 0) || value == Float::INFINITY
35
+ raise ArgumentError, ":#{key} must be a nonnegative Integer or Infinity"
36
+ end
37
+ end
38
+ end
39
+
40
+ def validate_each(record, attribute, value)
41
+ value = tokenize(value)
42
+ value_length = value.respond_to?(:length) ? value.length : value.to_s.length
43
+ errors_options = Helpers._except(options, *RESERVED_OPTIONS)
44
+
45
+ CHECKS.each do |key, validity_check|
46
+ next unless check_value = options[key]
47
+
48
+ if !value.nil? || skip_nil_check?(key)
49
+ next if value_length.send(validity_check, check_value)
50
+ end
51
+
52
+ errors_options[:count] = check_value
53
+
54
+ default_message = options[MESSAGES[key]]
55
+ errors_options[:message] ||= default_message if default_message
56
+
57
+ record.errors.add(attribute, MESSAGES[key], errors_options)
58
+ end
59
+ end
60
+
61
+ private
62
+
63
+ def tokenize(value)
64
+ if options[:tokenizer] && value.kind_of?(String)
65
+ options[:tokenizer].call(value)
66
+ end || value
67
+ end
68
+
69
+ def skip_nil_check?(key)
70
+ key == :maximum && options[:allow_nil].nil? && options[:allow_blank].nil?
71
+ end
72
+ end
73
+
74
+ module HelperMethods
75
+
76
+ # Validates that the specified attribute matches the length restrictions
77
+ # supplied. Only one option can be used at a time:
78
+ #
79
+ # class Person < ActiveRecord::Base
80
+ # validates_length_of :first_name, maximum: 30
81
+ # validates_length_of :last_name, maximum: 30, message: "less than 30 if you don't mind"
82
+ # validates_length_of :fax, in: 7..32, allow_nil: true
83
+ # validates_length_of :phone, in: 7..32, allow_blank: true
84
+ # validates_length_of :user_name, within: 6..20, too_long: 'pick a shorter name', too_short: 'pick a longer name'
85
+ # validates_length_of :zip_code, minimum: 5, too_short: 'please enter at least 5 characters'
86
+ # validates_length_of :smurf_leader, is: 4, message: "papa is spelled with 4 characters... don't play me."
87
+ # validates_length_of :essay, minimum: 100, too_short: 'Your essay must be at least 100 words.',
88
+ # tokenizer: ->(str) { str.scan(/\w+/) }
89
+ # end
90
+ #
91
+ # Configuration options:
92
+ # * <tt>:minimum</tt> - The minimum size of the attribute.
93
+ # * <tt>:maximum</tt> - The maximum size of the attribute. Allows +nil+ by
94
+ # default if not used with :minimum.
95
+ # * <tt>:is</tt> - The exact size of the attribute.
96
+ # * <tt>:within</tt> - A range specifying the minimum and maximum size of
97
+ # the attribute.
98
+ # * <tt>:in</tt> - A synonym (or alias) for <tt>:within</tt>.
99
+ # * <tt>:allow_nil</tt> - Attribute may be +nil+; skip validation.
100
+ # * <tt>:allow_blank</tt> - Attribute may be blank; skip validation.
101
+ # * <tt>:too_long</tt> - The error message if the attribute goes over the
102
+ # maximum (default is: "is too long (maximum is %{count} characters)").
103
+ # * <tt>:too_short</tt> - The error message if the attribute goes under the
104
+ # minimum (default is: "is too short (min is %{count} characters)").
105
+ # * <tt>:wrong_length</tt> - The error message if using the <tt>:is</tt>
106
+ # method and the attribute is the wrong size (default is: "is the wrong
107
+ # length (should be %{count} characters)").
108
+ # * <tt>:message</tt> - The error message to use for a <tt>:minimum</tt>,
109
+ # <tt>:maximum</tt>, or <tt>:is</tt> violation. An alias of the appropriate
110
+ # <tt>too_long</tt>/<tt>too_short</tt>/<tt>wrong_length</tt> message.
111
+ # * <tt>:tokenizer</tt> - Specifies how to split up the attribute string.
112
+ # (e.g. <tt>tokenizer: ->(str) { str.scan(/\w+/) }</tt> to count words
113
+ # as in above example). Defaults to <tt>->(value) { value.split(//) }</tt>
114
+ # which counts individual characters.
115
+ #
116
+ # There is also a list of default options supported by every validator:
117
+ # +:if+, +:unless+, +:on+ and +:strict+.
118
+ # See <tt>ActiveModel::Validation#validates</tt> for more information
119
+ def validates_length_of(*attr_names)
120
+ validates_with LengthValidator, _merge_attributes(attr_names)
121
+ end
122
+
123
+ alias_method :validates_size_of, :validates_length_of
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,17 @@
1
+ module UseCaseValidations
2
+ module Validations
3
+
4
+ class PresenceValidator < EachValidator # :nodoc:
5
+ def validate_each(record, attr_name, value)
6
+ record.errors.add(attr_name, :blank, options) if Helpers._blank?(value)
7
+ end
8
+ end
9
+
10
+ module HelperMethods
11
+ def validates_presence_of(*attr_names)
12
+ validates_with PresenceValidator, _merge_attributes(attr_names)
13
+ end
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,56 @@
1
+ module UseCaseValidations
2
+ module Validations
3
+
4
+ class UniquenessValidator < EachValidator
5
+ def validate_each(record, attribute, value)
6
+
7
+ return nil unless scope_method(record)
8
+
9
+ records.each do |other_record|
10
+ next if record == other_record || Helpers._marked_for_destruction?(other_record) || !scope_method(other_record)
11
+
12
+ if similar_objects?(record, other_record, attribute)
13
+ record.errors.add(attribute, :taken, options)
14
+ break
15
+ end
16
+ end
17
+
18
+ end
19
+
20
+ protected ########################### PROTECTED #######################
21
+
22
+ def records
23
+ [*base.target].inject([]) do |scoped_list, object|
24
+ scoped_list << object if scope_method(object)
25
+ scoped_list
26
+ end
27
+ end
28
+
29
+ def similar_objects?(record, other_record, attribute)
30
+ if options.key?(:conditions)
31
+ if base.method(options[:conditions]).arity == 3
32
+ base.send(options[:conditions], record, other_record, attribute)
33
+ else
34
+ base.send(options[:conditions], record, other_record)
35
+ end
36
+ else
37
+ record.send(attribute) == other_record.send(attribute)
38
+ end
39
+ end
40
+
41
+ private ###################### PRIVATE ####################
42
+
43
+ def scope_method(object)
44
+ options.key?(:scope) ? base.send(options[:scope], object) : true
45
+ end
46
+
47
+ end
48
+
49
+ module HelperMethods
50
+ def validates_uniqueness_of(*attr_names)
51
+ validates_with UniquenessValidator, _merge_attributes(attr_names)
52
+ end
53
+ end
54
+
55
+ end
56
+ end
@@ -0,0 +1,20 @@
1
+ module UseCaseValidations
2
+
3
+ class Validator
4
+
5
+ attr_reader :options
6
+ attr_accessor :base
7
+
8
+ def initialize(options = {})
9
+ @options = Helpers._except(options, :class).freeze
10
+ end
11
+
12
+ # Override this method in subclasses with validation logic, adding errors
13
+ # to the records +errors+ array where necessary.
14
+ def validate(record)
15
+ raise NotImplementedError, "Subclasses must implement a validate(record) method."
16
+ end
17
+
18
+ end
19
+
20
+ end
@@ -0,0 +1,3 @@
1
+ module UseCaseValidations
2
+ VERSION = "0.5.0"
3
+ end
@@ -0,0 +1,122 @@
1
+ require 'usecasing'
2
+
3
+ require "usecasing_validations/target"
4
+ require "usecasing_validations/helpers"
5
+ require "usecasing_validations/errors"
6
+ require "usecasing_validations/validator"
7
+ require "usecasing_validations/each_validator"
8
+ require "usecasing_validations/custom_validator"
9
+
10
+ require "usecasing_validations/validations/helper_methods"
11
+ require "usecasing_validations/validations/format"
12
+ require "usecasing_validations/validations/length"
13
+ require "usecasing_validations/validations/presence"
14
+ require "usecasing_validations/validations/uniqueness"
15
+
16
+
17
+ module UseCase
18
+ autoload :Validator, 'usecasing/validator'
19
+ autoload :DependsAll, 'usecasing/depends_all'
20
+ end
21
+
22
+
23
+ module UseCaseValidations
24
+
25
+ def self.included(base)
26
+ base.extend(Validations::HelperMethods)
27
+ base.class_eval { include Target }
28
+ base.extend(ClassMethods)
29
+ end
30
+
31
+ protected #################### PROTECTED ######################
32
+
33
+ def run_validations!(object_to_validate)
34
+ self.class.validators.each do |validator|
35
+ next unless option_if_succeeds(validator, object_to_validate)
36
+
37
+ validator.base = self
38
+ validator.validate(object_to_validate)
39
+ end
40
+ end
41
+
42
+ def valid?(object_to_validate)
43
+ extend_errors_if_necessary object_to_validate
44
+
45
+ object_to_validate.errors.clear if self.class.clear_errors?
46
+
47
+ run_validations! object_to_validate
48
+
49
+ object_to_validate.errors.empty?
50
+ end
51
+
52
+ private ######################## PRIVATE #######################
53
+
54
+ def extend_errors_if_necessary(object_to_validate)
55
+ return true if object_to_validate.respond_to?(:errors)
56
+
57
+ object_to_validate.instance_eval do
58
+ def errors; @errors ||= Errors.new(self); end
59
+ end
60
+ end
61
+
62
+ def option_if_succeeds(validator, object_to_validate)
63
+ if validator.options.key?(:if)
64
+ Helpers._call_proc_or_method(self, validator.options[:if], object_to_validate)
65
+ else
66
+ true
67
+ end
68
+ end
69
+
70
+ module ClassMethods
71
+
72
+ def clear_errors!
73
+ @clear_errors = true
74
+ end
75
+
76
+ def clear_errors?
77
+ defined?(@clear_errors) ? @clear_errors : false
78
+ end
79
+
80
+ def _validators
81
+ @_validators ||= Hash.new { |h,k| h[k] = [] }
82
+ end
83
+
84
+ def _validators=(value)
85
+ @_validators = value
86
+ end
87
+
88
+ def validate(*args, &block)
89
+ _validators[nil] << CustomValidator.new(args, &block)
90
+ end
91
+
92
+ def validates_with(*args, &block)
93
+ options = Helpers._extract_options!(args)
94
+ options[:class] = self
95
+
96
+ args.each do |klass|
97
+ validator = klass.new(options, &block)
98
+
99
+ if validator.respond_to?(:attributes) && !validator.attributes.empty?
100
+ validator.attributes.each do |attribute|
101
+ _validators[attribute.to_sym] << validator
102
+ end
103
+ else
104
+ _validators[nil] << validator
105
+ end
106
+ end
107
+ end
108
+
109
+ def validators
110
+ _validators.values.flatten.uniq
111
+ end
112
+
113
+ # Copy validators on inheritance.
114
+ def inherited(base)
115
+ dup = _validators.dup
116
+ base._validators = dup.each { |k, v| dup[k] = v.dup }
117
+ super
118
+ end
119
+
120
+ end #/ClassMethods
121
+
122
+ end
@@ -0,0 +1,17 @@
1
+ require 'usecasing_validations'
2
+
3
+ require 'pry'
4
+
5
+ Dir.chdir("spec/") do
6
+ Dir["support/models/*.rb"].each { |file| require file }
7
+ Dir["support/usecases/*.rb"].each { |file| require file }
8
+ end
9
+
10
+ RSpec.configure do |config|
11
+ config.treat_symbols_as_metadata_keys_with_true_values = true
12
+ config.run_all_when_everything_filtered = true
13
+ config.filter_run :focus
14
+ config.mock_framework = :mocha
15
+
16
+ config.order = 'random'
17
+ end
@@ -0,0 +1,9 @@
1
+ class RubyPost
2
+
3
+ attr_accessor :title, :body, :phone_number
4
+
5
+ def initialize(attributes = {})
6
+ (attributes || {}).each { |name, value| send("#{name}=", value) }
7
+ end
8
+
9
+ end
@@ -0,0 +1,28 @@
1
+ class RubyPostWithComments
2
+
3
+ class RubyComment
4
+
5
+ attr_accessor :title, :email, :post_id
6
+
7
+ def initialize(attributes = {})
8
+ (attributes || {}).each { |name, value| send("#{name}=", value) }
9
+ end
10
+
11
+ end
12
+
13
+
14
+ attr_reader :comments
15
+
16
+ def initialize(comments = {})
17
+ @comments = comments.map { |comment| RubyComment.new(comment) }
18
+ @comments = [] if @comments.nil?
19
+ end
20
+
21
+ def first_two_comments
22
+ [
23
+ comments[0],
24
+ comments[1]
25
+ ]
26
+ end
27
+
28
+ end
@@ -0,0 +1,34 @@
1
+ class ValidateComments < UseCase::Validator
2
+
3
+ target :comments, in: :post
4
+
5
+ validates_presence_of :title, message: "can't be blank!"
6
+
7
+ validates_format_of :email, with: /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i, message: "invalid format!"
8
+
9
+ validates_length_of :title, minimum: 6, allow_nil: true
10
+
11
+ validate :custom_validation1, :custom_validation2
12
+
13
+
14
+ protected ######################### PROTECTED ############################
15
+
16
+ def custom_validation1(comment)
17
+ if ['force_error1', 'force_error2'].include?(comment.title)
18
+ comment.errors.add(:title, 'custom_validation1')
19
+ return false
20
+ end
21
+
22
+ true
23
+ end
24
+
25
+ def custom_validation2(comment)
26
+ if comment.email == "force_error@gmail.com"
27
+ comment.errors.add(:email, 'custom_validation2')
28
+ return false
29
+ end
30
+
31
+ true
32
+ end
33
+
34
+ end
@@ -0,0 +1,14 @@
1
+ class ValidateCommentsCustomTarget < UseCase::Validator
2
+
3
+ def target
4
+ [
5
+ context.post.comments[0],
6
+ context.post.comments[1]
7
+ ]
8
+ end
9
+
10
+ validates_presence_of :title
11
+
12
+ validates_format_of :email, with: /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
13
+
14
+ end
@@ -0,0 +1,24 @@
1
+ module Group
2
+
3
+ class ValidatePostTitle < UseCase::Validator
4
+
5
+ target :post
6
+
7
+ validates_presence_of :title
8
+
9
+ end
10
+
11
+ class ValidatePostBody < UseCase::Validator
12
+
13
+ target :post
14
+
15
+ validates_presence_of :body
16
+
17
+ end
18
+
19
+ class ValidateDependsAll < UseCase::DependsAll
20
+
21
+ depends ValidatePostTitle, ValidatePostBody
22
+
23
+ end
24
+ end
@@ -0,0 +1,18 @@
1
+ class ValidatePost < UseCase::Validator
2
+
3
+ target :post
4
+
5
+ validates_presence_of :title, :body, message: "can't be blank!"
6
+
7
+ validates_presence_of :phone_number, if: ->(post) { context.validate_phone_number }
8
+
9
+ validates_format_of :phone_number, with: /\A[0-9 ]*\z/, message: "invalid format!", if: :validate_phone_number
10
+
11
+
12
+ protected ###################### PROTECTED ####################
13
+
14
+ def validate_phone_number(post)
15
+ context.validate_phone_number
16
+ end
17
+
18
+ end
@@ -0,0 +1,9 @@
1
+ class ValidatePostClearErrors < UseCase::Validator
2
+
3
+ clear_errors!
4
+
5
+ target :post
6
+
7
+ validates_presence_of :title, :body
8
+
9
+ end