micro-max-mod 0.0.1
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.
Potentially problematic release.
This version of micro-max-mod might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/micro-max-mod.gemspec +11 -0
- data/shoulda-matchers-8.0.1/LICENSE +22 -0
- data/shoulda-matchers-8.0.1/README.md +567 -0
- data/shoulda-matchers-8.0.1/docs/errors/NonCaseSwappableValueError.md +111 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/callback_matcher.rb +121 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/filter_param_matcher.rb +70 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/flash_store.rb +86 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/permit_matcher.rb +445 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +96 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/render_template_matcher.rb +84 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +145 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb +115 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/respond_with_matcher.rb +148 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/route_matcher.rb +207 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/route_params.rb +62 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/session_store.rb +34 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/set_flash_matcher.rb +228 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/set_session_matcher.rb +163 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller/set_session_or_flash_matcher.rb +107 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/action_controller.rb +24 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_changed_value_error.rb +45 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_does_not_exist_error.rb +23 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb +232 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter_and_validator.rb +62 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters.rb +40 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters_and_validators.rb +48 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher/successful_check.rb +14 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher/successful_setting.rb +14 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/allow_value_matcher.rb +695 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/comparison_matcher.rb +157 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +78 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/errors.rb +52 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb +125 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/helpers.rb +37 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb +45 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +67 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb +45 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb +44 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/numericality_matchers/range_matcher.rb +71 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/numericality_matchers/submatchers.rb +53 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/numericality_matchers.rb +9 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/qualifiers/allow_blank.rb +26 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/qualifiers/allow_nil.rb +26 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/qualifiers/ignore_interference_by_writer.rb +101 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/qualifiers/ignoring_interference_by_writer.rb +21 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/qualifiers.rb +14 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +180 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +128 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_comparison_of_matcher.rb +567 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +185 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb +272 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +664 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_length_of_matcher.rb +575 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +711 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +428 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validation_matcher/build_description.rb +62 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validation_matcher.rb +195 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validation_message_finder.rb +63 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model/validator.rb +127 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_model.rb +96 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb +217 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matcher.rb +2134 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/counter_cache_matcher.rb +74 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/dependent_matcher.rb +62 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/inverse_of_matcher.rb +41 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/join_table_matcher.rb +105 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +101 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +89 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb +142 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/optional_matcher.rb +71 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/order_matcher.rb +41 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/required_matcher.rb +76 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/source_matcher.rb +42 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers/through_matcher.rb +65 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/association_matchers.rb +9 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +784 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/encrypt_matcher.rb +174 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/have_attached_matcher.rb +343 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +366 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +287 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/have_implicit_order_column.rb +104 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +95 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/have_rich_text_matcher.rb +83 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/have_secure_token_matcher.rb +132 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/normalize_matcher.rb +151 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/serialize_matcher.rb +203 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/uniqueness/model.rb +58 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/uniqueness/namespace.rb +39 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/uniqueness/test_model_creator.rb +49 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/uniqueness/test_models.rb +55 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/uniqueness.rb +14 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +1197 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/active_record.rb +37 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/configuration.rb +31 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak/double.rb +103 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak/double_collection.rb +60 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak/double_implementation_registry.rb +31 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak/method_call.rb +44 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak/object_double.rb +43 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak/proxy_implementation.rb +32 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak/stub_implementation.rb +31 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak/world.rb +63 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/doublespeak.rb +38 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/error.rb +29 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/independent/delegate_method_matcher/target_not_defined_error.rb +15 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/independent/delegate_method_matcher.rb +540 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/independent.rb +11 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/configuration.rb +70 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/configuration_error.rb +9 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/inclusion.rb +20 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/libraries/action_controller.rb +33 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/libraries/active_model.rb +26 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/libraries/active_record.rb +26 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/libraries/missing_library.rb +19 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/libraries/rails.rb +31 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/libraries/routing.rb +29 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/libraries.rb +16 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/rails.rb +12 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/registry.rb +28 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/test_frameworks/active_support_test_case.rb +37 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/test_frameworks/minitest_4.rb +36 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/test_frameworks/minitest_5.rb +37 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/test_frameworks/missing_test_framework.rb +40 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/test_frameworks/rspec.rb +29 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/test_frameworks/test_unit.rb +36 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations/test_frameworks.rb +16 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/integrations.rb +43 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/matcher_collection.rb +99 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/matcher_context.rb +36 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/rails_shim.rb +190 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/routing.rb +10 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/util/word_wrap.rb +211 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/util.rb +110 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/version.rb +6 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers/warn.rb +28 -0
- data/shoulda-matchers-8.0.1/lib/shoulda/matchers.rb +25 -0
- data/shoulda-matchers-8.0.1/lib/shoulda-matchers.rb +149 -0
- data/shoulda-matchers-8.0.1/shoulda-matchers.gemspec +43 -0
- metadata +178 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
module Shoulda
|
|
2
|
+
module Matchers
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module AssociationMatchers
|
|
5
|
+
# @private
|
|
6
|
+
class CounterCacheMatcher
|
|
7
|
+
attr_accessor :missing_option
|
|
8
|
+
|
|
9
|
+
def initialize(counter_cache, name)
|
|
10
|
+
@counter_cache = counter_cache
|
|
11
|
+
@name = name
|
|
12
|
+
@missing_option = ''
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def description
|
|
16
|
+
"counter_cache => #{counter_cache}"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def matches?(subject)
|
|
20
|
+
self.subject = ModelReflector.new(subject, name)
|
|
21
|
+
|
|
22
|
+
if correct_value?
|
|
23
|
+
true
|
|
24
|
+
else
|
|
25
|
+
self.missing_option = "#{name} should have #{description}"
|
|
26
|
+
false
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
protected
|
|
31
|
+
|
|
32
|
+
attr_accessor :subject, :counter_cache, :name
|
|
33
|
+
|
|
34
|
+
def correct_value?
|
|
35
|
+
expected = normalize_value
|
|
36
|
+
|
|
37
|
+
if expected.is_a?(Hash)
|
|
38
|
+
option_verifier.correct_for_hash?(
|
|
39
|
+
:counter_cache,
|
|
40
|
+
expected,
|
|
41
|
+
)
|
|
42
|
+
else
|
|
43
|
+
option_verifier.correct_for_string?(
|
|
44
|
+
:counter_cache,
|
|
45
|
+
expected,
|
|
46
|
+
)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def option_verifier
|
|
51
|
+
@_option_verifier ||= OptionVerifier.new(subject)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def normalize_value
|
|
55
|
+
if Rails::VERSION::STRING >= '7.2'
|
|
56
|
+
case counter_cache
|
|
57
|
+
when true
|
|
58
|
+
{ active: true, column: nil }
|
|
59
|
+
when String, Symbol
|
|
60
|
+
{ active: true, column: counter_cache.to_s }
|
|
61
|
+
when Hash
|
|
62
|
+
{ active: true, column: nil }.merge!(counter_cache)
|
|
63
|
+
else
|
|
64
|
+
raise ArgumentError, 'Invalid counter_cache option'
|
|
65
|
+
end
|
|
66
|
+
else
|
|
67
|
+
counter_cache
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
module Shoulda
|
|
2
|
+
module Matchers
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module AssociationMatchers
|
|
5
|
+
# @private
|
|
6
|
+
class DependentMatcher
|
|
7
|
+
attr_accessor :missing_option
|
|
8
|
+
|
|
9
|
+
def initialize(dependent, name)
|
|
10
|
+
@dependent = dependent
|
|
11
|
+
@name = name
|
|
12
|
+
@missing_option = ''
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def description
|
|
16
|
+
"dependent => #{dependent}"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def matches?(subject)
|
|
20
|
+
self.subject = ModelReflector.new(subject, name)
|
|
21
|
+
|
|
22
|
+
if option_matches?
|
|
23
|
+
true
|
|
24
|
+
else
|
|
25
|
+
self.missing_option = generate_missing_option
|
|
26
|
+
false
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
protected
|
|
31
|
+
|
|
32
|
+
attr_accessor :subject, :dependent, :name
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def option_verifier
|
|
37
|
+
@_option_verifier ||= OptionVerifier.new(subject)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def option_matches?
|
|
41
|
+
option_verifier.correct_for?(option_type, :dependent, dependent)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def option_type
|
|
45
|
+
case dependent
|
|
46
|
+
when true, false then :boolean
|
|
47
|
+
else :string
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def generate_missing_option
|
|
52
|
+
[
|
|
53
|
+
"#{name} should have",
|
|
54
|
+
(dependent == true ? 'a' : dependent),
|
|
55
|
+
'dependency',
|
|
56
|
+
].join(' ')
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Shoulda
|
|
2
|
+
module Matchers
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module AssociationMatchers
|
|
5
|
+
# @private
|
|
6
|
+
class InverseOfMatcher
|
|
7
|
+
attr_accessor :missing_option
|
|
8
|
+
|
|
9
|
+
def initialize(inverse_of, name)
|
|
10
|
+
@inverse_of = inverse_of
|
|
11
|
+
@name = name
|
|
12
|
+
@missing_option = ''
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def description
|
|
16
|
+
"inverse_of => #{inverse_of}"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def matches?(subject)
|
|
20
|
+
self.subject = ModelReflector.new(subject, name)
|
|
21
|
+
|
|
22
|
+
if option_verifier.correct_for_string?(:inverse_of, inverse_of)
|
|
23
|
+
true
|
|
24
|
+
else
|
|
25
|
+
self.missing_option = "#{name} should have #{description}"
|
|
26
|
+
false
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
protected
|
|
31
|
+
|
|
32
|
+
attr_accessor :subject, :inverse_of, :name
|
|
33
|
+
|
|
34
|
+
def option_verifier
|
|
35
|
+
@_option_verifier ||= OptionVerifier.new(subject)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
module Shoulda
|
|
2
|
+
module Matchers
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module AssociationMatchers
|
|
5
|
+
# @private
|
|
6
|
+
class JoinTableMatcher
|
|
7
|
+
attr_reader :failure_message
|
|
8
|
+
|
|
9
|
+
alias :missing_option :failure_message
|
|
10
|
+
|
|
11
|
+
delegate :model_class, :join_table_name, :associated_class, :options,
|
|
12
|
+
:name, :option_verifier, to: :association_matcher
|
|
13
|
+
|
|
14
|
+
delegate :connection, to: :model_class
|
|
15
|
+
|
|
16
|
+
def initialize(association_matcher, reflector)
|
|
17
|
+
@association_matcher = association_matcher
|
|
18
|
+
@reflector = reflector
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def matches?(_subject)
|
|
22
|
+
join_table_option_correct? &&
|
|
23
|
+
join_table_exists? &&
|
|
24
|
+
join_table_has_correct_columns?
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def join_table_option_correct?
|
|
28
|
+
if options.key?(:join_table_name)
|
|
29
|
+
if option_verifier.correct_for_string?(
|
|
30
|
+
:join_table,
|
|
31
|
+
options[:join_table_name],
|
|
32
|
+
)
|
|
33
|
+
true
|
|
34
|
+
else
|
|
35
|
+
@failure_message = "#{name} should use"\
|
|
36
|
+
" #{options[:join_table_name].inspect} for :join_table option"
|
|
37
|
+
false
|
|
38
|
+
end
|
|
39
|
+
else
|
|
40
|
+
true
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def join_table_exists?
|
|
45
|
+
if connection.data_sources.
|
|
46
|
+
include?(join_table_name.to_s)
|
|
47
|
+
true
|
|
48
|
+
else
|
|
49
|
+
@failure_message = missing_table_message
|
|
50
|
+
false
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def join_table_has_correct_columns?
|
|
55
|
+
if missing_columns.empty?
|
|
56
|
+
true
|
|
57
|
+
else
|
|
58
|
+
@failure_message = missing_columns_message
|
|
59
|
+
false
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
protected
|
|
64
|
+
|
|
65
|
+
attr_reader :association_matcher, :reflector
|
|
66
|
+
|
|
67
|
+
private
|
|
68
|
+
|
|
69
|
+
delegate :foreign_key, :association_foreign_key, to: :reflector
|
|
70
|
+
|
|
71
|
+
def missing_columns
|
|
72
|
+
@_missing_columns ||= expected_join_table_columns.reject do |key|
|
|
73
|
+
actual_join_table_columns.include?(key.to_s)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def expected_join_table_columns
|
|
78
|
+
[foreign_key, association_foreign_key]
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def actual_join_table_columns
|
|
82
|
+
connection.columns(join_table_name).map(&:name)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def missing_table_message
|
|
86
|
+
"join table #{join_table_name} doesn't exist"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def missing_columns_message
|
|
90
|
+
missing = missing_columns.join(', ')
|
|
91
|
+
"join table #{join_table_name} missing #{column_label}: #{missing}"
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def column_label
|
|
95
|
+
if missing_columns.length > 1
|
|
96
|
+
'columns'
|
|
97
|
+
else
|
|
98
|
+
'column'
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
require 'delegate'
|
|
2
|
+
|
|
3
|
+
module Shoulda
|
|
4
|
+
module Matchers
|
|
5
|
+
module ActiveRecord
|
|
6
|
+
module AssociationMatchers
|
|
7
|
+
# @private
|
|
8
|
+
class ModelReflection < SimpleDelegator
|
|
9
|
+
def initialize(reflection)
|
|
10
|
+
super(reflection)
|
|
11
|
+
@reflection = reflection
|
|
12
|
+
@subject = reflection.active_record
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def associated_class
|
|
16
|
+
if polymorphic?
|
|
17
|
+
subject
|
|
18
|
+
else
|
|
19
|
+
reflection.klass
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def polymorphic?
|
|
24
|
+
reflection.options[:polymorphic]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def through?
|
|
28
|
+
reflection.options[:through]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def join_table_name
|
|
32
|
+
join_table_name =
|
|
33
|
+
has_and_belongs_to_many_name_table_name || reflection.join_table
|
|
34
|
+
join_table_name.to_s
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def association_relation(related_instance)
|
|
38
|
+
relation = associated_class.all
|
|
39
|
+
|
|
40
|
+
if reflection.scope
|
|
41
|
+
# Source: AR::Associations::AssociationScope#eval_scope
|
|
42
|
+
relation.instance_exec(related_instance, &reflection.scope)
|
|
43
|
+
else
|
|
44
|
+
relation
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def foreign_key
|
|
49
|
+
if has_and_belongs_to_many_reflection
|
|
50
|
+
has_and_belongs_to_many_reflection.foreign_key
|
|
51
|
+
elsif reflection.respond_to?(:foreign_key)
|
|
52
|
+
reflection.foreign_key
|
|
53
|
+
else
|
|
54
|
+
reflection.primary_key_name
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def association_foreign_key
|
|
59
|
+
if has_and_belongs_to_many_reflection
|
|
60
|
+
join_model = has_and_belongs_to_many_reflection.options[:class]
|
|
61
|
+
join_model.right_reflection.foreign_key
|
|
62
|
+
else
|
|
63
|
+
reflection.association_foreign_key
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def validate_inverse_of_through_association!
|
|
68
|
+
if through?
|
|
69
|
+
reflection.check_validity!
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def has_and_belongs_to_many_name
|
|
74
|
+
reflection.options[:through]
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def strict_loading?
|
|
78
|
+
reflection.options.fetch(:strict_loading, subject.strict_loading_by_default)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
protected
|
|
82
|
+
|
|
83
|
+
attr_reader :reflection, :subject
|
|
84
|
+
|
|
85
|
+
private
|
|
86
|
+
|
|
87
|
+
def has_and_belongs_to_many_name_table_name
|
|
88
|
+
has_and_belongs_to_many_reflection&.table_name
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def has_and_belongs_to_many_reflection
|
|
92
|
+
@_has_and_belongs_to_many_reflection ||=
|
|
93
|
+
if has_and_belongs_to_many_name
|
|
94
|
+
@subject.reflect_on_association(has_and_belongs_to_many_name)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
module Shoulda
|
|
2
|
+
module Matchers
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module AssociationMatchers
|
|
5
|
+
# @private
|
|
6
|
+
class ModelReflector
|
|
7
|
+
delegate(
|
|
8
|
+
:associated_class,
|
|
9
|
+
:association_foreign_key,
|
|
10
|
+
:foreign_key,
|
|
11
|
+
:foreign_type,
|
|
12
|
+
:has_and_belongs_to_many_name,
|
|
13
|
+
:join_table_name,
|
|
14
|
+
:polymorphic?,
|
|
15
|
+
:validate_inverse_of_through_association!,
|
|
16
|
+
to: :reflection,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
delegate(
|
|
20
|
+
:through?,
|
|
21
|
+
to: :reflection,
|
|
22
|
+
allow_nil: true,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
def initialize(subject, name)
|
|
26
|
+
@subject = subject
|
|
27
|
+
@name = name
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def association_relation
|
|
31
|
+
reflection.association_relation(subject)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def reflection
|
|
35
|
+
@_reflection ||= reflect_on_association(name)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def reflect_on_association(name)
|
|
39
|
+
reflection = model_class.reflect_on_association(name)
|
|
40
|
+
|
|
41
|
+
if reflection
|
|
42
|
+
ModelReflection.new(reflection)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def model_class
|
|
47
|
+
subject.class
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def build_relation_with_clause(name, value)
|
|
51
|
+
case name
|
|
52
|
+
when :conditions
|
|
53
|
+
associated_class.where(value)
|
|
54
|
+
when :order
|
|
55
|
+
associated_class.order(value)
|
|
56
|
+
else
|
|
57
|
+
raise ArgumentError, "Unknown clause '#{name}'"
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def extract_relation_clause_from(relation, name)
|
|
62
|
+
case name
|
|
63
|
+
when :conditions
|
|
64
|
+
relation.where_values_hash
|
|
65
|
+
when :order
|
|
66
|
+
relation.order_values.map do |value|
|
|
67
|
+
value_as_sql(value)
|
|
68
|
+
end.join(', ')
|
|
69
|
+
else
|
|
70
|
+
raise ArgumentError, "Unknown clause '#{name}'"
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
protected
|
|
75
|
+
|
|
76
|
+
attr_reader :subject, :name
|
|
77
|
+
|
|
78
|
+
def value_as_sql(value)
|
|
79
|
+
if value.respond_to?(:to_sql)
|
|
80
|
+
value.to_sql
|
|
81
|
+
else
|
|
82
|
+
value
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
module Shoulda
|
|
2
|
+
module Matchers
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module AssociationMatchers
|
|
5
|
+
# @private
|
|
6
|
+
class OptionVerifier
|
|
7
|
+
delegate :reflection, to: :reflector
|
|
8
|
+
|
|
9
|
+
DEFAULT_VALUE_OF_OPTIONS = {
|
|
10
|
+
has_many: {
|
|
11
|
+
validate: true,
|
|
12
|
+
},
|
|
13
|
+
}.freeze
|
|
14
|
+
RELATION_OPTIONS = [:conditions, :order].freeze
|
|
15
|
+
|
|
16
|
+
def initialize(reflector)
|
|
17
|
+
@reflector = reflector
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def correct_for_string?(name, expected_value)
|
|
21
|
+
correct_for?(:string, name, expected_value)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def correct_for_boolean?(name, expected_value)
|
|
25
|
+
correct_for?(:boolean, name, expected_value)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def correct_for_hash?(name, expected_value)
|
|
29
|
+
correct_for?(:hash, name, expected_value)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def correct_for_constant?(name, expected_unresolved_value)
|
|
33
|
+
correct_for?(:constant, name, expected_unresolved_value)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def correct_for_relation_clause?(name, expected_value)
|
|
37
|
+
correct_for?(:relation_clause, name, expected_value)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def correct_for?(*args)
|
|
41
|
+
expected_value, name, type = args.reverse
|
|
42
|
+
|
|
43
|
+
if expected_value.nil?
|
|
44
|
+
true
|
|
45
|
+
else
|
|
46
|
+
type_cast_expected_value = type_cast(
|
|
47
|
+
type,
|
|
48
|
+
expected_value_for(type, name, expected_value),
|
|
49
|
+
)
|
|
50
|
+
actual_value = type_cast(type, actual_value_for(name))
|
|
51
|
+
type_cast_expected_value == actual_value
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def actual_value_for(name)
|
|
56
|
+
if RELATION_OPTIONS.include?(name)
|
|
57
|
+
actual_value_for_relation_clause(name)
|
|
58
|
+
else
|
|
59
|
+
method_name = "actual_value_for_#{name}"
|
|
60
|
+
if respond_to?(method_name, true)
|
|
61
|
+
__send__(method_name)
|
|
62
|
+
else
|
|
63
|
+
actual_value_for_option(name)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
protected
|
|
69
|
+
|
|
70
|
+
attr_reader :reflector
|
|
71
|
+
|
|
72
|
+
def type_cast(type, value)
|
|
73
|
+
case type
|
|
74
|
+
when :string, :relation_clause
|
|
75
|
+
value.to_s
|
|
76
|
+
when :boolean
|
|
77
|
+
!!value
|
|
78
|
+
when :hash
|
|
79
|
+
Hash(value).stringify_keys
|
|
80
|
+
else
|
|
81
|
+
value
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def expected_value_for(type, name, value)
|
|
86
|
+
if RELATION_OPTIONS.include?(name)
|
|
87
|
+
expected_value_for_relation_clause(name, value)
|
|
88
|
+
elsif type == :constant
|
|
89
|
+
expected_value_for_constant(value)
|
|
90
|
+
else
|
|
91
|
+
value
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def expected_value_for_relation_clause(name, value)
|
|
96
|
+
relation = reflector.build_relation_with_clause(name, value)
|
|
97
|
+
reflector.extract_relation_clause_from(relation, name)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def expected_value_for_constant(name)
|
|
101
|
+
namespace = Shoulda::Matchers::Util.deconstantize(
|
|
102
|
+
reflector.model_class.to_s,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
["#{namespace}::#{name}", name].each do |path|
|
|
106
|
+
constant = Shoulda::Matchers::Util.safe_constantize(path)
|
|
107
|
+
|
|
108
|
+
if constant
|
|
109
|
+
return constant
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def actual_value_for_relation_clause(name)
|
|
115
|
+
reflector.extract_relation_clause_from(
|
|
116
|
+
reflector.association_relation,
|
|
117
|
+
name,
|
|
118
|
+
)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def actual_value_for_class_name
|
|
122
|
+
reflector.associated_class
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def actual_value_for_strict_loading
|
|
126
|
+
reflection.strict_loading?
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def actual_value_for_option(name)
|
|
130
|
+
option_value = reflection.options[name]
|
|
131
|
+
|
|
132
|
+
if option_value.nil?
|
|
133
|
+
DEFAULT_VALUE_OF_OPTIONS.dig(reflection.macro, name)
|
|
134
|
+
else
|
|
135
|
+
option_value
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
module Shoulda
|
|
2
|
+
module Matchers
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module AssociationMatchers
|
|
5
|
+
# @private
|
|
6
|
+
class OptionalMatcher
|
|
7
|
+
attr_reader :missing_option
|
|
8
|
+
|
|
9
|
+
def initialize(attribute_name, optional)
|
|
10
|
+
@attribute_name = attribute_name
|
|
11
|
+
@optional = optional
|
|
12
|
+
@submatcher = ActiveModel::AllowValueMatcher.new(nil).
|
|
13
|
+
for(attribute_name)
|
|
14
|
+
@missing_option = ''
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def description
|
|
18
|
+
"optional: #{optional}"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def matches?(subject)
|
|
22
|
+
if submatcher_passes?(subject)
|
|
23
|
+
true
|
|
24
|
+
else
|
|
25
|
+
@missing_option = build_missing_option
|
|
26
|
+
|
|
27
|
+
false
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
attr_reader :attribute_name, :optional, :submatcher
|
|
34
|
+
|
|
35
|
+
def submatcher_passes?(subject)
|
|
36
|
+
if optional
|
|
37
|
+
submatcher.matches?(subject)
|
|
38
|
+
else
|
|
39
|
+
submatcher.does_not_match?(subject)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def build_missing_option
|
|
44
|
+
String.new('and for the record ').tap do |missing_option_string|
|
|
45
|
+
missing_option_string <<
|
|
46
|
+
if optional
|
|
47
|
+
'not to '
|
|
48
|
+
else
|
|
49
|
+
'to '
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
missing_option_string << 'fail validation if '\
|
|
53
|
+
":#{attribute_name} is unset; i.e., either the association "\
|
|
54
|
+
'should have been defined with `optional: '\
|
|
55
|
+
"#{optional.inspect}`, or there "
|
|
56
|
+
|
|
57
|
+
missing_option_string <<
|
|
58
|
+
if optional
|
|
59
|
+
'should not '
|
|
60
|
+
else
|
|
61
|
+
'should '
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
missing_option_string << "be a presence validation on :#{attribute_name}"
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|