remarkable_activerecord 3.1.8 → 3.1.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 +140 -138
- data/LICENSE +20 -20
- data/README +80 -80
- data/lib/remarkable_activerecord.rb +29 -29
- data/lib/remarkable_activerecord/base.rb +248 -237
- data/lib/remarkable_activerecord/describe.rb +27 -27
- data/lib/remarkable_activerecord/human_names.rb +36 -36
- data/lib/remarkable_activerecord/matchers/accept_nested_attributes_for_matcher.rb +30 -30
- data/lib/remarkable_activerecord/matchers/allow_mass_assignment_of_matcher.rb +59 -59
- data/lib/remarkable_activerecord/matchers/allow_values_for_matcher.rb +85 -94
- data/lib/remarkable_activerecord/matchers/association_matcher.rb +283 -283
- data/lib/remarkable_activerecord/matchers/have_column_matcher.rb +68 -68
- data/lib/remarkable_activerecord/matchers/have_default_scope_matcher.rb +38 -38
- data/lib/remarkable_activerecord/matchers/have_index_matcher.rb +73 -73
- data/lib/remarkable_activerecord/matchers/have_readonly_attributes_matcher.rb +30 -30
- data/lib/remarkable_activerecord/matchers/have_scope_matcher.rb +85 -85
- data/lib/remarkable_activerecord/matchers/validate_acceptance_of_matcher.rb +50 -50
- data/lib/remarkable_activerecord/matchers/validate_associated_matcher.rb +97 -97
- data/lib/remarkable_activerecord/matchers/validate_confirmation_of_matcher.rb +44 -44
- data/lib/remarkable_activerecord/matchers/validate_exclusion_of_matcher.rb +53 -53
- data/lib/remarkable_activerecord/matchers/validate_inclusion_of_matcher.rb +52 -52
- data/lib/remarkable_activerecord/matchers/validate_length_of_matcher.rb +150 -150
- data/lib/remarkable_activerecord/matchers/validate_numericality_of_matcher.rb +181 -181
- data/lib/remarkable_activerecord/matchers/validate_presence_of_matcher.rb +29 -29
- data/lib/remarkable_activerecord/matchers/validate_uniqueness_of_matcher.rb +233 -233
- data/locale/en.yml +261 -261
- data/spec/accept_nested_attributes_for_matcher_spec.rb +1 -1
- data/spec/allow_mass_assignment_of_matcher_spec.rb +90 -82
- data/spec/allow_values_for_matcher_spec.rb +72 -63
- data/spec/association_matcher_spec.rb +612 -612
- data/spec/describe_spec.rb +3 -3
- data/spec/have_column_matcher_spec.rb +73 -73
- data/spec/have_default_scope_matcher_spec.rb +1 -1
- data/spec/have_index_matcher_spec.rb +87 -87
- data/spec/have_readonly_attributes_matcher_spec.rb +47 -47
- data/spec/have_scope_matcher_spec.rb +77 -77
- data/spec/model_builder.rb +101 -101
- data/spec/rcov.opts +1 -1
- data/spec/spec.opts +4 -4
- data/spec/spec_helper.rb +27 -27
- data/spec/validate_acceptance_of_matcher_spec.rb +68 -68
- data/spec/validate_associated_matcher_spec.rb +121 -121
- data/spec/validate_confirmation_of_matcher_spec.rb +58 -58
- data/spec/validate_length_of_matcher_spec.rb +218 -218
- data/spec/validate_numericality_of_matcher_spec.rb +179 -179
- data/spec/validate_presence_of_matcher_spec.rb +56 -56
- data/spec/validate_uniqueness_of_matcher_spec.rb +164 -164
- metadata +5 -5
@@ -1,68 +1,68 @@
|
|
1
|
-
module Remarkable
|
2
|
-
module ActiveRecord
|
3
|
-
module Matchers
|
4
|
-
class HaveColumnMatcher < Remarkable::ActiveRecord::Base #:nodoc:
|
5
|
-
arguments :collection => :columns, :as => :column
|
6
|
-
|
7
|
-
optional :type, :default, :precision, :limit, :scale, :sql_type
|
8
|
-
optional :primary, :null, :default => true
|
9
|
-
|
10
|
-
collection_assertions :column_exists?, :options_match?
|
11
|
-
|
12
|
-
before_assert do
|
13
|
-
@options.each{|k,v| @options[k] = v.to_s}
|
14
|
-
end
|
15
|
-
|
16
|
-
protected
|
17
|
-
|
18
|
-
def column_exists?
|
19
|
-
!column_type.nil?
|
20
|
-
end
|
21
|
-
|
22
|
-
def options_match?
|
23
|
-
actual = get_column_options(column_type, @options.keys)
|
24
|
-
return actual == @options, :actual => actual.inspect
|
25
|
-
end
|
26
|
-
|
27
|
-
def column_type
|
28
|
-
subject_class.columns.detect {|c| c.name == @column.to_s }
|
29
|
-
end
|
30
|
-
|
31
|
-
def get_column_options(column, keys)
|
32
|
-
keys.inject({}) do |hash, key|
|
33
|
-
hash[key] = column.instance_variable_get("@#{key}").to_s
|
34
|
-
hash
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def interpolation_options
|
39
|
-
{ :options => @options.inspect }
|
40
|
-
end
|
41
|
-
|
42
|
-
end
|
43
|
-
|
44
|
-
# Ensures that a column of the database actually exists.
|
45
|
-
#
|
46
|
-
# == Options
|
47
|
-
#
|
48
|
-
# * All options available in migrations are available:
|
49
|
-
#
|
50
|
-
# :type, :default, :precision, :limit, :scale, :sql_type, :primary, :null
|
51
|
-
#
|
52
|
-
# == Examples
|
53
|
-
#
|
54
|
-
# should_have_column :name, :type => :string, :default => ''
|
55
|
-
#
|
56
|
-
# it { should have_column(:name, :type => :string) }
|
57
|
-
# it { should have_column(:name).type(:string) }
|
58
|
-
#
|
59
|
-
def have_column(*args, &block)
|
60
|
-
HaveColumnMatcher.new(*args, &block).spec(self)
|
61
|
-
end
|
62
|
-
alias :have_columns :have_column
|
63
|
-
alias :have_db_column :have_column
|
64
|
-
alias :have_db_columns :have_column
|
65
|
-
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
1
|
+
module Remarkable
|
2
|
+
module ActiveRecord
|
3
|
+
module Matchers
|
4
|
+
class HaveColumnMatcher < Remarkable::ActiveRecord::Base #:nodoc:
|
5
|
+
arguments :collection => :columns, :as => :column
|
6
|
+
|
7
|
+
optional :type, :default, :precision, :limit, :scale, :sql_type
|
8
|
+
optional :primary, :null, :default => true
|
9
|
+
|
10
|
+
collection_assertions :column_exists?, :options_match?
|
11
|
+
|
12
|
+
before_assert do
|
13
|
+
@options.each{|k,v| @options[k] = v.to_s}
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
def column_exists?
|
19
|
+
!column_type.nil?
|
20
|
+
end
|
21
|
+
|
22
|
+
def options_match?
|
23
|
+
actual = get_column_options(column_type, @options.keys)
|
24
|
+
return actual == @options, :actual => actual.inspect
|
25
|
+
end
|
26
|
+
|
27
|
+
def column_type
|
28
|
+
subject_class.columns.detect {|c| c.name == @column.to_s }
|
29
|
+
end
|
30
|
+
|
31
|
+
def get_column_options(column, keys)
|
32
|
+
keys.inject({}) do |hash, key|
|
33
|
+
hash[key] = column.instance_variable_get("@#{key}").to_s
|
34
|
+
hash
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def interpolation_options
|
39
|
+
{ :options => @options.inspect }
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
# Ensures that a column of the database actually exists.
|
45
|
+
#
|
46
|
+
# == Options
|
47
|
+
#
|
48
|
+
# * All options available in migrations are available:
|
49
|
+
#
|
50
|
+
# :type, :default, :precision, :limit, :scale, :sql_type, :primary, :null
|
51
|
+
#
|
52
|
+
# == Examples
|
53
|
+
#
|
54
|
+
# should_have_column :name, :type => :string, :default => ''
|
55
|
+
#
|
56
|
+
# it { should have_column(:name, :type => :string) }
|
57
|
+
# it { should have_column(:name).type(:string) }
|
58
|
+
#
|
59
|
+
def have_column(*args, &block)
|
60
|
+
HaveColumnMatcher.new(*args, &block).spec(self)
|
61
|
+
end
|
62
|
+
alias :have_columns :have_column
|
63
|
+
alias :have_db_column :have_column
|
64
|
+
alias :have_db_columns :have_column
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -1,15 +1,15 @@
|
|
1
|
-
module Remarkable
|
2
|
-
module ActiveRecord
|
3
|
-
module Matchers
|
1
|
+
module Remarkable
|
2
|
+
module ActiveRecord
|
3
|
+
module Matchers
|
4
4
|
class HaveDefaultScopeMatcher < Remarkable::ActiveRecord::Base #:nodoc:
|
5
|
-
arguments
|
5
|
+
arguments
|
6
6
|
assertions :options_match?
|
7
|
-
|
7
|
+
|
8
8
|
optionals :conditions, :include, :joins, :limit, :offset, :order, :select,
|
9
9
|
:readonly, :group, :having, :from, :lock
|
10
|
-
|
11
|
-
protected
|
12
|
-
|
10
|
+
|
11
|
+
protected
|
12
|
+
|
13
13
|
def options_match?
|
14
14
|
default_scope.include?(@options)
|
15
15
|
end
|
@@ -21,29 +21,29 @@ module Remarkable
|
|
21
21
|
else
|
22
22
|
[]
|
23
23
|
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def interpolation_options
|
27
|
-
{ :options => @options.inspect, :actual => default_scope.inspect }
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|
31
|
-
|
32
|
-
# Ensures that the model has a default scope with the given options.
|
33
|
-
#
|
34
|
-
# == Options
|
35
|
-
#
|
24
|
+
end
|
25
|
+
|
26
|
+
def interpolation_options
|
27
|
+
{ :options => @options.inspect, :actual => default_scope.inspect }
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
# Ensures that the model has a default scope with the given options.
|
33
|
+
#
|
34
|
+
# == Options
|
35
|
+
#
|
36
36
|
# All options that the default scope would pass on to find: :conditions,
|
37
37
|
# :include, :joins, :limit, :offset, :order, :select, :readonly, :group,
|
38
|
-
# :having, :from, :lock.
|
39
|
-
#
|
40
|
-
# == Examples
|
41
|
-
#
|
42
|
-
# it { should have_default_scope(:conditions => {:visible => true}) }
|
43
|
-
# it { should have_default_scope.conditions(:visible => true) }
|
44
|
-
#
|
45
|
-
# Passes for:
|
46
|
-
#
|
38
|
+
# :having, :from, :lock.
|
39
|
+
#
|
40
|
+
# == Examples
|
41
|
+
#
|
42
|
+
# it { should have_default_scope(:conditions => {:visible => true}) }
|
43
|
+
# it { should have_default_scope.conditions(:visible => true) }
|
44
|
+
#
|
45
|
+
# Passes for:
|
46
|
+
#
|
47
47
|
# default_scope :conditions => { :visible => true }
|
48
48
|
#
|
49
49
|
# If you set two different default scopes, you have to spec them
|
@@ -58,12 +58,12 @@ module Remarkable
|
|
58
58
|
# should_have_default_scope :conditions => { :published => true } # Passes
|
59
59
|
#
|
60
60
|
# should_have_default_scope :conditions => { :published => true,
|
61
|
-
# :visible => true } # Fails
|
62
|
-
#
|
63
|
-
def have_default_scope(*args, &block)
|
64
|
-
HaveDefaultScopeMatcher.new(*args, &block).spec(self)
|
65
|
-
end
|
66
|
-
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
61
|
+
# :visible => true } # Fails
|
62
|
+
#
|
63
|
+
def have_default_scope(*args, &block)
|
64
|
+
HaveDefaultScopeMatcher.new(*args, &block).spec(self)
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -1,73 +1,73 @@
|
|
1
|
-
module Remarkable
|
2
|
-
module ActiveRecord
|
3
|
-
module Matchers
|
4
|
-
class HaveIndexMatcher < Remarkable::ActiveRecord::Base #:nodoc:
|
5
|
-
arguments :collection => :columns, :as => :column
|
6
|
-
|
7
|
-
optional :table_name
|
8
|
-
optional :unique, :default => true
|
9
|
-
|
10
|
-
collection_assertions :index_exists?, :is_unique?
|
11
|
-
|
12
|
-
protected
|
13
|
-
|
14
|
-
def index_exists?
|
15
|
-
!matched_index.nil?
|
16
|
-
end
|
17
|
-
|
18
|
-
def is_unique?
|
19
|
-
return true unless @options.key?(:unique)
|
20
|
-
return @options[:unique] == matched_index.unique, :actual => matched_index.unique
|
21
|
-
end
|
22
|
-
|
23
|
-
def matched_index
|
24
|
-
columns = [@column].flatten.map(&:to_s)
|
25
|
-
indexes.detect { |ind| ind.columns == columns }
|
26
|
-
end
|
27
|
-
|
28
|
-
def indexes
|
29
|
-
@indexes ||= ::ActiveRecord::Base.connection.indexes(current_table_name)
|
30
|
-
end
|
31
|
-
|
32
|
-
def interpolation_options
|
33
|
-
@subject ? { :table_name => current_table_name } : {}
|
34
|
-
end
|
35
|
-
|
36
|
-
private
|
37
|
-
|
38
|
-
def current_table_name
|
39
|
-
@options[:table_name] || subject_class.table_name
|
40
|
-
end
|
41
|
-
|
42
|
-
end
|
43
|
-
|
44
|
-
# Ensures the database column has specified index.
|
45
|
-
#
|
46
|
-
# == Options
|
47
|
-
#
|
48
|
-
# * <tt>unique</tt> - when supplied, tests if the index is unique or not
|
49
|
-
# * <tt>table_name</tt> - when supplied, tests if the index is defined for the given table
|
50
|
-
#
|
51
|
-
# == Examples
|
52
|
-
#
|
53
|
-
# it { should have_index(:ssn).unique(true) }
|
54
|
-
# it { should have_index([:name, :email]).unique(true) }
|
55
|
-
#
|
56
|
-
# should_have_index :ssn, :unique => true, :limit => 9, :null => false
|
57
|
-
#
|
58
|
-
# should_have_index :ssn do |m|
|
59
|
-
# m.unique
|
60
|
-
# m.limit = 9
|
61
|
-
# m.null = false
|
62
|
-
# end
|
63
|
-
#
|
64
|
-
def have_index(*args, &block)
|
65
|
-
HaveIndexMatcher.new(*args, &block).spec(self)
|
66
|
-
end
|
67
|
-
alias :have_indices :have_index
|
68
|
-
alias :have_db_index :have_index
|
69
|
-
alias :have_db_indices :have_index
|
70
|
-
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
1
|
+
module Remarkable
|
2
|
+
module ActiveRecord
|
3
|
+
module Matchers
|
4
|
+
class HaveIndexMatcher < Remarkable::ActiveRecord::Base #:nodoc:
|
5
|
+
arguments :collection => :columns, :as => :column
|
6
|
+
|
7
|
+
optional :table_name
|
8
|
+
optional :unique, :default => true
|
9
|
+
|
10
|
+
collection_assertions :index_exists?, :is_unique?
|
11
|
+
|
12
|
+
protected
|
13
|
+
|
14
|
+
def index_exists?
|
15
|
+
!matched_index.nil?
|
16
|
+
end
|
17
|
+
|
18
|
+
def is_unique?
|
19
|
+
return true unless @options.key?(:unique)
|
20
|
+
return @options[:unique] == matched_index.unique, :actual => matched_index.unique
|
21
|
+
end
|
22
|
+
|
23
|
+
def matched_index
|
24
|
+
columns = [@column].flatten.map(&:to_s)
|
25
|
+
indexes.detect { |ind| ind.columns == columns }
|
26
|
+
end
|
27
|
+
|
28
|
+
def indexes
|
29
|
+
@indexes ||= ::ActiveRecord::Base.connection.indexes(current_table_name)
|
30
|
+
end
|
31
|
+
|
32
|
+
def interpolation_options
|
33
|
+
@subject ? { :table_name => current_table_name } : {}
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def current_table_name
|
39
|
+
@options[:table_name] || subject_class.table_name
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
# Ensures the database column has specified index.
|
45
|
+
#
|
46
|
+
# == Options
|
47
|
+
#
|
48
|
+
# * <tt>unique</tt> - when supplied, tests if the index is unique or not
|
49
|
+
# * <tt>table_name</tt> - when supplied, tests if the index is defined for the given table
|
50
|
+
#
|
51
|
+
# == Examples
|
52
|
+
#
|
53
|
+
# it { should have_index(:ssn).unique(true) }
|
54
|
+
# it { should have_index([:name, :email]).unique(true) }
|
55
|
+
#
|
56
|
+
# should_have_index :ssn, :unique => true, :limit => 9, :null => false
|
57
|
+
#
|
58
|
+
# should_have_index :ssn do |m|
|
59
|
+
# m.unique
|
60
|
+
# m.limit = 9
|
61
|
+
# m.null = false
|
62
|
+
# end
|
63
|
+
#
|
64
|
+
def have_index(*args, &block)
|
65
|
+
HaveIndexMatcher.new(*args, &block).spec(self)
|
66
|
+
end
|
67
|
+
alias :have_indices :have_index
|
68
|
+
alias :have_db_index :have_index
|
69
|
+
alias :have_db_indices :have_index
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -1,30 +1,30 @@
|
|
1
|
-
module Remarkable
|
2
|
-
module ActiveRecord
|
3
|
-
module Matchers
|
4
|
-
class HaveReadonlyAttributesMatcher < Remarkable::ActiveRecord::Base #:nodoc:
|
5
|
-
arguments :collection => :attributes, :as => :attribute
|
6
|
-
collection_assertions :is_readonly?
|
7
|
-
|
8
|
-
private
|
9
|
-
|
10
|
-
def is_readonly?
|
11
|
-
readonly = subject_class.readonly_attributes || []
|
12
|
-
return readonly.include?(@attribute.to_s), :actual => readonly.to_a.inspect
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
# Ensures that the attribute cannot be changed once the record has been
|
17
|
-
# created.
|
18
|
-
#
|
19
|
-
# == Examples
|
20
|
-
#
|
21
|
-
# it { should have_readonly_attributes(:password, :admin_flag) }
|
22
|
-
#
|
23
|
-
def have_readonly_attributes(*attributes, &block)
|
24
|
-
HaveReadonlyAttributesMatcher.new(*attributes, &block).spec(self)
|
25
|
-
end
|
26
|
-
alias :have_readonly_attribute :have_readonly_attributes
|
27
|
-
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
1
|
+
module Remarkable
|
2
|
+
module ActiveRecord
|
3
|
+
module Matchers
|
4
|
+
class HaveReadonlyAttributesMatcher < Remarkable::ActiveRecord::Base #:nodoc:
|
5
|
+
arguments :collection => :attributes, :as => :attribute
|
6
|
+
collection_assertions :is_readonly?
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def is_readonly?
|
11
|
+
readonly = subject_class.readonly_attributes || []
|
12
|
+
return readonly.include?(@attribute.to_s), :actual => readonly.to_a.inspect
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Ensures that the attribute cannot be changed once the record has been
|
17
|
+
# created.
|
18
|
+
#
|
19
|
+
# == Examples
|
20
|
+
#
|
21
|
+
# it { should have_readonly_attributes(:password, :admin_flag) }
|
22
|
+
#
|
23
|
+
def have_readonly_attributes(*attributes, &block)
|
24
|
+
HaveReadonlyAttributesMatcher.new(*attributes, &block).spec(self)
|
25
|
+
end
|
26
|
+
alias :have_readonly_attribute :have_readonly_attributes
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -1,85 +1,85 @@
|
|
1
|
-
module Remarkable
|
2
|
-
module ActiveRecord
|
3
|
-
module Matchers
|
4
|
-
class HaveScopeMatcher < Remarkable::ActiveRecord::Base #:nodoc:
|
5
|
-
arguments :scope_name
|
6
|
-
assertions :is_scope?, :options_match?
|
7
|
-
|
8
|
-
optionals :with, :splat => true
|
9
|
-
optionals :conditions, :include, :joins, :limit, :offset, :order, :select,
|
10
|
-
:readonly, :group, :having, :from, :lock
|
11
|
-
|
12
|
-
protected
|
13
|
-
|
14
|
-
def is_scope?
|
15
|
-
@scope_object = if @options.key?(:with)
|
16
|
-
@options[:with] = [ @options[:with] ] unless Array === @options[:with]
|
17
|
-
subject_class.send(@scope_name, *@options[:with])
|
18
|
-
else
|
19
|
-
subject_class.send(@scope_name)
|
20
|
-
end
|
21
|
-
|
22
|
-
@scope_object.class == ::ActiveRecord::NamedScope::Scope
|
23
|
-
end
|
24
|
-
|
25
|
-
def options_match?
|
26
|
-
@options.empty? || @scope_object.proxy_options == @options.except(:with)
|
27
|
-
end
|
28
|
-
|
29
|
-
def interpolation_options
|
30
|
-
{ :options => @options.except(:with).inspect,
|
31
|
-
:actual => (@scope_object ? @scope_object.proxy_options.inspect : '{}')
|
32
|
-
}
|
33
|
-
end
|
34
|
-
|
35
|
-
end
|
36
|
-
|
37
|
-
# Ensures that the model has a method named scope that returns a NamedScope
|
38
|
-
# object with the supplied proxy options.
|
39
|
-
#
|
40
|
-
# == Options
|
41
|
-
#
|
42
|
-
# * <tt>with</tt> - Options to be sent to the named scope
|
43
|
-
#
|
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
|
-
#
|
48
|
-
# == Examples
|
49
|
-
#
|
50
|
-
# it { should have_scope(:visible, :conditions => {:visible => true}) }
|
51
|
-
# it { should have_scope(:visible).conditions(:visible => true) }
|
52
|
-
#
|
53
|
-
# Passes for
|
54
|
-
#
|
55
|
-
# named_scope :visible, :conditions => {:visible => true}
|
56
|
-
#
|
57
|
-
# Or for
|
58
|
-
#
|
59
|
-
# def self.visible
|
60
|
-
# scoped(:conditions => {:visible => true})
|
61
|
-
# end
|
62
|
-
#
|
63
|
-
# You can test lambdas or methods that return ActiveRecord#scoped calls:
|
64
|
-
#
|
65
|
-
# it { should have_scope(:recent, :with => 5) }
|
66
|
-
# it { should have_scope(:recent, :with => 1) }
|
67
|
-
#
|
68
|
-
# Passes for
|
69
|
-
#
|
70
|
-
# named_scope :recent, lambda {|c| {:limit => c}}
|
71
|
-
#
|
72
|
-
# Or for
|
73
|
-
#
|
74
|
-
# def self.recent(c)
|
75
|
-
# scoped(:limit => c)
|
76
|
-
# end
|
77
|
-
#
|
78
|
-
def have_scope(*args, &block)
|
79
|
-
HaveScopeMatcher.new(*args, &block).spec(self)
|
80
|
-
end
|
81
|
-
alias :have_named_scope :have_scope
|
82
|
-
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
1
|
+
module Remarkable
|
2
|
+
module ActiveRecord
|
3
|
+
module Matchers
|
4
|
+
class HaveScopeMatcher < Remarkable::ActiveRecord::Base #:nodoc:
|
5
|
+
arguments :scope_name
|
6
|
+
assertions :is_scope?, :options_match?
|
7
|
+
|
8
|
+
optionals :with, :splat => true
|
9
|
+
optionals :conditions, :include, :joins, :limit, :offset, :order, :select,
|
10
|
+
:readonly, :group, :having, :from, :lock
|
11
|
+
|
12
|
+
protected
|
13
|
+
|
14
|
+
def is_scope?
|
15
|
+
@scope_object = if @options.key?(:with)
|
16
|
+
@options[:with] = [ @options[:with] ] unless Array === @options[:with]
|
17
|
+
subject_class.send(@scope_name, *@options[:with])
|
18
|
+
else
|
19
|
+
subject_class.send(@scope_name)
|
20
|
+
end
|
21
|
+
|
22
|
+
@scope_object.class == ::ActiveRecord::NamedScope::Scope
|
23
|
+
end
|
24
|
+
|
25
|
+
def options_match?
|
26
|
+
@options.empty? || @scope_object.proxy_options == @options.except(:with)
|
27
|
+
end
|
28
|
+
|
29
|
+
def interpolation_options
|
30
|
+
{ :options => @options.except(:with).inspect,
|
31
|
+
:actual => (@scope_object ? @scope_object.proxy_options.inspect : '{}')
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
# Ensures that the model has a method named scope that returns a NamedScope
|
38
|
+
# object with the supplied proxy options.
|
39
|
+
#
|
40
|
+
# == Options
|
41
|
+
#
|
42
|
+
# * <tt>with</tt> - Options to be sent to the named scope
|
43
|
+
#
|
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
|
+
#
|
48
|
+
# == Examples
|
49
|
+
#
|
50
|
+
# it { should have_scope(:visible, :conditions => {:visible => true}) }
|
51
|
+
# it { should have_scope(:visible).conditions(:visible => true) }
|
52
|
+
#
|
53
|
+
# Passes for
|
54
|
+
#
|
55
|
+
# named_scope :visible, :conditions => {:visible => true}
|
56
|
+
#
|
57
|
+
# Or for
|
58
|
+
#
|
59
|
+
# def self.visible
|
60
|
+
# scoped(:conditions => {:visible => true})
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
# You can test lambdas or methods that return ActiveRecord#scoped calls:
|
64
|
+
#
|
65
|
+
# it { should have_scope(:recent, :with => 5) }
|
66
|
+
# it { should have_scope(:recent, :with => 1) }
|
67
|
+
#
|
68
|
+
# Passes for
|
69
|
+
#
|
70
|
+
# named_scope :recent, lambda {|c| {:limit => c}}
|
71
|
+
#
|
72
|
+
# Or for
|
73
|
+
#
|
74
|
+
# def self.recent(c)
|
75
|
+
# scoped(:limit => c)
|
76
|
+
# end
|
77
|
+
#
|
78
|
+
def have_scope(*args, &block)
|
79
|
+
HaveScopeMatcher.new(*args, &block).spec(self)
|
80
|
+
end
|
81
|
+
alias :have_named_scope :have_scope
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|