Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added blank_value? to size predicate #82

Merged
merged 3 commits into from
Nov 26, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,34 @@ person.email # => "me@example.org"
person.age # => raises NoMethodError because `:age` wasn't defined as attribute.
```

#### Blank Values

The framework will treat as valid any blank attributes, __without__ `presence`, for both `format` and `size` predicates.

```ruby
require 'lotus/validations'

class Person
include Lotus::Validations

attribute :name, type: String, size: 5..45
attribute :email, type: String, size: 20..80, format: /@/
attribute :skills, type: Array, size: 1..3
attribute :keys, type: Hash, size: 1..3
end

Person.new.valid? # < true
Person.new(name: '').valid? # < true
Person.new(skills: '').valid? # < true
Person.new(skills: ['ruby', 'lotus']).valid? # < true

Person.new(skills: []).valid? # < false
Person.new(keys: {}).valid? # < false
Person.new(keys: {a: :b}, skills: []).valid? # < false
```

If you want to _disable_ this behaviour, please, refer to [presence](https://github.com/lotus/validations#presence).

### Validations

If you prefer Lotus::Validations to **only define validations**, but **not attributes**,
Expand Down
4 changes: 4 additions & 0 deletions lib/lotus/validations/attribute.rb
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ def confirmation
#
# If the quantity is a Range, the size of the value MUST be included.
#
# If the attribute's value is blank, the size will not be considered
#
# The value is an object which implements `#size`.
#
# @raise [ArgumentError] if the defined quantity isn't a Numeric or a
Expand All @@ -181,6 +183,8 @@ def confirmation
# @since 0.2.0
# @api private
def size
return if blank_value?

_validate(__method__) do |validator|
case validator
when Numeric, ->(v) { v.respond_to?(:to_int) }
Expand Down
10 changes: 10 additions & 0 deletions lib/lotus/validations/blank_value_checker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,18 @@ def _blank_string?
# @since 0.2.2
# @api private
def _empty_value?
return false if _enumerable?
(@value.respond_to?(:empty?) and @value.empty?)
end

# Collectable classes should not be considered as blank value
# even if it's responds _true_ to its own `empty?` method.
#
# @since x.x.x
# @api private
def _enumerable?
@value.respond_to?(:each)
end
end
end
end
13 changes: 13 additions & 0 deletions test/composed_validation_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,19 @@

validator.valid?.must_equal true
end

# Bug https://github.com/lotus/validations/issues/81
it 'is valid if included attributes are blank and does not define presence constraint' do
validator = ComposedValidationsWithoutPresenceTest.new(email: '', name: '')

validator.valid?.must_equal true
end

it 'is not valid if included attributes are invalid' do
validator = ComposedValidationsWithoutPresenceTest.new(email: 'fo', name: 'o')

validator.valid?.must_equal false
end
end

describe 'nested composed validations' do
Expand Down
16 changes: 14 additions & 2 deletions test/fixtures.rb
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ class PresenceValidatorTest
class FormatValidatorTest
include Lotus::Validations

attribute :name, format: /\A[a-zA-Z]+\z/
attribute :age, type: String, format: /\A[0-9]+\z/
attribute :name, format: /\A[a-zA-Z]+\z/
attribute :age, type: String, format: /\A[0-9]+\z/
end

class InclusionValidatorTest
Expand Down Expand Up @@ -185,6 +185,12 @@ module EmailValidations
attribute :email, presence: true, format: /@/
end

module EmailValidationsWithoutPresence
include Lotus::Validations

attribute :email, format: /@/
end

module CommonValidations
include EmailValidations
end
Expand All @@ -193,6 +199,12 @@ class ComposedValidationsTest
include EmailValidations
end

class ComposedValidationsWithoutPresenceTest
include EmailValidationsWithoutPresence

attribute :name, size: 8..50
end

module PasswordValidations
include Lotus::Validations

Expand Down
16 changes: 16 additions & 0 deletions test/size_validation_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,22 @@
end
end

# Bug https://github.com/lotus/validations/issues/81
it 'is valid if attribute is defined as blank' do
validator = SizeValidatorTest.new(password: 'foobarbazqux', ssn: '')

validator.valid?.must_equal true
validator.errors.must_be_empty
end

it 'is not valid if attribute is an empty collection' do
validator = SizeValidatorTest.new(password: 'quxbazbarfoo', ssn: [])

validator.valid?.must_equal false
errors = validator.errors.for(:ssn)
errors.must_include Lotus::Validations::Error.new(:ssn, :size, 11, [])
end

it "raises an error when the validator can't be coerced into an integer" do
-> { SizeValidatorErrorTest.new(password: 'secret').valid? }.must_raise ArgumentError
end
Expand Down