usecasing_validations 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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