remarkable_activerecord 3.0.8 → 3.0.9
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/CHANGELOG +49 -10
- data/lib/remarkable_activerecord.rb +2 -1
- data/lib/remarkable_activerecord/describe.rb +84 -0
- data/lib/remarkable_activerecord/human_names.rb +2 -2
- data/lib/remarkable_activerecord/matchers/accept_nested_attributes_for_matcher.rb +18 -9
- data/lib/remarkable_activerecord/matchers/allow_mass_assignment_of_matcher.rb +2 -2
- data/lib/remarkable_activerecord/matchers/allow_values_for_matcher.rb +3 -3
- data/lib/remarkable_activerecord/matchers/association_matcher.rb +8 -8
- data/lib/remarkable_activerecord/matchers/have_column_matcher.rb +2 -2
- data/lib/remarkable_activerecord/matchers/have_default_scope_matcher.rb +7 -5
- data/lib/remarkable_activerecord/matchers/have_index_matcher.rb +11 -3
- data/lib/remarkable_activerecord/matchers/have_readonly_attributes_matcher.rb +2 -2
- data/lib/remarkable_activerecord/matchers/have_scope_matcher.rb +10 -10
- data/lib/remarkable_activerecord/matchers/validate_acceptance_of_matcher.rb +2 -2
- data/lib/remarkable_activerecord/matchers/validate_associated_matcher.rb +9 -5
- data/lib/remarkable_activerecord/matchers/validate_confirmation_of_matcher.rb +2 -2
- data/lib/remarkable_activerecord/matchers/validate_exclusion_of_matcher.rb +2 -2
- data/lib/remarkable_activerecord/matchers/validate_inclusion_of_matcher.rb +2 -2
- data/lib/remarkable_activerecord/matchers/validate_length_of_matcher.rb +12 -7
- data/lib/remarkable_activerecord/matchers/validate_numericality_of_matcher.rb +10 -5
- data/lib/remarkable_activerecord/matchers/validate_presence_of_matcher.rb +2 -2
- data/lib/remarkable_activerecord/matchers/validate_uniqueness_of_matcher.rb +41 -8
- data/locale/en.yml +9 -1
- data/spec/accept_nested_attributes_for_matcher_spec.rb +11 -0
- data/spec/association_matcher_spec.rb +29 -4
- data/spec/describe_spec.rb +57 -0
- data/spec/have_column_matcher_spec.rb +6 -1
- data/spec/have_scope_matcher_spec.rb +9 -2
- data/spec/spec_helper.rb +1 -1
- data/spec/validate_associated_matcher_spec.rb +5 -1
- data/spec/validate_length_of_matcher_spec.rb +7 -2
- data/spec/validate_numericality_of_matcher_spec.rb +8 -2
- data/spec/validate_uniqueness_of_matcher_spec.rb +25 -16
- metadata +5 -3
data/CHANGELOG
CHANGED
@@ -1,10 +1,50 @@
|
|
1
|
+
* Allow validate_uniqueness_of to work when scopes are not stringfiable values.
|
2
|
+
You can now give timestamps, datetime, date and boolean as scopes. [#60]
|
3
|
+
|
4
|
+
* Allow subjects to be overwriten quickly (quick subjects):
|
5
|
+
|
6
|
+
describe Post
|
7
|
+
should_validate_presente_of :title
|
8
|
+
|
9
|
+
describe :published => true do
|
10
|
+
should_validate_presence_of :published_at
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
Is the same as:
|
15
|
+
|
16
|
+
describe Post
|
17
|
+
should_validate_presente_of :title
|
18
|
+
|
19
|
+
describe "when published is true" do
|
20
|
+
subject { Post.new(:published => true) }
|
21
|
+
should_validate_presence_of :published_at
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
And the string can be also localized using I18n. [#57]
|
26
|
+
|
27
|
+
[COMPATIBILITY] validate_associated no longer accepts a block to confgure the
|
28
|
+
builder:
|
29
|
+
|
30
|
+
should_validate_associated(:tasks){ |p| p.tasks.build(:captcha => 'i_am_a_robot') }
|
31
|
+
|
32
|
+
The right way to do this is by giving an option called builder and a proc:
|
33
|
+
|
34
|
+
should_validate_associated :tasks, :builder => proc{ |p| p.tasks.build(:captcha => 'i_am_a_robot') }
|
35
|
+
|
36
|
+
* validate_uniqueness_of and accept_nested_attributes_for now use the new
|
37
|
+
interpolation option {{sentence}} [#58]
|
38
|
+
|
1
39
|
* Added accept_nested_attributes_for matcher [#39]
|
2
40
|
|
3
41
|
* Added have_default_scope matcher [#38]
|
4
42
|
|
5
|
-
* Allow :include, :
|
43
|
+
* Allow :conditions, :include, :joins, :limit, :offset, :order, :select, :readonly,
|
44
|
+
:group, :having, :from, :lock as quick accessors to have_scope matcher
|
6
45
|
|
7
|
-
* Allow all objects to be sent to have_scope (
|
46
|
+
* Allow all kind of objects to be sent to have_scope (including datetimes, arrays,
|
47
|
+
booleans and nil) (thanks to Szymon Nowak and Nolan Eakins) [#53]
|
8
48
|
|
9
49
|
* Added support to sql options in association_matcher: select, conditions, include,
|
10
50
|
group, having, order, limit and offset, plus finder_sql and counter_sql. [#48]
|
@@ -17,8 +57,8 @@
|
|
17
57
|
|
18
58
|
# v3.0
|
19
59
|
|
20
|
-
|
21
|
-
|
60
|
+
* Added more options to associations matcher. Previously it was handling just
|
61
|
+
:dependent and :through options. Now it deals with:
|
22
62
|
|
23
63
|
:through, :class_name, :foreign_key, :dependent, :join_table, :uniq,
|
24
64
|
:readonly, :validate, :autosave, :counter_cache, :polymorphic
|
@@ -55,10 +95,9 @@ subject definitions on rspec. This was also fixed.
|
|
55
95
|
|
56
96
|
# v2.x
|
57
97
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
matchers.
|
98
|
+
* Added associations, allow_mass_assignment, allow_values_for, have_column,
|
99
|
+
have_index, have_scope, have_readonly_attributes, validate_acceptance_of,
|
100
|
+
validate_associated, validate_confirmation_of, validate_exclusion_of,
|
101
|
+
validate_inclusion_of, validate_length_of, validate_numericality_of,
|
102
|
+
validate_presence_of and validate_uniqueness_of matchers.
|
64
103
|
|
@@ -11,7 +11,8 @@ end
|
|
11
11
|
|
12
12
|
# Load Remarkable ActiveRecord files
|
13
13
|
dir = File.dirname(__FILE__)
|
14
|
-
require File.join(dir, 'remarkable_activerecord', 'base')
|
14
|
+
require File.join(dir, 'remarkable_activerecord', 'base')
|
15
|
+
require File.join(dir, 'remarkable_activerecord', 'describe')
|
15
16
|
require File.join(dir, 'remarkable_activerecord', 'human_names')
|
16
17
|
|
17
18
|
# Add locale
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Remarkable
|
2
|
+
module ActiveRecord
|
3
|
+
|
4
|
+
def self.after_include(target)
|
5
|
+
target.class_inheritable_reader :default_subject_attributes
|
6
|
+
target.extend Describe
|
7
|
+
end
|
8
|
+
|
9
|
+
module Describe
|
10
|
+
|
11
|
+
# Overwrites describe to provide quick way to configure your subject:
|
12
|
+
#
|
13
|
+
# describe Post
|
14
|
+
# should_validate_presente_of :title
|
15
|
+
#
|
16
|
+
# describe :published => true do
|
17
|
+
# should_validate_presence_of :published_at
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# This is the same as:
|
22
|
+
#
|
23
|
+
# describe Post
|
24
|
+
# should_validate_presente_of :title
|
25
|
+
#
|
26
|
+
# describe "when published is true" do
|
27
|
+
# subject { Post.new(:published => true) }
|
28
|
+
# should_validate_presence_of :published_at
|
29
|
+
# end
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# The string can be localized using I18n. An example yml file is:
|
33
|
+
#
|
34
|
+
# locale:
|
35
|
+
# remarkable:
|
36
|
+
# active_record:
|
37
|
+
# describe:
|
38
|
+
# each: "{{key}} is {{value}}"
|
39
|
+
# prepend: "when "
|
40
|
+
# connector: " and "
|
41
|
+
#
|
42
|
+
def describe(*args, &block)
|
43
|
+
if described_class && args.first.is_a?(Hash)
|
44
|
+
attributes = args.shift
|
45
|
+
|
46
|
+
connector = Remarkable.t "remarkable.active_record.describe.connector", :default => " and "
|
47
|
+
|
48
|
+
description = if self.default_subject_attributes.blank?
|
49
|
+
Remarkable.t("remarkable.active_record.describe.prepend", :default => "when ")
|
50
|
+
else
|
51
|
+
connector.lstrip
|
52
|
+
end
|
53
|
+
|
54
|
+
pieces = []
|
55
|
+
attributes.each do |key, value|
|
56
|
+
translated_key = if described_class.respond_to?(:human_attribute_name)
|
57
|
+
described_class.human_attribute_name(key, :locale => Remarkable.locale)
|
58
|
+
else
|
59
|
+
key.to_s.humanize
|
60
|
+
end
|
61
|
+
|
62
|
+
pieces << Remarkable.t("remarkable.active_record.describe.each",
|
63
|
+
:default => "{{key}} is {{value}}",
|
64
|
+
:key => key, :value => value.inspect)
|
65
|
+
end
|
66
|
+
|
67
|
+
description << pieces.join(connector)
|
68
|
+
args.unshift(description)
|
69
|
+
|
70
|
+
# Creates an example group, send the method and eval the given block.
|
71
|
+
#
|
72
|
+
example_group = super(*args) do
|
73
|
+
write_inheritable_hash(:default_subject_attributes, attributes)
|
74
|
+
subject { self.class.described_class.new(self.class.default_subject_attributes) }
|
75
|
+
instance_eval(&block)
|
76
|
+
end
|
77
|
+
else
|
78
|
+
super(*args, &block)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -7,7 +7,7 @@ if defined?(Spec)
|
|
7
7
|
#
|
8
8
|
def self.build_description_with_i18n(*args)
|
9
9
|
args.inject("") do |description, arg|
|
10
|
-
arg = if
|
10
|
+
arg = if arg.respond_to?(:human_name)
|
11
11
|
arg.human_name(:locale => Remarkable.locale)
|
12
12
|
else
|
13
13
|
arg.to_s
|
@@ -26,7 +26,7 @@ if defined?(Spec)
|
|
26
26
|
|
27
27
|
# This is for rspec >= 1.2.0.
|
28
28
|
#
|
29
|
-
def build_description_from(*args)
|
29
|
+
def self.build_description_from(*args)
|
30
30
|
text = ExampleGroupMethods.build_description_with_i18n(*args)
|
31
31
|
text == "" ? nil : text
|
32
32
|
end
|
@@ -96,24 +96,33 @@ module Remarkable
|
|
96
96
|
#
|
97
97
|
# class Projects < ActiveRecord::Base
|
98
98
|
# has_many :tasks
|
99
|
-
# accepts_nested_attributes_for :tasks, :reject_if => proc { |a| a[:
|
99
|
+
# accepts_nested_attributes_for :tasks, :reject_if => proc { |a| a[:title].blank? }
|
100
100
|
# end
|
101
101
|
#
|
102
102
|
# You can have the following specs:
|
103
103
|
#
|
104
|
-
# should_accept_nested_attributes_for :tasks, :reject => { :
|
105
|
-
# should_accept_nested_attributes_for :tasks, :accept => { :
|
104
|
+
# should_accept_nested_attributes_for :tasks, :reject => { :title => '' } # Passes
|
105
|
+
# should_accept_nested_attributes_for :tasks, :accept => { :title => 'My task' } # Passes
|
106
106
|
#
|
107
|
-
# should_accept_nested_attributes_for :tasks, :accept => { :
|
108
|
-
# :reject => { :
|
107
|
+
# should_accept_nested_attributes_for :tasks, :accept => { :title => 'My task' },
|
108
|
+
# :reject => { :title => '' } # Passes
|
109
109
|
#
|
110
|
-
# should_accept_nested_attributes_for :tasks, :accept => { :
|
111
|
-
# should_accept_nested_attributes_for :tasks, :reject => { :
|
110
|
+
# should_accept_nested_attributes_for :tasks, :accept => { :title => '' } # Fail
|
111
|
+
# should_accept_nested_attributes_for :tasks, :reject => { :title => 'My task' } # Fail
|
112
112
|
#
|
113
113
|
# You can also give arrays to :accept and :reject to verify multiple attributes.
|
114
|
+
# In such cases the block syntax is more recommended for readability:
|
115
|
+
#
|
116
|
+
# should_accept_nested_attributes_for :tasks do
|
117
|
+
# m.allow_destroy(false)
|
118
|
+
# m.accept :title => 'My task'
|
119
|
+
# m.accept :title => 'Another task'
|
120
|
+
# m.reject :title => nil
|
121
|
+
# m.reject :title => ''
|
122
|
+
# end
|
114
123
|
#
|
115
|
-
def accept_nested_attributes_for(*args)
|
116
|
-
AcceptNestedAttributesForMatcher.new(*args).spec(self)
|
124
|
+
def accept_nested_attributes_for(*args, &block)
|
125
|
+
AcceptNestedAttributesForMatcher.new(*args, &block).spec(self)
|
117
126
|
end
|
118
127
|
|
119
128
|
end
|
@@ -26,8 +26,8 @@ module Remarkable
|
|
26
26
|
# should_allow_mass_assignment_of :email, :name
|
27
27
|
# it { should allow_mass_assignment_of(:email, :name) }
|
28
28
|
#
|
29
|
-
def allow_mass_assignment_of(*attributes)
|
30
|
-
AllowMassAssignmentOfMatcher.new(*attributes).spec(self)
|
29
|
+
def allow_mass_assignment_of(*attributes, &block)
|
30
|
+
AllowMassAssignmentOfMatcher.new(*attributes, &block).spec(self)
|
31
31
|
end
|
32
32
|
end
|
33
33
|
end
|
@@ -53,7 +53,7 @@ module Remarkable
|
|
53
53
|
options = if @in_range
|
54
54
|
{ :in => (@options[:in].first..@options[:in].last).inspect }
|
55
55
|
elsif @options[:in].is_a?(Array)
|
56
|
-
{ :in => @options[:in].map
|
56
|
+
{ :in => @options[:in].map{|i| i.inspect}.to_sentence }
|
57
57
|
else
|
58
58
|
{ :in => @options[:in].inspect }
|
59
59
|
end
|
@@ -83,9 +83,9 @@ module Remarkable
|
|
83
83
|
# it { should allow_values_for(:isbn, "isbn 1 2345 6789 0", "ISBN 1-2345-6789-0") }
|
84
84
|
# it { should_not allow_values_for(:isbn, "bad 1", "bad 2") }
|
85
85
|
#
|
86
|
-
def allow_values_for(attribute, *args)
|
86
|
+
def allow_values_for(attribute, *args, &block)
|
87
87
|
options = args.extract_options!
|
88
|
-
AllowValuesForMatcher.new(attribute, options.merge!(:in => args)).spec(self)
|
88
|
+
AllowValuesForMatcher.new(attribute, options.merge!(:in => args), &block).spec(self)
|
89
89
|
end
|
90
90
|
alias :validate_format_of :allow_values_for
|
91
91
|
|
@@ -150,8 +150,8 @@ module Remarkable
|
|
150
150
|
# should_belong_to :parent, :polymorphic => true
|
151
151
|
# it { should belong_to(:parent) }
|
152
152
|
#
|
153
|
-
def belong_to(*associations)
|
154
|
-
AssociationMatcher.new(:belongs_to, *associations).spec(self)
|
153
|
+
def belong_to(*associations, &block)
|
154
|
+
AssociationMatcher.new(:belongs_to, *associations, &block).spec(self)
|
155
155
|
end
|
156
156
|
|
157
157
|
# Ensures that the has_and_belongs_to_many relationship exists, if the join
|
@@ -175,8 +175,8 @@ module Remarkable
|
|
175
175
|
# should_have_and_belong_to_many :posts, :cars
|
176
176
|
# it{ should have_and_belong_to_many :posts, :cars }
|
177
177
|
#
|
178
|
-
def have_and_belong_to_many(*associations)
|
179
|
-
AssociationMatcher.new(:has_and_belongs_to_many, *associations).spec(self)
|
178
|
+
def have_and_belong_to_many(*associations, &block)
|
179
|
+
AssociationMatcher.new(:has_and_belongs_to_many, *associations, &block).spec(self)
|
180
180
|
end
|
181
181
|
|
182
182
|
# Ensures that the has_many relationship exists. Will also test that the
|
@@ -211,8 +211,8 @@ module Remarkable
|
|
211
211
|
# it{ should have_many(:enemies, :through => :friends) }
|
212
212
|
# it{ should have_many(:enemies, :dependent => :destroy) }
|
213
213
|
#
|
214
|
-
def have_many(*associations)
|
215
|
-
AssociationMatcher.new(:has_many, *associations).spec(self)
|
214
|
+
def have_many(*associations, &block)
|
215
|
+
AssociationMatcher.new(:has_many, *associations, &block).spec(self)
|
216
216
|
end
|
217
217
|
|
218
218
|
# Ensures that the has_many relationship exists. Will also test that the
|
@@ -240,8 +240,8 @@ module Remarkable
|
|
240
240
|
# should_have_one :universe
|
241
241
|
# it{ should have_one(:universe) }
|
242
242
|
#
|
243
|
-
def have_one(*associations)
|
244
|
-
AssociationMatcher.new(:has_one, *associations).spec(self)
|
243
|
+
def have_one(*associations, &block)
|
244
|
+
AssociationMatcher.new(:has_one, *associations, &block).spec(self)
|
245
245
|
end
|
246
246
|
|
247
247
|
end
|
@@ -56,8 +56,8 @@ module Remarkable
|
|
56
56
|
# it { should have_column(:name, :type => :string) }
|
57
57
|
# it { should have_column(:name).type(:string) }
|
58
58
|
#
|
59
|
-
def have_column(*args)
|
60
|
-
HaveColumnMatcher.new(*args).spec(self)
|
59
|
+
def have_column(*args, &block)
|
60
|
+
HaveColumnMatcher.new(*args, &block).spec(self)
|
61
61
|
end
|
62
62
|
alias :have_columns :have_column
|
63
63
|
alias :have_db_column :have_column
|
@@ -5,7 +5,8 @@ module Remarkable
|
|
5
5
|
arguments
|
6
6
|
assertions :options_match?
|
7
7
|
|
8
|
-
optionals :
|
8
|
+
optionals :conditions, :include, :joins, :limit, :offset, :order, :select,
|
9
|
+
:readonly, :group, :having, :from, :lock
|
9
10
|
|
10
11
|
protected
|
11
12
|
|
@@ -32,8 +33,9 @@ module Remarkable
|
|
32
33
|
#
|
33
34
|
# == Options
|
34
35
|
#
|
35
|
-
# All options that the default scope would pass on to find:
|
36
|
-
#
|
36
|
+
# All options that the default scope would pass on to find: :conditions,
|
37
|
+
# :include, :joins, :limit, :offset, :order, :select, :readonly, :group,
|
38
|
+
# :having, :from, :lock.
|
37
39
|
#
|
38
40
|
# == Examples
|
39
41
|
#
|
@@ -58,8 +60,8 @@ module Remarkable
|
|
58
60
|
# should_have_default_scope :conditions => { :published => true,
|
59
61
|
# :visible => true } # Fails
|
60
62
|
#
|
61
|
-
def have_default_scope(*args)
|
62
|
-
HaveDefaultScopeMatcher.new(*args).spec(self)
|
63
|
+
def have_default_scope(*args, &block)
|
64
|
+
HaveDefaultScopeMatcher.new(*args, &block).spec(self)
|
63
65
|
end
|
64
66
|
|
65
67
|
end
|
@@ -43,10 +43,18 @@ module Remarkable
|
|
43
43
|
# == Examples
|
44
44
|
#
|
45
45
|
# it { should have_index(:ssn).unique(true) }
|
46
|
-
# it { should have_index([:name, :email]).unique(true) }
|
46
|
+
# it { should have_index([:name, :email]).unique(true) }
|
47
|
+
#
|
48
|
+
# should_have_index :ssn, :unique => true, :limit => 9, :null => false
|
49
|
+
#
|
50
|
+
# should_have_index :ssn do |m|
|
51
|
+
# m.unique
|
52
|
+
# m.limit = 9
|
53
|
+
# m.null = false
|
54
|
+
# end
|
47
55
|
#
|
48
|
-
def have_index(*args)
|
49
|
-
HaveIndexMatcher.new(*args).spec(self)
|
56
|
+
def have_index(*args, &block)
|
57
|
+
HaveIndexMatcher.new(*args, &block).spec(self)
|
50
58
|
end
|
51
59
|
alias :have_indices :have_index
|
52
60
|
alias :have_db_index :have_index
|
@@ -20,8 +20,8 @@ module Remarkable
|
|
20
20
|
#
|
21
21
|
# it { should have_readonly_attributes(:password, :admin_flag) }
|
22
22
|
#
|
23
|
-
def have_readonly_attributes(*attributes)
|
24
|
-
HaveReadonlyAttributesMatcher.new(*attributes).spec(self)
|
23
|
+
def have_readonly_attributes(*attributes, &block)
|
24
|
+
HaveReadonlyAttributesMatcher.new(*attributes, &block).spec(self)
|
25
25
|
end
|
26
26
|
alias :have_readonly_attribute :have_readonly_attributes
|
27
27
|
|
@@ -6,17 +6,15 @@ module Remarkable
|
|
6
6
|
assertions :is_scope?, :options_match?
|
7
7
|
|
8
8
|
optionals :with, :splat => true
|
9
|
-
optionals :
|
9
|
+
optionals :conditions, :include, :joins, :limit, :offset, :order, :select,
|
10
|
+
:readonly, :group, :having, :from, :lock
|
10
11
|
|
11
12
|
protected
|
12
13
|
|
13
14
|
def is_scope?
|
14
|
-
@scope_object = if @options
|
15
|
-
|
16
|
-
|
17
|
-
else
|
18
|
-
subject_class.send(@scope_name, @options[:with])
|
19
|
-
end
|
15
|
+
@scope_object = if @options.key?(:with)
|
16
|
+
@options[:with] = [ @options[:with] ] unless Array === @options[:with]
|
17
|
+
subject_class.send(@scope_name, *@options[:with])
|
20
18
|
else
|
21
19
|
subject_class.send(@scope_name)
|
22
20
|
end
|
@@ -43,7 +41,9 @@ module Remarkable
|
|
43
41
|
#
|
44
42
|
# * <tt>with</tt> - Options to be sent to the named scope
|
45
43
|
#
|
46
|
-
#
|
44
|
+
# All options that the named scope would pass on to find: :conditions,
|
45
|
+
# :include, :joins, :limit, :offset, :order, :select, :readonly, :group,
|
46
|
+
# :having, :from, :lock.
|
47
47
|
#
|
48
48
|
# == Examples
|
49
49
|
#
|
@@ -75,8 +75,8 @@ module Remarkable
|
|
75
75
|
# scoped(:limit => c)
|
76
76
|
# end
|
77
77
|
#
|
78
|
-
def have_scope(*args)
|
79
|
-
HaveScopeMatcher.new(*args).spec(self)
|
78
|
+
def have_scope(*args, &block)
|
79
|
+
HaveScopeMatcher.new(*args, &block).spec(self)
|
80
80
|
end
|
81
81
|
alias :have_named_scope :have_scope
|
82
82
|
|
@@ -41,8 +41,8 @@ module Remarkable
|
|
41
41
|
# it { should validate_acceptance_of(:eula, :terms) }
|
42
42
|
# it { should validate_acceptance_of(:eula, :terms, :accept => true) }
|
43
43
|
#
|
44
|
-
def validate_acceptance_of(*attributes)
|
45
|
-
ValidateAcceptanceOfMatcher.new(*attributes).spec(self)
|
44
|
+
def validate_acceptance_of(*attributes, &block)
|
45
|
+
ValidateAcceptanceOfMatcher.new(*attributes, &block).spec(self)
|
46
46
|
end
|
47
47
|
|
48
48
|
end
|
@@ -2,8 +2,10 @@ module Remarkable
|
|
2
2
|
module ActiveRecord
|
3
3
|
module Matchers
|
4
4
|
class ValidateAssociatedMatcher < Remarkable::ActiveRecord::Base #:nodoc:
|
5
|
-
arguments :collection => :associations, :as => :association, :block =>
|
6
|
-
|
5
|
+
arguments :collection => :associations, :as => :association, :block => true
|
6
|
+
|
7
|
+
optional :message
|
8
|
+
optional :builder, :block => true
|
7
9
|
|
8
10
|
collection_assertions :find_association?, :is_valid?
|
9
11
|
default_options :message => :invalid
|
@@ -84,11 +86,13 @@ module Remarkable
|
|
84
86
|
# == Examples
|
85
87
|
#
|
86
88
|
# should_validate_associated :tasks
|
87
|
-
# should_validate_associated
|
88
|
-
#
|
89
|
+
# should_validate_associated :tasks, :builder => proc{ |p| p.tasks.build(:captcha => 'i_am_a_bot') }
|
90
|
+
#
|
91
|
+
# should_validate_associated :tasks do |m|
|
92
|
+
# m.builder { |p| p.tasks.build(:captcha => 'i_am_a_bot') }
|
93
|
+
# end
|
89
94
|
#
|
90
95
|
# it { should validate_associated(:tasks) }
|
91
|
-
# it { should validate_associated(:tasks){ |p| p.tasks.build(:captcha => 'i_am_a_bot') } }
|
92
96
|
# it { should validate_associated(:tasks, :builder => proc{ |p| p.tasks.build(:captcha => 'i_am_a_bot') }) }
|
93
97
|
#
|
94
98
|
def validate_associated(*args, &block)
|
@@ -35,8 +35,8 @@ module Remarkable
|
|
35
35
|
#
|
36
36
|
# it { should validate_confirmation_of(:email, :password) }
|
37
37
|
#
|
38
|
-
def validate_confirmation_of(*attributes)
|
39
|
-
ValidateConfirmationOfMatcher.new(*attributes).spec(self)
|
38
|
+
def validate_confirmation_of(*attributes, &block)
|
39
|
+
ValidateConfirmationOfMatcher.new(*attributes, &block).spec(self)
|
40
40
|
end
|
41
41
|
|
42
42
|
end
|
@@ -47,8 +47,8 @@ module Remarkable
|
|
47
47
|
# should_validate_exclusion_of :username, :in => ["admin", "user"]
|
48
48
|
# should_validate_exclusion_of :age, :in => 30..60
|
49
49
|
#
|
50
|
-
def validate_exclusion_of(*args)
|
51
|
-
ValidateExclusionOfMatcher.new(*args).spec(self)
|
50
|
+
def validate_exclusion_of(*args, &block)
|
51
|
+
ValidateExclusionOfMatcher.new(*args, &block).spec(self)
|
52
52
|
end
|
53
53
|
|
54
54
|
end
|
@@ -47,8 +47,8 @@ module Remarkable
|
|
47
47
|
# it { should validate_inclusion_of(:size, :in => ["S", "M", "L", "XL"]) }
|
48
48
|
# it { should validate_inclusion_of(:age, :in => 18..100) }
|
49
49
|
#
|
50
|
-
def validate_inclusion_of(*args)
|
51
|
-
ValidateInclusionOfMatcher.new(*args).spec(self)
|
50
|
+
def validate_inclusion_of(*args, &block)
|
51
|
+
ValidateInclusionOfMatcher.new(*args, &block).spec(self)
|
52
52
|
end
|
53
53
|
|
54
54
|
end
|
@@ -105,18 +105,23 @@ module Remarkable
|
|
105
105
|
#
|
106
106
|
# == Examples
|
107
107
|
#
|
108
|
-
# should_validate_length_of :password, :within => 6..20
|
109
|
-
# should_validate_length_of :password, :maximum => 20
|
110
|
-
# should_validate_length_of :password, :minimum => 6
|
111
|
-
# should_validate_length_of :age, :is => 18
|
112
|
-
#
|
113
108
|
# it { should validate_length_of(:password).within(6..20) }
|
114
109
|
# it { should validate_length_of(:password).maximum(20) }
|
115
110
|
# it { should validate_length_of(:password).minimum(6) }
|
116
111
|
# it { should validate_length_of(:age).is(18) }
|
112
|
+
#
|
113
|
+
# should_validate_length_of :password, :within => 6..20
|
114
|
+
# should_validate_length_of :password, :maximum => 20
|
115
|
+
# should_validate_length_of :password, :minimum => 6
|
116
|
+
# should_validate_length_of :age, :is => 18
|
117
|
+
#
|
118
|
+
# should_validate_length_of :password do |m|
|
119
|
+
# m.minimum 6
|
120
|
+
# m.maximum 20
|
121
|
+
# end
|
117
122
|
#
|
118
|
-
def validate_length_of(*attributes)
|
119
|
-
ValidateLengthOfMatcher.new(*attributes).spec(self)
|
123
|
+
def validate_length_of(*attributes, &block)
|
124
|
+
ValidateLengthOfMatcher.new(*attributes, &block).spec(self)
|
120
125
|
end
|
121
126
|
end
|
122
127
|
end
|
@@ -165,17 +165,22 @@ module Remarkable
|
|
165
165
|
#
|
166
166
|
# == Examples
|
167
167
|
#
|
168
|
-
# should_validate_numericality_of :age, :price
|
169
|
-
# should_validate_numericality_of :price, :only_integer => false, :greater_than => 10
|
170
|
-
#
|
171
168
|
# it { should validate_numericality_of(:age).odd }
|
172
169
|
# it { should validate_numericality_of(:age).even }
|
173
170
|
# it { should validate_numericality_of(:age).only_integer }
|
174
171
|
# it { should validate_numericality_of(:age, :odd => true) }
|
175
172
|
# it { should validate_numericality_of(:age, :even => true) }
|
173
|
+
#
|
174
|
+
# should_validate_numericality_of :age, :price
|
175
|
+
# should_validate_numericality_of :price, :only_integer => false, :greater_than => 10
|
176
|
+
#
|
177
|
+
# should_validate_numericality_of :price do |m|
|
178
|
+
# m.only_integer = false
|
179
|
+
# m.greater_than = 10
|
180
|
+
# end
|
176
181
|
#
|
177
|
-
def validate_numericality_of(*attributes)
|
178
|
-
ValidateNumericalityOfMatcher.new(*attributes).spec(self)
|
182
|
+
def validate_numericality_of(*attributes, &block)
|
183
|
+
ValidateNumericalityOfMatcher.new(*attributes, &block).spec(self)
|
179
184
|
end
|
180
185
|
|
181
186
|
end
|
@@ -56,8 +56,8 @@ module Remarkable
|
|
56
56
|
# should_validate_presence_of :name, :phone_number
|
57
57
|
# it { should validate_presence_of(:name, :phone_number) }
|
58
58
|
#
|
59
|
-
def validate_presence_of(*args)
|
60
|
-
ValidatePresenceOfMatcher.new(*args).spec(self)
|
59
|
+
def validate_presence_of(*args, &block)
|
60
|
+
ValidatePresenceOfMatcher.new(*args, &block).spec(self)
|
61
61
|
end
|
62
62
|
end
|
63
63
|
end
|
@@ -134,11 +134,36 @@ module Remarkable
|
|
134
134
|
|
135
135
|
super
|
136
136
|
end
|
137
|
-
|
138
|
-
# Returns a value to be used as new scope. It
|
139
|
-
#
|
137
|
+
|
138
|
+
# Returns a value to be used as new scope. It deals with four different
|
139
|
+
# cases: date, time, boolean and stringfiable (everything that can be
|
140
|
+
# converted to a string and the next value makes sense)
|
141
|
+
#
|
142
|
+
def new_value_for_scope(scope)
|
143
|
+
column_type = if @existing.respond_to?(:column_for_attribute)
|
144
|
+
@existing.column_for_attribute(scope)
|
145
|
+
else
|
146
|
+
nil
|
147
|
+
end
|
148
|
+
|
149
|
+
case column_type.type
|
150
|
+
when :int, :integer, :float, :decimal
|
151
|
+
new_value_for_stringfiable_scope(scope)
|
152
|
+
when :datetime, :timestamp, :time
|
153
|
+
Time.now + 10000
|
154
|
+
when :date
|
155
|
+
Date.today + 100
|
156
|
+
when :boolean
|
157
|
+
!@existing.send(scope)
|
158
|
+
else
|
159
|
+
new_value_for_stringfiable_scope(scope)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
# Returns a value to be used as scope by generating a range of values
|
164
|
+
# and searching for them in the database.
|
140
165
|
#
|
141
|
-
def
|
166
|
+
def new_value_for_stringfiable_scope(scope)
|
142
167
|
values = [(@existing.send(scope) || 999).next.to_s]
|
143
168
|
|
144
169
|
# Generate a range of values to search in the database
|
@@ -188,12 +213,20 @@ module Remarkable
|
|
188
213
|
# == Examples
|
189
214
|
#
|
190
215
|
# it { should validate_uniqueness_of(:keyword, :username) }
|
191
|
-
# it { should validate_uniqueness_of(:name, :message => "O NOES! SOMEONE STOELED YER NAME!") }
|
192
216
|
# it { should validate_uniqueness_of(:email, :scope => :name, :case_sensitive => false) }
|
193
|
-
# it { should validate_uniqueness_of(:address, :scope => [:first_name, :last_name]) }
|
217
|
+
# it { should validate_uniqueness_of(:address, :scope => [:first_name, :last_name]) }
|
218
|
+
#
|
219
|
+
# should_validate_uniqueness_of :keyword, :username
|
220
|
+
# should_validate_uniqueness_of :email, :scope => :name, :case_sensitive => false
|
221
|
+
# should_validate_uniqueness_of :address, :scope => [:first_name, :last_name]
|
222
|
+
#
|
223
|
+
# should_validate_uniqueness_of :email do |m|
|
224
|
+
# m.scope = name
|
225
|
+
# m.case_sensitive = false
|
226
|
+
# end
|
194
227
|
#
|
195
|
-
def validate_uniqueness_of(*attributes)
|
196
|
-
ValidateUniquenessOfMatcher.new(*attributes).spec(self)
|
228
|
+
def validate_uniqueness_of(*attributes, &block)
|
229
|
+
ValidateUniquenessOfMatcher.new(*attributes, &block).spec(self)
|
197
230
|
end
|
198
231
|
end
|
199
232
|
end
|
data/locale/en.yml
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
en:
|
2
2
|
remarkable:
|
3
3
|
active_record:
|
4
|
+
describe:
|
5
|
+
each: "{{key}} is {{value}}"
|
6
|
+
prepend: "when "
|
7
|
+
connector: " and "
|
4
8
|
expectations:
|
5
9
|
allow_nil: "{{subject_name}} to {{not}}allow nil values for {{attribute}}"
|
6
10
|
allow_blank: "{{subject_name}} to {{not}}allow blank values for {{attribute}}"
|
@@ -25,6 +29,10 @@ en:
|
|
25
29
|
allow_destroy:
|
26
30
|
positive: "allowing destroy"
|
27
31
|
negative: "not allowing destroy"
|
32
|
+
accept:
|
33
|
+
positive: "accepting {{sentence}}"
|
34
|
+
reject:
|
35
|
+
positive: "rejecting {{sentence}}"
|
28
36
|
|
29
37
|
allow_values_for:
|
30
38
|
description: "allow {{in}} as values for {{attributes}}"
|
@@ -239,7 +247,7 @@ en:
|
|
239
247
|
valid_with_new_scope: "{{subject_name}} to be valid when {{attribute}} scope ({{method}}) change"
|
240
248
|
optionals:
|
241
249
|
scope:
|
242
|
-
positive: "scoped to {{
|
250
|
+
positive: "scoped to {{sentence}}"
|
243
251
|
case_sensitive:
|
244
252
|
positive: "case sensitive"
|
245
253
|
negative: "case insensitive"
|
@@ -26,6 +26,10 @@ if RAILS_VERSION == '2.3.2'
|
|
26
26
|
|
27
27
|
matcher.allow_destroy
|
28
28
|
matcher.description.should == 'accept nested attributes for category allowing destroy'
|
29
|
+
|
30
|
+
matcher.accept(:name => 'jose')
|
31
|
+
matcher.accept(:name => 'maria')
|
32
|
+
matcher.description.should == 'accept nested attributes for category allowing destroy and accepting {:name=>"jose"} and {:name=>"maria"}'
|
29
33
|
end
|
30
34
|
|
31
35
|
it 'should set association_match? message' do
|
@@ -108,6 +112,13 @@ if RAILS_VERSION == '2.3.2'
|
|
108
112
|
should_accept_nested_attributes_for :category, :accept => [ { :name => 'Jose' }, { :name => 'Maria' } ]
|
109
113
|
should_accept_nested_attributes_for :category, :reject => [ { :name => '' } ]
|
110
114
|
|
115
|
+
should_accept_nested_attributes_for :category do |m|
|
116
|
+
m.allow_destroy
|
117
|
+
m.accept :name => "Jose"
|
118
|
+
m.accept :name => "Maria"
|
119
|
+
m.reject :name => ""
|
120
|
+
end
|
121
|
+
|
111
122
|
should_not_accept_nested_attributes_for :nothing
|
112
123
|
should_not_accept_nested_attributes_for :labels
|
113
124
|
should_not_accept_nested_attributes_for :tags
|
@@ -149,7 +149,14 @@ describe 'association_matcher' do
|
|
149
149
|
should_belong_to :company, :readonly => true
|
150
150
|
should_belong_to :company, :validate => true
|
151
151
|
should_belong_to :company, :class_name => "Company"
|
152
|
-
should_belong_to :company, :foreign_key => :company_id
|
152
|
+
should_belong_to :company, :foreign_key => :company_id
|
153
|
+
|
154
|
+
should_belong_to :company do |m|
|
155
|
+
m.readonly
|
156
|
+
m.validate
|
157
|
+
m.class_name = "Company"
|
158
|
+
m.foreign_key = :company_id
|
159
|
+
end
|
153
160
|
|
154
161
|
should_not_belong_to :project
|
155
162
|
should_not_have_one :company
|
@@ -291,7 +298,14 @@ describe 'association_matcher' do
|
|
291
298
|
should_have_and_belong_to_many :labels, :readonly => true
|
292
299
|
should_have_and_belong_to_many :labels, :validate => true
|
293
300
|
should_have_and_belong_to_many :labels, :class_name => "Label"
|
294
|
-
should_have_and_belong_to_many :labels, :foreign_key => :project_id
|
301
|
+
should_have_and_belong_to_many :labels, :foreign_key => :project_id
|
302
|
+
|
303
|
+
should_have_and_belong_to_many :labels do |m|
|
304
|
+
m.readonly
|
305
|
+
m.validate
|
306
|
+
m.class_name "Label"
|
307
|
+
m.foreign_key :project_id
|
308
|
+
end
|
295
309
|
|
296
310
|
should_not_have_and_belong_to_many :companies
|
297
311
|
should_not_have_one :label
|
@@ -455,7 +469,13 @@ describe 'association_matcher' do
|
|
455
469
|
should_have_many :tasks
|
456
470
|
should_have_many :tasks, :readonly => true
|
457
471
|
should_have_many :tasks, :validate => true
|
458
|
-
should_have_many :tasks, :through => :project_tasks
|
472
|
+
should_have_many :tasks, :through => :project_tasks
|
473
|
+
|
474
|
+
should_have_many :tasks do |m|
|
475
|
+
m.readonly
|
476
|
+
m.validate
|
477
|
+
m.through = :project_tasks
|
478
|
+
end
|
459
479
|
|
460
480
|
should_not_have_many :tasks, :readonly => false
|
461
481
|
should_not_have_many :tasks, :validate => false
|
@@ -605,7 +625,12 @@ describe 'association_matcher' do
|
|
605
625
|
|
606
626
|
should_have_one :manager
|
607
627
|
should_have_one :manager, :validate => true
|
608
|
-
should_have_one :manager, :through => :project_managers
|
628
|
+
should_have_one :manager, :through => :project_managers
|
629
|
+
|
630
|
+
should_have_one :manager do |m|
|
631
|
+
m.validate
|
632
|
+
m.through = :project_managers
|
633
|
+
end
|
609
634
|
|
610
635
|
should_not_have_one :manager, :validate => false
|
611
636
|
should_not_have_one :manager, :through => :another_thing
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
RAILS_I18n = true
|
4
|
+
|
5
|
+
class Post
|
6
|
+
attr_accessor :title, :published, :public
|
7
|
+
|
8
|
+
def initialize(attributes={})
|
9
|
+
attributes.each do |key, value|
|
10
|
+
send(:"#{key}=", value)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.human_name(*args)
|
15
|
+
"MyPost"
|
16
|
+
end
|
17
|
+
end unless defined?(Post)
|
18
|
+
|
19
|
+
describe Post do
|
20
|
+
it "should use human name on description" do
|
21
|
+
self.class.description.should == "MyPost"
|
22
|
+
end
|
23
|
+
|
24
|
+
describe :published => true do
|
25
|
+
it "should set the subject with published equals to true" do
|
26
|
+
subject.published.should be_true
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should generate a readable description" do
|
30
|
+
self.class.description.should == "MyPost when published is true"
|
31
|
+
end
|
32
|
+
|
33
|
+
describe :public => false do
|
34
|
+
it "should nest subject attributes" do
|
35
|
+
subject.published.should be_true
|
36
|
+
subject.public.should be_false
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should nest descriptions" do
|
40
|
+
self.class.description.should == "MyPost when published is true and public is false"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe :published => true, :public => false do
|
46
|
+
it "should set the subject with published equals to true and public equals to false" do
|
47
|
+
subject.published.should be_true
|
48
|
+
subject.public.should be_false
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should include both published and public in descriptions" do
|
52
|
+
self.class.description.should match(/MyPost/)
|
53
|
+
self.class.description.should match(/public is false/)
|
54
|
+
self.class.description.should match(/published is true/)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -61,7 +61,12 @@ describe 'have_column_matcher' do
|
|
61
61
|
should_have_column :email, :limit => 255
|
62
62
|
should_have_column :email, :default => 'jose.valim@gmail.com'
|
63
63
|
should_have_column :price, :precision => 10
|
64
|
-
should_have_column :price, :precision => 10, :scale => 2
|
64
|
+
should_have_column :price, :precision => 10, :scale => 2
|
65
|
+
|
66
|
+
should_have_column :price do |m|
|
67
|
+
m.scale = 2
|
68
|
+
m.precision = 10
|
69
|
+
end
|
65
70
|
|
66
71
|
should_not_have_column :name, :null => false
|
67
72
|
should_not_have_column :email, :limit => 400
|
@@ -49,7 +49,8 @@ describe 'have_scope' do
|
|
49
49
|
it { should have_scope(:recent, :order => 'created_at DESC') }
|
50
50
|
|
51
51
|
it { should have_scope(:latest).with(10).limit(10) }
|
52
|
-
it { should have_scope(:beginning).with(10).offset(10) }
|
52
|
+
it { should have_scope(:beginning).with(10).offset(10) }
|
53
|
+
it { should have_scope(:since).with(false).conditions(["created_at > ?", false]) }
|
53
54
|
it { should have_scope(:since).with(Time.at(0)).conditions(["created_at > ?", Time.at(0)]) }
|
54
55
|
it { should have_scope(:between).with(2, 10).conditions(["created_at > ? and created_at < ?", 2, 10]) }
|
55
56
|
|
@@ -66,8 +67,14 @@ describe 'have_scope' do
|
|
66
67
|
|
67
68
|
should_have_scope :latest, :with => 10, :limit => 10
|
68
69
|
should_have_scope :beginning, :with => 10, :offset => 10
|
70
|
+
should_have_scope :since, :with => false, :conditions => ["created_at > ?", false]
|
69
71
|
should_have_scope :since, :with => Time.at(0), :conditions => ["created_at > ?", Time.at(0)]
|
70
|
-
should_have_scope :between, :with => [ 2, 10 ], :conditions => [ "created_at > ? and created_at < ?", 2, 10 ]
|
72
|
+
should_have_scope :between, :with => [ 2, 10 ], :conditions => [ "created_at > ? and created_at < ?", 2, 10 ]
|
73
|
+
|
74
|
+
should_have_scope :between do |m|
|
75
|
+
m.with(2, 10)
|
76
|
+
m.conditions([ "created_at > ? and created_at < ?", 2, 10 ])
|
77
|
+
end
|
71
78
|
|
72
79
|
should_not_have_scope :null
|
73
80
|
should_not_have_scope :latest, :with => 5, :limit => 10
|
data/spec/spec_helper.rb
CHANGED
@@ -110,7 +110,11 @@ describe 'validate_associated' do
|
|
110
110
|
|
111
111
|
describe 'has_many with builder' do
|
112
112
|
before(:each){ define_and_validate(:has_many, :tasks, :with_builder => true) }
|
113
|
-
should_validate_associated
|
113
|
+
should_validate_associated :tasks, :builder => proc{ |p| p.tasks.build(:name => true) }
|
114
|
+
|
115
|
+
should_validate_associated :tasks do |m|
|
116
|
+
m.builder { |p| p.tasks.build(:name => true) }
|
117
|
+
end
|
114
118
|
end
|
115
119
|
|
116
120
|
describe 'has_and_belongs_to_many with skip validation' do
|
@@ -155,11 +155,16 @@ describe 'validate_length_of' do
|
|
155
155
|
before(:each) { define_and_validate }
|
156
156
|
|
157
157
|
should_validate_length_of :size, :in => 3..5
|
158
|
-
should_validate_length_of :size, :within => 3..5
|
158
|
+
should_validate_length_of :size, :within => 3..5
|
159
|
+
|
159
160
|
should_not_validate_length_of :size, :within => 2..5
|
160
161
|
should_not_validate_length_of :size, :within => 4..5
|
161
162
|
should_not_validate_length_of :size, :within => 3..4
|
162
163
|
should_not_validate_length_of :size, :within => 3..6
|
163
|
-
should_not_validate_length_of :category, :in => 3..5
|
164
|
+
should_not_validate_length_of :category, :in => 3..5
|
165
|
+
|
166
|
+
should_validate_length_of :size do |m|
|
167
|
+
m.in = 3..5
|
168
|
+
end
|
164
169
|
end
|
165
170
|
end
|
@@ -172,9 +172,15 @@ describe 'validate_numericality_of' do
|
|
172
172
|
should_validate_numericality_of :price
|
173
173
|
should_validate_numericality_of :price, :less_than => 100000
|
174
174
|
should_validate_numericality_of :price, :greater_than => 9999
|
175
|
-
should_validate_numericality_of :price, :less_than => 100000, :greater_than => 999
|
175
|
+
should_validate_numericality_of :price, :less_than => 100000, :greater_than => 999
|
176
|
+
|
176
177
|
should_not_validate_numericality_of :size
|
177
178
|
should_not_validate_numericality_of :price, :less_than => 55555
|
178
|
-
should_not_validate_numericality_of :price, :greater_than => 55555
|
179
|
+
should_not_validate_numericality_of :price, :greater_than => 55555
|
180
|
+
|
181
|
+
should_validate_numericality_of :price do |m|
|
182
|
+
m.less_than 100000
|
183
|
+
m.greater_than 999
|
184
|
+
end
|
179
185
|
end
|
180
186
|
end
|
@@ -5,12 +5,12 @@ describe 'validate_uniqueness_of' do
|
|
5
5
|
|
6
6
|
# Defines a model, create a validation and returns a raw matcher
|
7
7
|
def define_and_validate(options={})
|
8
|
-
@model = define_model :user, :username => :string, :email => :
|
8
|
+
@model = define_model :user, :username => :string, :email => :string, :public => :boolean, :deleted_at => :timestamp do
|
9
9
|
validates_uniqueness_of :username, options
|
10
10
|
end
|
11
11
|
|
12
12
|
# Create a model
|
13
|
-
User.create(:username => 'jose')
|
13
|
+
User.create(:username => 'jose', :deleted_at => 1.day.ago, :public => false)
|
14
14
|
|
15
15
|
validate_uniqueness_of(:username)
|
16
16
|
end
|
@@ -21,23 +21,25 @@ describe 'validate_uniqueness_of' do
|
|
21
21
|
it 'should contain a description' do
|
22
22
|
@matcher.description.should == 'require unique values for username'
|
23
23
|
|
24
|
-
@matcher.scope(:email)
|
25
|
-
@matcher.description.should == 'require unique values for username scoped to [:email]'
|
26
|
-
|
27
|
-
@matcher.scope(:email, :access_code)
|
28
|
-
@matcher.description.should == 'require unique values for username scoped to [:email, :access_code]'
|
29
|
-
|
30
24
|
@matcher.case_sensitive
|
31
|
-
@matcher.description.should == 'require unique values for username
|
25
|
+
@matcher.description.should == 'require unique values for username case sensitive'
|
32
26
|
|
33
27
|
@matcher.case_sensitive(false)
|
34
|
-
@matcher.description.should == 'require unique values for username
|
28
|
+
@matcher.description.should == 'require unique values for username case insensitive'
|
35
29
|
|
36
30
|
@matcher.allow_nil
|
37
|
-
@matcher.description.should == 'require unique values for username
|
31
|
+
@matcher.description.should == 'require unique values for username case insensitive and allowing nil values'
|
38
32
|
|
39
33
|
@matcher.allow_blank(false)
|
40
|
-
@matcher.description.should == 'require unique values for username
|
34
|
+
@matcher.description.should == 'require unique values for username case insensitive, allowing nil values, and not allowing blank values'
|
35
|
+
|
36
|
+
@matcher = validate_uniqueness_of(:username, :scope => :email)
|
37
|
+
@matcher.description.should == 'require unique values for username scoped to :email'
|
38
|
+
|
39
|
+
@matcher = validate_uniqueness_of(:username)
|
40
|
+
@matcher.scope(:email)
|
41
|
+
@matcher.scope(:public)
|
42
|
+
@matcher.description.should == 'require unique values for username scoped to :email and :public'
|
41
43
|
end
|
42
44
|
|
43
45
|
it 'should set responds_to_scope? message' do
|
@@ -72,10 +74,13 @@ describe 'validate_uniqueness_of' do
|
|
72
74
|
end
|
73
75
|
|
74
76
|
describe 'scoped to' do
|
75
|
-
it { should define_and_validate(:scope => :email).scope(:email) }
|
76
|
-
it { should define_and_validate(:scope =>
|
77
|
+
it { should define_and_validate(:scope => :email).scope(:email) }
|
78
|
+
it { should define_and_validate(:scope => :public).scope(:public) }
|
79
|
+
it { should define_and_validate(:scope => :deleted_at).scope(:deleted_at) }
|
80
|
+
it { should define_and_validate(:scope => [:email, :public]).scope(:email, :public) }
|
81
|
+
it { should define_and_validate(:scope => [:email, :public, :deleted_at]).scope(:email, :public, :deleted_at) }
|
77
82
|
it { should_not define_and_validate(:scope => :email).scope(:title) }
|
78
|
-
it { should_not define_and_validate(:scope => :email).scope(:
|
83
|
+
it { should_not define_and_validate(:scope => :email).scope(:public) }
|
79
84
|
end
|
80
85
|
|
81
86
|
create_message_specs(self)
|
@@ -169,6 +174,10 @@ describe 'validate_uniqueness_of' do
|
|
169
174
|
should_validate_uniqueness_of :username
|
170
175
|
should_validate_uniqueness_of :username, :scope => :email
|
171
176
|
should_not_validate_uniqueness_of :email
|
172
|
-
should_not_validate_uniqueness_of :username, :scope => :access_code
|
177
|
+
should_not_validate_uniqueness_of :username, :scope => :access_code
|
178
|
+
|
179
|
+
should_validate_uniqueness_of :username do |m|
|
180
|
+
m.scope :email
|
181
|
+
end
|
173
182
|
end
|
174
183
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: remarkable_activerecord
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0.
|
4
|
+
version: 3.0.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Carlos Brando
|
@@ -11,7 +11,7 @@ autorequire:
|
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
13
|
|
14
|
-
date: 2009-04-
|
14
|
+
date: 2009-04-25 00:00:00 +02:00
|
15
15
|
default_executable:
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
@@ -22,7 +22,7 @@ dependencies:
|
|
22
22
|
requirements:
|
23
23
|
- - ">="
|
24
24
|
- !ruby/object:Gem::Version
|
25
|
-
version: 3.0.
|
25
|
+
version: 3.0.9
|
26
26
|
version:
|
27
27
|
description: "Remarkable ActiveRecord: collection of matchers and macros with I18n for ActiveRecord"
|
28
28
|
email:
|
@@ -43,6 +43,7 @@ files:
|
|
43
43
|
- CHANGELOG
|
44
44
|
- lib/remarkable_activerecord/base.rb
|
45
45
|
- lib/remarkable_activerecord/human_names.rb
|
46
|
+
- lib/remarkable_activerecord/describe.rb
|
46
47
|
- lib/remarkable_activerecord/matchers/validate_confirmation_of_matcher.rb
|
47
48
|
- lib/remarkable_activerecord/matchers/validate_length_of_matcher.rb
|
48
49
|
- lib/remarkable_activerecord/matchers/have_default_scope_matcher.rb
|
@@ -98,6 +99,7 @@ test_files:
|
|
98
99
|
- spec/spec_helper.rb
|
99
100
|
- spec/validate_acceptance_of_matcher_spec.rb
|
100
101
|
- spec/accept_nested_attributes_for_matcher_spec.rb
|
102
|
+
- spec/describe_spec.rb
|
101
103
|
- spec/allow_mass_assignment_of_matcher_spec.rb
|
102
104
|
- spec/have_scope_matcher_spec.rb
|
103
105
|
- spec/validate_inclusion_of_matcher_spec.rb
|