shoulda-matchers 4.4.0 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE +22 -0
- data/README.md +18 -18
- data/lib/shoulda/matchers.rb +12 -13
- data/lib/shoulda/matchers/action_controller.rb +13 -13
- data/lib/shoulda/matchers/action_controller/callback_matcher.rb +4 -89
- data/lib/shoulda/matchers/action_controller/filter_param_matcher.rb +3 -2
- data/lib/shoulda/matchers/action_controller/flash_store.rb +2 -4
- data/lib/shoulda/matchers/action_controller/permit_matcher.rb +29 -27
- data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +6 -8
- data/lib/shoulda/matchers/action_controller/render_template_matcher.rb +6 -8
- data/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +16 -13
- data/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb +2 -1
- data/lib/shoulda/matchers/action_controller/route_matcher.rb +5 -6
- data/lib/shoulda/matchers/action_controller/route_params.rb +1 -1
- data/lib/shoulda/matchers/action_controller/set_session_or_flash_matcher.rb +19 -13
- data/lib/shoulda/matchers/active_model.rb +25 -15
- data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +29 -36
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_changed_value_error.rb +1 -1
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb +5 -5
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter_and_validator.rb +2 -2
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters.rb +1 -1
- data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters_and_validators.rb +1 -1
- data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb +51 -25
- data/lib/shoulda/matchers/active_model/helpers.rb +2 -2
- data/lib/shoulda/matchers/active_model/numericality_matchers.rb +0 -5
- data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +32 -34
- data/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_model/qualifiers/ignoring_interference_by_writer.rb +1 -1
- data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +10 -2
- data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +2 -2
- data/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb +8 -7
- data/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +26 -25
- data/lib/shoulda/matchers/active_model/validate_length_of_matcher.rb +6 -6
- data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +40 -27
- data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +4 -4
- data/lib/shoulda/matchers/active_model/validation_matcher.rb +6 -8
- data/lib/shoulda/matchers/active_model/validation_matcher/build_description.rb +2 -4
- data/lib/shoulda/matchers/active_model/validation_message_finder.rb +2 -4
- data/lib/shoulda/matchers/active_model/validator.rb +4 -9
- data/lib/shoulda/matchers/active_record.rb +26 -14
- data/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb +6 -3
- data/lib/shoulda/matchers/active_record/association_matcher.rb +101 -48
- data/lib/shoulda/matchers/active_record/association_matchers.rb +0 -12
- data/lib/shoulda/matchers/active_record/association_matchers/counter_cache_matcher.rb +5 -2
- data/lib/shoulda/matchers/active_record/association_matchers/dependent_matcher.rb +4 -4
- data/lib/shoulda/matchers/active_record/association_matchers/inverse_of_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_record/association_matchers/join_table_matcher.rb +11 -6
- data/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +2 -9
- data/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +12 -7
- data/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb +23 -5
- data/lib/shoulda/matchers/active_record/association_matchers/optional_matcher.rb +3 -3
- data/lib/shoulda/matchers/active_record/association_matchers/order_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_record/association_matchers/required_matcher.rb +4 -4
- data/lib/shoulda/matchers/active_record/association_matchers/source_matcher.rb +3 -2
- data/lib/shoulda/matchers/active_record/association_matchers/through_matcher.rb +7 -5
- data/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +18 -9
- data/lib/shoulda/matchers/active_record/have_attached_matcher.rb +46 -8
- data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +39 -17
- data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +1 -1
- data/lib/shoulda/matchers/active_record/have_implicit_order_column.rb +7 -7
- data/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +12 -10
- data/lib/shoulda/matchers/active_record/have_rich_text_matcher.rb +11 -7
- data/lib/shoulda/matchers/active_record/have_secure_token_matcher.rb +2 -0
- data/lib/shoulda/matchers/active_record/serialize_matcher.rb +13 -9
- data/lib/shoulda/matchers/active_record/uniqueness.rb +4 -4
- data/lib/shoulda/matchers/active_record/uniqueness/test_model_creator.rb +1 -3
- data/lib/shoulda/matchers/active_record/uniqueness/test_models.rb +0 -2
- data/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +78 -71
- data/lib/shoulda/matchers/doublespeak.rb +9 -9
- data/lib/shoulda/matchers/doublespeak/double.rb +1 -1
- data/lib/shoulda/matchers/doublespeak/double_collection.rb +3 -3
- data/lib/shoulda/matchers/doublespeak/double_implementation_registry.rb +8 -5
- data/lib/shoulda/matchers/doublespeak/object_double.rb +1 -1
- data/lib/shoulda/matchers/doublespeak/stub_implementation.rb +1 -5
- data/lib/shoulda/matchers/doublespeak/world.rb +2 -2
- data/lib/shoulda/matchers/error.rb +1 -1
- data/lib/shoulda/matchers/independent.rb +1 -0
- data/lib/shoulda/matchers/independent/delegate_method_matcher.rb +14 -16
- data/lib/shoulda/matchers/integrations.rb +6 -6
- data/lib/shoulda/matchers/integrations/configuration.rb +1 -1
- data/lib/shoulda/matchers/integrations/libraries/action_controller.rb +1 -1
- data/lib/shoulda/matchers/integrations/libraries/rails.rb +2 -2
- data/lib/shoulda/matchers/integrations/test_frameworks.rb +2 -4
- data/lib/shoulda/matchers/integrations/test_frameworks/active_support_test_case.rb +1 -1
- data/lib/shoulda/matchers/integrations/test_frameworks/minitest_4.rb +1 -1
- data/lib/shoulda/matchers/integrations/test_frameworks/minitest_5.rb +1 -1
- data/lib/shoulda/matchers/integrations/test_frameworks/missing_test_framework.rb +1 -1
- data/lib/shoulda/matchers/integrations/test_frameworks/test_unit.rb +1 -1
- data/lib/shoulda/matchers/rails_shim.rb +5 -42
- data/lib/shoulda/matchers/util.rb +9 -2
- data/lib/shoulda/matchers/util/word_wrap.rb +7 -7
- data/lib/shoulda/matchers/version.rb +1 -1
- data/lib/shoulda/matchers/warn.rb +3 -3
- data/shoulda-matchers.gemspec +12 -9
- metadata +14 -14
- data/lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb +0 -159
@@ -26,12 +26,7 @@ module Shoulda
|
|
26
26
|
|
27
27
|
def join_table_name
|
28
28
|
join_table_name =
|
29
|
-
|
30
|
-
has_and_belongs_to_many_name_table_name
|
31
|
-
else
|
32
|
-
reflection.join_table
|
33
|
-
end
|
34
|
-
|
29
|
+
has_and_belongs_to_many_name_table_name || reflection.join_table
|
35
30
|
join_table_name.to_s
|
36
31
|
end
|
37
32
|
|
@@ -82,9 +77,7 @@ module Shoulda
|
|
82
77
|
private
|
83
78
|
|
84
79
|
def has_and_belongs_to_many_name_table_name
|
85
|
-
|
86
|
-
has_and_belongs_to_many_reflection.table_name
|
87
|
-
end
|
80
|
+
has_and_belongs_to_many_reflection&.table_name
|
88
81
|
end
|
89
82
|
|
90
83
|
def has_and_belongs_to_many_reflection
|
@@ -12,13 +12,13 @@ module Shoulda
|
|
12
12
|
:join_table_name,
|
13
13
|
:polymorphic?,
|
14
14
|
:validate_inverse_of_through_association!,
|
15
|
-
to: :reflection
|
15
|
+
to: :reflection,
|
16
16
|
)
|
17
17
|
|
18
18
|
delegate(
|
19
19
|
:through?,
|
20
20
|
to: :reflection,
|
21
|
-
allow_nil: true
|
21
|
+
allow_nil: true,
|
22
22
|
)
|
23
23
|
|
24
24
|
def initialize(subject, name)
|
@@ -31,7 +31,7 @@ module Shoulda
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def reflection
|
34
|
-
@
|
34
|
+
@_reflection ||= reflect_on_association(name)
|
35
35
|
end
|
36
36
|
|
37
37
|
def reflect_on_association(name)
|
@@ -48,9 +48,12 @@ module Shoulda
|
|
48
48
|
|
49
49
|
def build_relation_with_clause(name, value)
|
50
50
|
case name
|
51
|
-
|
52
|
-
|
53
|
-
|
51
|
+
when :conditions
|
52
|
+
associated_class.where(value)
|
53
|
+
when :order
|
54
|
+
associated_class.order(value)
|
55
|
+
else
|
56
|
+
raise ArgumentError, "Unknown clause '#{name}'"
|
54
57
|
end
|
55
58
|
end
|
56
59
|
|
@@ -59,7 +62,9 @@ module Shoulda
|
|
59
62
|
when :conditions
|
60
63
|
relation.where_values_hash
|
61
64
|
when :order
|
62
|
-
relation.order_values.map
|
65
|
+
relation.order_values.map do |value|
|
66
|
+
value_as_sql(value)
|
67
|
+
end.join(', ')
|
63
68
|
else
|
64
69
|
raise ArgumentError, "Unknown clause '#{name}'"
|
65
70
|
end
|
@@ -6,7 +6,12 @@ module Shoulda
|
|
6
6
|
class OptionVerifier
|
7
7
|
delegate :reflection, to: :reflector
|
8
8
|
|
9
|
-
|
9
|
+
DEFAULT_VALUE_OF_OPTIONS = {
|
10
|
+
has_many: {
|
11
|
+
validate: true,
|
12
|
+
},
|
13
|
+
}.freeze
|
14
|
+
RELATION_OPTIONS = [:conditions, :order].freeze
|
10
15
|
|
11
16
|
def initialize(reflector)
|
12
17
|
@reflector = reflector
|
@@ -40,7 +45,7 @@ module Shoulda
|
|
40
45
|
else
|
41
46
|
type_cast_expected_value = type_cast(
|
42
47
|
type,
|
43
|
-
expected_value_for(type, name, expected_value)
|
48
|
+
expected_value_for(type, name, expected_value),
|
44
49
|
)
|
45
50
|
actual_value = type_cast(type, actual_value_for(name))
|
46
51
|
type_cast_expected_value == actual_value
|
@@ -55,7 +60,7 @@ module Shoulda
|
|
55
60
|
if respond_to?(method_name, true)
|
56
61
|
__send__(method_name)
|
57
62
|
else
|
58
|
-
|
63
|
+
actual_value_for_option(name)
|
59
64
|
end
|
60
65
|
end
|
61
66
|
end
|
@@ -94,7 +99,7 @@ module Shoulda
|
|
94
99
|
|
95
100
|
def expected_value_for_constant(name)
|
96
101
|
namespace = Shoulda::Matchers::Util.deconstantize(
|
97
|
-
reflector.model_class.to_s
|
102
|
+
reflector.model_class.to_s,
|
98
103
|
)
|
99
104
|
|
100
105
|
["#{namespace}::#{name}", name].each do |path|
|
@@ -107,12 +112,25 @@ module Shoulda
|
|
107
112
|
end
|
108
113
|
|
109
114
|
def actual_value_for_relation_clause(name)
|
110
|
-
reflector.extract_relation_clause_from(
|
115
|
+
reflector.extract_relation_clause_from(
|
116
|
+
reflector.association_relation,
|
117
|
+
name,
|
118
|
+
)
|
111
119
|
end
|
112
120
|
|
113
121
|
def actual_value_for_class_name
|
114
122
|
reflector.associated_class
|
115
123
|
end
|
124
|
+
|
125
|
+
def actual_value_for_option(name)
|
126
|
+
option_value = reflection.options[name]
|
127
|
+
|
128
|
+
if option_value.nil?
|
129
|
+
DEFAULT_VALUE_OF_OPTIONS.dig(reflection.macro, name)
|
130
|
+
else
|
131
|
+
option_value
|
132
|
+
end
|
133
|
+
end
|
116
134
|
end
|
117
135
|
end
|
118
136
|
end
|
@@ -32,9 +32,9 @@ module Shoulda
|
|
32
32
|
end
|
33
33
|
|
34
34
|
missing_option << (
|
35
|
-
'fail validation if '
|
36
|
-
":#{attribute_name} is unset; i.e., either the association "
|
37
|
-
'should have been defined with `optional: '
|
35
|
+
'fail validation if '\
|
36
|
+
":#{attribute_name} is unset; i.e., either the association "\
|
37
|
+
'should have been defined with `optional: '\
|
38
38
|
"#{optional.inspect}`, or there "
|
39
39
|
)
|
40
40
|
|
@@ -33,9 +33,9 @@ module Shoulda
|
|
33
33
|
end
|
34
34
|
|
35
35
|
missing_option << (
|
36
|
-
'fail validation if '
|
37
|
-
":#{attribute_name} is unset; i.e., either the association "
|
38
|
-
'should have been defined with `required: '
|
36
|
+
'fail validation if '\
|
37
|
+
":#{attribute_name} is unset; i.e., either the association "\
|
38
|
+
'should have been defined with `required: '\
|
39
39
|
"#{required.inspect}`, or there "
|
40
40
|
)
|
41
41
|
|
@@ -65,7 +65,7 @@ module Shoulda
|
|
65
65
|
end
|
66
66
|
|
67
67
|
def validation_message_key
|
68
|
-
|
68
|
+
:required
|
69
69
|
end
|
70
70
|
end
|
71
71
|
end
|
@@ -22,7 +22,8 @@ module Shoulda
|
|
22
22
|
if option_verifier.correct_for_string?(:source, source)
|
23
23
|
true
|
24
24
|
else
|
25
|
-
self.missing_option =
|
25
|
+
self.missing_option =
|
26
|
+
"#{name} should have #{source} as source option"
|
26
27
|
false
|
27
28
|
end
|
28
29
|
end
|
@@ -32,7 +33,7 @@ module Shoulda
|
|
32
33
|
attr_accessor :subject, :source, :name
|
33
34
|
|
34
35
|
def option_verifier
|
35
|
-
@
|
36
|
+
@_option_verifier ||= OptionVerifier.new(subject)
|
36
37
|
end
|
37
38
|
end
|
38
39
|
end
|
@@ -29,13 +29,14 @@ module Shoulda
|
|
29
29
|
if through_reflection.present?
|
30
30
|
true
|
31
31
|
else
|
32
|
-
self.missing_option =
|
32
|
+
self.missing_option =
|
33
|
+
"#{name} does not have any relationship to #{through}"
|
33
34
|
false
|
34
35
|
end
|
35
36
|
end
|
36
37
|
|
37
38
|
def through_reflection
|
38
|
-
@
|
39
|
+
@_through_reflection ||= subject.reflect_on_association(through)
|
39
40
|
end
|
40
41
|
|
41
42
|
def through_association_correct?
|
@@ -43,8 +44,9 @@ module Shoulda
|
|
43
44
|
true
|
44
45
|
else
|
45
46
|
self.missing_option =
|
46
|
-
"Expected #{name} to have #{name} through #{through}, "
|
47
|
-
|
47
|
+
"Expected #{name} to have #{name} through #{through}, "\
|
48
|
+
'but got it through ' +
|
49
|
+
option_verifier.actual_value_for(:through).to_s
|
48
50
|
false
|
49
51
|
end
|
50
52
|
end
|
@@ -54,7 +56,7 @@ module Shoulda
|
|
54
56
|
attr_accessor :through, :name, :subject
|
55
57
|
|
56
58
|
def option_verifier
|
57
|
-
@
|
59
|
+
@_option_verifier ||= OptionVerifier.new(subject)
|
58
60
|
end
|
59
61
|
end
|
60
62
|
end
|
@@ -6,16 +6,22 @@ module Shoulda
|
|
6
6
|
#
|
7
7
|
# class Process < ActiveRecord::Base
|
8
8
|
# enum status: [:running, :stopped, :suspended]
|
9
|
+
#
|
10
|
+
# alias_attribute :kind, :SomeLegacyField
|
11
|
+
#
|
12
|
+
# enum kind: [:foo, :bar]
|
9
13
|
# end
|
10
14
|
#
|
11
15
|
# # RSpec
|
12
16
|
# RSpec.describe Process, type: :model do
|
13
17
|
# it { should define_enum_for(:status) }
|
18
|
+
# it { should define_enum_for(:kind) }
|
14
19
|
# end
|
15
20
|
#
|
16
21
|
# # Minitest (Shoulda)
|
17
22
|
# class ProcessTest < ActiveSupport::TestCase
|
18
23
|
# should define_enum_for(:status)
|
24
|
+
# should define_enum_for(:kind)
|
19
25
|
# end
|
20
26
|
#
|
21
27
|
# #### Qualifiers
|
@@ -237,7 +243,7 @@ module Shoulda
|
|
237
243
|
"Expected #{model} to #{expectation}, but "
|
238
244
|
end
|
239
245
|
|
240
|
-
message << failure_message_continuation
|
246
|
+
message << "#{failure_message_continuation}."
|
241
247
|
|
242
248
|
Shoulda::Matchers.word_wrap(message)
|
243
249
|
end
|
@@ -252,7 +258,7 @@ module Shoulda
|
|
252
258
|
attr_reader :attribute_name, :options, :record,
|
253
259
|
:failure_message_continuation
|
254
260
|
|
255
|
-
def expectation
|
261
|
+
def expectation # rubocop:disable Metrics/MethodLength
|
256
262
|
if enum_defined?
|
257
263
|
expectation = "#{simple_description} backed by "
|
258
264
|
expectation << Shoulda::Matchers::Util.a_or_an(expected_column_type)
|
@@ -358,8 +364,8 @@ module Shoulda
|
|
358
364
|
true
|
359
365
|
else
|
360
366
|
@failure_message_continuation =
|
361
|
-
"However, #{attribute_name.inspect} is "
|
362
|
-
Shoulda::Matchers::Util.a_or_an(column.type)
|
367
|
+
"However, #{attribute_name.inspect} is "\
|
368
|
+
"#{Shoulda::Matchers::Util.a_or_an(column.type)}"\
|
363
369
|
' column'
|
364
370
|
false
|
365
371
|
end
|
@@ -370,7 +376,10 @@ module Shoulda
|
|
370
376
|
end
|
371
377
|
|
372
378
|
def column
|
373
|
-
|
379
|
+
key = attribute_name.to_s
|
380
|
+
column_name = model.attribute_alias(key) || key
|
381
|
+
|
382
|
+
model.columns_hash[column_name]
|
374
383
|
end
|
375
384
|
|
376
385
|
def model
|
@@ -421,9 +430,9 @@ module Shoulda
|
|
421
430
|
def expected_prefix
|
422
431
|
if options.include?(:prefix)
|
423
432
|
if options[:prefix] == true
|
424
|
-
attribute_name
|
433
|
+
attribute_name
|
425
434
|
else
|
426
|
-
options[:prefix]
|
435
|
+
options[:prefix]
|
427
436
|
end
|
428
437
|
end
|
429
438
|
end
|
@@ -431,9 +440,9 @@ module Shoulda
|
|
431
440
|
def expected_suffix
|
432
441
|
if options.include?(:suffix)
|
433
442
|
if options[:suffix] == true
|
434
|
-
attribute_name
|
443
|
+
attribute_name
|
435
444
|
else
|
436
|
-
options[:suffix]
|
445
|
+
options[:suffix]
|
437
446
|
end
|
438
447
|
end
|
439
448
|
end
|
@@ -1,10 +1,52 @@
|
|
1
1
|
module Shoulda
|
2
2
|
module Matchers
|
3
3
|
module ActiveRecord
|
4
|
+
# The `have_one_attached` matcher tests usage of the
|
5
|
+
# `has_one_attached` macro.
|
6
|
+
#
|
7
|
+
# #### Example
|
8
|
+
#
|
9
|
+
# class User < ApplicationRecord
|
10
|
+
# has_one_attached :avatar
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# # RSpec
|
14
|
+
# RSpec.describe User, type: :model do
|
15
|
+
# it { should have_one_attached(:avatar) }
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# # Minitest (Shoulda)
|
19
|
+
# class UserTest < ActiveSupport::TestCase
|
20
|
+
# should have_one_attached(:avatar)
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# @return [HaveAttachedMatcher]
|
24
|
+
#
|
4
25
|
def have_one_attached(name)
|
5
26
|
HaveAttachedMatcher.new(:one, name)
|
6
27
|
end
|
7
28
|
|
29
|
+
# The `have_many_attached` matcher tests usage of the
|
30
|
+
# `has_many_attached` macro.
|
31
|
+
#
|
32
|
+
# #### Example
|
33
|
+
#
|
34
|
+
# class Message < ApplicationRecord
|
35
|
+
# has_many_attached :images
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# # RSpec
|
39
|
+
# RSpec.describe Message, type: :model do
|
40
|
+
# it { should have_many_attached(:images) }
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# # Minitest (Shoulda)
|
44
|
+
# class MessageTest < ActiveSupport::TestCase
|
45
|
+
# should have_many_attached(:images)
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# @return [HaveAttachedMatcher]
|
49
|
+
#
|
8
50
|
def have_many_attached(name)
|
9
51
|
HaveAttachedMatcher.new(:many, name)
|
10
52
|
end
|
@@ -92,10 +134,8 @@ Did not expect #{expectation}, but it does.
|
|
92
134
|
|
93
135
|
def attachments_association_name
|
94
136
|
case macro
|
95
|
-
when :one then
|
96
|
-
|
97
|
-
when :many then
|
98
|
-
"#{name}_attachments"
|
137
|
+
when :one then "#{name}_attachment"
|
138
|
+
when :many then "#{name}_attachments"
|
99
139
|
end
|
100
140
|
end
|
101
141
|
|
@@ -121,10 +161,8 @@ Did not expect #{expectation}, but it does.
|
|
121
161
|
|
122
162
|
def blobs_association_name
|
123
163
|
case macro
|
124
|
-
when :one then
|
125
|
-
|
126
|
-
when :many then
|
127
|
-
"#{name}_blobs"
|
164
|
+
when :one then "#{name}_blob"
|
165
|
+
when :many then "#{name}_blobs"
|
128
166
|
end
|
129
167
|
end
|
130
168
|
|
@@ -84,6 +84,8 @@ module Shoulda
|
|
84
84
|
|
85
85
|
# @private
|
86
86
|
class HaveDbColumnMatcher
|
87
|
+
OPTIONS = %i(precision limit default null scale primary).freeze
|
88
|
+
|
87
89
|
def initialize(column)
|
88
90
|
@column = column
|
89
91
|
@options = {}
|
@@ -95,7 +97,8 @@ module Shoulda
|
|
95
97
|
end
|
96
98
|
|
97
99
|
def with_options(opts = {})
|
98
|
-
|
100
|
+
validate_options(opts)
|
101
|
+
OPTIONS.each do |attribute|
|
99
102
|
if opts.key?(attribute.to_sym)
|
100
103
|
@options[attribute.to_sym] = opts[attribute.to_sym]
|
101
104
|
end
|
@@ -125,23 +128,38 @@ module Shoulda
|
|
125
128
|
|
126
129
|
def description
|
127
130
|
desc = "have db column named #{@column}"
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
desc << " of
|
131
|
+
if @options.key?(:column_type)
|
132
|
+
desc << " of type #{@options[:column_type]}"
|
133
|
+
end
|
134
|
+
if @options.key?(:precision)
|
135
|
+
desc << " of precision #{@options[:precision]}"
|
136
|
+
end
|
137
|
+
desc << " of limit #{@options[:limit]}" if @options.key?(:limit)
|
138
|
+
desc << " of default #{@options[:default]}" if @options.key?(:default)
|
139
|
+
desc << " of null #{@options[:null]}" if @options.key?(:null)
|
140
|
+
desc << " of primary #{@options[:primary]}" if @options.key?(:primary)
|
141
|
+
desc << " of scale #{@options[:scale]}" if @options.key?(:scale)
|
135
142
|
desc
|
136
143
|
end
|
137
144
|
|
138
145
|
protected
|
139
146
|
|
147
|
+
def validate_options(opts)
|
148
|
+
invalid_options = opts.keys.map(&:to_sym) - OPTIONS
|
149
|
+
if invalid_options.any?
|
150
|
+
raise(
|
151
|
+
ArgumentError,
|
152
|
+
"Unknown option(s): #{invalid_options.map(&:inspect).join(', ')}",
|
153
|
+
)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
140
157
|
def column_exists?
|
141
158
|
if model_class.column_names.include?(@column.to_s)
|
142
159
|
true
|
143
160
|
else
|
144
|
-
@missing =
|
161
|
+
@missing =
|
162
|
+
"#{model_class} does not have a db column named #{@column}."
|
145
163
|
false
|
146
164
|
end
|
147
165
|
end
|
@@ -152,8 +170,9 @@ module Shoulda
|
|
152
170
|
if matched_column.type.to_s == @options[:column_type].to_s
|
153
171
|
true
|
154
172
|
else
|
155
|
-
@missing =
|
156
|
-
|
173
|
+
@missing =
|
174
|
+
"#{model_class} has a db column named #{@column} " <<
|
175
|
+
"of type #{matched_column.type}, not #{@options[:column_type]}."
|
157
176
|
false
|
158
177
|
end
|
159
178
|
end
|
@@ -229,18 +248,21 @@ module Shoulda
|
|
229
248
|
true
|
230
249
|
else
|
231
250
|
@missing = "#{model_class} has a db column named #{@column} "
|
232
|
-
|
233
|
-
@
|
234
|
-
|
235
|
-
|
236
|
-
|
251
|
+
@missing <<
|
252
|
+
if @options[:primary]
|
253
|
+
'that is not primary, but should be'
|
254
|
+
else
|
255
|
+
'that is primary, but should not be'
|
256
|
+
end
|
237
257
|
false
|
238
258
|
end
|
239
259
|
end
|
240
260
|
|
241
261
|
def matched_column
|
242
262
|
@_matched_column ||= begin
|
243
|
-
column = model_class.columns.detect
|
263
|
+
column = model_class.columns.detect do |each|
|
264
|
+
each.name == @column.to_s
|
265
|
+
end
|
244
266
|
DecoratedColumn.new(model_class, column)
|
245
267
|
end
|
246
268
|
end
|