hanami-validations 0.5.0 → 0.6.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.
@@ -0,0 +1,47 @@
1
+ require 'hanami/validations'
2
+
3
+ module Hanami
4
+ module Validations
5
+ # Validations mixin for forms/HTTP params.
6
+ #
7
+ # This must be used when the input comes from a browser or an HTTP endpoint.
8
+ # It knows how to deal with common data types, and common edge cases like blank strings.
9
+ #
10
+ # @since 0.6.0
11
+ #
12
+ # @example
13
+ # require 'hanami/validations/form'
14
+ #
15
+ # class Signup
16
+ # include Hanami::Validations::Form
17
+ # end
18
+ module Form
19
+ # Override Ruby's hook for modules.
20
+ #
21
+ # @param base [Class] the target action
22
+ #
23
+ # @since 0.6.0
24
+ # @api private
25
+ #
26
+ # @see http://www.ruby-doc.org/core/Module.html#method-i-included
27
+ def self.included(base)
28
+ base.class_eval do
29
+ include Validations
30
+ extend ClassMethods
31
+ end
32
+ end
33
+
34
+ # @since 0.6.0
35
+ # @api private
36
+ module ClassMethods
37
+ private
38
+
39
+ # @since 0.6.0
40
+ # @api private
41
+ def _schema_type
42
+ :Form
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,46 @@
1
+ module Hanami
2
+ module Validations
3
+ # Inline predicate
4
+ #
5
+ # @since 0.6.0
6
+ # @api private
7
+ class InlinePredicate
8
+ # @since 0.6.0
9
+ # @api private
10
+ attr_reader :name
11
+
12
+ # @since 0.6.0
13
+ # @api private
14
+ attr_reader :message
15
+
16
+ # Return a new instance.
17
+ #
18
+ # @param name [Symbol] inline predicate name
19
+ # @param message [String] optional failure message
20
+ # @param blk [Proc] predicate implementation
21
+ #
22
+ # @return [Hanami::Validations::InlinePredicate] a new instance
23
+ #
24
+ # @since 0.6.0
25
+ # @api private
26
+ def initialize(name, message, &blk)
27
+ @name = name
28
+ @message = message
29
+ @blk = blk
30
+ end
31
+
32
+ # @since 0.6.0
33
+ # @api private
34
+ def to_proc
35
+ @blk
36
+ end
37
+
38
+ # @since 0.6.0
39
+ # @api private
40
+ def ==(other)
41
+ self.class == other.class &&
42
+ name == other.name
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,65 @@
1
+ require 'hanami/utils/string'
2
+
3
+ module Hanami
4
+ module Validations
5
+ # Validations message namespace.
6
+ #
7
+ # For a given `FooValidator` class, it will look for I18n messages within
8
+ # the `foo` group.
9
+ #
10
+ # @since 0.6.0
11
+ # @api private
12
+ class Namespace
13
+ # @since 0.6.0
14
+ # @api private
15
+ SUFFIX = 'Validator'.freeze
16
+
17
+ # @since 0.6.0
18
+ # @api private
19
+ SUFFIX_REPLACEMENT = ''.freeze
20
+
21
+ # @since 0.6.0
22
+ # @api private
23
+ RUBY_NAMESPACE_SEPARATOR = '/'.freeze
24
+
25
+ # @since 0.6.0
26
+ # @api private
27
+ RUBY_NAMESPACE_REPLACEMENT = '.'.freeze
28
+
29
+ # @since 0.6.0
30
+ # @api private
31
+ def self.new(name, klass)
32
+ result = name || klass.name
33
+ return nil if result.nil?
34
+
35
+ super(result)
36
+ end
37
+
38
+ # @since 0.6.0
39
+ # @api private
40
+ def initialize(name)
41
+ @name = name
42
+ end
43
+
44
+ # @since 0.6.0
45
+ # @api private
46
+ def to_s
47
+ underscored_name.gsub(RUBY_NAMESPACE_SEPARATOR, RUBY_NAMESPACE_REPLACEMENT)
48
+ end
49
+
50
+ private
51
+
52
+ # @since 0.6.0
53
+ # @api private
54
+ def underscored_name
55
+ Utils::String.new(name_without_suffix).underscore
56
+ end
57
+
58
+ # @since 0.6.0
59
+ # @api private
60
+ def name_without_suffix
61
+ @name.sub(SUFFIX, SUFFIX_REPLACEMENT)
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,45 @@
1
+ require 'dry/logic/predicates'
2
+ require 'hanami/utils/class_attribute'
3
+
4
+ module Hanami
5
+ module Validations
6
+ # Mixin to include when defining shared predicates
7
+ #
8
+ # @since 0.6.0
9
+ #
10
+ # @see Hanami::Validations::ClassMethods#predicates
11
+ #
12
+ # @example
13
+ # require 'hanami/validations'
14
+ #
15
+ # module MySharedPredicates
16
+ # include Hanami::Validations::Predicates
17
+ #
18
+ # predicate :foo? fo |actual|
19
+ # actual == 'foo'
20
+ # end
21
+ # end
22
+ #
23
+ # class MyValidator
24
+ # include Hanami::Validations
25
+ # predicates MySharedPredicates
26
+ #
27
+ # validations do
28
+ # required(:name).filled(:foo?)
29
+ # end
30
+ # end
31
+ module Predicates
32
+ # @since 0.6.0
33
+ # @api private
34
+ def self.included(base)
35
+ base.class_eval do
36
+ include Dry::Logic::Predicates
37
+ include Utils::ClassAttribute
38
+
39
+ class_attribute :messages
40
+ class_attribute :messages_path
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -1,6 +1,6 @@
1
1
  module Hanami
2
2
  module Validations
3
3
  # @since 0.1.0
4
- VERSION = '0.5.0'.freeze
4
+ VERSION = '0.6.0'.freeze
5
5
  end
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hanami-validations
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luca Guidi
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2016-01-22 00:00:00.000000000 Z
13
+ date: 2016-07-22 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: hanami-utils
@@ -18,14 +18,28 @@ dependencies:
18
18
  requirements:
19
19
  - - "~>"
20
20
  - !ruby/object:Gem::Version
21
- version: '0.7'
21
+ version: '0.8'
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
26
  - - "~>"
27
27
  - !ruby/object:Gem::Version
28
- version: '0.7'
28
+ version: '0.8'
29
+ - !ruby/object:Gem::Dependency
30
+ name: dry-validation
31
+ requirement: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - "~>"
34
+ - !ruby/object:Gem::Version
35
+ version: '0.9'
36
+ type: :runtime
37
+ prerelease: false
38
+ version_requirements: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - "~>"
41
+ - !ruby/object:Gem::Version
42
+ version: '0.9'
29
43
  - !ruby/object:Gem::Dependency
30
44
  name: bundler
31
45
  requirement: !ruby/object:Gem::Requirement
@@ -83,15 +97,10 @@ files:
83
97
  - hanami-validations.gemspec
84
98
  - lib/hanami-validations.rb
85
99
  - lib/hanami/validations.rb
86
- - lib/hanami/validations/attribute.rb
87
- - lib/hanami/validations/attribute_definer.rb
88
- - lib/hanami/validations/blank_value_checker.rb
89
- - lib/hanami/validations/coercions.rb
90
- - lib/hanami/validations/error.rb
91
- - lib/hanami/validations/errors.rb
92
- - lib/hanami/validations/nested_attributes.rb
93
- - lib/hanami/validations/validation_set.rb
94
- - lib/hanami/validations/validator.rb
100
+ - lib/hanami/validations/form.rb
101
+ - lib/hanami/validations/inline_predicate.rb
102
+ - lib/hanami/validations/namespace.rb
103
+ - lib/hanami/validations/predicates.rb
95
104
  - lib/hanami/validations/version.rb
96
105
  homepage: http://hanamirb.org
97
106
  licenses:
@@ -105,7 +114,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
105
114
  requirements:
106
115
  - - ">="
107
116
  - !ruby/object:Gem::Version
108
- version: 2.0.0
117
+ version: 2.2.0
109
118
  required_rubygems_version: !ruby/object:Gem::Requirement
110
119
  requirements:
111
120
  - - ">="
@@ -113,9 +122,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
113
122
  version: '0'
114
123
  requirements: []
115
124
  rubyforge_project:
116
- rubygems_version: 2.5.1
125
+ rubygems_version: 2.6.4
117
126
  signing_key:
118
127
  specification_version: 4
119
128
  summary: Validations mixin for Ruby objects
120
129
  test_files: []
121
- has_rdoc:
@@ -1,252 +0,0 @@
1
- require 'hanami/validations/coercions'
2
-
3
- # Quick fix for non MRI VMs that don't implement Range#size
4
- #
5
- # @since 0.1.0
6
- class Range
7
- def size
8
- to_a.size
9
- end unless instance_methods.include?(:size)
10
- end
11
-
12
- module Hanami
13
- module Validations
14
- # A validable attribute
15
- #
16
- # @since 0.1.0
17
- # @api private
18
- class Attribute
19
- # Attribute naming convention for "confirmation" validation
20
- #
21
- # @see Hanami::Validations::Attribute#confirmation
22
- #
23
- # @since 0.2.0
24
- # @api private
25
- CONFIRMATION_TEMPLATE = '%{name}_confirmation'.freeze
26
-
27
- # Instantiate an attribute
28
- #
29
- # @param attributes [Hash] a set of attributes and values coming from the
30
- # input
31
- # @param name [Symbol] the name of the attribute
32
- # @param value [Object,nil] the value coming from the input
33
- # @param validations [Hash] a set of validation rules
34
- #
35
- # @since 0.2.0
36
- # @api private
37
- def initialize(attributes, name, value, validations, errors)
38
- @attributes = attributes
39
- @name = name
40
- @value = value
41
- @validations = validations
42
- @errors = errors
43
- end
44
-
45
- # @api private
46
- # @since 0.2.0
47
- def validate
48
- presence
49
- acceptance
50
-
51
- return if skip?
52
-
53
- format
54
- inclusion
55
- exclusion
56
- size
57
- confirmation
58
- nested
59
-
60
- @errors
61
- end
62
-
63
- # @api private
64
- # @since 0.2.0
65
- attr_reader :value
66
-
67
- private
68
- # Validates presence of the value.
69
- # This fails with `nil` and "blank" values.
70
- #
71
- # An object is blank if it isn't `nil`, but doesn't hold a value.
72
- # Empty strings and enumerables are an example.
73
- #
74
- # @see Hanami::Validations::ClassMethods#attribute
75
- # @see Hanami::Validations::Attribute#nil_value?
76
- #
77
- # @since 0.2.0
78
- # @api private
79
- def presence
80
- _validate(__method__) { !blank_value? }
81
- end
82
-
83
- # Validates acceptance of the value.
84
- #
85
- # This passes if the value is "truthy", it fails if not.
86
- #
87
- # Truthy examples: `Object.new`, `1`, `"1"`, `true`.
88
- # Falsy examples: `nil`, `0`, `"0"`, `false`, `""`.
89
- #
90
- # @see Hanami::Validations::ClassMethods#attribute
91
- # @see http://www.rubydoc.info/gems/hanami-utils/Hanami/Utils/Kernel#Boolean-class_method
92
- #
93
- # @since 0.2.0
94
- # @api private
95
- def acceptance
96
- _validate(__method__) do
97
- !blank_value? && Hanami::Utils::Kernel.Boolean(@value)
98
- end
99
- end
100
-
101
- # Validates format of the value.
102
- #
103
- # Coerces the value to a string and then check if it satisfies the defined
104
- # matcher.
105
- #
106
- # @see Hanami::Validations::ClassMethods#attribute
107
- #
108
- # @since 0.2.0
109
- # @api private
110
- def format
111
- _validate(__method__) {|matcher| @value.to_s.match(matcher) } unless blank_value?
112
- end
113
-
114
- # Validates inclusion of the value in the defined collection.
115
- #
116
- # The collection is an objects which implements `#include?`.
117
- #
118
- # @see Hanami::Validations::ClassMethods#attribute
119
- #
120
- # @since 0.2.0
121
- # @api private
122
- def inclusion
123
- _validate(__method__) {|collection| collection.include?(value) }
124
- end
125
-
126
- # Validates exclusion of the value in the defined collection.
127
- #
128
- # The collection is an objects which implements `#include?`.
129
- #
130
- # @see Hanami::Validations::ClassMethods#attribute
131
- #
132
- # @since 0.2.0
133
- # @api private
134
- def exclusion
135
- _validate(__method__) {|collection| !collection.include?(value) }
136
- end
137
-
138
- # Validates confirmation of the value with another corresponding value.
139
- #
140
- # Given a `:password` attribute, it passes if the corresponding attribute
141
- # `:password_confirmation` has the same value.
142
- #
143
- # @see Hanami::Validations::ClassMethods#attribute
144
- # @see Hanami::Validations::Attribute::CONFIRMATION_TEMPLATE
145
- #
146
- # @since 0.2.0
147
- # @api private
148
- def confirmation
149
- _validate(__method__) do
150
- _attribute == _attribute(CONFIRMATION_TEMPLATE % { name: @name })
151
- end
152
- end
153
-
154
- # Validates if value's size matches the defined quantity.
155
- #
156
- # The quantity can be a Ruby Numeric:
157
- #
158
- # * `Integer`
159
- # * `Fixnum`
160
- # * `Float`
161
- # * `BigNum`
162
- # * `BigDecimal`
163
- # * `Complex`
164
- # * `Rational`
165
- # * Octal literals
166
- # * Hex literals
167
- # * `#to_int`
168
- #
169
- # The quantity can be also any object which implements `#include?`.
170
- #
171
- # If the quantity is a Numeric, the size of the value MUST be exactly the
172
- # same.
173
- #
174
- # If the quantity is a Range, the size of the value MUST be included.
175
- #
176
- # If the attribute's value is blank, the size will not be considered
177
- #
178
- # The value is an object which implements `#size`.
179
- #
180
- # @raise [ArgumentError] if the defined quantity isn't a Numeric or a
181
- # collection
182
- #
183
- # @see Hanami::Validations::ClassMethods#attribute
184
- #
185
- # @since 0.2.0
186
- # @api private
187
- def size
188
- return if blank_value?
189
-
190
- _validate(__method__) do |validator|
191
- case validator
192
- when Numeric, ->(v) { v.respond_to?(:to_int) }
193
- value.size == validator.to_int
194
- when Range
195
- validator.include?(value.size)
196
- else
197
- raise ArgumentError.new("Size validator must be a number or a range, it was: #{ validator }")
198
- end
199
- end
200
- end
201
-
202
- # Validates nested Hanami Validations objects
203
- #
204
- # @since 0.2.4
205
- # @api private
206
- def nested
207
- _validate(__method__) do |validator|
208
- errors = value.validate
209
- errors.each do |error|
210
- new_error = Error.new(error.attribute, error.validation, error.expected, error.actual, @name)
211
- @errors.add new_error.attribute, new_error
212
- end
213
- true
214
- end
215
- end
216
-
217
- # @since 0.1.0
218
- # @api private
219
- def skip?
220
- @value.nil?
221
- end
222
-
223
- # Checks if the value is "blank".
224
- #
225
- # @see Hanami::Validations::BlankValueChecker
226
- #
227
- # @since 0.2.0
228
- # @api private
229
- def blank_value?
230
- BlankValueChecker.new(@value).blank_value?
231
- end
232
-
233
- # Reads an attribute from the validator.
234
- #
235
- # @since 0.2.0
236
- # @api private
237
- def _attribute(name = @name)
238
- @attributes[name.to_sym]
239
- end
240
-
241
- # Run a single validation and collects the results.
242
- #
243
- # @since 0.2.0
244
- # @api private
245
- def _validate(validation)
246
- if (validator = @validations[validation]) && !(yield validator)
247
- @errors.add(@name, Error.new(@name, validation, @validations.fetch(validation), @value))
248
- end
249
- end
250
- end
251
- end
252
- end