shoulda-matchers 3.1.0 → 5.2.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.
Files changed (288) hide show
  1. checksums.yaml +5 -5
  2. data/{MIT-LICENSE → LICENSE} +1 -1
  3. data/README.md +407 -232
  4. data/docs/errors/NonCaseSwappableValueError.md +2 -2
  5. data/lib/shoulda/matchers/action_controller/callback_matcher.rb +7 -80
  6. data/lib/shoulda/matchers/action_controller/filter_param_matcher.rb +4 -3
  7. data/lib/shoulda/matchers/action_controller/flash_store.rb +2 -4
  8. data/lib/shoulda/matchers/action_controller/permit_matcher.rb +36 -30
  9. data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +8 -10
  10. data/lib/shoulda/matchers/action_controller/render_template_matcher.rb +7 -9
  11. data/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +18 -15
  12. data/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb +3 -2
  13. data/lib/shoulda/matchers/action_controller/respond_with_matcher.rb +3 -3
  14. data/lib/shoulda/matchers/action_controller/route_matcher.rb +88 -29
  15. data/lib/shoulda/matchers/action_controller/route_params.rb +2 -2
  16. data/lib/shoulda/matchers/action_controller/set_flash_matcher.rb +4 -4
  17. data/lib/shoulda/matchers/action_controller/set_session_matcher.rb +3 -3
  18. data/lib/shoulda/matchers/action_controller/set_session_or_flash_matcher.rb +19 -13
  19. data/lib/shoulda/matchers/action_controller.rb +2 -0
  20. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_changed_value_error.rb +1 -1
  21. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb +5 -9
  22. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter_and_validator.rb +2 -2
  23. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters.rb +1 -1
  24. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters_and_validators.rb +1 -1
  25. data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +42 -39
  26. data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +1 -1
  27. data/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb +52 -26
  28. data/lib/shoulda/matchers/active_model/helpers.rb +2 -2
  29. data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +32 -30
  30. data/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +2 -1
  31. data/lib/shoulda/matchers/active_model/qualifiers/allow_blank.rb +26 -0
  32. data/lib/shoulda/matchers/active_model/qualifiers/allow_nil.rb +26 -0
  33. data/lib/shoulda/matchers/active_model/qualifiers/ignoring_interference_by_writer.rb +1 -1
  34. data/lib/shoulda/matchers/active_model/qualifiers.rb +2 -0
  35. data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +30 -6
  36. data/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +8 -3
  37. data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +31 -16
  38. data/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb +52 -16
  39. data/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +137 -84
  40. data/lib/shoulda/matchers/active_model/validate_length_of_matcher.rb +159 -46
  41. data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +130 -66
  42. data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +251 -24
  43. data/lib/shoulda/matchers/active_model/validation_matcher/build_description.rb +12 -9
  44. data/lib/shoulda/matchers/active_model/validation_matcher.rb +38 -6
  45. data/lib/shoulda/matchers/active_model/validation_message_finder.rb +2 -4
  46. data/lib/shoulda/matchers/active_model/validator.rb +4 -9
  47. data/lib/shoulda/matchers/active_model.rb +3 -5
  48. data/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb +10 -7
  49. data/lib/shoulda/matchers/active_record/association_matcher.rb +386 -111
  50. data/lib/shoulda/matchers/active_record/association_matchers/counter_cache_matcher.rb +5 -2
  51. data/lib/shoulda/matchers/active_record/association_matchers/dependent_matcher.rb +4 -4
  52. data/lib/shoulda/matchers/active_record/association_matchers/inverse_of_matcher.rb +1 -1
  53. data/lib/shoulda/matchers/active_record/association_matchers/join_table_matcher.rb +11 -6
  54. data/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +14 -15
  55. data/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +30 -8
  56. data/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb +34 -11
  57. data/lib/shoulda/matchers/active_record/association_matchers/optional_matcher.rb +69 -0
  58. data/lib/shoulda/matchers/active_record/association_matchers/order_matcher.rb +1 -1
  59. data/lib/shoulda/matchers/active_record/association_matchers/required_matcher.rb +74 -0
  60. data/lib/shoulda/matchers/active_record/association_matchers/source_matcher.rb +3 -2
  61. data/lib/shoulda/matchers/active_record/association_matchers/through_matcher.rb +7 -5
  62. data/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +458 -42
  63. data/lib/shoulda/matchers/active_record/have_attached_matcher.rb +185 -0
  64. data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +63 -23
  65. data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +164 -48
  66. data/lib/shoulda/matchers/active_record/have_implicit_order_column.rb +106 -0
  67. data/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +13 -11
  68. data/lib/shoulda/matchers/active_record/have_rich_text_matcher.rb +83 -0
  69. data/lib/shoulda/matchers/active_record/have_secure_token_matcher.rb +132 -0
  70. data/lib/shoulda/matchers/active_record/serialize_matcher.rb +18 -18
  71. data/lib/shoulda/matchers/active_record/uniqueness/test_model_creator.rb +1 -3
  72. data/lib/shoulda/matchers/active_record/uniqueness/test_models.rb +0 -2
  73. data/lib/shoulda/matchers/active_record/uniqueness.rb +1 -1
  74. data/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +430 -200
  75. data/lib/shoulda/matchers/active_record.rb +28 -20
  76. data/lib/shoulda/matchers/configuration.rb +12 -1
  77. data/lib/shoulda/matchers/doublespeak/double.rb +1 -1
  78. data/lib/shoulda/matchers/doublespeak/double_collection.rb +3 -3
  79. data/lib/shoulda/matchers/doublespeak/double_implementation_registry.rb +8 -5
  80. data/lib/shoulda/matchers/doublespeak/object_double.rb +6 -2
  81. data/lib/shoulda/matchers/doublespeak/stub_implementation.rb +1 -5
  82. data/lib/shoulda/matchers/doublespeak/world.rb +2 -2
  83. data/lib/shoulda/matchers/doublespeak.rb +2 -1
  84. data/lib/shoulda/matchers/error.rb +1 -1
  85. data/lib/shoulda/matchers/independent/delegate_method_matcher.rb +109 -29
  86. data/lib/shoulda/matchers/independent.rb +2 -2
  87. data/lib/shoulda/matchers/integrations/configuration.rb +8 -4
  88. data/lib/shoulda/matchers/integrations/libraries/action_controller.rb +1 -1
  89. data/lib/shoulda/matchers/integrations/libraries/rails.rb +2 -2
  90. data/lib/shoulda/matchers/integrations/test_frameworks/active_support_test_case.rb +1 -1
  91. data/lib/shoulda/matchers/integrations/test_frameworks/minitest_4.rb +1 -1
  92. data/lib/shoulda/matchers/integrations/test_frameworks/minitest_5.rb +1 -1
  93. data/lib/shoulda/matchers/integrations/test_frameworks/missing_test_framework.rb +1 -1
  94. data/lib/shoulda/matchers/integrations/test_frameworks/test_unit.rb +1 -1
  95. data/lib/shoulda/matchers/rails_shim.rb +172 -51
  96. data/lib/shoulda/matchers/routing.rb +2 -2
  97. data/lib/shoulda/matchers/util/word_wrap.rb +17 -12
  98. data/lib/shoulda/matchers/util.rb +39 -5
  99. data/lib/shoulda/matchers/version.rb +1 -1
  100. data/lib/shoulda/matchers/warn.rb +4 -3
  101. data/shoulda-matchers.gemspec +33 -15
  102. metadata +31 -338
  103. data/.gitignore +0 -12
  104. data/.hound.yml +0 -3
  105. data/.hound_config/ruby.yml +0 -12
  106. data/.travis.yml +0 -19
  107. data/.yardopts +0 -10
  108. data/Appraisals +0 -73
  109. data/CONTRIBUTING.md +0 -101
  110. data/Gemfile +0 -15
  111. data/Gemfile.lock +0 -70
  112. data/NEWS.md +0 -986
  113. data/Rakefile +0 -39
  114. data/custom_plan.rb +0 -88
  115. data/doc_config/gh-pages/index.html.erb +0 -9
  116. data/doc_config/yard/setup.rb +0 -22
  117. data/doc_config/yard/templates/default/fulldoc/html/css/bootstrap.css +0 -5967
  118. data/doc_config/yard/templates/default/fulldoc/html/css/full_list.css +0 -12
  119. data/doc_config/yard/templates/default/fulldoc/html/css/global.css +0 -62
  120. data/doc_config/yard/templates/default/fulldoc/html/css/solarized.css +0 -69
  121. data/doc_config/yard/templates/default/fulldoc/html/css/style.css +0 -312
  122. data/doc_config/yard/templates/default/fulldoc/html/full_list.erb +0 -32
  123. data/doc_config/yard/templates/default/fulldoc/html/full_list_class.erb +0 -1
  124. data/doc_config/yard/templates/default/fulldoc/html/full_list_method.erb +0 -8
  125. data/doc_config/yard/templates/default/fulldoc/html/js/app.js +0 -298
  126. data/doc_config/yard/templates/default/fulldoc/html/js/full_list.js +0 -1
  127. data/doc_config/yard/templates/default/fulldoc/html/js/jquery.stickyheaders.js +0 -289
  128. data/doc_config/yard/templates/default/fulldoc/html/js/underscore.min.js +0 -6
  129. data/doc_config/yard/templates/default/fulldoc/html/setup.rb +0 -8
  130. data/doc_config/yard/templates/default/layout/html/breadcrumb.erb +0 -14
  131. data/doc_config/yard/templates/default/layout/html/fonts.erb +0 -1
  132. data/doc_config/yard/templates/default/layout/html/footer.erb +0 -6
  133. data/doc_config/yard/templates/default/layout/html/layout.erb +0 -23
  134. data/doc_config/yard/templates/default/layout/html/search.erb +0 -13
  135. data/doc_config/yard/templates/default/layout/html/setup.rb +0 -40
  136. data/doc_config/yard/templates/default/method_details/html/source.erb +0 -10
  137. data/doc_config/yard/templates/default/module/html/box_info.erb +0 -31
  138. data/gemfiles/4.0.0.gemfile +0 -38
  139. data/gemfiles/4.0.0.gemfile.lock +0 -223
  140. data/gemfiles/4.0.1.gemfile +0 -38
  141. data/gemfiles/4.0.1.gemfile.lock +0 -225
  142. data/gemfiles/4.1.gemfile +0 -38
  143. data/gemfiles/4.1.gemfile.lock +0 -220
  144. data/gemfiles/4.2.gemfile +0 -38
  145. data/gemfiles/4.2.gemfile.lock +0 -243
  146. data/lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb +0 -159
  147. data/lib/shoulda/matchers/independent/delegate_method_matcher/stubbed_target.rb +0 -37
  148. data/script/SUPPORTED_VERSIONS +0 -1
  149. data/script/install_gems_in_all_appraisals +0 -14
  150. data/script/run_all_tests +0 -14
  151. data/script/update_gem_in_all_appraisals +0 -15
  152. data/script/update_gems_in_all_appraisals +0 -14
  153. data/spec/acceptance/active_model_integration_spec.rb +0 -23
  154. data/spec/acceptance/independent_matchers_spec.rb +0 -125
  155. data/spec/acceptance/multiple_libraries_integration_spec.rb +0 -55
  156. data/spec/acceptance/rails_integration_spec.rb +0 -156
  157. data/spec/acceptance_spec_helper.rb +0 -23
  158. data/spec/doublespeak_spec_helper.rb +0 -2
  159. data/spec/report_warnings.rb +0 -7
  160. data/spec/spec_helper.rb +0 -21
  161. data/spec/support/acceptance/adds_shoulda_matchers_to_project.rb +0 -133
  162. data/spec/support/acceptance/helpers/active_model_helpers.rb +0 -11
  163. data/spec/support/acceptance/helpers/array_helpers.rb +0 -13
  164. data/spec/support/acceptance/helpers/base_helpers.rb +0 -19
  165. data/spec/support/acceptance/helpers/command_helpers.rb +0 -55
  166. data/spec/support/acceptance/helpers/file_helpers.rb +0 -19
  167. data/spec/support/acceptance/helpers/gem_helpers.rb +0 -31
  168. data/spec/support/acceptance/helpers/minitest_helpers.rb +0 -11
  169. data/spec/support/acceptance/helpers/n_unit_helpers.rb +0 -25
  170. data/spec/support/acceptance/helpers/pluralization_helpers.rb +0 -13
  171. data/spec/support/acceptance/helpers/rails_version_helpers.rb +0 -11
  172. data/spec/support/acceptance/helpers/rspec_helpers.rb +0 -24
  173. data/spec/support/acceptance/helpers/ruby_version_helpers.rb +0 -9
  174. data/spec/support/acceptance/helpers/step_helpers.rb +0 -127
  175. data/spec/support/acceptance/helpers.rb +0 -31
  176. data/spec/support/acceptance/matchers/have_output.rb +0 -31
  177. data/spec/support/acceptance/matchers/indicate_number_of_tests_was_run_matcher.rb +0 -55
  178. data/spec/support/acceptance/matchers/indicate_that_tests_were_run_matcher.rb +0 -103
  179. data/spec/support/tests/bundle.rb +0 -94
  180. data/spec/support/tests/command_runner.rb +0 -230
  181. data/spec/support/tests/current_bundle.rb +0 -61
  182. data/spec/support/tests/database.rb +0 -28
  183. data/spec/support/tests/database_adapters/postgresql.rb +0 -25
  184. data/spec/support/tests/database_adapters/sqlite3.rb +0 -26
  185. data/spec/support/tests/database_configuration.rb +0 -33
  186. data/spec/support/tests/database_configuration_registry.rb +0 -28
  187. data/spec/support/tests/filesystem.rb +0 -100
  188. data/spec/support/tests/version.rb +0 -45
  189. data/spec/support/unit/active_record/create_table.rb +0 -54
  190. data/spec/support/unit/attribute.rb +0 -47
  191. data/spec/support/unit/capture.rb +0 -40
  192. data/spec/support/unit/change_value.rb +0 -111
  193. data/spec/support/unit/create_model_arguments/basic.rb +0 -135
  194. data/spec/support/unit/create_model_arguments/has_many.rb +0 -15
  195. data/spec/support/unit/create_model_arguments/uniqueness_matcher.rb +0 -74
  196. data/spec/support/unit/helpers/active_model_helpers.rb +0 -27
  197. data/spec/support/unit/helpers/active_model_versions.rb +0 -28
  198. data/spec/support/unit/helpers/active_record_versions.rb +0 -24
  199. data/spec/support/unit/helpers/active_resource_builder.rb +0 -27
  200. data/spec/support/unit/helpers/allow_value_matcher_helpers.rb +0 -15
  201. data/spec/support/unit/helpers/class_builder.rb +0 -90
  202. data/spec/support/unit/helpers/column_type_helpers.rb +0 -26
  203. data/spec/support/unit/helpers/confirmation_matcher_helpers.rb +0 -17
  204. data/spec/support/unit/helpers/controller_builder.rb +0 -63
  205. data/spec/support/unit/helpers/database_helpers.rb +0 -20
  206. data/spec/support/unit/helpers/i18n_faker.rb +0 -15
  207. data/spec/support/unit/helpers/mailer_builder.rb +0 -12
  208. data/spec/support/unit/helpers/model_builder.rb +0 -114
  209. data/spec/support/unit/helpers/rails_versions.rb +0 -28
  210. data/spec/support/unit/helpers/validation_matcher_scenario_helpers.rb +0 -44
  211. data/spec/support/unit/i18n.rb +0 -7
  212. data/spec/support/unit/load_environment.rb +0 -12
  213. data/spec/support/unit/matchers/deprecate.rb +0 -60
  214. data/spec/support/unit/matchers/fail_with_message_including_matcher.rb +0 -51
  215. data/spec/support/unit/matchers/fail_with_message_matcher.rb +0 -62
  216. data/spec/support/unit/matchers/print_warning_including.rb +0 -59
  217. data/spec/support/unit/model_creation_strategies/active_model.rb +0 -111
  218. data/spec/support/unit/model_creation_strategies/active_record.rb +0 -77
  219. data/spec/support/unit/model_creators/active_model.rb +0 -39
  220. data/spec/support/unit/model_creators/active_record/has_and_belongs_to_many.rb +0 -95
  221. data/spec/support/unit/model_creators/active_record/has_many.rb +0 -67
  222. data/spec/support/unit/model_creators/active_record/uniqueness_matcher.rb +0 -42
  223. data/spec/support/unit/model_creators/active_record.rb +0 -43
  224. data/spec/support/unit/model_creators/basic.rb +0 -97
  225. data/spec/support/unit/model_creators.rb +0 -19
  226. data/spec/support/unit/rails_application.rb +0 -126
  227. data/spec/support/unit/record_builder_with_i18n_validation_message.rb +0 -69
  228. data/spec/support/unit/record_validating_confirmation_builder.rb +0 -51
  229. data/spec/support/unit/record_with_different_error_attribute_builder.rb +0 -92
  230. data/spec/support/unit/shared_examples/ignoring_interference_by_writer.rb +0 -79
  231. data/spec/support/unit/shared_examples/numerical_submatcher.rb +0 -17
  232. data/spec/support/unit/shared_examples/set_session_or_flash.rb +0 -360
  233. data/spec/support/unit/validation_matcher_scenario.rb +0 -62
  234. data/spec/unit/shoulda/matchers/action_controller/callback_matcher_spec.rb +0 -82
  235. data/spec/unit/shoulda/matchers/action_controller/filter_param_matcher_spec.rb +0 -28
  236. data/spec/unit/shoulda/matchers/action_controller/permit_matcher_spec.rb +0 -592
  237. data/spec/unit/shoulda/matchers/action_controller/redirect_to_matcher_spec.rb +0 -42
  238. data/spec/unit/shoulda/matchers/action_controller/render_template_matcher_spec.rb +0 -76
  239. data/spec/unit/shoulda/matchers/action_controller/render_with_layout_matcher_spec.rb +0 -62
  240. data/spec/unit/shoulda/matchers/action_controller/rescue_from_matcher_spec.rb +0 -90
  241. data/spec/unit/shoulda/matchers/action_controller/respond_with_matcher_spec.rb +0 -31
  242. data/spec/unit/shoulda/matchers/action_controller/route_matcher_spec.rb +0 -330
  243. data/spec/unit/shoulda/matchers/action_controller/route_params_spec.rb +0 -30
  244. data/spec/unit/shoulda/matchers/action_controller/set_flash_matcher_spec.rb +0 -67
  245. data/spec/unit/shoulda/matchers/action_controller/set_session_matcher_spec.rb +0 -17
  246. data/spec/unit/shoulda/matchers/action_controller/set_session_or_flash_matcher_spec.rb +0 -562
  247. data/spec/unit/shoulda/matchers/active_model/allow_mass_assignment_of_matcher_spec.rb +0 -115
  248. data/spec/unit/shoulda/matchers/active_model/allow_value_matcher_spec.rb +0 -823
  249. data/spec/unit/shoulda/matchers/active_model/disallow_value_matcher_spec.rb +0 -86
  250. data/spec/unit/shoulda/matchers/active_model/have_secure_password_matcher_spec.rb +0 -20
  251. data/spec/unit/shoulda/matchers/active_model/helpers_spec.rb +0 -162
  252. data/spec/unit/shoulda/matchers/active_model/validate_absence_of_matcher_spec.rb +0 -266
  253. data/spec/unit/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb +0 -91
  254. data/spec/unit/shoulda/matchers/active_model/validate_confirmation_of_matcher_spec.rb +0 -149
  255. data/spec/unit/shoulda/matchers/active_model/validate_exclusion_of_matcher_spec.rb +0 -207
  256. data/spec/unit/shoulda/matchers/active_model/validate_inclusion_of_matcher_spec.rb +0 -1015
  257. data/spec/unit/shoulda/matchers/active_model/validate_length_of_matcher_spec.rb +0 -288
  258. data/spec/unit/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +0 -1837
  259. data/spec/unit/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +0 -380
  260. data/spec/unit/shoulda/matchers/active_record/accept_nested_attributes_for_matcher_spec.rb +0 -107
  261. data/spec/unit/shoulda/matchers/active_record/association_matcher_spec.rb +0 -1242
  262. data/spec/unit/shoulda/matchers/active_record/association_matchers/model_reflection_spec.rb +0 -251
  263. data/spec/unit/shoulda/matchers/active_record/define_enum_for_matcher_spec.rb +0 -168
  264. data/spec/unit/shoulda/matchers/active_record/have_db_column_matcher_spec.rb +0 -111
  265. data/spec/unit/shoulda/matchers/active_record/have_db_index_matcher_spec.rb +0 -85
  266. data/spec/unit/shoulda/matchers/active_record/have_readonly_attributes_matcher_spec.rb +0 -41
  267. data/spec/unit/shoulda/matchers/active_record/serialize_matcher_spec.rb +0 -86
  268. data/spec/unit/shoulda/matchers/active_record/validate_uniqueness_of_matcher_spec.rb +0 -1418
  269. data/spec/unit/shoulda/matchers/doublespeak/double_collection_spec.rb +0 -190
  270. data/spec/unit/shoulda/matchers/doublespeak/double_implementation_registry_spec.rb +0 -21
  271. data/spec/unit/shoulda/matchers/doublespeak/double_spec.rb +0 -271
  272. data/spec/unit/shoulda/matchers/doublespeak/object_double_spec.rb +0 -77
  273. data/spec/unit/shoulda/matchers/doublespeak/proxy_implementation_spec.rb +0 -72
  274. data/spec/unit/shoulda/matchers/doublespeak/stub_implementation_spec.rb +0 -101
  275. data/spec/unit/shoulda/matchers/doublespeak/world_spec.rb +0 -80
  276. data/spec/unit/shoulda/matchers/doublespeak_spec.rb +0 -27
  277. data/spec/unit/shoulda/matchers/independent/delegate_method_matcher/stubbed_target_spec.rb +0 -43
  278. data/spec/unit/shoulda/matchers/independent/delegate_method_matcher_spec.rb +0 -517
  279. data/spec/unit/shoulda/matchers/routing/route_matcher_spec.rb +0 -242
  280. data/spec/unit/shoulda/matchers/util/word_wrap_spec.rb +0 -252
  281. data/spec/unit_spec_helper.rb +0 -46
  282. data/spec/warnings_spy/filesystem.rb +0 -45
  283. data/spec/warnings_spy/partitioner.rb +0 -36
  284. data/spec/warnings_spy/reader.rb +0 -53
  285. data/spec/warnings_spy/reporter.rb +0 -88
  286. data/spec/warnings_spy.rb +0 -64
  287. data/tasks/documentation.rb +0 -199
  288. data/zeus.json +0 -11
@@ -11,7 +11,7 @@ module Shoulda
11
11
  # end
12
12
  #
13
13
  # # RSpec
14
- # describe Person do
14
+ # RSpec.describe Person, type: :model do
15
15
  # it { should belong_to(:organization) }
16
16
  # end
17
17
  #
@@ -28,7 +28,7 @@ module Shoulda
28
28
  # end
29
29
  #
30
30
  # # RSpec
31
- # describe Comment do
31
+ # RSpec.describe Comment, type: :model do
32
32
  # it { should belong_to(:commentable) }
33
33
  # end
34
34
  #
@@ -49,7 +49,7 @@ module Shoulda
49
49
  # end
50
50
  #
51
51
  # # RSpec
52
- # describe Person do
52
+ # RSpec.describe Person, type: :model do
53
53
  # it do
54
54
  # should belong_to(:family).
55
55
  # conditions(everyone_is_perfect: false)
@@ -72,7 +72,7 @@ module Shoulda
72
72
  # end
73
73
  #
74
74
  # # RSpec
75
- # describe Person do
75
+ # RSpec.describe Person, type: :model do
76
76
  # it { should belong_to(:previous_company).order('hired_on desc') }
77
77
  # end
78
78
  #
@@ -91,7 +91,7 @@ module Shoulda
91
91
  # end
92
92
  #
93
93
  # # RSpec
94
- # describe Person do
94
+ # RSpec.describe Person, type: :model do
95
95
  # it { should belong_to(:ancient_city).class_name('City') }
96
96
  # end
97
97
  #
@@ -109,7 +109,7 @@ module Shoulda
109
109
  # end
110
110
  #
111
111
  # # RSpec
112
- # describe Person do
112
+ # RSpec.describe Person, type: :model do
113
113
  # it do
114
114
  # should belong_to(:great_country).
115
115
  # with_primary_key('country_id')
@@ -131,7 +131,7 @@ module Shoulda
131
131
  # end
132
132
  #
133
133
  # # RSpec
134
- # describe Person do
134
+ # RSpec.describe Person, type: :model do
135
135
  # it do
136
136
  # should belong_to(:great_country).
137
137
  # with_foreign_key('country_id')
@@ -153,7 +153,7 @@ module Shoulda
153
153
  # end
154
154
  #
155
155
  # # RSpec
156
- # describe Person do
156
+ # RSpec.describe Person, type: :model do
157
157
  # it { should belong_to(:world).dependent(:destroy) }
158
158
  # end
159
159
  #
@@ -165,7 +165,7 @@ module Shoulda
165
165
  # To assert that *any* `:dependent` option was specified, use `true`:
166
166
  #
167
167
  # # RSpec
168
- # describe Person do
168
+ # RSpec.describe Person, type: :model do
169
169
  # it { should belong_to(:world).dependent(true) }
170
170
  # end
171
171
  #
@@ -176,7 +176,7 @@ module Shoulda
176
176
  # end
177
177
  #
178
178
  # # RSpec
179
- # describe Person do
179
+ # RSpec.describe Person, type: :model do
180
180
  # it { should belong_to(:company).dependent(false) }
181
181
  # end
182
182
  #
@@ -190,7 +190,7 @@ module Shoulda
190
190
  # end
191
191
  #
192
192
  # # RSpec
193
- # describe Person do
193
+ # RSpec.describe Person, type: :model do
194
194
  # it { should belong_to(:organization).counter_cache(true) }
195
195
  # end
196
196
  #
@@ -208,7 +208,7 @@ module Shoulda
208
208
  # end
209
209
  #
210
210
  # # RSpec
211
- # describe Person do
211
+ # RSpec.describe Person, type: :model do
212
212
  # it { should belong_to(:organization).touch(true) }
213
213
  # end
214
214
  #
@@ -217,7 +217,7 @@ module Shoulda
217
217
  # should belong_to(:organization).touch(true)
218
218
  # end
219
219
  #
220
- # #### autosave
220
+ # ##### autosave
221
221
  #
222
222
  # Use `autosave` to assert that the `:autosave` option was specified.
223
223
  #
@@ -226,7 +226,7 @@ module Shoulda
226
226
  # end
227
227
  #
228
228
  # # RSpec
229
- # describe Account do
229
+ # RSpec.describe Account, type: :model do
230
230
  # it { should belong_to(:bank).autosave(true) }
231
231
  # end
232
232
  #
@@ -253,6 +253,73 @@ module Shoulda
253
253
  # should belong_to(:organization).inverse_of(:employees)
254
254
  # end
255
255
  #
256
+ # ##### required
257
+ #
258
+ # Use `required` to assert that the association is not allowed to be nil.
259
+ # (Enabled by default in Rails 5+.)
260
+ #
261
+ # class Person < ActiveRecord::Base
262
+ # belongs_to :organization, required: true
263
+ # end
264
+ #
265
+ # # RSpec
266
+ # describe Person
267
+ # it { should belong_to(:organization).required }
268
+ # end
269
+ #
270
+ # # Minitest (Shoulda)
271
+ # class PersonTest < ActiveSupport::TestCase
272
+ # should belong_to(:organization).required
273
+ # end
274
+ #
275
+ # ##### without_validating_presence
276
+ #
277
+ # Use `without_validating_presence` with `belong_to` to prevent the
278
+ # matcher from checking whether the association disallows nil (Rails 5+
279
+ # only). This can be helpful if you have a custom hook that always sets
280
+ # the association to a meaningful value:
281
+ #
282
+ # class Person < ActiveRecord::Base
283
+ # belongs_to :organization
284
+ #
285
+ # before_validation :autoassign_organization
286
+ #
287
+ # private
288
+ #
289
+ # def autoassign_organization
290
+ # self.organization = Organization.create!
291
+ # end
292
+ # end
293
+ #
294
+ # # RSpec
295
+ # describe Person
296
+ # it { should belong_to(:organization).without_validating_presence }
297
+ # end
298
+ #
299
+ # # Minitest (Shoulda)
300
+ # class PersonTest < ActiveSupport::TestCase
301
+ # should belong_to(:organization).without_validating_presence
302
+ # end
303
+ #
304
+ # ##### optional
305
+ #
306
+ # Use `optional` to assert that the association is allowed to be nil.
307
+ # (Rails 5+ only.)
308
+ #
309
+ # class Person < ActiveRecord::Base
310
+ # belongs_to :organization, optional: true
311
+ # end
312
+ #
313
+ # # RSpec
314
+ # describe Person
315
+ # it { should belong_to(:organization).optional }
316
+ # end
317
+ #
318
+ # # Minitest (Shoulda)
319
+ # class PersonTest < ActiveSupport::TestCase
320
+ # should belong_to(:organization).optional
321
+ # end
322
+ #
256
323
  # @return [AssociationMatcher]
257
324
  #
258
325
  def belong_to(name)
@@ -267,7 +334,7 @@ module Shoulda
267
334
  # end
268
335
  #
269
336
  # # RSpec
270
- # describe Person do
337
+ # RSpec.describe Person, type: :model do
271
338
  # it { should have_many(:friends) }
272
339
  # end
273
340
  #
@@ -284,7 +351,7 @@ module Shoulda
284
351
  # end
285
352
  #
286
353
  # # RSpec
287
- # describe Person do
354
+ # RSpec.describe Person, type: :model do
288
355
  # it { should have_many(:pictures) }
289
356
  # end
290
357
  #
@@ -305,7 +372,7 @@ module Shoulda
305
372
  # end
306
373
  #
307
374
  # # RSpec
308
- # describe Person do
375
+ # RSpec.describe Person, type: :model do
309
376
  # it { should have_many(:coins).conditions(quality: 'mint') }
310
377
  # end
311
378
  #
@@ -324,7 +391,7 @@ module Shoulda
324
391
  # end
325
392
  #
326
393
  # # RSpec
327
- # describe Person do
394
+ # RSpec.describe Person, type: :model do
328
395
  # it { should have_many(:shirts).order('color') }
329
396
  # end
330
397
  #
@@ -343,7 +410,7 @@ module Shoulda
343
410
  # end
344
411
  #
345
412
  # # RSpec
346
- # describe Person do
413
+ # RSpec.describe Person, type: :model do
347
414
  # it { should have_many(:hopes).class_name('Dream') }
348
415
  # end
349
416
  #
@@ -361,7 +428,7 @@ module Shoulda
361
428
  # end
362
429
  #
363
430
  # # RSpec
364
- # describe Person do
431
+ # RSpec.describe Person, type: :model do
365
432
  # it { should have_many(:worries).with_primary_key('worrier_id') }
366
433
  # end
367
434
  #
@@ -379,7 +446,7 @@ module Shoulda
379
446
  # end
380
447
  #
381
448
  # # RSpec
382
- # describe Person do
449
+ # RSpec.describe Person, type: :model do
383
450
  # it { should have_many(:worries).with_foreign_key('worrier_id') }
384
451
  # end
385
452
  #
@@ -397,7 +464,7 @@ module Shoulda
397
464
  # end
398
465
  #
399
466
  # # RSpec
400
- # describe Person do
467
+ # RSpec.describe Person, type: :model do
401
468
  # it { should have_many(:secret_documents).dependent(:destroy) }
402
469
  # end
403
470
  #
@@ -416,7 +483,7 @@ module Shoulda
416
483
  # end
417
484
  #
418
485
  # # RSpec
419
- # describe Person do
486
+ # RSpec.describe Person, type: :model do
420
487
  # it { should have_many(:acquaintances).through(:friends) }
421
488
  # end
422
489
  #
@@ -435,7 +502,7 @@ module Shoulda
435
502
  # end
436
503
  #
437
504
  # # RSpec
438
- # describe Person do
505
+ # RSpec.describe Person, type: :model do
439
506
  # it do
440
507
  # should have_many(:job_offers).
441
508
  # through(:friends).
@@ -459,7 +526,7 @@ module Shoulda
459
526
  # end
460
527
  #
461
528
  # # RSpec
462
- # describe Person do
529
+ # RSpec.describe Person, type: :model do
463
530
  # it { should have_many(:ideas).validate(false) }
464
531
  # end
465
532
  #
@@ -468,7 +535,7 @@ module Shoulda
468
535
  # should have_many(:ideas).validate(false)
469
536
  # end
470
537
  #
471
- # #### autosave
538
+ # ##### autosave
472
539
  #
473
540
  # Use `autosave` to assert that the `:autosave` option was specified.
474
541
  #
@@ -477,7 +544,7 @@ module Shoulda
477
544
  # end
478
545
  #
479
546
  # # RSpec
480
- # describe Player do
547
+ # RSpec.describe Player, type: :model do
481
548
  # it { should have_many(:games).autosave(true) }
482
549
  # end
483
550
  #
@@ -486,6 +553,43 @@ module Shoulda
486
553
  # should have_many(:games).autosave(true)
487
554
  # end
488
555
  #
556
+ # ##### index_errors
557
+ #
558
+ # Use `index_errors` to assert that the `:index_errors` option was
559
+ # specified.
560
+ #
561
+ # class Player < ActiveRecord::Base
562
+ # has_many :games, index_errors: true
563
+ # end
564
+ #
565
+ # # RSpec
566
+ # RSpec.describe Player, type: :model do
567
+ # it { should have_many(:games).index_errors(true) }
568
+ # end
569
+ #
570
+ # # Minitest (Shoulda)
571
+ # class PlayerTest < ActiveSupport::TestCase
572
+ # should have_many(:games).index_errors(true)
573
+ # end
574
+ #
575
+ # ##### inverse_of
576
+ #
577
+ # Use `inverse_of` to assert that the `:inverse_of` option was specified.
578
+ #
579
+ # class Organization < ActiveRecord::Base
580
+ # has_many :employees, inverse_of: :company
581
+ # end
582
+ #
583
+ # # RSpec
584
+ # describe Organization
585
+ # it { should have_many(:employees).inverse_of(:company) }
586
+ # end
587
+ #
588
+ # # Minitest (Shoulda)
589
+ # class OrganizationTest < ActiveSupport::TestCase
590
+ # should have_many(:employees).inverse_of(:company)
591
+ # end
592
+ #
489
593
  # @return [AssociationMatcher]
490
594
  #
491
595
  def have_many(name)
@@ -500,7 +604,7 @@ module Shoulda
500
604
  # end
501
605
  #
502
606
  # # RSpec
503
- # describe Person do
607
+ # RSpec.describe Person, type: :model do
504
608
  # it { should have_one(:partner) }
505
609
  # end
506
610
  #
@@ -521,7 +625,7 @@ module Shoulda
521
625
  # end
522
626
  #
523
627
  # # RSpec
524
- # describe Person do
628
+ # RSpec.describe Person, type: :model do
525
629
  # it { should have_one(:pet).conditions('weight < 80') }
526
630
  # end
527
631
  #
@@ -540,7 +644,7 @@ module Shoulda
540
644
  # end
541
645
  #
542
646
  # # RSpec
543
- # describe Person do
647
+ # RSpec.describe Person, type: :model do
544
648
  # it { should have_one(:focus).order('priority desc') }
545
649
  # end
546
650
  #
@@ -559,7 +663,7 @@ module Shoulda
559
663
  # end
560
664
  #
561
665
  # # RSpec
562
- # describe Person do
666
+ # RSpec.describe Person, type: :model do
563
667
  # it { should have_one(:chance).class_name('Opportunity') }
564
668
  # end
565
669
  #
@@ -577,7 +681,7 @@ module Shoulda
577
681
  # end
578
682
  #
579
683
  # # RSpec
580
- # describe Person do
684
+ # RSpec.describe Person, type: :model do
581
685
  # it { should have_one(:contract).dependent(:nullify) }
582
686
  # end
583
687
  #
@@ -595,7 +699,7 @@ module Shoulda
595
699
  # end
596
700
  #
597
701
  # # RSpec
598
- # describe Person do
702
+ # RSpec.describe Person, type: :model do
599
703
  # it { should have_one(:job).with_primary_key('worker_id') }
600
704
  # end
601
705
  #
@@ -613,7 +717,7 @@ module Shoulda
613
717
  # end
614
718
  #
615
719
  # # RSpec
616
- # describe Person do
720
+ # RSpec.describe Person, type: :model do
617
721
  # it { should have_one(:job).with_foreign_key('worker_id') }
618
722
  # end
619
723
  #
@@ -632,7 +736,7 @@ module Shoulda
632
736
  # end
633
737
  #
634
738
  # # RSpec
635
- # describe Person do
739
+ # RSpec.describe Person, type: :model do
636
740
  # it { should have_one(:life).through(:partner) }
637
741
  # end
638
742
  #
@@ -651,7 +755,7 @@ module Shoulda
651
755
  # end
652
756
  #
653
757
  # # RSpec
654
- # describe Person do
758
+ # RSpec.describe Person, type: :model do
655
759
  # it { should have_one(:car).through(:partner).source(:vehicle) }
656
760
  # end
657
761
  #
@@ -669,7 +773,7 @@ module Shoulda
669
773
  # end
670
774
  #
671
775
  # # RSpec
672
- # describe Person do
776
+ # RSpec.describe Person, type: :model do
673
777
  # it { should have_one(:parking_card).validate(false) }
674
778
  # end
675
779
  #
@@ -678,7 +782,7 @@ module Shoulda
678
782
  # should have_one(:parking_card).validate(false)
679
783
  # end
680
784
  #
681
- # #### autosave
785
+ # ##### autosave
682
786
  #
683
787
  # Use `autosave` to assert that the `:autosave` option was specified.
684
788
  #
@@ -687,7 +791,7 @@ module Shoulda
687
791
  # end
688
792
  #
689
793
  # # RSpec
690
- # describe Account do
794
+ # RSpec.describe Account, type: :model do
691
795
  # it { should have_one(:bank).autosave(true) }
692
796
  # end
693
797
  #
@@ -696,6 +800,25 @@ module Shoulda
696
800
  # should have_one(:bank).autosave(true)
697
801
  # end
698
802
  #
803
+ # ##### required
804
+ #
805
+ # Use `required` to assert that the association is not allowed to be nil.
806
+ # (Rails 5+ only.)
807
+ #
808
+ # class Person < ActiveRecord::Base
809
+ # has_one :brain, required: true
810
+ # end
811
+ #
812
+ # # RSpec
813
+ # describe Person
814
+ # it { should have_one(:brain).required }
815
+ # end
816
+ #
817
+ # # Minitest (Shoulda)
818
+ # class PersonTest < ActiveSupport::TestCase
819
+ # should have_one(:brain).required
820
+ # end
821
+ #
699
822
  # @return [AssociationMatcher]
700
823
  #
701
824
  def have_one(name)
@@ -711,7 +834,7 @@ module Shoulda
711
834
  # end
712
835
  #
713
836
  # # RSpec
714
- # describe Person do
837
+ # RSpec.describe Person, type: :model do
715
838
  # it { should have_and_belong_to_many(:awards) }
716
839
  # end
717
840
  #
@@ -732,7 +855,7 @@ module Shoulda
732
855
  # end
733
856
  #
734
857
  # # RSpec
735
- # describe Person do
858
+ # RSpec.describe Person, type: :model do
736
859
  # it do
737
860
  # should have_and_belong_to_many(:issues).
738
861
  # conditions(difficulty: 'hard')
@@ -755,7 +878,7 @@ module Shoulda
755
878
  # end
756
879
  #
757
880
  # # RSpec
758
- # describe Person do
881
+ # RSpec.describe Person, type: :model do
759
882
  # it do
760
883
  # should have_and_belong_to_many(:projects).
761
884
  # order('time_spent')
@@ -778,7 +901,7 @@ module Shoulda
778
901
  # end
779
902
  #
780
903
  # # RSpec
781
- # describe Person do
904
+ # RSpec.describe Person, type: :model do
782
905
  # it do
783
906
  # should have_and_belong_to_many(:places_visited).
784
907
  # class_name('City')
@@ -797,21 +920,21 @@ module Shoulda
797
920
  # asserts that the table you're referring to actually exists.
798
921
  #
799
922
  # class Person < ActiveRecord::Base
800
- # has_and_belongs_to_many :issues, join_table: 'people_tickets'
923
+ # has_and_belongs_to_many :issues, join_table: :people_tickets
801
924
  # end
802
925
  #
803
926
  # # RSpec
804
- # describe Person do
927
+ # RSpec.describe Person, type: :model do
805
928
  # it do
806
929
  # should have_and_belong_to_many(:issues).
807
- # join_table('people_tickets')
930
+ # join_table(:people_tickets)
808
931
  # end
809
932
  # end
810
933
  #
811
934
  # # Minitest (Shoulda)
812
935
  # class PersonTest < ActiveSupport::TestCase
813
936
  # should have_and_belong_to_many(:issues).
814
- # join_table('people_tickets')
937
+ # join_table(:people_tickets)
815
938
  # end
816
939
  #
817
940
  # ##### validate
@@ -823,7 +946,7 @@ module Shoulda
823
946
  # end
824
947
  #
825
948
  # # RSpec
826
- # describe Person do
949
+ # RSpec.describe Person, type: :model do
827
950
  # it do
828
951
  # should have_and_belong_to_many(:interviews).
829
952
  # validate(false)
@@ -836,7 +959,7 @@ module Shoulda
836
959
  # validate(false)
837
960
  # end
838
961
  #
839
- # #### autosave
962
+ # ##### autosave
840
963
  #
841
964
  # Use `autosave` to assert that the `:autosave` option was specified.
842
965
  #
@@ -845,7 +968,7 @@ module Shoulda
845
968
  # end
846
969
  #
847
970
  # # RSpec
848
- # describe Publisher do
971
+ # RSpec.describe Publisher, type: :model do
849
972
  # it { should have_and_belong_to_many(:advertisers).autosave(true) }
850
973
  # end
851
974
  #
@@ -862,6 +985,13 @@ module Shoulda
862
985
 
863
986
  # @private
864
987
  class AssociationMatcher
988
+ MACROS = {
989
+ 'belongs_to' => 'belong to',
990
+ 'has_many' => 'have many',
991
+ 'has_one' => 'have one',
992
+ 'has_and_belongs_to_many' => 'have and belong to many',
993
+ }.freeze
994
+
865
995
  delegate :reflection, :model_class, :associated_class, :through?,
866
996
  :polymorphic?, to: :reflector
867
997
 
@@ -873,42 +1003,63 @@ module Shoulda
873
1003
  @options = {}
874
1004
  @submatchers = []
875
1005
  @missing = ''
1006
+
1007
+ if macro == :belongs_to
1008
+ required(belongs_to_required_by_default?)
1009
+ end
876
1010
  end
877
1011
 
878
1012
  def through(through)
879
- through_matcher = AssociationMatchers::ThroughMatcher.new(through, name)
880
- add_submatcher(through_matcher)
1013
+ add_submatcher(
1014
+ AssociationMatchers::ThroughMatcher,
1015
+ through,
1016
+ name,
1017
+ )
881
1018
  self
882
1019
  end
883
1020
 
884
1021
  def dependent(dependent)
885
- dependent_matcher = AssociationMatchers::DependentMatcher.new(dependent, name)
886
- add_submatcher(dependent_matcher)
1022
+ add_submatcher(
1023
+ AssociationMatchers::DependentMatcher,
1024
+ dependent,
1025
+ name,
1026
+ )
887
1027
  self
888
1028
  end
889
1029
 
890
1030
  def order(order)
891
- order_matcher = AssociationMatchers::OrderMatcher.new(order, name)
892
- add_submatcher(order_matcher)
1031
+ add_submatcher(
1032
+ AssociationMatchers::OrderMatcher,
1033
+ order,
1034
+ name,
1035
+ )
893
1036
  self
894
1037
  end
895
1038
 
896
1039
  def counter_cache(counter_cache = true)
897
- counter_cache_matcher = AssociationMatchers::CounterCacheMatcher.new(counter_cache, name)
898
- add_submatcher(counter_cache_matcher)
1040
+ add_submatcher(
1041
+ AssociationMatchers::CounterCacheMatcher,
1042
+ counter_cache,
1043
+ name,
1044
+ )
899
1045
  self
900
1046
  end
901
1047
 
902
1048
  def inverse_of(inverse_of)
903
- inverse_of_matcher =
904
- AssociationMatchers::InverseOfMatcher.new(inverse_of, name)
905
- add_submatcher(inverse_of_matcher)
1049
+ add_submatcher(
1050
+ AssociationMatchers::InverseOfMatcher,
1051
+ inverse_of,
1052
+ name,
1053
+ )
906
1054
  self
907
1055
  end
908
1056
 
909
1057
  def source(source)
910
- source_matcher = AssociationMatchers::SourceMatcher.new(source, name)
911
- add_submatcher(source_matcher)
1058
+ add_submatcher(
1059
+ AssociationMatchers::SourceMatcher,
1060
+ source,
1061
+ name,
1062
+ )
912
1063
  self
913
1064
  end
914
1065
 
@@ -922,6 +1073,11 @@ module Shoulda
922
1073
  self
923
1074
  end
924
1075
 
1076
+ def index_errors(index_errors)
1077
+ @options[:index_errors] = index_errors
1078
+ self
1079
+ end
1080
+
925
1081
  def class_name(class_name)
926
1082
  @options[:class_name] = class_name
927
1083
  self
@@ -937,6 +1093,26 @@ module Shoulda
937
1093
  self
938
1094
  end
939
1095
 
1096
+ def required(required = true)
1097
+ remove_submatcher(AssociationMatchers::OptionalMatcher)
1098
+ add_submatcher(
1099
+ AssociationMatchers::RequiredMatcher,
1100
+ name,
1101
+ required,
1102
+ )
1103
+ self
1104
+ end
1105
+
1106
+ def optional(optional = true)
1107
+ remove_submatcher(AssociationMatchers::RequiredMatcher)
1108
+ add_submatcher(
1109
+ AssociationMatchers::OptionalMatcher,
1110
+ name,
1111
+ optional,
1112
+ )
1113
+ self
1114
+ end
1115
+
940
1116
  def validate(validate = true)
941
1117
  @options[:validate] = validate
942
1118
  self
@@ -952,9 +1128,16 @@ module Shoulda
952
1128
  self
953
1129
  end
954
1130
 
1131
+ def without_validating_presence
1132
+ remove_submatcher(AssociationMatchers::RequiredMatcher)
1133
+ self
1134
+ end
1135
+
955
1136
  def description
956
1137
  description = "#{macro_description} #{name}"
957
- description += " class_name => #{options[:class_name]}" if options.key?(:class_name)
1138
+ if options.key?(:class_name)
1139
+ description += " class_name => #{options[:class_name]}"
1140
+ end
958
1141
  [description, submatchers.map(&:description)].flatten.join(' ')
959
1142
  end
960
1143
 
@@ -970,12 +1153,14 @@ module Shoulda
970
1153
  @subject = subject
971
1154
  association_exists? &&
972
1155
  macro_correct? &&
1156
+ validate_inverse_of_through_association &&
973
1157
  (polymorphic? || class_exists?) &&
974
1158
  foreign_key_exists? &&
975
1159
  primary_key_exists? &&
976
1160
  class_name_correct? &&
977
1161
  join_table_correct? &&
978
1162
  autosave_correct? &&
1163
+ index_errors_correct? &&
979
1164
  conditions_correct? &&
980
1165
  validate_correct? &&
981
1166
  touch_correct? &&
@@ -987,7 +1172,8 @@ module Shoulda
987
1172
  end
988
1173
 
989
1174
  def option_verifier
990
- @option_verifier ||= AssociationMatchers::OptionVerifier.new(reflector)
1175
+ @_option_verifier ||=
1176
+ AssociationMatchers::OptionVerifier.new(reflector)
991
1177
  end
992
1178
 
993
1179
  protected
@@ -995,44 +1181,49 @@ module Shoulda
995
1181
  attr_reader :submatchers, :missing, :subject, :macro
996
1182
 
997
1183
  def reflector
998
- @reflector ||= AssociationMatchers::ModelReflector.new(subject, name)
1184
+ @_reflector ||= AssociationMatchers::ModelReflector.new(subject, name)
999
1185
  end
1000
1186
 
1001
- def add_submatcher(matcher)
1002
- @submatchers << matcher
1187
+ def add_submatcher(matcher_class, *args)
1188
+ remove_submatcher(matcher_class)
1189
+ submatchers << matcher_class.new(*args)
1003
1190
  end
1004
1191
 
1005
- def macro_description
1006
- case macro.to_s
1007
- when 'belongs_to'
1008
- 'belong to'
1009
- when 'has_many'
1010
- 'have many'
1011
- when 'has_one'
1012
- 'have one'
1013
- when 'has_and_belongs_to_many'
1014
- 'have and belong to many'
1192
+ def remove_submatcher(matcher_class)
1193
+ submatchers.delete_if do |submatcher|
1194
+ submatcher.is_a?(matcher_class)
1015
1195
  end
1016
1196
  end
1017
1197
 
1198
+ def macro_description
1199
+ MACROS[macro.to_s]
1200
+ end
1201
+
1018
1202
  def expectation
1019
- "#{model_class.name} to have a #{macro} association called #{name}"
1203
+ expectation =
1204
+ "#{model_class.name} to have a #{macro} association called #{name}"
1205
+
1206
+ if through?
1207
+ expectation << " through #{reflector.has_and_belongs_to_many_name}"
1208
+ end
1209
+
1210
+ expectation
1020
1211
  end
1021
1212
 
1022
1213
  def missing_options
1023
1214
  missing_options = [missing, missing_options_for_failing_submatchers]
1024
- missing_options.flatten.compact.join(', ')
1215
+ missing_options.flatten.select(&:present?).join(', ')
1025
1216
  end
1026
1217
 
1027
1218
  def failing_submatchers
1028
- @failing_submatchers ||= submatchers.reject do |matcher|
1219
+ @_failing_submatchers ||= submatchers.reject do |matcher|
1029
1220
  matcher.matches?(subject)
1030
1221
  end
1031
1222
  end
1032
1223
 
1033
1224
  def missing_options_for_failing_submatchers
1034
- if defined?(@failing_submatchers)
1035
- @failing_submatchers.map(&:missing_option)
1225
+ if defined?(@_failing_submatchers)
1226
+ @_failing_submatchers.map(&:missing_option)
1036
1227
  else
1037
1228
  []
1038
1229
  end
@@ -1059,6 +1250,14 @@ module Shoulda
1059
1250
  end
1060
1251
  end
1061
1252
 
1253
+ def validate_inverse_of_through_association
1254
+ reflector.validate_inverse_of_through_association!
1255
+ true
1256
+ rescue ::ActiveRecord::ActiveRecordError => e
1257
+ @missing = e.message
1258
+ false
1259
+ end
1260
+
1062
1261
  def macro_supports_primary_key?
1063
1262
  macro == :belongs_to ||
1064
1263
  ([:has_many, :has_one].include?(macro) && !through?)
@@ -1084,10 +1283,14 @@ module Shoulda
1084
1283
 
1085
1284
  def class_name_correct?
1086
1285
  if options.key?(:class_name)
1087
- if option_verifier.correct_for_constant?(:class_name, options[:class_name])
1286
+ if option_verifier.correct_for_constant?(
1287
+ :class_name,
1288
+ options[:class_name],
1289
+ )
1088
1290
  true
1089
1291
  else
1090
- @missing = "#{name} should resolve to #{options[:class_name]} for class_name"
1292
+ @missing = "#{name} should resolve to #{options[:class_name]}"\
1293
+ ' for class_name'
1091
1294
  false
1092
1295
  end
1093
1296
  else
@@ -1096,7 +1299,10 @@ module Shoulda
1096
1299
  end
1097
1300
 
1098
1301
  def join_table_correct?
1099
- if macro != :has_and_belongs_to_many || join_table_matcher.matches?(@subject)
1302
+ if (
1303
+ macro != :has_and_belongs_to_many ||
1304
+ join_table_matcher.matches?(@subject)
1305
+ )
1100
1306
  true
1101
1307
  else
1102
1308
  @missing = join_table_matcher.failure_message
@@ -1105,8 +1311,10 @@ module Shoulda
1105
1311
  end
1106
1312
 
1107
1313
  def join_table_matcher
1108
- @join_table_matcher ||=
1109
- AssociationMatchers::JoinTableMatcher.new(self, reflector)
1314
+ @_join_table_matcher ||= AssociationMatchers::JoinTableMatcher.new(
1315
+ self,
1316
+ reflector,
1317
+ )
1110
1318
  end
1111
1319
 
1112
1320
  def class_exists?
@@ -1119,10 +1327,14 @@ module Shoulda
1119
1327
 
1120
1328
  def autosave_correct?
1121
1329
  if options.key?(:autosave)
1122
- if option_verifier.correct_for_boolean?(:autosave, options[:autosave])
1330
+ if option_verifier.correct_for_boolean?(
1331
+ :autosave,
1332
+ options[:autosave],
1333
+ )
1123
1334
  true
1124
1335
  else
1125
- @missing = "#{name} should have autosave set to #{options[:autosave]}"
1336
+ @missing = "#{name} should have autosave set to"\
1337
+ " #{options[:autosave]}"
1126
1338
  false
1127
1339
  end
1128
1340
  else
@@ -1130,12 +1342,32 @@ module Shoulda
1130
1342
  end
1131
1343
  end
1132
1344
 
1345
+ def index_errors_correct?
1346
+ return true unless options.key?(:index_errors)
1347
+
1348
+ if option_verifier.correct_for_boolean?(
1349
+ :index_errors,
1350
+ options[:index_errors],
1351
+ )
1352
+ true
1353
+ else
1354
+ @missing =
1355
+ "#{name} should have index_errors set to " +
1356
+ options[:index_errors].to_s
1357
+ false
1358
+ end
1359
+ end
1360
+
1133
1361
  def conditions_correct?
1134
1362
  if options.key?(:conditions)
1135
- if option_verifier.correct_for_relation_clause?(:conditions, options[:conditions])
1363
+ if option_verifier.correct_for_relation_clause?(
1364
+ :conditions,
1365
+ options[:conditions],
1366
+ )
1136
1367
  true
1137
1368
  else
1138
- @missing = "#{name} should have the following conditions: #{options[:conditions]}"
1369
+ @missing = "#{name} should have the following conditions:" +
1370
+ " #{options[:conditions]}"
1139
1371
  false
1140
1372
  end
1141
1373
  else
@@ -1162,24 +1394,49 @@ module Shoulda
1162
1394
  end
1163
1395
 
1164
1396
  def class_has_foreign_key?(klass)
1165
- if options.key?(:foreign_key)
1166
- option_verifier.correct_for_string?(:foreign_key, options[:foreign_key])
1397
+ @missing = validate_foreign_key(klass)
1398
+
1399
+ @missing.nil?
1400
+ end
1401
+
1402
+ def validate_foreign_key(klass)
1403
+ if options.key?(:foreign_key) && !foreign_key_correct?
1404
+ foreign_key_failure_message(klass, options[:foreign_key])
1405
+ elsif !has_column?(klass, actual_foreign_key)
1406
+ foreign_key_failure_message(klass, actual_foreign_key)
1407
+ end
1408
+ end
1409
+
1410
+ def has_column?(klass, column)
1411
+ case column
1412
+ when Array
1413
+ column.all? { |c| has_column?(klass, c.to_s) }
1167
1414
  else
1168
- if klass.column_names.include?(foreign_key)
1169
- true
1170
- else
1171
- @missing = "#{klass} does not have a #{foreign_key} foreign key."
1172
- false
1173
- end
1415
+ column_names_for(klass).include?(column.to_s)
1174
1416
  end
1175
1417
  end
1176
1418
 
1419
+ def foreign_key_correct?
1420
+ option_verifier.correct_for_string?(
1421
+ :foreign_key,
1422
+ options[:foreign_key],
1423
+ )
1424
+ end
1425
+
1426
+ def foreign_key_failure_message(klass, foreign_key)
1427
+ "#{klass} does not have a #{foreign_key} foreign key."
1428
+ end
1429
+
1177
1430
  def primary_key_correct?(klass)
1178
1431
  if options.key?(:primary_key)
1179
- if option_verifier.correct_for_string?(:primary_key, options[:primary_key])
1432
+ if option_verifier.correct_for_string?(
1433
+ :primary_key,
1434
+ options[:primary_key],
1435
+ )
1180
1436
  true
1181
1437
  else
1182
- @missing = "#{klass} does not have a #{options[:primary_key]} primary key"
1438
+ @missing = "#{klass} does not have a #{options[:primary_key]}"\
1439
+ ' primary key'
1183
1440
  false
1184
1441
  end
1185
1442
  else
@@ -1187,19 +1444,27 @@ module Shoulda
1187
1444
  end
1188
1445
  end
1189
1446
 
1190
- def foreign_key
1191
- if foreign_key_reflection
1192
- if foreign_key_reflection.respond_to?(:foreign_key)
1193
- foreign_key_reflection.foreign_key.to_s
1194
- else
1195
- foreign_key_reflection.primary_key_name.to_s
1196
- end
1447
+ def actual_foreign_key
1448
+ return unless foreign_key_reflection
1449
+
1450
+ if foreign_key_reflection.options[:foreign_key]
1451
+ foreign_key_reflection.options[:foreign_key]
1452
+ elsif foreign_key_reflection.respond_to?(:foreign_key)
1453
+ foreign_key_reflection.foreign_key
1454
+ else
1455
+ foreign_key_reflection.primary_key_name
1197
1456
  end
1198
1457
  end
1199
1458
 
1200
1459
  def foreign_key_reflection
1201
- if [:has_one, :has_many].include?(macro) && reflection.options.include?(:inverse_of)
1202
- associated_class.reflect_on_association(reflection.options[:inverse_of])
1460
+ if (
1461
+ [:has_one, :has_many].include?(macro) &&
1462
+ reflection.options.include?(:inverse_of) &&
1463
+ reflection.options[:inverse_of] != false
1464
+ )
1465
+ associated_class.reflect_on_association(
1466
+ reflection.options[:inverse_of],
1467
+ )
1203
1468
  else
1204
1469
  reflection
1205
1470
  end
@@ -1208,6 +1473,16 @@ module Shoulda
1208
1473
  def submatchers_match?
1209
1474
  failing_submatchers.empty?
1210
1475
  end
1476
+
1477
+ def column_names_for(klass)
1478
+ klass.column_names
1479
+ rescue ::ActiveRecord::StatementInvalid
1480
+ []
1481
+ end
1482
+
1483
+ def belongs_to_required_by_default?
1484
+ ::ActiveRecord::Base.belongs_to_required_by_default
1485
+ end
1211
1486
  end
1212
1487
  end
1213
1488
  end