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 CHANGED
@@ -1,3 +1,7 @@
1
+ == 0.2.0
2
+ Test::Unit::TestCase support. You should use shoulda-context
3
+ Fixed logic bug with #does_not_match?
4
+
1
5
  == 0.1.0
2
6
  Version bump. API is stable
3
7
 
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 Rails just add the library to your Gemfile
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
- As long as your model responds to the following methods:
73
+ Your model should respond to the following methods:
47
74
 
48
- * valid? - only used to generate errors on the model
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
@@ -0,0 +1,3 @@
1
+ module RSpec::Matchers
2
+ include ValidAttribute::Method
3
+ end
@@ -0,0 +1,3 @@
1
+ class Test::Unit::TestCase
2
+ extend ::ValidAttribute::Method
3
+ end
@@ -1,3 +1,3 @@
1
1
  module ValidAttribute
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -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
- module RSpec::Matchers
86
- include ValidAttribute
87
- end if defined?(RSpec)
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
@@ -0,0 +1,12 @@
1
+ class User
2
+ attr_accessor :name
3
+ attr_accessor :email
4
+
5
+ def errors
6
+ @error ||= {}
7
+ end
8
+
9
+ def self.model_name
10
+ 'User'
11
+ end
12
+ end
@@ -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 'valid data' do
28
- before do
29
- @user.stubs(:valid?).returns(true)
30
- end
31
-
32
- it 'passes with values' do
33
- matcher = @should.have_valid(:name).when('Brian', 'Stephanie')
34
- matcher.matches?(@user).should be_true
35
- end
36
- end
37
-
38
- describe 'data is first invalid then invalid' do
39
- before do
40
- @user.stubs(:valid?).returns(false).then.returns(true).then.returns(false).then.returns(true)
41
- @user.stubs(:errors).returns({:name => []}).then.returns({}).then.returns({:name => []}).then.returns({})
42
- @matcher = @should.have_valid(:name).when('abc', 123)
43
- @matches = @matcher.matches?(@user)
44
- @does_not_match = @matcher.does_not_match?(@user)
45
- end
46
-
47
- it 'matches? returns false' do
48
- @matches.should be_false
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
- it 'has a failure message of the failed values' do
82
- @matcher.failure_message.should == " expected User#name to accept the values: 'abc', 456"
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
- it 'has a negative failure message of the passed values' do
86
- @matcher.negative_failure_message.should == " expected User#name to not accept the values: 123, 'def'"
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 (ex. it { should have_valid(:name).when('Brian') })"
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.1.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-07 00:00:00 -04:00
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