shoulda-matchers 2.6.1 → 2.6.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (146) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +9 -0
  4. data/.yardopts +8 -0
  5. data/Appraisals +82 -33
  6. data/Gemfile +18 -2
  7. data/Gemfile.lock +13 -1
  8. data/NEWS.md +27 -2
  9. data/README.md +83 -1329
  10. data/Rakefile +118 -1
  11. data/cucumber.yml +1 -0
  12. data/doc_config/gh-pages/index.html.erb +9 -0
  13. data/doc_config/yard/setup.rb +22 -0
  14. data/doc_config/yard/templates/default/fulldoc/html/css/bootstrap.css +5967 -0
  15. data/doc_config/yard/templates/default/fulldoc/html/css/full_list.css +12 -0
  16. data/doc_config/yard/templates/default/fulldoc/html/css/global.css +45 -0
  17. data/doc_config/yard/templates/default/fulldoc/html/css/solarized.css +69 -0
  18. data/doc_config/yard/templates/default/fulldoc/html/css/style.css +283 -0
  19. data/doc_config/yard/templates/default/fulldoc/html/full_list.erb +32 -0
  20. data/doc_config/yard/templates/default/fulldoc/html/full_list_class.erb +1 -0
  21. data/doc_config/yard/templates/default/fulldoc/html/full_list_method.erb +8 -0
  22. data/doc_config/yard/templates/default/fulldoc/html/js/app.js +298 -0
  23. data/doc_config/yard/templates/default/fulldoc/html/js/full_list.js +1 -0
  24. data/doc_config/yard/templates/default/fulldoc/html/js/jquery.stickyheaders.js +289 -0
  25. data/doc_config/yard/templates/default/fulldoc/html/js/underscore.min.js +6 -0
  26. data/doc_config/yard/templates/default/fulldoc/html/setup.rb +8 -0
  27. data/doc_config/yard/templates/default/layout/html/breadcrumb.erb +14 -0
  28. data/doc_config/yard/templates/default/layout/html/fonts.erb +1 -0
  29. data/doc_config/yard/templates/default/layout/html/layout.erb +23 -0
  30. data/doc_config/yard/templates/default/layout/html/search.erb +13 -0
  31. data/doc_config/yard/templates/default/layout/html/setup.rb +40 -0
  32. data/doc_config/yard/templates/default/method_details/html/source.erb +10 -0
  33. data/doc_config/yard/templates/default/module/html/box_info.erb +31 -0
  34. data/docs.watchr +5 -0
  35. data/features/rails_integration.feature +32 -0
  36. data/features/step_definitions/rails_steps.rb +55 -9
  37. data/features/support/env.rb +1 -0
  38. data/gemfiles/3.0.gemfile +13 -1
  39. data/gemfiles/3.0.gemfile.lock +13 -1
  40. data/gemfiles/3.1.gemfile +17 -2
  41. data/gemfiles/3.1.gemfile.lock +31 -2
  42. data/gemfiles/3.1_1.9.2.gemfile +33 -0
  43. data/gemfiles/3.1_1.9.2.gemfile.lock +203 -0
  44. data/gemfiles/3.2.gemfile +18 -2
  45. data/gemfiles/3.2.gemfile.lock +32 -2
  46. data/gemfiles/3.2_1.9.2.gemfile +32 -0
  47. data/gemfiles/3.2_1.9.2.gemfile.lock +200 -0
  48. data/gemfiles/4.0.0.gemfile +20 -1
  49. data/gemfiles/4.0.0.gemfile.lock +46 -2
  50. data/gemfiles/4.0.1.gemfile +20 -1
  51. data/gemfiles/4.0.1.gemfile.lock +46 -2
  52. data/gemfiles/4.1.gemfile +21 -2
  53. data/gemfiles/4.1.gemfile.lock +47 -4
  54. data/lib/shoulda/matchers/action_controller.rb +0 -20
  55. data/lib/shoulda/matchers/action_controller/callback_matcher.rb +119 -28
  56. data/lib/shoulda/matchers/action_controller/filter_param_matcher.rb +22 -6
  57. data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +43 -10
  58. data/lib/shoulda/matchers/action_controller/render_template_matcher.rb +40 -13
  59. data/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +63 -11
  60. data/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb +34 -1
  61. data/lib/shoulda/matchers/action_controller/respond_with_matcher.rb +84 -15
  62. data/lib/shoulda/matchers/action_controller/route_matcher.rb +84 -28
  63. data/lib/shoulda/matchers/action_controller/route_params.rb +4 -3
  64. data/lib/shoulda/matchers/action_controller/set_session_matcher.rb +76 -13
  65. data/lib/shoulda/matchers/action_controller/set_the_flash_matcher.rb +147 -13
  66. data/lib/shoulda/matchers/action_controller/strong_parameters_matcher.rb +148 -2
  67. data/lib/shoulda/matchers/active_model.rb +0 -25
  68. data/lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb +66 -9
  69. data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +161 -19
  70. data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +5 -5
  71. data/lib/shoulda/matchers/active_model/ensure_exclusion_of_matcher.rb +92 -13
  72. data/lib/shoulda/matchers/active_model/ensure_inclusion_of_matcher.rb +218 -16
  73. data/lib/shoulda/matchers/active_model/ensure_length_of_matcher.rb +198 -32
  74. data/lib/shoulda/matchers/active_model/errors.rb +5 -2
  75. data/lib/shoulda/matchers/active_model/exception_message_finder.rb +1 -1
  76. data/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb +29 -8
  77. data/lib/shoulda/matchers/active_model/helpers.rb +20 -8
  78. data/lib/shoulda/matchers/active_model/numericality_matchers.rb +9 -0
  79. data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +4 -6
  80. data/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb +4 -3
  81. data/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +3 -2
  82. data/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb +4 -3
  83. data/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb +4 -3
  84. data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +52 -14
  85. data/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +51 -13
  86. data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +53 -7
  87. data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +275 -19
  88. data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +84 -14
  89. data/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb +170 -41
  90. data/lib/shoulda/matchers/active_model/validation_matcher.rb +20 -15
  91. data/lib/shoulda/matchers/active_model/validation_message_finder.rb +1 -2
  92. data/lib/shoulda/matchers/active_record.rb +1 -12
  93. data/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb +89 -15
  94. data/lib/shoulda/matchers/active_record/association_matcher.rb +726 -70
  95. data/lib/shoulda/matchers/active_record/association_matchers.rb +9 -0
  96. data/lib/shoulda/matchers/active_record/association_matchers/counter_cache_matcher.rb +4 -3
  97. data/lib/shoulda/matchers/active_record/association_matchers/dependent_matcher.rb +4 -3
  98. data/lib/shoulda/matchers/active_record/association_matchers/inverse_of_matcher.rb +4 -3
  99. data/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +2 -1
  100. data/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +4 -3
  101. data/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb +4 -5
  102. data/lib/shoulda/matchers/active_record/association_matchers/order_matcher.rb +4 -3
  103. data/lib/shoulda/matchers/active_record/association_matchers/source_matcher.rb +4 -3
  104. data/lib/shoulda/matchers/active_record/association_matchers/through_matcher.rb +4 -3
  105. data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +79 -15
  106. data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +64 -15
  107. data/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +21 -7
  108. data/lib/shoulda/matchers/active_record/serialize_matcher.rb +85 -10
  109. data/lib/shoulda/matchers/assertion_error.rb +7 -1
  110. data/lib/shoulda/matchers/doublespeak.rb +2 -1
  111. data/lib/shoulda/matchers/doublespeak/double.rb +3 -1
  112. data/lib/shoulda/matchers/doublespeak/double_collection.rb +2 -1
  113. data/lib/shoulda/matchers/doublespeak/double_implementation_registry.rb +1 -0
  114. data/lib/shoulda/matchers/doublespeak/object_double.rb +2 -1
  115. data/lib/shoulda/matchers/doublespeak/proxy_implementation.rb +2 -1
  116. data/lib/shoulda/matchers/doublespeak/structs.rb +2 -0
  117. data/lib/shoulda/matchers/doublespeak/stub_implementation.rb +2 -1
  118. data/lib/shoulda/matchers/doublespeak/world.rb +3 -4
  119. data/lib/shoulda/matchers/error.rb +1 -0
  120. data/lib/shoulda/matchers/independent/delegate_matcher.rb +108 -20
  121. data/lib/shoulda/matchers/independent/delegate_matcher/stubbed_target.rb +4 -3
  122. data/lib/shoulda/matchers/integrations/nunit_test_case_detection.rb +3 -0
  123. data/lib/shoulda/matchers/rails_shim.rb +3 -2
  124. data/lib/shoulda/matchers/version.rb +2 -1
  125. data/lib/shoulda/matchers/warn.rb +1 -0
  126. data/script/SUPPORTED_VERSIONS +1 -0
  127. data/script/install_gems_in_all_appraisals +14 -0
  128. data/script/run_all_tests +14 -0
  129. data/shoulda-matchers.gemspec +0 -10
  130. data/spec/report_warnings.rb +7 -0
  131. data/spec/shoulda/matchers/action_controller/route_matcher_spec.rb +1 -1
  132. data/spec/shoulda/matchers/action_controller/strong_parameters_matcher_spec.rb +9 -0
  133. data/spec/shoulda/matchers/active_model/validate_uniqueness_of_matcher_spec.rb +0 -36
  134. data/spec/shoulda/matchers/active_model/validation_message_finder_spec.rb +2 -2
  135. data/spec/shoulda/matchers/doublespeak/double_spec.rb +1 -1
  136. data/spec/shoulda/matchers/doublespeak/world_spec.rb +11 -29
  137. data/spec/shoulda/matchers/doublespeak_spec.rb +3 -3
  138. data/spec/spec_helper.rb +17 -0
  139. data/spec/support/class_builder.rb +4 -0
  140. data/spec/support/test_application.rb +1 -1
  141. data/spec/warnings_spy.rb +64 -0
  142. data/spec/warnings_spy/filesystem.rb +45 -0
  143. data/spec/warnings_spy/partitioner.rb +29 -0
  144. data/spec/warnings_spy/reader.rb +64 -0
  145. data/spec/warnings_spy/reporter.rb +87 -0
  146. metadata +49 -134
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b85c41db70063753c27b74688e7f408a7029b260
4
- data.tar.gz: 91b6b554334647019c6d128c91185c82c16fc7c6
3
+ metadata.gz: 8ff48aa28034edc27f14e97808a24f0e777cf3ab
4
+ data.tar.gz: 6432f92a9497036932281d941a437b40f5636e06
5
5
  SHA512:
6
- metadata.gz: a2c0632389bba8f78c1aa1064a02fdcf30aad6265c05f19fa0de73ed4b510bb8a1a29e7b5848fbbbadece76474f33603025d7ab9ed145a081fcb1e068a046b16
7
- data.tar.gz: 3abc44fa128068136b1674fb922bb0468993f8f76f4d047bffe8833cb94e41c5ce6e8379337eb86c5cf991369b8dadf4baf0dc84fc57663b2eb41c361cf123cb
6
+ metadata.gz: 7f64a534e64d8f070d5e5d524bb9b21df80fa2afe93f4be3cf7b44e6ecb7a33fff7c91b87756194548fb0670548d0302467ce2d83e1371c42bf80f7283c1673b
7
+ data.tar.gz: 940a2d667949ef94d42ada95554fda4a288af2d8cfa95f307900a3e345f46d867ca9cae347758e1f3bf2782e482397cc83a109aeb7359fbb3c69406f0abb0523
data/.gitignore CHANGED
@@ -2,6 +2,7 @@
2
2
  *.swo
3
3
  *.swp
4
4
  .bundle
5
+ .gh-pages
5
6
  .svn/
6
7
  .yardoc
7
8
  coverage
data/.travis.yml CHANGED
@@ -16,6 +16,10 @@ matrix:
16
16
  - rvm: rbx-19mode
17
17
  - rvm: jruby-19mode
18
18
  include:
19
+ - rvm: 1.9.2
20
+ gemfile: gemfiles/3.1_1.9.2.gemfile
21
+ - rvm: 1.9.2
22
+ gemfile: gemfiles/3.2_1.9.2.gemfile
19
23
  - rvm: 1.9.3
20
24
  gemfile: gemfiles/4.0.0.gemfile
21
25
  - rvm: 1.9.3
@@ -34,3 +38,8 @@ matrix:
34
38
  gemfile: gemfiles/3.2.gemfile
35
39
  - rvm: jruby-19mode
36
40
  gemfile: gemfiles/3.2.gemfile
41
+ exclude:
42
+ - rvm: 1.9.2
43
+ gemfile: gemfiles/3.1.gemfile
44
+ - rvm: 1.9.2
45
+ gemfile: gemfiles/3.2.gemfile
data/.yardopts ADDED
@@ -0,0 +1,8 @@
1
+ --no-private
2
+ --protected
3
+ --readme README.md
4
+ --files lib/**/*.rb
5
+ --markup markdown
6
+ --hide-tag return
7
+ --hide-tag param
8
+ -e ./doc_config/yard/setup.rb
data/Appraisals CHANGED
@@ -1,5 +1,42 @@
1
- rails_4_0 = proc do
1
+ ruby_version = Gem::Version.new(RUBY_VERSION + '')
2
+
3
+ spring = proc do
4
+ gem 'spring'
5
+ gem 'spring-commands-rspec'
6
+ end
7
+
8
+ rails_3 = proc do
9
+ gem 'strong_parameters'
10
+ end
11
+
12
+ rails_3_1 = proc do
13
+ instance_eval(&rails_3)
14
+ gem 'rails', '~> 3.1.8'
15
+ gem 'bcrypt-ruby', '~> 3.0.0'
16
+ gem 'jquery-rails'
17
+ gem 'sass-rails', '~> 3.1.5'
18
+ gem 'coffee-rails', '~> 3.1.1'
19
+ gem 'uglifier', '>= 1.0.3'
20
+ end
21
+
22
+ rails_3_2 = proc do
23
+ instance_eval(&rails_3)
24
+ gem 'rails', '~> 3.2.13'
25
+ gem 'bcrypt-ruby', '~> 3.0.0'
26
+ gem 'jquery-rails'
27
+ gem 'sass-rails', '~> 3.2.3'
28
+ gem 'coffee-rails', '~> 3.2.1'
29
+ gem 'uglifier', '>= 1.0.3'
30
+ end
31
+
32
+ rails_4 = proc do
33
+ instance_eval(&spring)
34
+ gem 'uglifier', '>= 1.3.0'
35
+ gem 'coffee-rails', '~> 4.0.0'
2
36
  gem 'jquery-rails'
37
+ gem 'turbolinks'
38
+ gem 'jbuilder', '~> 1.2'
39
+ gem 'sdoc'
3
40
  gem 'activeresource', '4.0.0'
4
41
  # Test suite makes heavy use of attr_accessible
5
42
  gem 'protected_attributes'
@@ -7,47 +44,59 @@ end
7
44
 
8
45
  #---
9
46
 
10
- if RUBY_VERSION < '2.0'
47
+ if Gem::Requirement.new('< 2').satisfied_by?(ruby_version)
11
48
  appraise '3.0' do
49
+ instance_eval(&rails_3)
12
50
  gem 'rails', '~> 3.0.17'
13
- gem 'strong_parameters'
14
51
  end
15
52
 
16
- appraise '3.1' do
17
- gem 'rails', '~> 3.1.8'
18
- gem 'bcrypt-ruby', '~> 3.0.0'
19
- gem 'jquery-rails'
20
- gem 'sass-rails'
21
- gem 'strong_parameters'
53
+ if Gem::Requirement.new('= 1.9.2').satisfied_by?(ruby_version)
54
+ appraise '3.1-1.9.2' do
55
+ instance_eval(&rails_3_1)
56
+ gem 'turn', '0.8.2'
57
+ end
58
+ else
59
+ appraise '3.1' do
60
+ instance_eval(&rails_3_1)
61
+ gem 'turn', '~> 0.8.3'
62
+ end
22
63
  end
23
64
  end
24
65
 
25
- appraise '3.2' do
26
- gem 'rails', '~> 3.2.13'
27
- gem 'bcrypt-ruby', '~> 3.0.0'
28
- gem 'jquery-rails'
29
- gem 'sass-rails'
30
- gem 'strong_parameters'
66
+ if Gem::Requirement.new('= 1.9.2').satisfied_by?(ruby_version)
67
+ appraise '3.2-1.9.2' do
68
+ instance_eval(&rails_3_2)
69
+ end
70
+ else
71
+ appraise '3.2' do
72
+ instance_eval(&rails_3_2)
73
+ instance_eval(&spring)
74
+ end
31
75
  end
32
76
 
33
- appraise '4.0.0' do
34
- instance_eval(&rails_4_0)
35
- gem 'rails', '4.0.0'
36
- gem 'sass-rails', '4.0.0'
37
- gem 'bcrypt-ruby', '~> 3.0.0'
38
- end
77
+ if Gem::Requirement.new('> 1.9.2').satisfied_by?(ruby_version)
78
+ appraise '4.0.0' do
79
+ instance_eval(&rails_4)
80
+ gem 'rails', '4.0.0'
81
+ gem 'sass-rails', '~> 4.0.0'
82
+ gem 'bcrypt-ruby', '~> 3.0.0'
83
+ end
39
84
 
40
- appraise '4.0.1' do
41
- instance_eval(&rails_4_0)
42
- gem 'rails', '4.0.1'
43
- gem 'sass-rails', '4.0.1'
44
- gem 'bcrypt-ruby', '~> 3.1.2'
45
- end
85
+ appraise '4.0.1' do
86
+ instance_eval(&rails_4)
87
+ gem 'rails', '4.0.1'
88
+ gem 'sass-rails', '~> 4.0.0'
89
+ gem 'bcrypt-ruby', '~> 3.1.2'
90
+ end
46
91
 
47
- appraise '4.1' do
48
- instance_eval(&rails_4_0)
49
- gem 'rails', '~> 4.1.0'
50
- gem 'sass-rails', '4.0.3'
51
- gem 'bcrypt-ruby', '~> 3.1.2'
52
- gem "protected_attributes", '~> 1.0.6'
92
+ appraise '4.1' do
93
+ instance_eval(&rails_4)
94
+ gem 'rails', '~> 4.1.0'
95
+ gem 'jbuilder', '~> 2.0'
96
+ gem 'sass-rails', '~> 4.0.3'
97
+ gem 'sdoc', '~> 0.4.0'
98
+ gem 'bcrypt', '~> 3.1.7'
99
+ gem 'protected_attributes', "~> 1.0.6"
100
+ gem 'spring'
101
+ end
53
102
  end
data/Gemfile CHANGED
@@ -2,12 +2,28 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
+ gem 'appraisal', '~> 1.0.0.beta2'
6
+ gem 'aruba'
7
+ gem 'bourne', '~> 1.3'
8
+ gem 'bundler', '~> 1.1'
9
+ gem 'cucumber', '~> 1.1'
10
+ gem 'pry'
11
+ gem 'rails', '~> 3.0'
12
+ gem 'rake', '>= 0.9.2'
13
+ gem 'rspec-rails', '>= 2.13.1', '< 3'
14
+
15
+ # YARD
16
+ gem 'yard'
17
+ gem 'redcarpet'
18
+ gem 'pygments.rb'
19
+ gem 'watchr'
20
+
5
21
  # For test Rails application
6
22
  gem 'shoulda-context', '~> 1.2.0'
7
23
  gem 'sqlite3', :platform => :ruby
8
24
 
9
- # Can't wrap in platform :jruby do...end block because appraisal doesn't support
10
- # it
25
+ # Can't wrap in platform :jruby do...end block because appraisal doesn't
26
+ # support it
11
27
  gem 'activerecord-jdbc-adapter', :platform => :jruby
12
28
  gem 'activerecord-jdbcsqlite3-adapter', :platform => :jruby
13
29
  gem 'jdbc-sqlite3', :platform => :jruby
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- shoulda-matchers (2.6.1)
4
+ shoulda-matchers (2.6.2)
5
5
  activesupport (>= 3.0.0)
6
6
 
7
7
  GEM
@@ -75,10 +75,14 @@ GEM
75
75
  multi_json (1.8.4)
76
76
  multi_test (0.0.3)
77
77
  polyglot (0.3.3)
78
+ posix-spawn (0.3.8)
78
79
  pry (0.9.12.6)
79
80
  coderay (~> 1.0)
80
81
  method_source (~> 0.8)
81
82
  slop (~> 3.4)
83
+ pygments.rb (0.3.7)
84
+ posix-spawn (~> 0.3.6)
85
+ yajl-ruby (~> 1.1.0)
82
86
  rack (1.4.5)
83
87
  rack-cache (1.2)
84
88
  rack (>= 0.4)
@@ -104,6 +108,7 @@ GEM
104
108
  rake (10.1.1)
105
109
  rdoc (3.12.2)
106
110
  json (~> 1.4)
111
+ redcarpet (3.0.0)
107
112
  rspec-core (2.14.7)
108
113
  rspec-expectations (2.14.4)
109
114
  diff-lcs (>= 1.1.3, < 2.0)
@@ -130,6 +135,9 @@ GEM
130
135
  polyglot
131
136
  polyglot (>= 0.3.1)
132
137
  tzinfo (0.3.38)
138
+ watchr (0.7)
139
+ yajl-ruby (1.1.0)
140
+ yard (0.8.7.3)
133
141
 
134
142
  PLATFORMS
135
143
  ruby
@@ -145,10 +153,14 @@ DEPENDENCIES
145
153
  jdbc-sqlite3
146
154
  jruby-openssl
147
155
  pry
156
+ pygments.rb
148
157
  rails (~> 3.0)
149
158
  rake (>= 0.9.2)
159
+ redcarpet
150
160
  rspec-rails (>= 2.13.1, < 3)
151
161
  shoulda-context (~> 1.2.0)
152
162
  shoulda-matchers!
153
163
  sqlite3
154
164
  therubyrhino
165
+ watchr
166
+ yard
data/NEWS.md CHANGED
@@ -1,12 +1,37 @@
1
+ # HEAD
2
+
3
+ # 2.6.2
4
+
5
+ ### Bug fixes
6
+
7
+ * If you have a Rails >= 4.1 project and you are running tests using Spring,
8
+ matchers that depend on assertions within Rails' testing layer (e.g.
9
+ `render_template` and `route`) will no longer fail.
10
+
11
+ * Fix `permit` so that it can be used more than once in the same test.
12
+
13
+ * Revert change to `validate_uniqueness_of` made in 2.6.0 so that it no longer
14
+ provides default values for non-primary, non-nullable columns. This approach
15
+ was causing test failures because it makes the assumption that none of these
16
+ columns allow only specific values, which is not true. If you get an error
17
+ from `validate_uniqueness_of`, your best bet continues to be creating a record
18
+ manually and calling `validate_uniqueness_of` on that instead.
19
+
20
+ ### Other changes
21
+
22
+ * The majority of warnings that the gem produced have been removed. The gem
23
+ still produces warnings under Ruby 1.9.3; we will address this in a future
24
+ release.
25
+
1
26
  # 2.6.1
2
27
 
3
- ## Features
28
+ ### Features
4
29
 
5
30
  * Teach `with_message` qualifier on `allow_value` to accept a hash of i18n
6
31
  interpolation values:
7
32
  `allow_value('foo').for(:attr).with_message(:greater_than, values: { count: 20 })`.
8
33
 
9
- ## Bug fixes
34
+ ### Bug fixes
10
35
 
11
36
  * Revert changes to `validate_numericality_of` made in the last release, which
12
37
  made it so that comparison qualifiers specified on the validation are tested
data/README.md CHANGED
@@ -6,28 +6,92 @@ shoulda-matchers provides Test::Unit- and RSpec-compatible one-liners that test
6
6
  common Rails functionality. These tests would otherwise be much longer, more
7
7
  complex, and error-prone.
8
8
 
9
+ ### ActiveModel Matchers
10
+
11
+ * **[allow_mass_assignment_of](lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb)**
12
+ tests usage of Rails 3's `attr_accessible` and `attr_protected` macros.
13
+ * **[allow_value](lib/shoulda/matchers/active_model/allow_value_matcher.rb)** tests usage of
14
+ the `validates_format_of` validation.
15
+ * **[ensure_inclusion_of](lib/shoulda/matchers/active_model/ensure_inclusion_of_matcher.rb)** tests
16
+ usage of `validates_inclusion_of`.
17
+ * **[ensure_exclusion_of](lib/shoulda/matchers/active_model/ensure_exclusion_of_matcher.rb)** tests
18
+ usage of `validates_exclusion_of`.
19
+ * **[ensure_length_of](lib/shoulda/matchers/active_model/ensure_length_of_matcher.rb)** tests usage
20
+ of `validates_length_of`.
21
+ * **[have_secure_password](lib/shoulda/matchers/active_model/have_secure_password_matcher.rb)** tests
22
+ usage of `has_secure_password`.
23
+ * **[validate_confirmation_of](lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb)**
24
+ tests usage of `validates_confirmation_of`.
25
+ * **[validate_numericality_of](lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb)**
26
+ tests usage of `validates_numericality_of`.
27
+ * **[validate_presence_of](lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb)** tests
28
+ usage of `validates_presence_of`.
29
+ * **[validate_uniqueness_of](lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb)** tests
30
+ usage of `validates_uniqueness_of`.
31
+
32
+ ### ActiveRecord Matchers
33
+
34
+ * **[accept_nested_attributes_for](lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb)**
35
+ tests usage of the `accepts_nested_attributes_for` macro.
36
+ * **[belong_to](lib/shoulda/matchers/active_record/association_matcher.rb)** tests
37
+ your `belongs_to` associations.
38
+ * **[have_many](lib/shoulda/matchers/active_record/association_matcher.rb)** tests
39
+ your `has_many` associations.
40
+ * **[have_one](lib/shoulda/matchers/active_record/association_matcher.rb)** tests your
41
+ `has_one` associations.
42
+ * **[have_and_belong_to_many](lib/shoulda/matchers/active_record/association_matcher.rb)**
43
+ tests your `has_and_belongs_to_many` associations.
44
+ * **[have_db_column](lib/shoulda/matchers/active_record/have_db_column_matcher.rb)** tests that
45
+ the table that backs your model has a specific column.
46
+ * **[have_db_index](lib/shoulda/matchers/active_record/have_db_index_matcher.rb)** tests that the
47
+ table that backs your model has an index on a specific column.
48
+ * **[have_readonly_attribute](lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb)**
49
+ tests usage of the `attr_readonly` macro.
50
+ * **[serialize](lib/shoulda/matchers/active_record/serialize_matcher.rb)** tests usage of the
51
+ `serialize` macro.
52
+
53
+ ### ActionController Matchers
54
+
55
+ * **[filter_param](lib/shoulda/matchers/action_controller/filter_param_matcher.rb)** tests
56
+ parameter filtering configuration.
57
+ * **[redirect_to](lib/shoulda/matchers/action_controller/redirect_to_matcher.rb)** tests that
58
+ an action redirects to a certain location.
59
+ * **[render_template](lib/shoulda/matchers/action_controller/render_template_matcher.rb)** tests
60
+ that an action renders a template.
61
+ * **[render_with_layout](lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb)** tests
62
+ that an action is rendereed with a certain layout.
63
+ * **[rescue_from](lib/shoulda/matchers/action_controller/rescue_from_matcher.rb)** tests usage
64
+ of the `rescue_from` macro.
65
+ * **[respond_with](lib/shoulda/matchers/action_controller/respond_with_matcher.rb)** tests that
66
+ an action responds with a certain status code.
67
+ * **[route](lib/shoulda/matchers/action_controller/route_matcher.rb)** tests your routes.
68
+ * **[set_session](lib/shoulda/matchers/action_controller/set_session_matcher.rb)** makes
69
+ assertions on the `session` hash.
70
+ * **[set_the_flash](lib/shoulda/matchers/action_controller/set_the_flash_matcher.rb)** makes
71
+ assertions on the `flash` hash.
72
+
73
+ ### Independent Matchers
74
+
75
+ * **[delegate_matcher](lib/shoulda/matchers/independent/delegate_matcher.rb)**
76
+ tests that an object forwards messages to other, internal objects by way of
77
+ delegation.
78
+
9
79
  ## Installation
10
80
 
11
81
  ### RSpec
12
82
 
13
83
  Include the gem in your Gemfile:
14
84
 
15
- ```ruby
85
+ ``` ruby
16
86
  group :test do
17
- gem 'shoulda-matchers'
87
+ gem 'shoulda-matchers', require: false
18
88
  end
19
89
  ```
20
90
 
21
- Note that if you're using a Rails preloader like Spring, you'll need to manually
22
- require shoulda-matchers in your spec_helper after you require RSpec:
23
-
24
- ```ruby
25
- # Gemfile
26
- group :test do
27
- gem 'shoulda-matchers', require: false
28
- end
91
+ Then require the gem following rspec-rails in your rails_helper (or spec_helper
92
+ if you're using RSpec 2.x):
29
93
 
30
- # spec_helper
94
+ ``` ruby
31
95
  require 'rspec/rails'
32
96
  require 'shoulda/matchers'
33
97
  ```
@@ -72,1329 +136,19 @@ gem 'shoulda-matchers'
72
136
  gem 'activemodel'
73
137
  ```
74
138
 
75
- ## Usage
76
-
77
- Different matchers apply to different parts of Rails:
78
-
79
- * [ActiveModel](#activemodel-matchers)
80
- * [ActiveRecord](#activerecord-matchers)
81
- * [ActionController](#actioncontroller-matchers)
82
-
83
- ### ActiveModel Matchers
84
-
85
- *Jump to: [allow_mass_assignment_of](#allow_mass_assignment_of), [allow_value](#allow_value), [ensure_inclusion_of](#ensure_inclusion_of), [ensure_exclusion_of](#ensure_exclusion_of), [ensure_length_of](#ensure_length_of), [have_secure_password](#have_secure_password), [validate_absence_of](#validate_absence_of), [validate_acceptance_of](#validate_acceptance_of), [validate_confirmation_of](#validate_confirmation_of), [validate_numericality_of](#validate_numericality_of), [validate_presence_of](#validate_presence_of), [validate_uniqueness_of](#validate_uniqueness_of)*
86
-
87
- Note that all of the examples in this section are based on an ActiveRecord
88
- model for simplicity, but these matchers will work just as well using an
89
- ActiveModel model.
90
-
91
- #### allow_mass_assignment_of
92
-
93
- The `allow_mass_assignment_of` matcher tests usage of Rails 3's
94
- `attr_accessible` and `attr_protected` macros, asserting that attributes can or
95
- cannot be mass-assigned on a record.
96
-
97
- ```ruby
98
- class Post < ActiveRecord::Base
99
- attr_accessible :title
100
- attr_accessible :published_status, as: :admin
101
- end
102
-
103
- class User < ActiveRecord::Base
104
- attr_protected :encrypted_password
105
- end
106
-
107
- # RSpec
108
- describe Post do
109
- it { should allow_mass_assignment_of(:title) }
110
- it { should allow_mass_assignment_of(:published_status).as(:admin) }
111
- end
112
-
113
- describe User do
114
- it { should_not allow_mass_assignment_of(:encrypted_password) }
115
- end
116
-
117
- # Test::Unit
118
- class PostTest < ActiveSupport::TestCase
119
- should allow_mass_assignment_of(:title)
120
- should allow_mass_assignment_of(:published_status).as(:admin)
121
- end
122
-
123
- class UserTest < ActiveSupport::TestCase
124
- should_not allow_mass_assignment_of(:encrypted_password)
125
- end
126
- ```
127
-
128
- #### allow_value
129
-
130
- The `allow_value` matcher tests usage of the `validates_format_of` validation.
131
- It asserts that an attribute can be set to one or more values, succeeding if
132
- none of the values cause the record to be invalid.
133
-
134
- ```ruby
135
- class UserProfile < ActiveRecord::Base
136
- validates_format_of :website_url, with: URI.regexp
137
-
138
- validates_format_of :birthday_as_string,
139
- with: /^(\d+)-(\d+)-(\d+)$/,
140
- on: :create
141
-
142
- validates_format_of :state,
143
- with: /^(open|closed)$/,
144
- message: 'State must be open or closed'
145
- end
146
-
147
- # RSpec
148
- describe UserProfile do
149
- it { should allow_value('http://foo.com', 'http://bar.com/baz').for(:website_url) }
150
- it { should_not allow_value('asdfjkl').for(:website_url) }
151
-
152
- it do
153
- should allow_value('2013-01-01').
154
- for(:birthday_as_string).
155
- on(:create)
156
- end
157
-
158
- it do
159
- should allow_value('open', 'closed').
160
- for(:state).
161
- with_message('State must be open or closed')
162
- end
163
- end
164
-
165
- # Test::Unit
166
- class UserProfileTest < ActiveSupport::TestCase
167
- should allow_value('http://foo.com', 'http://bar.com/baz').for(:website_url)
168
- should_not allow_value('asdfjkl').for(:website_url)
169
-
170
- should allow_value('2013-01-01').
171
- for(:birthday_as_string).
172
- on(:create)
173
-
174
- should allow_value('open', 'closed').
175
- for(:state).
176
- with_message('State must be open or closed')
177
- end
178
- ```
179
-
180
- **PLEASE NOTE:** Using `should_not` with `allow_value` completely negates the
181
- assertion. This means that if multiple values are given to `allow_value`, the
182
- matcher succeeds once it sees the *first* value that will cause the record to be
183
- invalid:
184
-
185
- ```ruby
186
- describe User do
187
- # 'b' and 'c' will not be tested
188
- it { should_not allow_value('a', 'b', 'c').for(:website_url) }
189
- end
190
- ```
191
-
192
- #### ensure_inclusion_of
193
-
194
- The `ensure_inclusion_of` matcher tests usage of the `validates_inclusion_of`
195
- validation, asserting that an attribute can take a set of values and cannot
196
- take values outside of this set.
197
-
198
- ```ruby
199
- class Issue < ActiveRecord::Base
200
- validates_inclusion_of :state, in: %w(open resolved unresolved)
201
- validates_inclusion_of :priority, in: 1..5
202
-
203
- validates_inclusion_of :severity,
204
- in: %w(low medium high),
205
- message: 'Severity must be low, medium, or high'
206
- end
207
-
208
- # RSpec
209
- describe Issue do
210
- it { should ensure_inclusion_of(:state).in_array(%w(open resolved unresolved)) }
211
- it { should ensure_inclusion_of(:priority).in_range(1..5) }
212
-
213
- it do
214
- should ensure_inclusion_of(:severity).
215
- in_array(%w(low medium high)).
216
- with_message('Severity must be low, medium, or high')
217
- end
218
- end
219
-
220
- # Test::Unit
221
- class IssueTest < ActiveSupport::TestCase
222
- should ensure_inclusion_of(:state).in_array(%w(open resolved unresolved))
223
- should ensure_inclusion_of(:priority).in_range(1..5)
224
-
225
- should ensure_inclusion_of(:severity).
226
- in_array(%w(low medium high)).
227
- with_message('Severity must be low, medium, or high')
228
- end
229
- ```
230
-
231
- #### ensure_exclusion_of
232
-
233
- The `ensure_exclusion_of` matcher tests usage of the `validates_exclusion_of`
234
- validation, asserting that an attribute cannot take a set of values.
235
-
236
- ```ruby
237
- class Game < ActiveRecord::Base
238
- validates_exclusion_of :supported_os, in: ['Mac', 'Linux']
239
- validates_exclusion_of :floors_with_enemies, in: 5..8
240
-
241
- validates_exclusion_of :weapon,
242
- in: ['pistol', 'paintball gun', 'stick'],
243
- message: 'You chose a puny weapon'
244
- end
245
-
246
- # RSpec
247
- describe Game do
248
- it { should ensure_exclusion_of(:supported_os).in_array(['Mac', 'Linux']) }
249
- it { should ensure_exclusion_of(:floors_with_enemies).in_range(5..8) }
250
-
251
- it do
252
- should ensure_exclusion_of(:weapon).
253
- in_array(['pistol', 'paintball gun', 'stick']).
254
- with_message('You chose a puny weapon')
255
- end
256
- end
257
-
258
- # Test::Unit
259
- class GameTest < ActiveSupport::TestCase
260
- should ensure_exclusion_of(:supported_os).in_array(['Mac', 'Linux'])
261
- should ensure_exclusion_of(:floors_with_enemies).in_range(5..8)
262
-
263
- should ensure_exclusion_of(:weapon).
264
- in_array(['pistol', 'paintball gun', 'stick']).
265
- with_message('You chose a puny weapon')
266
- end
267
- ```
268
-
269
- #### ensure_length_of
270
-
271
- The `ensure_length_of` matcher tests usage of the `validates_length_of` matcher.
272
-
273
- ```ruby
274
- class User < ActiveRecord::Base
275
- validates_length_of :bio, minimum: 15
276
- validates_length_of :favorite_superhero, is: 6
277
- validates_length_of :status_update, maximum: 140
278
- validates_length_of :password, in: 5..30
279
-
280
- validates_length_of :api_token,
281
- in: 10..20,
282
- message: 'API token must be in between 10 and 20 characters'
283
-
284
- validates_length_of :secret_key, in: 15..100,
285
- too_short: 'Secret key must be more than 15 characters',
286
- too_long: 'Secret key cannot be more than 100 characters'
287
- end
288
-
289
- # RSpec
290
- describe User do
291
- it { should ensure_length_of(:bio).is_at_least(15) }
292
- it { should ensure_length_of(:favorite_superhero).is_equal_to(6) }
293
- it { should ensure_length_of(:status_update).is_at_most(140) }
294
- it { should ensure_length_of(:password).is_at_least(5).is_at_most(30) }
295
-
296
- it do
297
- should ensure_length_of(:api_token).
298
- is_at_least(10).
299
- is_at_most(20).
300
- with_message('Password must be in between 10 and 20 characters')
301
- end
302
-
303
- it do
304
- should ensure_length_of(:secret_key).
305
- is_at_least(15).
306
- is_at_most(100).
307
- with_short_message('Secret key must be more than 15 characters').
308
- with_long_message('Secret key cannot be more than 100 characters')
309
- end
310
- end
311
-
312
- # Test::Unit
313
- class UserTest < ActiveSupport::TestCase
314
- should ensure_length_of(:bio).is_at_least(15)
315
- should ensure_length_of(:favorite_superhero).is_equal_to(6)
316
- should ensure_length_of(:status_update).is_at_most(140)
317
- should ensure_length_of(:password).is_at_least(5).is_at_most(30)
318
-
319
- should ensure_length_of(:api_token).
320
- is_at_least(15).
321
- is_at_most(20).
322
- with_message('Password must be in between 15 and 20 characters')
323
-
324
- should ensure_length_of(:secret_key).
325
- is_at_least(15).
326
- is_at_most(100).
327
- with_short_message('Secret key must be more than 15 characters').
328
- with_long_message('Secret key cannot be more than 100 characters')
329
- end
330
- ```
331
-
332
- #### have_secure_password
333
-
334
- The `have_secure_password` matcher tests usage of the `has_secure_password`
335
- macro.
336
-
337
- ```ruby
338
- class User < ActiveRecord::Base
339
- has_secure_password
340
- end
341
-
342
- # RSpec
343
- describe User do
344
- it { should have_secure_password }
345
- end
346
-
347
- # Test::Unit
348
- class UserTest < ActiveSupport::TestCase
349
- should have_secure_password
350
- end
351
- ```
352
-
353
- #### validate_absence_of
354
-
355
- The `validate_absence_of` matcher tests the usage of the
356
- `validates_absence_of` validation.
357
-
358
- ```ruby
359
- class Tank
360
- include ActiveModel::Model
361
-
362
- validates_absence_of :arms
363
- validates_absence_of :legs,
364
- message: "Tanks don't have legs."
365
- end
366
-
367
- # RSpec
368
- describe Tank do
369
- it { should validate_absence_of(:arms) }
370
-
371
- it do
372
- should validate_absence_of(:legs).
373
- with_message("Tanks don't have legs.")
374
- end
375
- end
376
-
377
- # Test::Unit
378
- class TankTest < ActiveSupport::TestCase
379
- should validate_absence_of(:arms)
380
-
381
- should validate_absence_of(:legs).
382
- with_message("Tanks don't have legs.")
383
- end
384
- ```
385
-
386
- #### validate_acceptance_of
387
-
388
- The `validate_acceptance_of` matcher tests usage of the
389
- `validates_acceptance_of` validation.
390
-
391
- ```ruby
392
- class Registration < ActiveRecord::Base
393
- validates_acceptance_of :eula
394
- validates_acceptance_of :terms_of_service,
395
- message: 'You must accept the terms of service'
396
- end
397
-
398
- # RSpec
399
- describe Registration do
400
- it { should validate_acceptance_of(:eula) }
401
-
402
- it do
403
- should validate_acceptance_of(:terms_of_service).
404
- with_message('You must accept the terms of service')
405
- end
406
- end
407
-
408
- # Test::Unit
409
- class RegistrationTest < ActiveSupport::TestCase
410
- should validate_acceptance_of(:eula)
411
-
412
- should validate_acceptance_of(:terms_of_service).
413
- with_message('You must accept the terms of service')
414
- end
415
- ```
416
-
417
- #### validate_confirmation_of
418
-
419
- The `validate_confirmation_of` matcher tests usage of the
420
- `validates_confirmation_of` validation.
421
-
422
- ```ruby
423
- class User < ActiveRecord::Base
424
- validates_confirmation_of :email
425
- validates_confirmation_of :password, message: 'Please re-enter your password'
426
- end
427
-
428
- # RSpec
429
- describe User do
430
- it do
431
- should validate_confirmation_of(:email)
432
- end
433
-
434
- it do
435
- should validate_confirmation_of(:password).
436
- with_message('Please re-enter your password')
437
- end
438
- end
439
-
440
- # Test::Unit
441
- class UserTest < ActiveSupport::TestCase
442
- should validate_confirmation_of(:email)
443
-
444
- should validate_confirmation_of(:password).
445
- with_message('Please re-enter your password')
446
- end
447
- ```
448
-
449
- #### validate_numericality_of
450
-
451
- The `validate_numericality_of` matcher tests usage of the
452
- `validates_numericality_of` validation.
453
-
454
- ```ruby
455
- class Person < ActiveRecord::Base
456
- validates_numericality_of :gpa
457
- validates_numericality_of :age, only_integer: true
458
- validates_numericality_of :legal_age, greater_than: 21
459
- validates_numericality_of :height, greater_than_or_equal_to: 55
460
- validates_numericality_of :weight, equal_to: 150
461
- validates_numericality_of :number_of_cars, less_than: 2
462
- validates_numericality_of :birth_year, less_than_or_equal_to: 1987
463
- validates_numericality_of :birth_day, odd: true
464
- validates_numericality_of :birth_month, even: true
465
- validates_numericality_of :rank, less_than_or_equal_to: 10, allow_nil: true
466
-
467
- validates_numericality_of :number_of_dependents,
468
- message: 'Number of dependents must be a number'
469
- end
470
-
471
- # RSpec
472
- describe Person do
473
- it { should validate_numericality_of(:gpa) }
474
- it { should validate_numericality_of(:age).only_integer }
475
- it { should validate_numericality_of(:legal_age).is_greater_than(21) }
476
- it { should validate_numericality_of(:height).is_greater_than_or_equal_to(55) }
477
- it { should validate_numericality_of(:weight).is_equal_to(150) }
478
- it { should validate_numericality_of(:number_of_cars).is_less_than(2) }
479
- it { should validate_numericality_of(:birth_year).is_less_than_or_equal_to(1987) }
480
- it { should validate_numericality_of(:birth_day).odd }
481
- it { should validate_numericality_of(:birth_month).even }
482
-
483
- it do
484
- should validate_numericality_of(:number_of_dependents).
485
- with_message('Number of dependents must be a number')
486
- end
487
- end
488
-
489
- # Test::Unit
490
- class PersonTest < ActiveSupport::TestCase
491
- should validate_numericality_of(:gpa)
492
- should validate_numericality_of(:age).only_integer
493
- should validate_numericality_of(:legal_age).is_greater_than(21)
494
- should validate_numericality_of(:height).is_greater_than_or_equal_to(55)
495
- should validate_numericality_of(:weight).is_equal_to(150)
496
- should validate_numericality_of(:number_of_cars).is_less_than(2)
497
- should validate_numericality_of(:birth_year).is_less_than_or_equal_to(1987)
498
- should validate_numericality_of(:birth_day).odd
499
- should validate_numericality_of(:birth_month).even
500
-
501
- should validate_numericality_of(:number_of_dependents).
502
- with_message('Number of dependents must be a number')
503
- end
504
- ```
505
-
506
- #### validate_presence_of
507
-
508
- The `validate_presence_of` matcher tests usage of the `validates_presence_of`
509
- matcher.
510
-
511
- ```ruby
512
- class Robot < ActiveRecord::Base
513
- validates_presence_of :arms
514
- validates_presence_of :legs, message: 'Robot has no legs'
515
- end
516
-
517
- # RSpec
518
- describe Robot do
519
- it { should validate_presence_of(:arms) }
520
- it { should validate_presence_of(:legs).with_message('Robot has no legs') }
521
- end
522
-
523
- # Test::Unit
524
- class RobotTest < ActiveSupport::TestCase
525
- should validate_presence_of(:arms)
526
- should validate_presence_of(:legs).with_message('Robot has no legs')
527
- end
528
- ```
529
-
530
- #### validate_uniqueness_of
531
-
532
- The `validate_uniqueness_of` matcher tests usage of the
533
- `validates_uniqueness_of` validation.
534
-
535
- ```ruby
536
- class Post < ActiveRecord::Base
537
- validates_uniqueness_of :permalink
538
- validates_uniqueness_of :slug, scope: :user_id
539
- validates_uniqueness_of :key, case_insensitive: true
540
- validates_uniqueness_of :author_id, allow_nil: true
541
-
542
- validates_uniqueness_of :title, message: 'Please choose another title'
543
- end
544
-
545
- # RSpec
546
- describe Post do
547
- it { should validate_uniqueness_of(:permalink) }
548
- it { should validate_uniqueness_of(:slug).scoped_to(:user_id) }
549
- it { should validate_uniqueness_of(:key).case_insensitive }
550
- it { should validate_uniqueness_of(:author_id).allow_nil }
551
-
552
- it do
553
- should validate_uniqueness_of(:title).
554
- with_message('Please choose another title')
555
- end
556
- end
557
-
558
- # Test::Unit
559
- class PostTest < ActiveSupport::TestCase
560
- should validate_uniqueness_of(:permalink)
561
- should validate_uniqueness_of(:slug).scoped_to(:user_id)
562
- should validate_uniqueness_of(:key).case_insensitive
563
- should validate_uniqueness_of(:author_id).allow_nil
564
-
565
- should validate_uniqueness_of(:title).
566
- with_message('Please choose another title')
567
- end
568
- ```
569
-
570
- **PLEASE NOTE:** This matcher works differently from other validation matchers.
571
- Since the very concept of uniqueness depends on checking against a pre-existing
572
- record in the database, this matcher will first use the model you're testing to
573
- query for such a record, and if it can't find an existing one, it will create
574
- one itself. Sometimes this step fails, especially if you have other validations
575
- on the attribute you're testing (or, if you have database-level restrictions on
576
- any attributes). In this case, the solution is to create a record before you use
577
- `validate_uniqueness_of`.
578
-
579
- For example, if you have this model:
580
-
581
- ```ruby
582
- class Post < ActiveRecord::Base
583
- validates_presence_of :permalink
584
- validates_uniqueness_of :permalink
585
- end
586
- ```
587
-
588
- then you will need to test it like this:
589
-
590
- ```ruby
591
- describe Post do
592
- it do
593
- Post.create!(title: 'This is the title')
594
- should validate_uniqueness_of(:permalink)
595
- end
596
- end
597
- ```
598
-
599
- ### ActiveRecord Matchers
600
-
601
- *Jump to: [accept_nested_attributes_for](#accept_nested_attributes_for), [belong_to](#belong_to), [have_many](#have_many), [have_one](#have_one), [have_and_belong_to_many](#have_and_belong_to_many), [have_db_column](#have_db_column), [have_db_index](#have_db_index), [have_readonly_attribute](#have_readonly_attribute), [serialize](#serialize)*
602
-
603
- #### accept_nested_attributes_for
604
-
605
- The `accept_nested_attributes_for` matcher tests usage of the
606
- `accepts_nested_attributes_for` macro.
607
-
608
- ```ruby
609
- class Car < ActiveRecord::Base
610
- accept_nested_attributes_for :doors
611
- accept_nested_attributes_for :mirrors, allow_destroy: true
612
- accept_nested_attributes_for :windows, limit: 3
613
- accept_nested_attributes_for :engine, update_only: true
614
- end
615
-
616
- # RSpec
617
- describe Car do
618
- it { should accept_nested_attributes_for(:doors) }
619
- it { should accept_nested_attributes_for(:mirrors).allow_destroy(true) }
620
- it { should accept_nested_attributes_for(:windows).limit(3) }
621
- it { should accept_nested_attributes_for(:engine).update_only(true) }
622
- end
623
-
624
- # Test::Unit (using Shoulda)
625
- class CarTest < ActiveSupport::TestCase
626
- should accept_nested_attributes_for(:doors)
627
- should accept_nested_attributes_for(:mirrors).allow_destroy(true)
628
- should accept_nested_attributes_for(:windows).limit(3)
629
- should accept_nested_attributes_for(:engine).update_only(true)
630
- end
631
- ```
632
-
633
- #### belong_to
634
-
635
- The `belong_to` matcher tests your `belongs_to` associations.
636
-
637
- ```ruby
638
- class Person < ActiveRecord::Base
639
- belongs_to :organization
640
- belongs_to :family, -> { where(everyone_is_perfect: false) }
641
- belongs_to :previous_company, -> { order('hired_on desc') }
642
- belongs_to :ancient_city, class_name: 'City'
643
- belongs_to :great_country, foreign_key: 'country_id'
644
- belongs_to :mental_institution, touch: true
645
- belongs_to :world, dependent: :destroy
646
- end
647
-
648
- # RSpec
649
- describe Person do
650
- it { should belong_to(:organization) }
651
- it { should belong_to(:family).conditions(everyone_is_perfect: false) }
652
- it { should belong_to(:previous_company).order('hired_on desc') }
653
- it { should belong_to(:ancient_city).class_name('City') }
654
- it { should belong_to(:great_country).with_foreign_key('country_id') }
655
- it { should belong_to(:mental_institution).touch(true) }
656
- it { should belong_to(:world).dependent(:destroy) }
657
- end
658
-
659
- # Test::Unit
660
- class PersonTest < ActiveSupport::TestCase
661
- should belong_to(:organization)
662
- should belong_to(:family).conditions(everyone_is_perfect: false)
663
- should belong_to(:previous_company).order('hired_on desc')
664
- should belong_to(:ancient_city).class_name('City')
665
- should belong_to(:great_country).with_foreign_key('country_id')
666
- should belong_to(:mental_institution).touch(true)
667
- should belong_to(:world).dependent(:destroy)
668
- end
669
- ```
670
-
671
- #### have_many
672
-
673
- The `have_many` matcher tests your `has_many` and `has_many :through` associations.
674
-
675
- ```ruby
676
- class Person < ActiveRecord::Base
677
- has_many :friends
678
- has_many :acquaintances, through: :friends
679
- has_many :job_offers, through: :friends, source: :opportunities
680
- has_many :coins, -> { where(condition: 'mint') }
681
- has_many :shirts, -> { order('color') }
682
- has_many :hopes, class_name: 'Dream'
683
- has_many :worries, foreign_key: 'worrier_id'
684
- has_many :distractions, counter_cache: true
685
- has_many :ideas, validate: false
686
- has_many :topics_of_interest, touch: true
687
- has_many :secret_documents, dependent: :destroy
688
- end
689
-
690
- # RSpec
691
- describe Person do
692
- it { should have_many(:friends) }
693
- it { should have_many(:acquaintances).through(:friends) }
694
- it { should have_many(:job_offers).through(:friends).source(:opportunities) }
695
- it { should have_many(:coins).conditions(condition: 'mint') }
696
- it { should have_many(:shirts).order('color') }
697
- it { should have_many(:hopes).class_name('Dream') }
698
- it { should have_many(:worries).with_foreign_key('worrier_id') }
699
- it { should have_many(:ideas).validate(false) }
700
- it { should have_many(:distractions).counter_cache(true) }
701
- it { should have_many(:topics_of_interest).touch(true) }
702
- it { should have_many(:secret_documents).dependent(:destroy) }
703
- end
704
-
705
- # Test::Unit
706
- class PersonTest < ActiveSupport::TestCase
707
- should have_many(:friends)
708
- should have_many(:acquaintances).through(:friends)
709
- should have_many(:job_offers).through(:friends).source(:opportunities)
710
- should have_many(:coins).conditions(condition: 'mint')
711
- should have_many(:shirts).order('color')
712
- should have_many(:hopes).class_name('Dream')
713
- should have_many(:worries).with_foreign_key('worrier_id')
714
- should have_many(:ideas).validate(false)
715
- should have_many(:distractions).counter_cache(true)
716
- should have_many(:topics_of_interest).touch(true)
717
- should have_many(:secret_documents).dependent(:destroy)
718
- end
719
- ```
720
-
721
- #### have_one
722
-
723
- The `have_one` matcher tests your `has_one` and `has_one :through` associations.
724
-
725
- ```ruby
726
- class Person < ActiveRecord::Base
727
- has_one :partner
728
- has_one :life, through: :partner
729
- has_one :car, through: :partner, source: :vehicle
730
- has_one :pet, -> { where('weight < 80') }
731
- has_one :focus, -> { order('priority desc') }
732
- has_one :chance, class_name: 'Opportunity'
733
- has_one :job, foreign_key: 'worker_id'
734
- has_one :parking_card, validate: false
735
- has_one :contract, dependent: :nullify
736
- end
737
-
738
- # RSpec
739
- describe Person do
740
- it { should have_one(:partner) }
741
- it { should have_one(:life).through(:partner) }
742
- it { should have_one(:car).through(:partner).source(:vehicle) }
743
- it { should have_one(:pet).conditions('weight < 80') }
744
- it { should have_one(:focus).order('priority desc') }
745
- it { should have_one(:chance).class_name('Opportunity') }
746
- it { should have_one(:job).with_foreign_key('worker_id') }
747
- it { should have_one(:parking_card).validate(false) }
748
- it { should have_one(:contract).dependent(:nullify) }
749
- end
750
-
751
- # Test::Unit
752
- class PersonTest < ActiveSupport::TestCase
753
- should have_one(:partner)
754
- should have_one(:life).through(:partner)
755
- should have_one(:car).through(:partner).source(:vehicle)
756
- should have_one(:pet).conditions('weight < 80')
757
- should have_one(:focus).order('priority desc')
758
- should have_one(:chance).class_name('Opportunity')
759
- should have_one(:job).with_foreign_key('worker_id')
760
- should have_one(:parking_card).validate(false)
761
- should have_one(:contract).dependent(:nullify)
762
- end
763
- ```
764
-
765
- #### have_and_belong_to_many
766
-
767
- The `have_and_belong_to_many` matcher tests your `has_and_belongs_to_many`
768
- associations.
769
-
770
- ```ruby
771
- class Person < ActiveRecord::Base
772
- has_and_belongs_to_many :awards
773
- has_and_belongs_to_many :issues, -> { where(difficulty: 'hard') }
774
- has_and_belongs_to_many :projects, -> { order('time_spent') }
775
- has_and_belongs_to_many :places_visited, class_name: 'City'
776
- has_and_belongs_to_many :interviews, validate: false
777
- end
778
-
779
- # RSpec
780
- describe Person do
781
- it { should have_and_belong_to_many(:awards) }
782
- it { should have_and_belong_to_many(:issues).conditions(difficulty: 'hard') }
783
- it { should have_and_belong_to_many(:projects).order('time_spent') }
784
- it { should have_and_belong_to_many(:places_visited).class_name('City') }
785
- it { should have_and_belong_to_many(:interviews).validate(false) }
786
- end
787
-
788
- # Test::Unit
789
- class PersonTest < ActiveSupport::TestCase
790
- should have_and_belong_to_many(:awards)
791
- should have_and_belong_to_many(:issues).conditions(difficulty: 'hard')
792
- should have_and_belong_to_many(:projects).order('time_spent')
793
- should have_and_belong_to_many(:places_visited).class_name('City')
794
- should have_and_belong_to_many(:interviews).validate(false)
795
- end
796
- ```
797
-
798
- #### have_db_column
799
-
800
- The `have_db_column` matcher tests that the table that backs your model
801
- has a specific column.
802
-
803
- ```ruby
804
- class CreatePhones < ActiveRecord::Migration
805
- def change
806
- create_table :phones do |t|
807
- t.decimal :supported_ios_version
808
- t.string :model, null: false
809
- t.decimal :camera_aperture, precision: 1
810
- end
811
- end
812
- end
813
-
814
- # RSpec
815
- describe Phone do
816
- it { should have_db_column(:supported_ios_version) }
817
- it { should have_db_column(:model).with_options(null: false) }
818
-
819
- it do
820
- should have_db_column(:camera_aperture).
821
- of_type(:decimal).
822
- with_options(precision: 1)
823
- end
824
- end
825
-
826
- # Test::Unit
827
- class PhoneTest < ActiveSupport::TestCase
828
- should have_db_column(:supported_ios_version)
829
- should have_db_column(:model).with_options(null: false)
830
-
831
- should have_db_column(:camera_aperture).
832
- of_type(:decimal).
833
- with_options(precision: 1)
834
- end
835
- ```
836
-
837
- #### have_db_index
838
-
839
- The `have_db_index` matcher tests that the table that backs your model has a
840
- index on a specific column.
841
-
842
- ```ruby
843
- class CreateBlogs < ActiveRecord::Migration
844
- def change
845
- create_table :blogs do |t|
846
- t.integer :user_id, null: false
847
- t.string :name, null: false
848
- end
849
-
850
- add_index :blogs, :user_id
851
- add_index :blogs, :name, unique: true
852
- end
853
- end
854
-
855
- # RSpec
856
- describe Blog do
857
- it { should have_db_index(:user_id) }
858
- it { should have_db_index(:name).unique(true) }
859
- end
860
-
861
- # Test::Unit
862
- class BlogTest < ActiveSupport::TestCase
863
- should have_db_index(:user_id)
864
- should have_db_index(:name).unique(true)
865
- end
866
- ```
867
-
868
- #### have_readonly_attribute
869
-
870
- The `have_readonly_attribute` matcher tests usage of the `attr_readonly` macro.
871
-
872
- ```ruby
873
- class User < ActiveRecord::Base
874
- attr_readonly :password
875
- end
876
-
877
- # RSpec
878
- describe User do
879
- it { should have_readonly_attribute(:password) }
880
- end
881
-
882
- # Test::Unit
883
- class UserTest < ActiveSupport::TestCase
884
- should have_readonly_attribute(:password)
885
- end
886
- ```
887
-
888
- #### serialize
889
-
890
- The `serialize` matcher tests usage of the `serialize` macro.
891
-
892
- ```ruby
893
- class ProductOptionsSerializer
894
- def load(string)
895
- # ...
896
- end
897
-
898
- def dump(options)
899
- # ...
900
- end
901
- end
902
-
903
- class Product < ActiveRecord::Base
904
- serialize :customizations
905
- serialize :specifications, ProductSpecsSerializer
906
- serialize :options, ProductOptionsSerializer.new
907
- end
908
-
909
- # RSpec
910
- describe Product do
911
- it { should serialize(:customizations) }
912
- it { should serialize(:specifications).as(ProductSpecsSerializer) }
913
- it { should serialize(:options).as_instance_of(ProductOptionsSerializer) }
914
- end
915
-
916
- # Test::Unit
917
- class ProductTest < ActiveSupport::TestCase
918
- should serialize(:customizations)
919
- should serialize(:specifications).as(ProductSpecsSerializer)
920
- should serialize(:options).as_instance_of(ProductOptionsSerializer)
921
- end
922
- ```
923
-
924
- ### ActionController Matchers
925
-
926
- *Jump to: [filter_param](#filter_param), [permit](#permit), [redirect_to](#redirect_to), [render_template](#render_template), [render_with_layout](#render_with_layout), [rescue_from](#rescue_from), [respond_with](#respond_with), [route](#route), [set_session](#set_session), [set_the_flash](#set_the_flash), [use_after_filter / use_after_action](#use_after_filter--use_after_action), [use_around_filter / use_around_action](#use_around_filter--use_around_action), [use_before_filter / use_around_action](#use_before_filter--use_before_action)*
927
-
928
- #### filter_param
929
-
930
- The `filter_param` matcher tests parameter filtering configuration.
931
-
932
- ```ruby
933
- class MyApplication < Rails::Application
934
- config.filter_parameters << :secret_key
935
- end
936
-
937
- # RSpec
938
- describe ApplicationController do
939
- it { should filter_param(:secret_key) }
940
- end
941
-
942
- # Test::Unit
943
- class ApplicationControllerTest < ActionController::TestCase
944
- should filter_param(:secret_key)
945
- end
946
- ```
947
-
948
- #### permit
949
-
950
- The `permit` matcher tests that only whitelisted parameters are permitted.
951
-
952
- ```ruby
953
- class UserController < ActionController::Base
954
- def create
955
- User.create(user_params)
956
- end
957
-
958
- private
959
-
960
- def user_params
961
- params.require(:user).permit(:email)
962
- end
963
- end
964
-
965
- # RSpec
966
- describe UserController do
967
- it { should permit(:email).for(:create) }
968
- end
969
-
970
- # Test::Unit
971
- class UserControllerTest < ActionController::TestCase
972
- should permit(:email).for(:create)
973
- end
974
- ```
975
-
976
- #### redirect_to
977
-
978
- The `redirect_to` matcher tests that an action redirects to a certain location.
979
- In a test suite using RSpec, it is very similar to rspec-rails's `redirect_to`
980
- matcher. In a test suite using Test::Unit / Shoulda, it provides a more
981
- expressive syntax over `assert_redirected_to`.
982
-
983
- ```ruby
984
- class PostsController < ApplicationController
985
- def show
986
- redirect_to :index
987
- end
988
- end
989
-
990
- # RSpec
991
- describe PostsController do
992
- describe 'GET #list' do
993
- before { get :list }
994
-
995
- it { should redirect_to(posts_path) }
996
- end
997
- end
998
-
999
- # Test::Unit
1000
- class PostsControllerTest < ActionController::TestCase
1001
- context 'GET #list' do
1002
- setup { get :list }
1003
-
1004
- should redirect_to { posts_path }
1005
- end
1006
- end
1007
- ```
1008
-
1009
- #### render_template
1010
-
1011
- The `render_template` matcher tests that an action renders a template.
1012
- In RSpec, it is very similar to rspec-rails's `render_template` matcher.
1013
- In Test::Unit, it provides a more expressive syntax over `assert_template`.
1014
-
1015
- ```ruby
1016
- class PostsController < ApplicationController
1017
- def show
1018
- end
1019
- end
1020
-
1021
- # RSpec
1022
- describe PostsController do
1023
- describe 'GET #show' do
1024
- before { get :show }
1025
-
1026
- it { should render_template('show') }
1027
- end
1028
- end
1029
-
1030
- # Test::Unit
1031
- class PostsControllerTest < ActionController::TestCase
1032
- context 'GET #show' do
1033
- setup { get :show }
1034
-
1035
- should render_template('show')
1036
- end
1037
- end
1038
- ```
1039
-
1040
- #### render_with_layout
1041
-
1042
- The `render_with_layout` matcher tests that an action is rendered with a certain
1043
- layout.
1044
-
1045
- ```ruby
1046
- class PostsController < ApplicationController
1047
- def show
1048
- render layout: 'posts'
1049
- end
1050
- end
1051
-
1052
- # RSpec
1053
- describe PostsController do
1054
- describe 'GET #show' do
1055
- before { get :show }
1056
-
1057
- it { should render_with_layout('posts') }
1058
- end
1059
- end
1060
-
1061
- # Test::Unit
1062
- class PostsControllerTest < ActionController::TestCase
1063
- context 'GET #show' do
1064
- setup { get :show }
1065
-
1066
- should render_with_layout('posts')
1067
- end
1068
- end
1069
- ```
1070
-
1071
- #### rescue_from
1072
-
1073
- The `rescue_from` matcher tests usage of the `rescue_from` macro.
1074
-
1075
- ```ruby
1076
- class ApplicationController < ActionController::Base
1077
- rescue_from ActiveRecord::RecordNotFound, with: :handle_not_found
1078
-
1079
- private
1080
-
1081
- def handle_not_found
1082
- # ...
1083
- end
1084
- end
1085
-
1086
- # RSpec
1087
- describe ApplicationController do
1088
- it do
1089
- should rescue_from(ActiveRecord::RecordNotFound).
1090
- with(:handle_not_found)
1091
- end
1092
- end
1093
-
1094
- # Test::Unit
1095
- class ApplicationControllerTest < ActionController::TestCase
1096
- should rescue_from(ActiveRecord::RecordNotFound).
1097
- with(:handle_not_found)
1098
- end
1099
- ```
1100
-
1101
- #### respond_with
1102
-
1103
- The `respond_with` matcher tests that an action responds with a certain status
1104
- code.
1105
-
1106
- ```ruby
1107
- class PostsController < ApplicationController
1108
- def index
1109
- render status: 403
1110
- end
1111
-
1112
- def show
1113
- render status: :locked
1114
- end
1115
-
1116
- def destroy
1117
- render status: 508
1118
- end
1119
- end
1120
-
1121
- # RSpec
1122
- describe PostsController do
1123
- describe 'GET #index' do
1124
- before { get :index }
1125
-
1126
- it { should respond_with(403) }
1127
- end
1128
-
1129
- describe 'GET #show' do
1130
- before { get :show }
1131
-
1132
- it { should respond_with(:locked) }
1133
- end
1134
-
1135
- describe 'DELETE #destroy' do
1136
- before { delete :destroy }
1137
-
1138
- it { should respond_with(500..600) }
1139
- end
1140
- end
1141
-
1142
- # Test::Unit
1143
- class PostsControllerTest < ActionController::TestCase
1144
- context 'GET #index' do
1145
- setup { get :index }
1146
-
1147
- should respond_with(403)
1148
- end
1149
-
1150
- context 'GET #show' do
1151
- setup { get :show }
1152
-
1153
- should respond_with(:locked)
1154
- end
1155
-
1156
- context 'DELETE #destroy' do
1157
- setup { delete :destroy }
1158
-
1159
- should respond_with(500..600)
1160
- end
1161
- end
1162
- ```
1163
-
1164
- #### route
1165
-
1166
- The `route` matcher tests that a route resolves to a controller, action, and
1167
- params; and that the controller, action, and params generates the same route. For
1168
- an RSpec suite, this is like using a combination of `route_to` and
1169
- `be_routable`. For a Test::Unit suite, it provides a more expressive syntax
1170
- over `assert_routing`.
1171
-
1172
- ```ruby
1173
- My::Application.routes.draw do
1174
- get '/posts', controller: 'posts', action: 'index'
1175
- get '/posts/:id' => 'posts#show'
1176
- end
1177
-
1178
- # RSpec
1179
- describe 'Routing' do
1180
- it { should route(:get, '/posts').to(controller: 'posts', action: 'index') }
1181
- it { should route(:get, '/posts/1').to('posts#show', id: 1) }
1182
- end
1183
-
1184
- # Test::Unit
1185
- class RoutesTest < ActionController::IntegrationTest
1186
- should route(:get, '/posts').to(controller: 'posts', action: 'index')
1187
- should route(:get, '/posts/1').to('posts#show', id: 1)
1188
- end
1189
- ```
1190
-
1191
- #### set_session
1192
-
1193
- The `set_session` matcher asserts that a key in the `session` hash has been set
1194
- to a certain value.
1195
-
1196
- ```ruby
1197
- class PostsController < ApplicationController
1198
- def show
1199
- session[:foo] = 'bar'
1200
- end
1201
- end
1202
-
1203
- # RSpec
1204
- describe PostsController do
1205
- describe 'GET #show' do
1206
- before { get :show }
1207
-
1208
- it { should set_session(:foo).to('bar') }
1209
- it { should_not set_session(:baz) }
1210
- end
1211
- end
1212
-
1213
- # Test::Unit
1214
- class PostsControllerTest < ActionController::TestCase
1215
- context 'GET #show' do
1216
- setup { get :show }
1217
-
1218
- should set_session(:foo).to('bar')
1219
- should_not set_session(:baz)
1220
- end
1221
- end
1222
- ```
1223
-
1224
- #### set_the_flash
1225
-
1226
- The `set_the_flash` matcher asserts that a key in the `flash` hash is set to a
1227
- certain value.
1228
-
1229
- ```ruby
1230
- class PostsController < ApplicationController
1231
- def index
1232
- flash[:foo] = 'A candy bar'
1233
- end
1234
-
1235
- def show
1236
- flash.now[:foo] = 'bar'
1237
- end
1238
-
1239
- def destroy
1240
- end
1241
- end
1242
-
1243
- # RSpec
1244
- describe PostsController do
1245
- describe 'GET #index' do
1246
- before { get :index }
1247
-
1248
- it { should set_the_flash.to('bar') }
1249
- it { should set_the_flash.to(/bar/) }
1250
- it { should set_the_flash[:foo].to('bar') }
1251
- it { should_not set_the_flash[:baz] }
1252
- end
1253
-
1254
- describe 'GET #show' do
1255
- before { get :show }
1256
-
1257
- it { should set_the_flash.now }
1258
- it { should set_the_flash[:foo].now }
1259
- it { should set_the_flash[:foo].to('bar').now }
1260
- end
1261
-
1262
- describe 'DELETE #destroy' do
1263
- before { delete :destroy }
1264
-
1265
- it { should_not set_the_flash }
1266
- end
1267
- end
1268
-
1269
- # Test::Unit
1270
- class PostsControllerTest < ActionController::TestCase
1271
- context 'GET #index' do
1272
- setup { get :index }
1273
-
1274
- should set_the_flash.to('bar')
1275
- should set_the_flash.to(/bar/)
1276
- should set_the_flash[:foo].to('bar')
1277
- should_not set_the_flash[:baz]
1278
- end
1279
-
1280
- context 'GET #show' do
1281
- setup { get :show }
1282
-
1283
- should set_the_flash.now
1284
- should set_the_flash[:foo].now
1285
- should set_the_flash[:foo].to('bar').now
1286
- end
1287
-
1288
- context 'DELETE #destroy' do
1289
- setup { delete :destroy }
1290
-
1291
- should_not set_the_flash
1292
- end
1293
- end
1294
- ```
1295
-
1296
- #### use_after_filter / use_after_action
139
+ ## Generating documentation
1297
140
 
1298
- The `use_after_filter` ensures a given `after_filter` is used. This is also
1299
- available as `use_after_action` to provide Rails 4 support.
141
+ YARD is used to generate documentation, which can be viewed [online][rubydocs].
142
+ You can preview changes you make to the documentation locally by running
1300
143
 
1301
- ```ruby
1302
- class UserController < ActionController::Base
1303
- after_filter :log_activity
1304
- end
144
+ yard doc
1305
145
 
1306
- # RSpec
1307
- describe UserController do
1308
- it { should use_after_filter(:log_activity) }
1309
- end
1310
-
1311
- # Test::Unit
1312
- class UserControllerTest < ActionController::TestCase
1313
- should use_after_filter(:log_activity)
1314
- end
1315
- ```
146
+ from this directory. Then, open `doc/index.html` in your browser.
1316
147
 
1317
- #### use_around_filter / use_around_action
148
+ If you want to see a live preview as you work without having to run `yard` over
149
+ and over again, keep this command running in a separate terminal session:
1318
150
 
1319
- The `use_around_filter` ensures a given `around_filter` is used. This is also
1320
- available as `use_around_action` to provide Rails 4 support.
1321
-
1322
- ```ruby
1323
- class UserController < ActionController::Base
1324
- around_filter :log_activity
1325
- end
1326
-
1327
- # RSpec
1328
- describe UserController do
1329
- it { should use_around_filter(:log_activity) }
1330
- end
1331
-
1332
- # Test::Unit
1333
- class UserControllerTest < ActionController::TestCase
1334
- should use_around_filter(:log_activity)
1335
- end
1336
- ```
1337
-
1338
- #### use_before_filter / use_before_action
1339
-
1340
- The `use_before_filter` ensures a given `before_filter` is used. This is also
1341
- available as `use_before_action` for Rails 4 support.
1342
-
1343
- ```ruby
1344
- class UserController < ActionController::Base
1345
- before_filter :authenticate_user!
1346
- end
1347
-
1348
- # RSpec
1349
- describe UserController do
1350
- it { should use_before_filter(:authenticate_user!) }
1351
- end
1352
-
1353
- # Test::Unit
1354
- class UserControllerTest < ActionController::TestCase
1355
- should use_before_filter(:authenticate_user!)
1356
- end
1357
- ```
1358
-
1359
- ## Independent Matchers
1360
-
1361
- Matchers to test non-Rails-dependent code:
1362
-
1363
- #### delegate_method
1364
-
1365
- ```ruby
1366
- class Human < ActiveRecord::Base
1367
- has_one :robot
1368
- delegate :work, to: :robot
1369
-
1370
- # alternatively, if you are not using Rails
1371
- def work
1372
- robot.work
1373
- end
1374
-
1375
- def protect
1376
- robot.protect('Sarah Connor')
1377
- end
1378
-
1379
- def speak
1380
- robot.beep_boop
1381
- end
1382
- end
1383
-
1384
- # RSpec
1385
- describe Human do
1386
- it { should delegate_method(:work).to(:robot) }
1387
- it { should delegate_method(:protect).to(:robot).with_arguments('Sarah Connor') }
1388
- it { should delegate_method(:beep_boop).to(:robot).as(:speak) }
1389
- end
1390
-
1391
- # Test::Unit
1392
- class HumanTest < ActiveSupport::TestCase
1393
- should delegate_method(:work).to(:robot)
1394
- should delegate_method(:protect).to(:robot).with_arguments('Sarah Connor')
1395
- should delegate_method(:beep_boop).to(:robot).as(:speak)
1396
- end
1397
- ```
151
+ watchr docs.watchr
1398
152
 
1399
153
  ## Versioning
1400
154