valid_attribute 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY +4 -0
- data/README.markdown +35 -8
- data/lib/valid_attribute/matcher.rb +71 -0
- data/lib/valid_attribute/method.rb +38 -0
- data/lib/valid_attribute/rspec.rb +3 -0
- data/lib/valid_attribute/test_unit.rb +3 -0
- data/lib/valid_attribute/version.rb +1 -1
- data/lib/valid_attribute.rb +8 -84
- data/spec/spec_helper.rb +1 -1
- data/spec/test_unit_spec.rb +12 -0
- data/spec/user.rb +12 -0
- data/spec/valid_attribute_spec.rb +76 -71
- metadata +10 -2
data/HISTORY
CHANGED
data/README.markdown
CHANGED
@@ -4,17 +4,26 @@ ValidAttribute is a minimalist framework for validation BDD.
|
|
4
4
|
|
5
5
|
## Installation ##
|
6
6
|
|
7
|
-
If you're using
|
7
|
+
If you're using `RSpec` just add the `valid_attribute` to your `Gemfile`
|
8
8
|
|
9
9
|
gem 'valid_attribute'
|
10
10
|
|
11
|
-
Then add it to your spec_helper
|
11
|
+
Then add it to your `spec_helper.rb`
|
12
12
|
|
13
13
|
require 'valid_attribute'
|
14
14
|
|
15
|
+
or if you're using `Test::Unit`, you must use [Thoughtbot](http://thoughtbot.com)'s [shoulda-context](https://github.com/thoughtbot/shoulda-context)
|
16
|
+
|
17
|
+
# Gemfile
|
18
|
+
gem 'shoulda-context'
|
19
|
+
|
20
|
+
# test_helper.rb
|
21
|
+
require 'shoulda-context'
|
22
|
+
require 'valid_attribute'
|
23
|
+
|
15
24
|
## Usage ##
|
16
25
|
|
17
|
-
Instead of having validation specific matchers ValidAttribute only cares if the attribute is valid under certain circumstances
|
26
|
+
Instead of having validation specific matchers `ValidAttribute` only cares if the attribute is valid under certain circumstances
|
18
27
|
|
19
28
|
class User
|
20
29
|
include ActiveModel::Validations
|
@@ -26,12 +35,13 @@ Instead of having validation specific matchers ValidAttribute only cares if the
|
|
26
35
|
validates :password, :confirmation => true, :presence => true
|
27
36
|
end
|
28
37
|
|
38
|
+
# RSpec
|
29
39
|
describe User do
|
30
40
|
# The .when method can take any number of values that you want to pass
|
31
41
|
it { should have_valid(:email).when('test@test.com', 'test+spam@gmail.com') }
|
32
42
|
it { should_not have_valid(:email).when('fail', 123) }
|
33
|
-
it { should have_valid(:name).when('TestName')
|
34
|
-
it { should_not have_valid(:name).when('Test')
|
43
|
+
it { should have_valid(:name).when('TestName') }
|
44
|
+
it { should_not have_valid(:name).when('Test') }
|
35
45
|
|
36
46
|
# Because 'should' works off the the 'subject' in RSpec we can set other values if necessary for a given validation test
|
37
47
|
describe 'password' do
|
@@ -41,12 +51,29 @@ Instead of having validation specific matchers ValidAttribute only cares if the
|
|
41
51
|
end
|
42
52
|
end
|
43
53
|
|
54
|
+
# TestUnit
|
55
|
+
require 'should/context'
|
56
|
+
class UserTest < Test::Unit::TestCase
|
57
|
+
# The .when method can take any number of values that you want to pass
|
58
|
+
should have_valid(:email).when('test@test.com', 'test+spam@gmail.com')
|
59
|
+
should_not have_valid(:email).when('fail', 123)
|
60
|
+
should have_valid(:name).when('TestName')
|
61
|
+
should_not have_valid(:name).when('Test')
|
62
|
+
|
63
|
+
# Because 'shoulda-context' works off the the 'subject' we can set other values if necessary for a given validation test
|
64
|
+
context 'password' do
|
65
|
+
subject { User.new(:password_confirmation => 'password') }
|
66
|
+
should have_valid(:password).when('password')
|
67
|
+
should_not have_valid(:password).when(nil)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
44
71
|
## Non-ActiveModel models ##
|
45
72
|
|
46
|
-
|
73
|
+
Your model should respond to the following methods:
|
47
74
|
|
48
|
-
* valid
|
49
|
-
* errors - should be a collection of attributes that have validation errors.
|
75
|
+
* `valid?` - only used to generate errors on the model
|
76
|
+
* `errors` - should be a collection of attributes that have validation errors.
|
50
77
|
|
51
78
|
Other than that everything should work!
|
52
79
|
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module ValidAttribute
|
2
|
+
class Matcher
|
3
|
+
attr_accessor :attr, :values, :subject, :failed_values, :passed_values
|
4
|
+
|
5
|
+
def initialize(attr)
|
6
|
+
self.attr = attr
|
7
|
+
end
|
8
|
+
|
9
|
+
def when(*values)
|
10
|
+
self.values = values
|
11
|
+
self
|
12
|
+
end
|
13
|
+
|
14
|
+
def failure_message
|
15
|
+
if failed_values.size == 1
|
16
|
+
" expected #{subject.class}##{attr} to accept the value: #{quote_values(failed_values)}"
|
17
|
+
else
|
18
|
+
" expected #{subject.class}##{attr} to accept the values: #{quote_values(failed_values)}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def negative_failure_message
|
23
|
+
if passed_values.size == 1
|
24
|
+
" expected #{subject.class}##{attr} to not accept the value: #{quote_values(passed_values)}"
|
25
|
+
else
|
26
|
+
" expected #{subject.class}##{attr} to not accept the values: #{quote_values(passed_values)}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def description
|
31
|
+
"be valid when: #{quote_values(values)}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def matches?(subject)
|
35
|
+
check_values(subject)
|
36
|
+
failed_values.empty?
|
37
|
+
end
|
38
|
+
|
39
|
+
def does_not_match?(subject)
|
40
|
+
check_values(subject)
|
41
|
+
!failed_values.empty? && passed_values.empty?
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def check_values(subject)
|
47
|
+
unless values
|
48
|
+
raise ::ValidAttribute::NoValues, "you need to set the values with .when on the matcher. Example: have_valid(:name).when('Brian')"
|
49
|
+
end
|
50
|
+
|
51
|
+
self.subject = subject
|
52
|
+
self.failed_values = []
|
53
|
+
self.passed_values = []
|
54
|
+
|
55
|
+
values.each do |value|
|
56
|
+
subject.send("#{attr}=", value)
|
57
|
+
subject.valid?
|
58
|
+
if subject.errors.key?(attr)
|
59
|
+
self.failed_values << value
|
60
|
+
else
|
61
|
+
self.passed_values << value
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def quote_values(values)
|
67
|
+
values.map { |value| value.is_a?(String) ? "'#{value}'" : value }.join(', ')
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module ValidAttribute
|
2
|
+
module Method
|
3
|
+
# Assert an attribute is valid with any number of test values
|
4
|
+
#
|
5
|
+
# examples:
|
6
|
+
# describe User do
|
7
|
+
# it { should have_valid(:name).when('Brian') }
|
8
|
+
# it { should_not have_valid(:name).when(nil) }
|
9
|
+
#
|
10
|
+
# # if we want to test uniqueness we need to setup an existing value
|
11
|
+
# context 'email' do
|
12
|
+
# before { User.create(:email => 'brian@test.com') }
|
13
|
+
# it { should have_valid(:email).when('test@test.com', 'test+spam@gmail.com') }
|
14
|
+
# it { should_not have_valid(:email).when('abc', 123, 'brian@test.com') }
|
15
|
+
# end
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# If you are using Test::Unit you should use {http://thoughtbot.com Thoughtbot}'s {https://github.com/thoughtbot/shoulda-context shoulda-context}:
|
19
|
+
# class UserTest < Test::Unit::TestCase
|
20
|
+
# should have_valid(:name).when('Brian')
|
21
|
+
# should_not have_valid(:name).when('nil')
|
22
|
+
#
|
23
|
+
# # if we want to test uniqueness we need to setup an existing value
|
24
|
+
# context 'email' do
|
25
|
+
# setup { User.create(:email => 'brian@test.com') }
|
26
|
+
# should have_valid(:email).when('test@test.com', 'test+spam@gmail.com')
|
27
|
+
# should_not have_valid(:email).when('abc', 123, 'brian@test.com')
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# @param [Symbol]
|
32
|
+
#
|
33
|
+
# @return [ValidAttribute::Matcher]
|
34
|
+
def have_valid(attr)
|
35
|
+
::ValidAttribute::Matcher.new(attr)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/valid_attribute.rb
CHANGED
@@ -1,88 +1,12 @@
|
|
1
|
+
require 'valid_attribute/matcher'
|
2
|
+
require 'valid_attribute/method'
|
3
|
+
|
1
4
|
module ValidAttribute
|
2
5
|
class NoValues < StandardError; end
|
3
|
-
# Test if an attribute is valid
|
4
|
-
#
|
5
|
-
# examples:
|
6
|
-
# it { should have_valid(:name).when('Brian') }
|
7
|
-
# it { should_not have_valid(:name).when(nil) }
|
8
|
-
# it { should have_valid(:email).when('test@test.com', 'test+spam@gmail.com') }
|
9
|
-
# it { should_not have_valid(:email).when('abc', 123) }
|
10
|
-
#
|
11
|
-
# @param [Symbol]
|
12
|
-
#
|
13
|
-
# @return [ValidAttribute::ValidAttributeMatcher]
|
14
|
-
def have_valid(attr)
|
15
|
-
ValidAttributeMatcher.new(attr)
|
16
|
-
end
|
17
|
-
|
18
|
-
class ValidAttributeMatcher
|
19
|
-
attr_accessor :attr, :values, :subject, :failed_values, :passed_values
|
20
|
-
|
21
|
-
def initialize(attr)
|
22
|
-
self.attr = attr
|
23
|
-
end
|
24
|
-
|
25
|
-
def when(*values)
|
26
|
-
self.values = values
|
27
|
-
self
|
28
|
-
end
|
29
|
-
|
30
|
-
def failure_message
|
31
|
-
if failed_values.size == 1
|
32
|
-
" expected #{subject.class.model_name}##{attr} to accept the value: #{quote_values(failed_values)}"
|
33
|
-
else
|
34
|
-
" expected #{subject.class.model_name}##{attr} to accept the values: #{quote_values(failed_values)}"
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def negative_failure_message
|
39
|
-
if passed_values.size == 1
|
40
|
-
" expected #{subject.class.model_name}##{attr} to not accept the value: #{quote_values(passed_values)}"
|
41
|
-
else
|
42
|
-
" expected #{subject.class.model_name}##{attr} to not accept the values: #{quote_values(passed_values)}"
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def matches?(subject)
|
47
|
-
check_values(subject)
|
48
|
-
failed_values.empty?
|
49
|
-
end
|
50
|
-
|
51
|
-
def does_not_match?(subject)
|
52
|
-
check_values(subject)
|
53
|
-
passed_values.empty?
|
54
|
-
end
|
55
|
-
|
56
|
-
private
|
57
|
-
|
58
|
-
def check_values(subject)
|
59
|
-
unless values
|
60
|
-
raise ::ValidAttribute::NoValues, "you need to set the values with .when on the matcher (ex. it { should have_valid(:name).when('Brian') })"
|
61
|
-
end
|
62
|
-
|
63
|
-
self.subject = subject
|
64
|
-
self.failed_values = []
|
65
|
-
self.passed_values = []
|
66
|
-
|
67
|
-
values.each do |value|
|
68
|
-
subject.send("#{attr}=", value)
|
69
|
-
subject.valid?
|
70
|
-
if subject.errors.key?(attr)
|
71
|
-
self.failed_values << value
|
72
|
-
else
|
73
|
-
self.passed_values << value
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
def quote_values(values)
|
79
|
-
values.map { |value| value.is_a?(String) ? "'#{value}'" : value }.join(', ')
|
80
|
-
end
|
81
|
-
|
82
|
-
end
|
83
6
|
end
|
84
7
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
8
|
+
if defined?(RSpec)
|
9
|
+
require 'valid_attribute/rspec'
|
10
|
+
else
|
11
|
+
require 'valid_attribute/test_unit'
|
12
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -5,10 +5,10 @@ Bundler.setup
|
|
5
5
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
6
6
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
7
7
|
require 'ruby-debug'
|
8
|
-
require 'valid_attribute'
|
9
8
|
require 'rspec'
|
10
9
|
require 'rspec/autorun'
|
11
10
|
require 'bourne'
|
11
|
+
require 'valid_attribute'
|
12
12
|
|
13
13
|
RSpec.configure do |config|
|
14
14
|
config.mock_with :mocha
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# This is a RSpec spec to test TestUnit... yeah that's right
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'test/unit'
|
5
|
+
require 'valid_attribute/test_unit'
|
6
|
+
|
7
|
+
describe 'Test::Unit::TestCase' do
|
8
|
+
it '.have_valid' do
|
9
|
+
Test::Unit::TestCase.have_valid(:name).should be_instance_of(ValidAttribute::Matcher)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
data/spec/user.rb
ADDED
@@ -1,20 +1,8 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'user'
|
2
3
|
|
3
4
|
class Should
|
4
|
-
include ValidAttribute
|
5
|
-
end
|
6
|
-
|
7
|
-
class User
|
8
|
-
attr_accessor :name
|
9
|
-
attr_accessor :email
|
10
|
-
|
11
|
-
def errors
|
12
|
-
@error ||= {}
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.model_name
|
16
|
-
'User'
|
17
|
-
end
|
5
|
+
include ValidAttribute::Method
|
18
6
|
end
|
19
7
|
|
20
8
|
describe 'ValidAttribute' do
|
@@ -24,66 +12,83 @@ describe 'ValidAttribute' do
|
|
24
12
|
@user = User.new
|
25
13
|
end
|
26
14
|
|
27
|
-
describe '
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
end
|
50
|
-
|
51
|
-
it 'does_not_match? returns false' do
|
52
|
-
@does_not_match.should be_false
|
53
|
-
end
|
54
|
-
|
55
|
-
it 'has a failure message of the failed values' do
|
56
|
-
@matcher.failure_message.should == " expected User#name to accept the value: 'abc'"
|
57
|
-
end
|
58
|
-
|
59
|
-
it 'has a negative failure message of the passed values' do
|
60
|
-
@matcher.negative_failure_message.should == " expected User#name to not accept the value: 123"
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
describe 'data is first invalid then valid then invalid then valid' do
|
65
|
-
before do
|
66
|
-
@user.stubs(:valid?).returns(false).then.returns(true).then.returns(false).then.returns(false).then.returns(true).then.returns(false)
|
67
|
-
@user.stubs(:errors).returns({:name => []}).then.returns({}).then.returns({:name => []}).then.returns({}).then.returns({:name => []}).then.returns({}).then.returns({:name => []}).then.returns({})
|
68
|
-
@matcher = @should.have_valid(:name).when('abc', 123, 456, 'def')
|
69
|
-
@matches = @matcher.matches?(@user)
|
70
|
-
@does_not_match = @matcher.does_not_match?(@user)
|
71
|
-
end
|
72
|
-
|
73
|
-
it 'matches? returns false' do
|
74
|
-
@matches.should be_false
|
75
|
-
end
|
76
|
-
|
77
|
-
it 'does_not_match? returns true' do
|
78
|
-
@does_not_match.should be_false
|
15
|
+
describe 'matcher result' do
|
16
|
+
context 'data is valid' do
|
17
|
+
before do
|
18
|
+
@user.stubs(:valid?).returns(true)
|
19
|
+
@user.stubs(:errors).returns({})
|
20
|
+
@matcher = @should.have_valid(:name).when('abc', 123)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'matches? returns true' do
|
24
|
+
@matcher.matches?(@user).should be_true
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'does_not_match? returns false' do
|
28
|
+
@matcher.does_not_match?(@user).should be_false
|
29
|
+
end
|
30
|
+
|
31
|
+
describe 'messages' do
|
32
|
+
it '#negative_failue_message' do
|
33
|
+
@matcher.matches?(@user)
|
34
|
+
@matcher.negative_failure_message.should == " expected User#name to not accept the values: 'abc', 123"
|
35
|
+
end
|
36
|
+
end
|
79
37
|
end
|
80
38
|
|
81
|
-
|
82
|
-
|
39
|
+
context 'data is invalid' do
|
40
|
+
before do
|
41
|
+
@user.stubs(:valid?).returns(false)
|
42
|
+
@user.stubs(:errors).returns({:name => []})
|
43
|
+
@matcher = @should.have_valid(:name).when('abc', 123)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'matches? returns false' do
|
47
|
+
@matcher.matches?(@user).should be_false
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'does_not_match? returns true' do
|
51
|
+
@matcher.does_not_match?(@user).should be_true
|
52
|
+
end
|
53
|
+
|
54
|
+
describe 'messages' do
|
55
|
+
it '#failue_message' do
|
56
|
+
@matcher.matches?(@user)
|
57
|
+
@matcher.failure_message.should == " expected User#name to accept the values: 'abc', 123"
|
58
|
+
end
|
59
|
+
end
|
83
60
|
end
|
84
61
|
|
85
|
-
|
86
|
-
|
62
|
+
context 'data is valid then invalid' do
|
63
|
+
before do
|
64
|
+
@user.stubs(:valid?).returns(true).then.returns(false)
|
65
|
+
@user.stubs(:errors).returns({}).then.returns({:name => []})
|
66
|
+
@matcher = @should.have_valid(:name).when('abc', 123)
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'matches? returns false' do
|
70
|
+
@matcher.matches?(@user).should be_false
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'does_not_match? returns false' do
|
74
|
+
@matcher.does_not_match?(@user).should be_false
|
75
|
+
end
|
76
|
+
|
77
|
+
describe 'messages' do
|
78
|
+
it '#failure_message' do
|
79
|
+
@matcher.matches?(@user)
|
80
|
+
@matcher.failure_message.should == " expected User#name to accept the value: 123"
|
81
|
+
end
|
82
|
+
|
83
|
+
it '#negative_failure_message' do
|
84
|
+
@matcher.matches?(@user)
|
85
|
+
@matcher.negative_failure_message.should == " expected User#name to not accept the value: 'abc'"
|
86
|
+
end
|
87
|
+
|
88
|
+
it '#description' do
|
89
|
+
@matcher.description.should == "be valid when: 'abc', 123"
|
90
|
+
end
|
91
|
+
end
|
87
92
|
end
|
88
93
|
end
|
89
94
|
|
@@ -91,7 +96,7 @@ describe 'ValidAttribute' do
|
|
91
96
|
matcher = @should.have_valid(:name)
|
92
97
|
expect do
|
93
98
|
matcher.matches?(@user)
|
94
|
-
end.to raise_error ValidAttribute::NoValues, "you need to set the values with .when on the matcher
|
99
|
+
end.to raise_error ValidAttribute::NoValues, "you need to set the values with .when on the matcher. Example: have_valid(:name).when('Brian')"
|
95
100
|
end
|
96
101
|
|
97
102
|
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: valid_attribute
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.
|
5
|
+
version: 0.2.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Brian Cardarella
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-05-
|
13
|
+
date: 2011-05-28 00:00:00 -04:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -64,8 +64,14 @@ files:
|
|
64
64
|
- README.markdown
|
65
65
|
- Rakefile
|
66
66
|
- lib/valid_attribute.rb
|
67
|
+
- lib/valid_attribute/matcher.rb
|
68
|
+
- lib/valid_attribute/method.rb
|
69
|
+
- lib/valid_attribute/rspec.rb
|
70
|
+
- lib/valid_attribute/test_unit.rb
|
67
71
|
- lib/valid_attribute/version.rb
|
68
72
|
- spec/spec_helper.rb
|
73
|
+
- spec/test_unit_spec.rb
|
74
|
+
- spec/user.rb
|
69
75
|
- spec/valid_attribute_spec.rb
|
70
76
|
- valid_attribute.gemspec
|
71
77
|
has_rdoc: true
|
@@ -98,4 +104,6 @@ specification_version: 3
|
|
98
104
|
summary: Minimalist validation matcher framework
|
99
105
|
test_files:
|
100
106
|
- spec/spec_helper.rb
|
107
|
+
- spec/test_unit_spec.rb
|
108
|
+
- spec/user.rb
|
101
109
|
- spec/valid_attribute_spec.rb
|