accept_values_for 0.2.1 → 0.3.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.
- data/Readme.textile +53 -11
- data/VERSION +1 -1
- data/accept_values_for.gemspec +57 -0
- data/lib/discover.rb +127 -0
- data/spec/discover_spec.rb +68 -0
- data/spec/spec_helper.rb +10 -1
- metadata +8 -4
data/Readme.textile
CHANGED
@@ -2,25 +2,67 @@ h1. Accept values for
|
|
2
2
|
|
3
3
|
h2. Description
|
4
4
|
|
5
|
-
In order to spec
|
6
|
-
|
7
|
-
With this matcher you can specify which values of model attribute should be accepted by model validation and which should not.
|
5
|
+
In order to spec ActiveRecord models.
|
6
|
+
I decided to write a few custom matchers that makes the work match easier:
|
8
7
|
|
9
8
|
|
10
|
-
h2.
|
9
|
+
h2. Matchers
|
11
10
|
|
12
|
-
|
13
|
-
|
11
|
+
* accept_values_for
|
12
|
+
* discover
|
14
13
|
|
15
|
-
|
16
|
-
|
14
|
+
h3. Accept values for
|
17
15
|
|
16
|
+
"Rpec matcher to test the validation":http://gusiev.com/2010/06/ultimate-rspec-matcher-to-test-validation/
|
18
17
|
|
19
|
-
|
20
|
-
|
18
|
+
<pre>
|
19
|
+
describe User do
|
21
20
|
|
21
|
+
subject { User.new(@valid_attributes)}
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
it { should accept_values_for(:email, "john@example.com", "lambda@gusiev.com") }
|
26
|
+
it { should_not accept_values_for(:email, "invalid", nil, "a@b", "john@.com") }
|
27
|
+
|
28
|
+
end</pre>
|
29
|
+
|
30
|
+
h3. Discovery matcher
|
31
|
+
|
32
|
+
"Rspec matcher to test named scopes":http://gusiev.com/2010/07/bdd-rspec-matcher-to-test-named_scope-scoped-rails
|
33
|
+
|
34
|
+
|
35
|
+
<pre><code>describe "#by_category_id named scope" do
|
36
|
+
let(:given_category) do
|
37
|
+
Factory.create(:given_category)
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
let(:product_in_given_category) do
|
42
|
+
Factory.create(
|
43
|
+
:product,
|
44
|
+
:categories => [category]
|
45
|
+
)
|
46
|
+
end
|
47
|
+
|
48
|
+
let(:product_not_in_given_category) do
|
49
|
+
Factory.create(
|
50
|
+
:product,
|
51
|
+
:categories => [Factory.create(:category)]
|
52
|
+
)
|
22
53
|
end
|
23
|
-
|
54
|
+
|
55
|
+
# This might be tricky to redefine subject as the finder result
|
56
|
+
# but in this way we can delegate the matcher to subject and
|
57
|
+
# avoid writing test descriptions.
|
58
|
+
subject { described_class.by_category_id(given_category.id) }
|
59
|
+
|
60
|
+
it { should discover(product_in_given_category) }
|
61
|
+
it { should_not discover(product_not_in_given_category) }
|
62
|
+
|
63
|
+
end
|
64
|
+
</code></pre>
|
65
|
+
|
24
66
|
|
25
67
|
h2. Dependencies
|
26
68
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{accept_values_for}
|
8
|
+
s.version = "0.3.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Bogdan Gusiev"]
|
12
|
+
s.date = %q{2010-07-12}
|
13
|
+
s.description = %q{Rspec: When you have a complex validation(e.g. regexp or custom method) on ActiveRecord model
|
14
|
+
you have to write annoying easy specs on which values should be accepted by your validation method and which should not.
|
15
|
+
accepts_values_for rspec matcher simplify the code. See example for more information.
|
16
|
+
}
|
17
|
+
s.email = %q{agresso@gmail.com}
|
18
|
+
s.files = [
|
19
|
+
"Gemfile",
|
20
|
+
"Rakefile",
|
21
|
+
"Readme.textile",
|
22
|
+
"VERSION",
|
23
|
+
"accept_values_for.gemspec",
|
24
|
+
"lib/accept_values_for.rb",
|
25
|
+
"lib/discover.rb",
|
26
|
+
"spec/accept_values_for_spec.rb",
|
27
|
+
"spec/discover_spec.rb",
|
28
|
+
"spec/spec_helper.rb"
|
29
|
+
]
|
30
|
+
s.homepage = %q{http://github.com/bogdan/accept_values_for}
|
31
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
32
|
+
s.require_paths = ["lib"]
|
33
|
+
s.rubygems_version = %q{1.3.6}
|
34
|
+
s.summary = %q{In order to test a complex validation for ActiveRecord models Implemented accept_values_for custom rspec matcher}
|
35
|
+
s.test_files = [
|
36
|
+
"spec/discover_spec.rb",
|
37
|
+
"spec/accept_values_for_spec.rb",
|
38
|
+
"spec/spec_helper.rb"
|
39
|
+
]
|
40
|
+
|
41
|
+
if s.respond_to? :specification_version then
|
42
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
43
|
+
s.specification_version = 3
|
44
|
+
|
45
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
46
|
+
s.add_runtime_dependency(%q<activerecord>, [">= 0"])
|
47
|
+
s.add_runtime_dependency(%q<rspec>, [">= 0"])
|
48
|
+
else
|
49
|
+
s.add_dependency(%q<activerecord>, [">= 0"])
|
50
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
51
|
+
end
|
52
|
+
else
|
53
|
+
s.add_dependency(%q<activerecord>, [">= 0"])
|
54
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
data/lib/discover.rb
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
if defined?(ActiveRecord)
|
2
|
+
|
3
|
+
# In order to spec ActiveRecord finders
|
4
|
+
# Implemented discover custom matcher
|
5
|
+
#
|
6
|
+
# :call-seq:
|
7
|
+
# Class.named_scope.should discover(model1, model2)
|
8
|
+
# Class.named_scope.should_not discover(model3, model4)
|
9
|
+
#
|
10
|
+
# matcher subject should be an instance of ActiverRecord::NamedScope::Scoped or Array
|
11
|
+
# models should be an instace of ActiverRecord::Base
|
12
|
+
#
|
13
|
+
# Use this if you need to check the inclution of objects ActiveRecord finders result
|
14
|
+
# and it's order
|
15
|
+
#
|
16
|
+
# == Examples
|
17
|
+
#
|
18
|
+
# class Group < AR::Base
|
19
|
+
# named_scope :approved, :conditions => "approved = true"
|
20
|
+
# named_scope :order_by_name, :order => "name"
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# Group.approved.should discover(Group.create!(:approved => true))
|
24
|
+
# Group.approved.should_not discover(Group.create!(:approved => false))
|
25
|
+
# Group.order_by_name.should discover(Group.create!(:name => "apple"), Group.create!(:name => "bear").with_exact_order)
|
26
|
+
#
|
27
|
+
#
|
28
|
+
def discover(*objects)
|
29
|
+
Rspec::Discover.new(*objects)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
module Rspec
|
35
|
+
class Discover #:nodoc:
|
36
|
+
|
37
|
+
def initialize(*objects)
|
38
|
+
@objects = objects
|
39
|
+
end
|
40
|
+
|
41
|
+
def with_exact_order
|
42
|
+
@with_exact_order = true
|
43
|
+
self
|
44
|
+
end
|
45
|
+
|
46
|
+
def matches?(scope)
|
47
|
+
@scope = scope
|
48
|
+
return valid_findness? && valid_indexes?
|
49
|
+
end
|
50
|
+
|
51
|
+
def does_not_match?(scope)
|
52
|
+
@scope = scope
|
53
|
+
if @with_exact_order
|
54
|
+
raise "calling #with_exact_order is not allowed with should_not match"
|
55
|
+
end
|
56
|
+
return valid_not_findness?
|
57
|
+
end
|
58
|
+
|
59
|
+
def failure_message_for_should
|
60
|
+
result = @not_found_object_ids.any? ?
|
61
|
+
"expected #{@scope.inspect} to include objects: #{@not_found_object_ids.inspect}" :
|
62
|
+
"expected #{@scope.inspect} to be ordered as: #{@objects.map(&:id).inspect}"
|
63
|
+
result += ", but it was not. "
|
64
|
+
if @not_found_object_ids.any?
|
65
|
+
result += found_objects_string
|
66
|
+
end
|
67
|
+
result
|
68
|
+
end
|
69
|
+
|
70
|
+
def failure_message_for_should_not
|
71
|
+
result = "expected #{@scope.inspect} to not include objects: #{@found_object_ids.inspect}"
|
72
|
+
result += ", but it was. "
|
73
|
+
result += found_objects_string
|
74
|
+
result
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
def description
|
79
|
+
"discover #{@objects.map(&:inspect).join(', ')} " + ordering_string
|
80
|
+
end
|
81
|
+
|
82
|
+
protected
|
83
|
+
|
84
|
+
def valid_findness?
|
85
|
+
result = true
|
86
|
+
@not_found_object_ids = []
|
87
|
+
@objects.each do |object|
|
88
|
+
unless @scope.include?(object)
|
89
|
+
@not_found_object_ids << object.id
|
90
|
+
result = false
|
91
|
+
end
|
92
|
+
end
|
93
|
+
result
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
def valid_indexes?
|
98
|
+
return true unless @with_exact_order
|
99
|
+
indexes = @objects.map{|o| @scope.index(o)}
|
100
|
+
return indexes.sort == indexes
|
101
|
+
end
|
102
|
+
|
103
|
+
def valid_not_findness?
|
104
|
+
result = true
|
105
|
+
@found_object_ids = []
|
106
|
+
@objects.each do |object|
|
107
|
+
if @scope.include?(object)
|
108
|
+
@found_object_ids << object.id
|
109
|
+
result = false
|
110
|
+
end
|
111
|
+
end
|
112
|
+
result
|
113
|
+
end
|
114
|
+
|
115
|
+
def found_objects_string
|
116
|
+
"Found objects: " + @scope.map(&:id).inspect
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
def ordering_string
|
121
|
+
@with_exact_order ? "with exact order" : ""
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Discover" do
|
4
|
+
|
5
|
+
|
6
|
+
let(:named_scope) {
|
7
|
+
Group.by_char("j")
|
8
|
+
}
|
9
|
+
let(:java) { Group.create!(:name => "java") }
|
10
|
+
let(:json) { Group.create!(:name => "json") }
|
11
|
+
let(:jruby) { Group.create!(:name => "jruby") }
|
12
|
+
let(:ruby) { Group.create!(:name => "ruby")}
|
13
|
+
let(:python) { Group.create!(:name => "python")}
|
14
|
+
|
15
|
+
describe "#does_not_match?" do
|
16
|
+
|
17
|
+
context "if scope contains any of the specified values" do
|
18
|
+
subject { discover(java, ruby) }
|
19
|
+
before(:each) do
|
20
|
+
subject.does_not_match?(named_scope).should be_false
|
21
|
+
end
|
22
|
+
|
23
|
+
it { subject.failure_message_for_should_not.should == "expected #{named_scope.inspect} to not include objects: #{[java.id].inspect}, but it was. Found objects: #{named_scope.map(&:id).inspect}"}
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "#matches?" do
|
30
|
+
context "if scope doesn't contain any of the specified objects" do
|
31
|
+
subject { discover(java, ruby) }
|
32
|
+
before(:each) do
|
33
|
+
subject.matches?(named_scope).should be_false
|
34
|
+
end
|
35
|
+
|
36
|
+
it {subject.failure_message_for_should.should == "expected #{named_scope.inspect} to include objects: #{[ruby.id].inspect}, but it was not. Found objects: #{named_scope.map(&:id).inspect}"}
|
37
|
+
end
|
38
|
+
|
39
|
+
context "if scope contain all of the specified objects but without correct order" do
|
40
|
+
subject { discover(jruby, java).with_exact_order }
|
41
|
+
before(:each) do
|
42
|
+
subject.matches?(named_scope).should be_false
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should render error message correctly" do
|
46
|
+
subject.failure_message_for_should.should == "expected #{named_scope.inspect} to be ordered as: #{[jruby.id, java.id].inspect}, but it was not. "
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "api" do
|
52
|
+
subject {
|
53
|
+
named_scope
|
54
|
+
}
|
55
|
+
|
56
|
+
it { should discover(java) }
|
57
|
+
|
58
|
+
it { should discover(json, java, jruby) }
|
59
|
+
it { should discover(java, jruby, json).with_exact_order }
|
60
|
+
it { should discover(java, json).with_exact_order }
|
61
|
+
|
62
|
+
it { should_not discover(ruby) }
|
63
|
+
it { should_not discover(ruby, python) }
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -3,6 +3,7 @@ require 'spec'
|
|
3
3
|
require 'spec/autorun'
|
4
4
|
require 'active_record'
|
5
5
|
require 'lib/accept_values_for'
|
6
|
+
require 'lib/discover'
|
6
7
|
|
7
8
|
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
|
8
9
|
ActiveRecord::Base.configurations = true
|
@@ -13,6 +14,7 @@ ActiveRecord::Schema.define(:version => 1) do
|
|
13
14
|
create_table :people do |t|
|
14
15
|
t.string :gender
|
15
16
|
t.integer :group_id
|
17
|
+
t.string :name
|
16
18
|
end
|
17
19
|
|
18
20
|
create_table :groups do |t|
|
@@ -23,7 +25,14 @@ end
|
|
23
25
|
Spec::Runner.configure do |config|
|
24
26
|
config.before(:each) do
|
25
27
|
class ::Group < ActiveRecord::Base
|
26
|
-
|
28
|
+
has_many :people
|
29
|
+
|
30
|
+
named_scope :by_char, lambda { |char|
|
31
|
+
{
|
32
|
+
:conditions => ["name like ?", char + "%"],
|
33
|
+
:order => "name"
|
34
|
+
}
|
35
|
+
}
|
27
36
|
end
|
28
37
|
|
29
38
|
class ::Person < ActiveRecord::Base
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 3
|
8
|
+
- 0
|
9
|
+
version: 0.3.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Bogdan Gusiev
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
17
|
+
date: 2010-07-12 00:00:00 +03:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -58,8 +58,11 @@ files:
|
|
58
58
|
- Rakefile
|
59
59
|
- Readme.textile
|
60
60
|
- VERSION
|
61
|
+
- accept_values_for.gemspec
|
61
62
|
- lib/accept_values_for.rb
|
63
|
+
- lib/discover.rb
|
62
64
|
- spec/accept_values_for_spec.rb
|
65
|
+
- spec/discover_spec.rb
|
63
66
|
- spec/spec_helper.rb
|
64
67
|
has_rdoc: true
|
65
68
|
homepage: http://github.com/bogdan/accept_values_for
|
@@ -92,5 +95,6 @@ signing_key:
|
|
92
95
|
specification_version: 3
|
93
96
|
summary: In order to test a complex validation for ActiveRecord models Implemented accept_values_for custom rspec matcher
|
94
97
|
test_files:
|
98
|
+
- spec/discover_spec.rb
|
95
99
|
- spec/accept_values_for_spec.rb
|
96
100
|
- spec/spec_helper.rb
|