remarkable_activerecord 3.0.7 → 3.0.8
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 +9 -3
- data/lib/remarkable_activerecord/matchers/accept_nested_attributes_for_matcher.rb +121 -0
- data/lib/remarkable_activerecord/matchers/have_default_scope_matcher.rb +67 -0
- data/lib/remarkable_activerecord/matchers/have_scope_matcher.rb +7 -2
- data/lib/remarkable_activerecord/matchers/validate_presence_of_matcher.rb +36 -1
- data/lib/remarkable_activerecord/matchers/validate_uniqueness_of_matcher.rb +10 -1
- data/locale/en.yml +20 -1
- data/spec/accept_nested_attributes_for_matcher_spec.rb +119 -0
- data/spec/have_default_scope_matcher_spec.rb +52 -0
- data/spec/have_scope_matcher_spec.rb +22 -17
- metadata +11 -7
data/CHANGELOG
CHANGED
@@ -1,9 +1,15 @@
|
|
1
|
-
*
|
1
|
+
* Added accept_nested_attributes_for matcher [#39]
|
2
|
+
|
3
|
+
* Added have_default_scope matcher [#38]
|
4
|
+
|
5
|
+
* Allow :include, :join, :group and :having as quick accessors to have_scope matcher
|
6
|
+
|
7
|
+
* Allow all objects to be sent to have_scope (thanks to Szymon Nowak and Nolan Eakins) [#53]
|
2
8
|
|
3
9
|
* Added support to sql options in association_matcher: select, conditions, include,
|
4
|
-
group, having, order, limit and offset. [#48]
|
10
|
+
group, having, order, limit and offset, plus finder_sql and counter_sql. [#48]
|
5
11
|
|
6
|
-
* :source and :source_type are
|
12
|
+
* :source and :source_type are now supported by association matcher [#47]
|
7
13
|
|
8
14
|
* validate_inclusion_of became smarter since it now tests invalid values too [#36]
|
9
15
|
|
@@ -0,0 +1,121 @@
|
|
1
|
+
module Remarkable
|
2
|
+
module ActiveRecord
|
3
|
+
module Matchers
|
4
|
+
class AcceptNestedAttributesForMatcher < Remarkable::ActiveRecord::Base #:nodoc:
|
5
|
+
arguments :collection => :associations, :as => :association
|
6
|
+
|
7
|
+
collection_assertions :association_exists?, :is_autosave?, :responds_to_attributes?,
|
8
|
+
:allows_destroy?, :accepts?, :rejects?
|
9
|
+
|
10
|
+
optionals :allow_destroy, :default => true
|
11
|
+
optionals :accept, :reject, :splat => true
|
12
|
+
|
13
|
+
protected
|
14
|
+
|
15
|
+
def association_exists?
|
16
|
+
reflection
|
17
|
+
end
|
18
|
+
|
19
|
+
def is_autosave?
|
20
|
+
reflection.options[:autosave] == true
|
21
|
+
end
|
22
|
+
|
23
|
+
def responds_to_attributes?
|
24
|
+
@subject.respond_to?(:"#{@association}_attributes=", true)
|
25
|
+
end
|
26
|
+
|
27
|
+
def allows_destroy?
|
28
|
+
return true unless @options.key?(:allow_destroy)
|
29
|
+
|
30
|
+
@subject.instance_eval <<-ALLOW_DESTROY
|
31
|
+
def assign_nested_attributes_for_#{reflection_type}_association(association, attrs, allow)
|
32
|
+
return allow
|
33
|
+
end
|
34
|
+
ALLOW_DESTROY
|
35
|
+
|
36
|
+
actual = @subject.send(:"#{@association}_attributes=", {})
|
37
|
+
return actual == @options[:allow_destroy], :actual => actual
|
38
|
+
end
|
39
|
+
|
40
|
+
def accepts?
|
41
|
+
return true unless @options.key?(:accept)
|
42
|
+
|
43
|
+
[@options[:accept]].flatten.each do |attributes|
|
44
|
+
return false, :attributes => attributes.inspect if reject_if_proc.call(attributes)
|
45
|
+
end
|
46
|
+
|
47
|
+
true
|
48
|
+
end
|
49
|
+
|
50
|
+
def rejects?
|
51
|
+
return true unless @options.key?(:reject)
|
52
|
+
|
53
|
+
[@options[:reject]].flatten.each do |attributes|
|
54
|
+
return false, :attributes => attributes.inspect unless reject_if_proc.call(attributes)
|
55
|
+
end
|
56
|
+
|
57
|
+
true
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def reflection
|
63
|
+
@reflection ||= subject_class.reflect_on_association(@association.to_sym)
|
64
|
+
end
|
65
|
+
|
66
|
+
def reflection_type
|
67
|
+
case reflection.macro
|
68
|
+
when :has_one, :belongs_to
|
69
|
+
:one_to_one
|
70
|
+
when :has_many, :has_and_belongs_to_many
|
71
|
+
:collection
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def reject_if_proc
|
76
|
+
subject_class.reject_new_nested_attributes_procs[@association.to_sym]
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
# Ensures that the model accepts nested attributes for the given associations.
|
82
|
+
#
|
83
|
+
# == Options
|
84
|
+
#
|
85
|
+
# * <tt>allow_destroy</tt> - When true allows the association to be destroyed
|
86
|
+
# * <tt>accept</tt> - attributes that should be accepted by the :reject_if proc
|
87
|
+
# * <tt>reject</tt> - attributes that should be rejected by the :reject_if proc
|
88
|
+
#
|
89
|
+
# == Examples
|
90
|
+
#
|
91
|
+
# should_accept_nested_attributes_for :tasks
|
92
|
+
# should_accept_nested_attributes_for :tasks, :allow_destroy => true
|
93
|
+
#
|
94
|
+
# :accept and :reject takes objects that are verified against the proc. So
|
95
|
+
# having a model:
|
96
|
+
#
|
97
|
+
# class Projects < ActiveRecord::Base
|
98
|
+
# has_many :tasks
|
99
|
+
# accepts_nested_attributes_for :tasks, :reject_if => proc { |a| a[:name].blank? }
|
100
|
+
# end
|
101
|
+
#
|
102
|
+
# You can have the following specs:
|
103
|
+
#
|
104
|
+
# should_accept_nested_attributes_for :tasks, :reject => { :name => '' } # Passes
|
105
|
+
# should_accept_nested_attributes_for :tasks, :accept => { :name => 'My task' } # Passes
|
106
|
+
#
|
107
|
+
# should_accept_nested_attributes_for :tasks, :accept => { :name => 'My task' },
|
108
|
+
# :reject => { :name => '' } # Passes
|
109
|
+
#
|
110
|
+
# should_accept_nested_attributes_for :tasks, :accept => { :name => '' } # Fail
|
111
|
+
# should_accept_nested_attributes_for :tasks, :reject => { :name => 'My task' } # Fail
|
112
|
+
#
|
113
|
+
# You can also give arrays to :accept and :reject to verify multiple attributes.
|
114
|
+
#
|
115
|
+
def accept_nested_attributes_for(*args)
|
116
|
+
AcceptNestedAttributesForMatcher.new(*args).spec(self)
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Remarkable
|
2
|
+
module ActiveRecord
|
3
|
+
module Matchers
|
4
|
+
class HaveDefaultScopeMatcher < Remarkable::ActiveRecord::Base #:nodoc:
|
5
|
+
arguments
|
6
|
+
assertions :options_match?
|
7
|
+
|
8
|
+
optionals :select, :conditions, :join, :include, :group, :having, :order, :limit, :offset
|
9
|
+
|
10
|
+
protected
|
11
|
+
|
12
|
+
def options_match?
|
13
|
+
default_scope.include?(@options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def default_scope
|
17
|
+
@default_scope ||= if @subject
|
18
|
+
scopes = subject_class.default_scoping || []
|
19
|
+
scopes.map!{ |s| s[:find] }
|
20
|
+
else
|
21
|
+
[]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def interpolation_options
|
26
|
+
{ :options => @options.inspect, :actual => default_scope.inspect }
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
# Ensures that the model has a default scope with the given options.
|
32
|
+
#
|
33
|
+
# == Options
|
34
|
+
#
|
35
|
+
# All options that the default scope would pass on to find: select, conditions,
|
36
|
+
# join, include, group, having, order, limit e offset.
|
37
|
+
#
|
38
|
+
# == Examples
|
39
|
+
#
|
40
|
+
# it { should have_default_scope(:conditions => {:visible => true}) }
|
41
|
+
# it { should have_default_scope.conditions(:visible => true) }
|
42
|
+
#
|
43
|
+
# Passes for:
|
44
|
+
#
|
45
|
+
# default_scope :conditions => { :visible => true }
|
46
|
+
#
|
47
|
+
# If you set two different default scopes, you have to spec them
|
48
|
+
# separatedly. Given the scopes:
|
49
|
+
#
|
50
|
+
# default_scope :conditions => { :visible => true }
|
51
|
+
# default_scope :conditions => { :published => true }
|
52
|
+
#
|
53
|
+
# Then we have the matchers:
|
54
|
+
#
|
55
|
+
# should_have_default_scope :conditions => { :visible => true } # Passes
|
56
|
+
# should_have_default_scope :conditions => { :published => true } # Passes
|
57
|
+
#
|
58
|
+
# should_have_default_scope :conditions => { :published => true,
|
59
|
+
# :visible => true } # Fails
|
60
|
+
#
|
61
|
+
def have_default_scope(*args)
|
62
|
+
HaveDefaultScopeMatcher.new(*args).spec(self)
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -5,13 +5,18 @@ module Remarkable
|
|
5
5
|
arguments :scope_name
|
6
6
|
assertions :is_scope?, :options_match?
|
7
7
|
|
8
|
-
optionals :with, :
|
8
|
+
optionals :with, :splat => true
|
9
|
+
optionals :select, :conditions, :join, :include, :group, :having, :order, :limit, :offset
|
9
10
|
|
10
11
|
protected
|
11
12
|
|
12
13
|
def is_scope?
|
13
14
|
@scope_object = if @options[:with]
|
14
|
-
|
15
|
+
if @options[:with].is_a?(Array)
|
16
|
+
subject_class.send(@scope_name, *@options[:with])
|
17
|
+
else
|
18
|
+
subject_class.send(@scope_name, @options[:with])
|
19
|
+
end
|
15
20
|
else
|
16
21
|
subject_class.send(@scope_name)
|
17
22
|
end
|
@@ -1,5 +1,40 @@
|
|
1
1
|
module Remarkable
|
2
|
-
module ActiveRecord
|
2
|
+
module ActiveRecord
|
3
|
+
# Holds ActiveRecord matchers.
|
4
|
+
#
|
5
|
+
# == Validations matchers
|
6
|
+
#
|
7
|
+
# Remarkable supports all ActiveRecord validations, and the only options
|
8
|
+
# not supported in those matchers is the :on options. So whenever you have
|
9
|
+
# to test that a validation runs on update, you have to do reproduce the
|
10
|
+
# state in your tests:
|
11
|
+
#
|
12
|
+
# describe Project do
|
13
|
+
# describe 'validations on create' do
|
14
|
+
# should_validate_presence_of :title
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# describe 'validations on update' do
|
18
|
+
# subject { Post.create!(@valid_attributes) }
|
19
|
+
# should_validate_presence_of :updated_at
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# Another behavior in validations is the :message option. Whenever you change
|
24
|
+
# the message in your model, it must be given in your tests too:
|
25
|
+
#
|
26
|
+
# class Post < ActiveRecord::Base
|
27
|
+
# validates_presence_of :title, :message => 'must be filled'
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# describe Post do
|
31
|
+
# should_validate_presence_of :title #=> fails
|
32
|
+
# should_validate_presence_of :title, :message => 'must be filled'
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# However, if you change the title using the I18n API, you don't need to
|
36
|
+
# specify the message in your tests, because it's retrieved properly.
|
37
|
+
#
|
3
38
|
module Matchers
|
4
39
|
class ValidatePresenceOfMatcher < Remarkable::ActiveRecord::Base #:nodoc:
|
5
40
|
arguments :collection => :attributes, :as => :attribute
|
@@ -165,7 +165,16 @@ module Remarkable
|
|
165
165
|
#
|
166
166
|
# Requires an existing record in the database. If you supply :allow_nil as
|
167
167
|
# option, you need to have in the database a record which is not nil in the
|
168
|
-
# given attributes. The same is required for allow_blank option.
|
168
|
+
# given attributes. The same is required for allow_blank option.
|
169
|
+
#
|
170
|
+
# Notice that the record being validate should not be the same as in the
|
171
|
+
# database. In other words, you can't do this:
|
172
|
+
#
|
173
|
+
# subject { Post.create!(@valid_attributes) }
|
174
|
+
# should_validate_uniquness_of :title
|
175
|
+
#
|
176
|
+
# But don't worry, if you eventually do that, a helpful error message
|
177
|
+
# will be raised.
|
169
178
|
#
|
170
179
|
# == Options
|
171
180
|
#
|
data/locale/en.yml
CHANGED
@@ -11,6 +11,20 @@ en:
|
|
11
11
|
allow_blank:
|
12
12
|
positive: "allowing blank values"
|
13
13
|
negative: "not allowing blank values"
|
14
|
+
|
15
|
+
accept_nested_attributes_for:
|
16
|
+
description: "accept nested attributes for {{associations}}"
|
17
|
+
expectations:
|
18
|
+
association_exists: "{{subject_name}} to have association {{association}}, but does not"
|
19
|
+
is_autosave: "{{subject_name}} to have association {{association}} with autosave true, got false"
|
20
|
+
responds_to_attributes: "{{subject_name}} to respond to :{{association}}_attributes=, but does not"
|
21
|
+
allows_destroy: "{{subject_name}} with allow destroy equals to {{allow_destroy}}, got {{actual}}"
|
22
|
+
accepts: "{{subject_name}} to accept attributes {{attributes}} for {{association}}, but does not"
|
23
|
+
rejects: "{{subject_name}} to reject attributes {{attributes}} for {{association}}, but does not"
|
24
|
+
optionals:
|
25
|
+
allow_destroy:
|
26
|
+
positive: "allowing destroy"
|
27
|
+
negative: "not allowing destroy"
|
14
28
|
|
15
29
|
allow_values_for:
|
16
30
|
description: "allow {{in}} as values for {{attributes}}"
|
@@ -103,7 +117,12 @@ en:
|
|
103
117
|
positive: "with default value {{inspect}}"
|
104
118
|
negative: "with default value {{inspect}}"
|
105
119
|
limit:
|
106
|
-
positive: "with limit {{inspect}}"
|
120
|
+
positive: "with limit {{inspect}}"
|
121
|
+
|
122
|
+
have_default_scope:
|
123
|
+
description: "have a default scope with {{options}}"
|
124
|
+
expectations:
|
125
|
+
options_match: "default scope with {{options}}, got {{actual}}"
|
107
126
|
|
108
127
|
have_index:
|
109
128
|
description: "have index for column(s) {{columns}}"
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
if RAILS_VERSION == '2.3.2'
|
4
|
+
describe 'accept_nested_attributes_for' do
|
5
|
+
include ModelBuilder
|
6
|
+
|
7
|
+
def define_and_validate(default=:category, options={})
|
8
|
+
@model = define_model :product do
|
9
|
+
has_one :category
|
10
|
+
has_many :orders
|
11
|
+
has_many :labels
|
12
|
+
has_many :tags, :autosave => true
|
13
|
+
|
14
|
+
accepts_nested_attributes_for :category, options
|
15
|
+
accepts_nested_attributes_for :orders, options
|
16
|
+
end
|
17
|
+
|
18
|
+
accept_nested_attributes_for *default
|
19
|
+
end
|
20
|
+
|
21
|
+
describe 'messages' do
|
22
|
+
|
23
|
+
it 'should contain a description' do
|
24
|
+
matcher = define_and_validate
|
25
|
+
matcher.description.should == 'accept nested attributes for category'
|
26
|
+
|
27
|
+
matcher.allow_destroy
|
28
|
+
matcher.description.should == 'accept nested attributes for category allowing destroy'
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should set association_match? message' do
|
32
|
+
matcher = define_and_validate(:nothing)
|
33
|
+
matcher.matches?(@model)
|
34
|
+
matcher.failure_message.should == 'Expected Product to have association nothing, but does not'
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should set is_autosave? message' do
|
38
|
+
matcher = define_and_validate(:labels)
|
39
|
+
matcher.matches?(@model)
|
40
|
+
matcher.failure_message.should == 'Expected Product to have association labels with autosave true, got false'
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should set responds_to_attributes? message' do
|
44
|
+
matcher = define_and_validate(:tags)
|
45
|
+
matcher.matches?(@model)
|
46
|
+
matcher.failure_message.should == 'Expected Product to respond to :tags_attributes=, but does not'
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should set allows_destroy? message' do
|
50
|
+
matcher = define_and_validate(:category, :allow_destroy => false)
|
51
|
+
matcher.allow_destroy.matches?(@model)
|
52
|
+
matcher.failure_message.should == 'Expected Product with allow destroy equals to true, got false'
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should set accepts? message' do
|
56
|
+
matcher = define_and_validate(:category, :reject_if => proc{|a| true })
|
57
|
+
matcher.accept({}).matches?(@model)
|
58
|
+
matcher.failure_message.should == 'Expected Product to accept attributes {} for category, but does not'
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should set rejects? message' do
|
62
|
+
matcher = define_and_validate(:category, :reject_if => proc{|a| false })
|
63
|
+
matcher.reject({}).matches?(@model)
|
64
|
+
matcher.failure_message.should == 'Expected Product to reject attributes {} for category, but does not'
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
describe 'matchers' do
|
70
|
+
it { should define_and_validate(:category) }
|
71
|
+
it { should define_and_validate(:orders) }
|
72
|
+
|
73
|
+
it { should_not define_and_validate(:nothing) }
|
74
|
+
it { should_not define_and_validate(:labels) }
|
75
|
+
it { should_not define_and_validate(:tags) }
|
76
|
+
|
77
|
+
describe 'with allow destroy as option' do
|
78
|
+
it { should define_and_validate(:category, :allow_destroy => true).allow_destroy }
|
79
|
+
it { should define_and_validate(:category, :allow_destroy => false).allow_destroy(false) }
|
80
|
+
it { should_not define_and_validate(:category, :allow_destroy => false).allow_destroy }
|
81
|
+
it { should_not define_and_validate(:category, :allow_destroy => true).allow_destroy(false) }
|
82
|
+
|
83
|
+
it { should define_and_validate(:orders, :allow_destroy => true).allow_destroy }
|
84
|
+
it { should define_and_validate(:orders, :allow_destroy => false).allow_destroy(false) }
|
85
|
+
it { should_not define_and_validate(:orders, :allow_destroy => false).allow_destroy }
|
86
|
+
it { should_not define_and_validate(:orders, :allow_destroy => true).allow_destroy(false) }
|
87
|
+
end
|
88
|
+
|
89
|
+
describe 'with accept as option' do
|
90
|
+
it { should define_and_validate(:category, :reject_if => proc{ |a| a[:name].blank? }).accept({ :name => 'Jose' }) }
|
91
|
+
it { should define_and_validate(:category, :reject_if => proc{ |a| a[:name].blank? }).accept({ :name => 'Jose' }, { :name => 'Maria' }) }
|
92
|
+
it { should_not define_and_validate(:category, :reject_if => proc{ |a| a[:name].blank? }).accept({ :name => '' }) }
|
93
|
+
end
|
94
|
+
|
95
|
+
describe 'with reject as option' do
|
96
|
+
it { should define_and_validate(:category, :reject_if => proc{ |a| !a[:name].blank? }).reject({ :name => 'Jose' }) }
|
97
|
+
it { should define_and_validate(:category, :reject_if => proc{ |a| !a[:name].blank? }).reject({ :name => 'Jose' }, { :name => 'Maria' }) }
|
98
|
+
it { should_not define_and_validate(:category, :reject_if => proc{ |a| !a[:name].blank? }).reject({ :name => '' }) }
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe 'macros' do
|
103
|
+
before(:each){ define_and_validate(:category, :allow_destroy => true, :reject_if => proc{ |a| a[:name].blank? }) }
|
104
|
+
|
105
|
+
should_accept_nested_attributes_for :category
|
106
|
+
should_accept_nested_attributes_for :category, :allow_destroy => true
|
107
|
+
should_accept_nested_attributes_for :category, :accept => { :name => 'Jose' }
|
108
|
+
should_accept_nested_attributes_for :category, :accept => [ { :name => 'Jose' }, { :name => 'Maria' } ]
|
109
|
+
should_accept_nested_attributes_for :category, :reject => [ { :name => '' } ]
|
110
|
+
|
111
|
+
should_not_accept_nested_attributes_for :nothing
|
112
|
+
should_not_accept_nested_attributes_for :labels
|
113
|
+
should_not_accept_nested_attributes_for :tags
|
114
|
+
should_not_accept_nested_attributes_for :category, :allow_destroy => false
|
115
|
+
should_not_accept_nested_attributes_for :category, :accept => [ { :name => '' } ]
|
116
|
+
should_not_accept_nested_attributes_for :category, :reject => [ { :name => 'Jose' }, { :name => 'Maria' } ]
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
if RAILS_VERSION == '2.3.2'
|
4
|
+
describe 'have_default_scope' do
|
5
|
+
include ModelBuilder
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@model = define_model :product, :published => :boolean do
|
9
|
+
default_scope :order => 'created_at DESC'
|
10
|
+
default_scope :conditions => { :published => true }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe 'messages' do
|
15
|
+
|
16
|
+
it 'should contain a description' do
|
17
|
+
matcher = have_default_scope(:conditions => {:special => true})
|
18
|
+
matcher.description.should == 'have a default scope with {:conditions=>{:special=>true}}'
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should set options_match? message' do
|
22
|
+
matcher = have_default_scope(:conditions => {:special => true})
|
23
|
+
matcher.matches?(@model)
|
24
|
+
matcher.failure_message.should == 'Expected default scope with {:conditions=>{:special=>true}}, got [{:order=>"created_at DESC"}, {:conditions=>{:published=>true}}]'
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
describe 'matchers' do
|
30
|
+
it { should have_default_scope(:order => 'created_at DESC') }
|
31
|
+
it { should have_default_scope(:conditions => { :published => true }) }
|
32
|
+
|
33
|
+
it { should_not have_default_scope(:order => 'created_at ASC') }
|
34
|
+
it { should_not have_default_scope(:conditions => { :published => false }) }
|
35
|
+
it { should_not have_default_scope(:conditions => { :published => true }, :order => 'created_at DESC') }
|
36
|
+
|
37
|
+
describe 'when the model has no default scope' do
|
38
|
+
before(:each){ @model = define_model(:task) }
|
39
|
+
it { @model.should_not have_default_scope }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe 'macros' do
|
44
|
+
should_have_default_scope :order => 'created_at DESC'
|
45
|
+
should_have_default_scope :conditions => { :published => true }
|
46
|
+
|
47
|
+
should_not_have_default_scope :order => 'created_at ASC'
|
48
|
+
should_not_have_default_scope :conditions => { :published => false }
|
49
|
+
should_not_have_default_scope :conditions => { :published => true }, :order => 'created_at DESC'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -8,6 +8,7 @@ describe 'have_scope' do
|
|
8
8
|
named_scope :recent, :order => 'created_at DESC'
|
9
9
|
named_scope :latest, lambda {|c| {:limit => c}}
|
10
10
|
named_scope :since, lambda {|t| {:conditions => ['created_at > ?', t]}}
|
11
|
+
named_scope :between, lambda { |a, b| { :conditions => [ 'created_at > ? and created_at < ?', a, b ] } }
|
11
12
|
|
12
13
|
def self.beginning(c)
|
13
14
|
scoped(:offset => c)
|
@@ -22,23 +23,23 @@ describe 'have_scope' do
|
|
22
23
|
describe 'messages' do
|
23
24
|
|
24
25
|
it 'should contain a description' do
|
25
|
-
|
26
|
-
|
26
|
+
matcher = have_scope(:title)
|
27
|
+
matcher.description.should == 'have to scope itself to {} when :title is called'
|
27
28
|
|
28
|
-
|
29
|
-
|
29
|
+
matcher.with(1)
|
30
|
+
matcher.description.should == 'have to scope itself to {} when :title is called with [1] as argument'
|
30
31
|
end
|
31
32
|
|
32
33
|
it 'should set is_scope? message' do
|
33
|
-
|
34
|
-
|
35
|
-
|
34
|
+
matcher = have_scope(:null)
|
35
|
+
matcher.matches?(@model)
|
36
|
+
matcher.failure_message.should == 'Expected :null when called on Product return an instance of ActiveRecord::NamedScope::Scope'
|
36
37
|
end
|
37
38
|
|
38
39
|
it 'should set options_match? message' do
|
39
|
-
|
40
|
-
|
41
|
-
|
40
|
+
matcher = have_scope(:recent, :conditions => {:special => true})
|
41
|
+
matcher.matches?(@model)
|
42
|
+
matcher.failure_message.should == 'Expected :recent when called on Product scope to {:conditions=>{:special=>true}}, got {:order=>"created_at DESC"}'
|
42
43
|
end
|
43
44
|
|
44
45
|
end
|
@@ -47,14 +48,16 @@ describe 'have_scope' do
|
|
47
48
|
it { should have_scope(:recent) }
|
48
49
|
it { should have_scope(:recent, :order => 'created_at DESC') }
|
49
50
|
|
50
|
-
it { should have_scope(:latest
|
51
|
-
it { should have_scope(:beginning
|
52
|
-
it { should have_scope(:since
|
51
|
+
it { should have_scope(:latest).with(10).limit(10) }
|
52
|
+
it { should have_scope(:beginning).with(10).offset(10) }
|
53
|
+
it { should have_scope(:since).with(Time.at(0)).conditions(["created_at > ?", Time.at(0)]) }
|
54
|
+
it { should have_scope(:between).with(2, 10).conditions(["created_at > ? and created_at < ?", 2, 10]) }
|
53
55
|
|
54
|
-
it { should_not have_scope(:null) }
|
55
|
-
it { should_not have_scope(:latest
|
56
|
-
it { should_not have_scope(:beginning
|
57
|
-
it { should_not have_scope(:since
|
56
|
+
it { should_not have_scope(:null) }
|
57
|
+
it { should_not have_scope(:latest).with(5).limit(10) }
|
58
|
+
it { should_not have_scope(:beginning).with(5).offset(10) }
|
59
|
+
it { should_not have_scope(:since).with(Time.at(0)).conditions(["created_at > ?", Time.at(1)]) }
|
60
|
+
it { should_not have_scope(:between).with(2, 10).conditions(["updated_at > ? and updated_at < ?", 2, 10]) }
|
58
61
|
end
|
59
62
|
|
60
63
|
describe 'macros' do
|
@@ -64,10 +67,12 @@ describe 'have_scope' do
|
|
64
67
|
should_have_scope :latest, :with => 10, :limit => 10
|
65
68
|
should_have_scope :beginning, :with => 10, :offset => 10
|
66
69
|
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 ]
|
67
71
|
|
68
72
|
should_not_have_scope :null
|
69
73
|
should_not_have_scope :latest, :with => 5, :limit => 10
|
70
74
|
should_not_have_scope :beginning, :with => 5, :offset => 10
|
71
75
|
should_not_have_scope :since, :with => Time.at(0), :conditions => ["created_at > ?", Time.at(1)]
|
76
|
+
should_not_have_scope :between, :with => [ 2, 10 ], :conditions => [ "updated_at > ? and updated_at < ?", 2, 10 ]
|
72
77
|
end
|
73
78
|
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.8
|
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-24 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.8
|
26
26
|
version:
|
27
27
|
description: "Remarkable ActiveRecord: collection of matchers and macros with I18n for ActiveRecord"
|
28
28
|
email:
|
@@ -41,13 +41,13 @@ files:
|
|
41
41
|
- README
|
42
42
|
- LICENSE
|
43
43
|
- CHANGELOG
|
44
|
-
- lib/remarkable_activerecord
|
45
44
|
- lib/remarkable_activerecord/base.rb
|
46
45
|
- lib/remarkable_activerecord/human_names.rb
|
47
|
-
- lib/remarkable_activerecord/matchers
|
48
46
|
- lib/remarkable_activerecord/matchers/validate_confirmation_of_matcher.rb
|
49
47
|
- lib/remarkable_activerecord/matchers/validate_length_of_matcher.rb
|
48
|
+
- lib/remarkable_activerecord/matchers/have_default_scope_matcher.rb
|
50
49
|
- lib/remarkable_activerecord/matchers/have_readonly_attributes_matcher.rb
|
50
|
+
- lib/remarkable_activerecord/matchers/accept_nested_attributes_for_matcher.rb
|
51
51
|
- lib/remarkable_activerecord/matchers/validate_exclusion_of_matcher.rb
|
52
52
|
- lib/remarkable_activerecord/matchers/validate_associated_matcher.rb
|
53
53
|
- lib/remarkable_activerecord/matchers/have_column_matcher.rb
|
@@ -65,6 +65,8 @@ files:
|
|
65
65
|
- locale/en.yml
|
66
66
|
has_rdoc: true
|
67
67
|
homepage: http://github.com/carlosbrando/remarkable
|
68
|
+
licenses: []
|
69
|
+
|
68
70
|
post_install_message:
|
69
71
|
rdoc_options: []
|
70
72
|
|
@@ -85,9 +87,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
85
87
|
requirements: []
|
86
88
|
|
87
89
|
rubyforge_project: remarkable
|
88
|
-
rubygems_version: 1.3.
|
90
|
+
rubygems_version: 1.3.2
|
89
91
|
signing_key:
|
90
|
-
specification_version:
|
92
|
+
specification_version: 3
|
91
93
|
summary: "Remarkable ActiveRecord: collection of matchers and macros with I18n for ActiveRecord"
|
92
94
|
test_files:
|
93
95
|
- spec/validate_associated_matcher_spec.rb
|
@@ -95,6 +97,7 @@ test_files:
|
|
95
97
|
- spec/rcov.opts
|
96
98
|
- spec/spec_helper.rb
|
97
99
|
- spec/validate_acceptance_of_matcher_spec.rb
|
100
|
+
- spec/accept_nested_attributes_for_matcher_spec.rb
|
98
101
|
- spec/allow_mass_assignment_of_matcher_spec.rb
|
99
102
|
- spec/have_scope_matcher_spec.rb
|
100
103
|
- spec/validate_inclusion_of_matcher_spec.rb
|
@@ -104,6 +107,7 @@ test_files:
|
|
104
107
|
- spec/allow_values_for_matcher_spec.rb
|
105
108
|
- spec/validate_uniqueness_of_matcher_spec.rb
|
106
109
|
- spec/have_column_matcher_spec.rb
|
110
|
+
- spec/have_default_scope_matcher_spec.rb
|
107
111
|
- spec/have_index_matcher_spec.rb
|
108
112
|
- spec/association_matcher_spec.rb
|
109
113
|
- spec/validate_exclusion_of_matcher_spec.rb
|