thoughtbot-shoulda 2.10.2 → 2.11.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (241) hide show
  1. data/CONTRIBUTION_GUIDELINES.rdoc +5 -5
  2. data/README.rdoc +72 -89
  3. data/Rakefile +31 -33
  4. data/lib/shoulda.rb +6 -6
  5. data/lib/shoulda/action_controller.rb +8 -0
  6. data/lib/shoulda/action_controller/macros.rb +54 -73
  7. data/lib/shoulda/action_controller/matchers.rb +7 -5
  8. data/lib/shoulda/action_controller/matchers/assign_to_matcher.rb +10 -7
  9. data/lib/shoulda/action_controller/matchers/filter_param_matcher.rb +18 -1
  10. data/lib/shoulda/action_controller/matchers/redirect_to_matcher.rb +62 -0
  11. data/lib/shoulda/action_controller/matchers/render_template_matcher.rb +54 -0
  12. data/lib/shoulda/action_controller/matchers/render_with_layout_matcher.rb +33 -15
  13. data/lib/shoulda/action_controller/matchers/respond_with_content_type_matcher.rb +10 -10
  14. data/lib/shoulda/action_controller/matchers/respond_with_matcher.rb +17 -13
  15. data/lib/shoulda/action_controller/matchers/route_matcher.rb +3 -3
  16. data/lib/shoulda/action_controller/matchers/set_session_matcher.rb +13 -2
  17. data/lib/shoulda/action_controller/matchers/set_the_flash_matcher.rb +1 -1
  18. data/lib/shoulda/action_mailer.rb +3 -0
  19. data/lib/shoulda/action_mailer/assertions.rb +4 -0
  20. data/lib/shoulda/action_mailer/matchers.rb +22 -0
  21. data/lib/shoulda/action_mailer/matchers/have_sent_email.rb +110 -0
  22. data/lib/shoulda/active_record/helpers.rb +8 -3
  23. data/lib/shoulda/active_record/macros.rb +88 -143
  24. data/lib/shoulda/active_record/matchers.rb +0 -1
  25. data/lib/shoulda/active_record/matchers/allow_mass_assignment_of_matcher.rb +1 -1
  26. data/lib/shoulda/active_record/matchers/allow_value_matcher.rb +10 -2
  27. data/lib/shoulda/active_record/matchers/association_matcher.rb +8 -8
  28. data/lib/shoulda/active_record/matchers/ensure_inclusion_of_matcher.rb +1 -1
  29. data/lib/shoulda/active_record/matchers/ensure_length_of_matcher.rb +2 -2
  30. data/lib/shoulda/active_record/matchers/have_db_column_matcher.rb +11 -11
  31. data/lib/shoulda/active_record/matchers/have_db_index_matcher.rb +8 -8
  32. data/lib/shoulda/active_record/matchers/validate_format_of_matcher.rb +2 -4
  33. data/lib/shoulda/active_record/matchers/validate_uniqueness_of_matcher.rb +3 -3
  34. data/lib/shoulda/active_record/matchers/validation_matcher.rb +0 -1
  35. data/lib/shoulda/assertions.rb +10 -2
  36. data/lib/shoulda/autoload_macros.rb +20 -20
  37. data/lib/shoulda/context.rb +70 -39
  38. data/lib/shoulda/{rspec.rb → integrations/rspec.rb} +2 -0
  39. data/lib/shoulda/integrations/rspec2.rb +22 -0
  40. data/lib/shoulda/{test_unit.rb → integrations/test_unit.rb} +0 -0
  41. data/lib/shoulda/macros.rb +46 -18
  42. data/lib/shoulda/rails.rb +0 -5
  43. data/lib/shoulda/tasks/yaml_to_shoulda.rake +11 -11
  44. data/lib/shoulda/version.rb +4 -0
  45. data/rails/init.rb +3 -2
  46. data/test/fail_macros.rb +20 -4
  47. data/test/functional/posts_controller_test.rb +7 -7
  48. data/test/functional/users_controller_test.rb +1 -1
  49. data/test/matchers/action_mailer/have_sent_email_test.rb +70 -0
  50. data/test/matchers/active_record/allow_mass_assignment_of_matcher_test.rb +7 -1
  51. data/test/matchers/active_record/allow_value_matcher_test.rb +1 -1
  52. data/test/matchers/active_record/association_matcher_test.rb +16 -16
  53. data/test/matchers/active_record/ensure_inclusion_of_matcher_test.rb +3 -2
  54. data/test/matchers/active_record/ensure_length_of_matcher_test.rb +1 -1
  55. data/test/matchers/active_record/have_db_column_matcher_test.rb +1 -1
  56. data/test/matchers/active_record/have_db_index_matcher_test.rb +1 -1
  57. data/test/matchers/active_record/have_readonly_attributes_matcher_test.rb +1 -1
  58. data/test/matchers/active_record/validate_acceptance_of_matcher_test.rb +1 -1
  59. data/test/matchers/active_record/validate_format_of_matcher_test.rb +1 -1
  60. data/test/matchers/active_record/validate_numericality_of_matcher_test.rb +1 -1
  61. data/test/matchers/active_record/validate_presence_of_matcher_test.rb +1 -1
  62. data/test/matchers/active_record/validate_uniqueness_of_matcher_test.rb +1 -1
  63. data/test/matchers/controller/assign_to_matcher_test.rb +11 -1
  64. data/test/matchers/controller/filter_param_matcher_test.rb +10 -2
  65. data/test/matchers/controller/redirect_to_matcher_test.rb +37 -0
  66. data/test/matchers/controller/render_template_matcher_test.rb +37 -0
  67. data/test/matchers/controller/render_with_layout_matcher_test.rb +15 -1
  68. data/test/matchers/controller/respond_with_content_type_matcher_test.rb +1 -1
  69. data/test/matchers/controller/respond_with_matcher_test.rb +1 -11
  70. data/test/matchers/controller/route_matcher_test.rb +18 -1
  71. data/test/matchers/controller/set_session_matcher_test.rb +11 -1
  72. data/test/matchers/controller/set_the_flash_matcher.rb +1 -1
  73. data/test/other/autoload_macro_test.rb +1 -1
  74. data/test/other/context_test.rb +210 -27
  75. data/test/other/convert_to_should_syntax_test.rb +1 -1
  76. data/test/other/helpers_test.rb +13 -36
  77. data/test/other/private_helpers_test.rb +2 -2
  78. data/test/other/should_test.rb +13 -13
  79. data/test/{model_builder.rb → rails2_model_builder.rb} +32 -8
  80. data/test/{rails_root → rails2_root}/app/controllers/application_controller.rb +0 -3
  81. data/test/{rails_root → rails2_root}/app/controllers/posts_controller.rb +0 -0
  82. data/test/{rails_root → rails2_root}/app/controllers/users_controller.rb +0 -0
  83. data/test/{rails_root → rails2_root}/app/helpers/application_helper.rb +0 -0
  84. data/test/{rails_root → rails2_root}/app/helpers/posts_helper.rb +0 -0
  85. data/test/{rails_root → rails2_root}/app/helpers/users_helper.rb +0 -0
  86. data/test/{rails_root → rails2_root}/app/models/address.rb +0 -0
  87. data/test/rails2_root/app/models/flea.rb +11 -0
  88. data/test/{rails_root → rails2_root}/app/models/friendship.rb +0 -0
  89. data/test/rails2_root/app/models/notifier.rb +8 -0
  90. data/test/{rails_root → rails2_root}/app/models/pets/cat.rb +0 -0
  91. data/test/{rails_root → rails2_root}/app/models/pets/dog.rb +0 -0
  92. data/test/{rails_root → rails2_root}/app/models/post.rb +1 -1
  93. data/test/{rails_root → rails2_root}/app/models/product.rb +0 -0
  94. data/test/{rails_root → rails2_root}/app/models/profile.rb +0 -0
  95. data/test/{rails_root → rails2_root}/app/models/registration.rb +0 -0
  96. data/test/{rails_root → rails2_root}/app/models/tag.rb +0 -0
  97. data/test/{rails_root → rails2_root}/app/models/tagging.rb +0 -0
  98. data/test/{rails_root → rails2_root}/app/models/treat.rb +0 -0
  99. data/test/{rails_root → rails2_root}/app/models/user.rb +0 -0
  100. data/test/{rails_root → rails2_root}/app/views/layouts/posts.rhtml +0 -0
  101. data/test/{rails_root → rails2_root}/app/views/layouts/users.rhtml +0 -0
  102. data/test/{rails_root → rails2_root}/app/views/layouts/wide.html.erb +0 -0
  103. data/test/rails2_root/app/views/notifier/the_email.html.erb +1 -0
  104. data/test/{rails_root → rails2_root}/app/views/posts/edit.rhtml +0 -0
  105. data/test/{rails_root → rails2_root}/app/views/posts/index.rhtml +0 -0
  106. data/test/{rails_root → rails2_root}/app/views/posts/new.rhtml +0 -0
  107. data/test/{rails_root → rails2_root}/app/views/posts/show.rhtml +0 -0
  108. data/test/{rails_root → rails2_root}/app/views/users/edit.rhtml +0 -0
  109. data/test/{rails_root → rails2_root}/app/views/users/index.rhtml +0 -0
  110. data/test/{rails_root → rails2_root}/app/views/users/new.rhtml +0 -0
  111. data/test/{rails_root → rails2_root}/app/views/users/show.rhtml +0 -0
  112. data/test/{rails_root → rails2_root}/config/boot.rb +0 -0
  113. data/test/{rails_root → rails2_root}/config/database.yml +1 -1
  114. data/test/{rails_root → rails2_root}/config/environment.rb +0 -1
  115. data/test/rails2_root/config/environments/test.rb +23 -0
  116. data/test/{rails_root → rails2_root}/config/initializers/new_rails_defaults.rb +0 -0
  117. data/test/{rails_root → rails2_root}/config/initializers/shoulda.rb +0 -0
  118. data/test/{rails_root → rails2_root}/config/routes.rb +0 -0
  119. data/test/{rails_root → rails2_root}/db/migrate/001_create_users.rb +0 -0
  120. data/test/{rails_root → rails2_root}/db/migrate/002_create_posts.rb +0 -0
  121. data/test/{rails_root → rails2_root}/db/migrate/003_create_taggings.rb +0 -0
  122. data/test/{rails_root → rails2_root}/db/migrate/004_create_tags.rb +0 -0
  123. data/test/{rails_root → rails2_root}/db/migrate/005_create_dogs.rb +0 -0
  124. data/test/{rails_root → rails2_root}/db/migrate/006_create_addresses.rb +0 -0
  125. data/test/{rails_root → rails2_root}/db/migrate/007_create_fleas.rb +0 -0
  126. data/test/{rails_root → rails2_root}/db/migrate/008_create_dogs_fleas.rb +0 -0
  127. data/test/{rails_root → rails2_root}/db/migrate/009_create_products.rb +0 -0
  128. data/test/{rails_root → rails2_root}/db/migrate/010_create_friendships.rb +0 -0
  129. data/test/{rails_root → rails2_root}/db/migrate/011_create_treats.rb +0 -0
  130. data/test/{rails_root → rails2_root}/db/migrate/20090506203502_create_profiles.rb +0 -0
  131. data/test/{rails_root → rails2_root}/db/migrate/20090506203536_create_registrations.rb +0 -0
  132. data/test/{rails_root → rails2_root}/db/migrate/20090513104502_create_cats.rb +0 -0
  133. data/test/{rails_root → rails2_root}/db/schema.rb +0 -0
  134. data/test/{rails_root → rails2_root}/public/404.html +0 -0
  135. data/test/{rails_root → rails2_root}/public/422.html +0 -0
  136. data/test/{rails_root → rails2_root}/public/500.html +0 -0
  137. data/test/{rails_root → rails2_root}/script/console +0 -0
  138. data/test/{rails_root → rails2_root}/script/generate +0 -0
  139. data/test/{rails_root → rails2_root}/test/shoulda_macros/custom_macro.rb +0 -0
  140. data/test/{rails_root → rails2_root}/vendor/gems/gem_with_macro-0.0.1/shoulda_macros/gem_macro.rb +0 -0
  141. data/test/{rails_root → rails2_root}/vendor/plugins/plugin_with_macro/shoulda_macros/plugin_macro.rb +0 -0
  142. data/test/rails2_test_helper.rb +6 -0
  143. data/test/rails3_model_builder.rb +118 -0
  144. data/test/rails3_root/Gemfile +28 -0
  145. data/test/rails3_root/README +244 -0
  146. data/test/rails3_root/Rakefile +10 -0
  147. data/test/rails3_root/app/controllers/application_controller.rb +22 -0
  148. data/test/rails3_root/app/controllers/posts_controller.rb +87 -0
  149. data/test/rails3_root/app/controllers/users_controller.rb +82 -0
  150. data/test/rails3_root/app/helpers/application_helper.rb +2 -0
  151. data/test/rails3_root/app/models/address.rb +7 -0
  152. data/test/rails3_root/app/models/flea.rb +11 -0
  153. data/test/rails3_root/app/models/friendship.rb +4 -0
  154. data/test/rails3_root/app/models/notifier.rb +8 -0
  155. data/test/rails3_root/app/models/pets/cat.rb +7 -0
  156. data/test/rails3_root/app/models/pets/dog.rb +10 -0
  157. data/test/rails3_root/app/models/post.rb +12 -0
  158. data/test/rails3_root/app/models/product.rb +12 -0
  159. data/test/rails3_root/app/models/profile.rb +2 -0
  160. data/test/rails3_root/app/models/registration.rb +2 -0
  161. data/test/rails3_root/app/models/tag.rb +8 -0
  162. data/test/rails3_root/app/models/tagging.rb +4 -0
  163. data/test/rails3_root/app/models/treat.rb +3 -0
  164. data/test/rails3_root/app/models/user.rb +32 -0
  165. data/test/rails3_root/app/views/layouts/application.html.erb +14 -0
  166. data/test/rails3_root/app/views/layouts/posts.rhtml +19 -0
  167. data/test/rails3_root/app/views/layouts/users.rhtml +17 -0
  168. data/test/rails3_root/app/views/layouts/wide.html.erb +1 -0
  169. data/test/rails3_root/app/views/notifier/the_email.html.erb +1 -0
  170. data/test/rails3_root/app/views/posts/edit.rhtml +27 -0
  171. data/test/rails3_root/app/views/posts/index.rhtml +25 -0
  172. data/test/rails3_root/app/views/posts/new.rhtml +24 -0
  173. data/test/rails3_root/app/views/posts/show.rhtml +18 -0
  174. data/test/rails3_root/app/views/users/edit.rhtml +22 -0
  175. data/test/rails3_root/app/views/users/index.rhtml +22 -0
  176. data/test/rails3_root/app/views/users/new.rhtml +21 -0
  177. data/test/rails3_root/app/views/users/show.rhtml +13 -0
  178. data/test/rails3_root/config.ru +4 -0
  179. data/test/rails3_root/config/application.rb +46 -0
  180. data/test/rails3_root/config/boot.rb +6 -0
  181. data/test/rails3_root/config/database.yml +22 -0
  182. data/test/rails3_root/config/environment.rb +5 -0
  183. data/test/rails3_root/config/environments/development.rb +19 -0
  184. data/test/rails3_root/config/environments/production.rb +42 -0
  185. data/test/rails3_root/config/environments/test.rb +32 -0
  186. data/test/rails3_root/config/initializers/backtrace_silencers.rb +7 -0
  187. data/test/rails3_root/config/initializers/inflections.rb +10 -0
  188. data/test/rails3_root/config/initializers/mime_types.rb +5 -0
  189. data/test/rails3_root/config/initializers/secret_token.rb +7 -0
  190. data/test/rails3_root/config/initializers/session_store.rb +8 -0
  191. data/test/rails3_root/config/locales/en.yml +5 -0
  192. data/test/rails3_root/config/routes.rb +4 -0
  193. data/test/rails3_root/db/migrate/001_create_users.rb +19 -0
  194. data/test/rails3_root/db/migrate/002_create_posts.rb +13 -0
  195. data/test/rails3_root/db/migrate/003_create_taggings.rb +12 -0
  196. data/test/rails3_root/db/migrate/004_create_tags.rb +11 -0
  197. data/test/rails3_root/db/migrate/005_create_dogs.rb +12 -0
  198. data/test/rails3_root/db/migrate/006_create_addresses.rb +14 -0
  199. data/test/rails3_root/db/migrate/007_create_fleas.rb +11 -0
  200. data/test/rails3_root/db/migrate/008_create_dogs_fleas.rb +12 -0
  201. data/test/rails3_root/db/migrate/009_create_products.rb +17 -0
  202. data/test/rails3_root/db/migrate/010_create_friendships.rb +14 -0
  203. data/test/rails3_root/db/migrate/011_create_treats.rb +12 -0
  204. data/test/rails3_root/db/migrate/20090506203502_create_profiles.rb +12 -0
  205. data/test/rails3_root/db/migrate/20090506203536_create_registrations.rb +14 -0
  206. data/test/rails3_root/db/migrate/20090513104502_create_cats.rb +12 -0
  207. data/test/rails3_root/db/seeds.rb +7 -0
  208. data/test/rails3_root/public/404.html +26 -0
  209. data/test/rails3_root/public/422.html +26 -0
  210. data/test/rails3_root/public/500.html +26 -0
  211. data/test/{rails_root/config/environments/test.rb → rails3_root/public/favicon.ico} +0 -0
  212. data/test/rails3_root/public/images/rails.png +0 -0
  213. data/test/rails3_root/public/index.html +279 -0
  214. data/test/rails3_root/public/javascripts/application.js +2 -0
  215. data/test/rails3_root/public/javascripts/controls.js +965 -0
  216. data/test/rails3_root/public/javascripts/dragdrop.js +974 -0
  217. data/test/rails3_root/public/javascripts/effects.js +1123 -0
  218. data/test/rails3_root/public/javascripts/prototype.js +4874 -0
  219. data/test/rails3_root/public/javascripts/rails.js +118 -0
  220. data/test/rails3_root/public/robots.txt +5 -0
  221. data/test/rails3_root/script/rails +9 -0
  222. data/test/rails3_root/test/performance/browsing_test.rb +9 -0
  223. data/test/rails3_root/test/test_helper.rb +13 -0
  224. data/test/rails3_test_helper.rb +6 -0
  225. data/test/test_helper.rb +16 -8
  226. data/test/unit/address_test.rb +1 -1
  227. data/test/unit/cat_test.rb +1 -1
  228. data/test/unit/dog_test.rb +1 -1
  229. data/test/unit/flea_test.rb +9 -1
  230. data/test/unit/friendship_test.rb +1 -1
  231. data/test/unit/post_test.rb +1 -5
  232. data/test/unit/product_test.rb +1 -1
  233. data/test/unit/tag_test.rb +1 -5
  234. data/test/unit/tagging_test.rb +1 -1
  235. data/test/unit/user_test.rb +3 -37
  236. metadata +184 -118
  237. data/lib/shoulda/action_view.rb +0 -10
  238. data/lib/shoulda/action_view/macros.rb +0 -61
  239. data/lib/shoulda/active_record/matchers/have_named_scope_matcher.rb +0 -128
  240. data/test/matchers/active_record/have_named_scope_matcher_test.rb +0 -65
  241. data/test/rails_root/app/models/flea.rb +0 -3
@@ -36,6 +36,7 @@ module Shoulda # :nodoc:
36
36
 
37
37
  def to(params)
38
38
  @params = params
39
+ stringify_params!
39
40
  self
40
41
  end
41
42
 
@@ -47,7 +48,6 @@ module Shoulda # :nodoc:
47
48
  def matches?(controller)
48
49
  @controller = controller
49
50
  guess_controller!
50
- stringify_params!
51
51
  route_recognized?
52
52
  end
53
53
 
@@ -65,13 +65,13 @@ module Shoulda # :nodoc:
65
65
 
66
66
  def stringify_params!
67
67
  @params.each do |key, value|
68
- @params[key] = value.to_param
68
+ @params[key] = value.is_a?(Array) ? value.collect {|v| v.to_param } : value.to_param
69
69
  end
70
70
  end
71
71
 
72
72
  def route_recognized?
73
73
  begin
74
- @context.send(:assert_routing,
74
+ @context.send(:assert_routing,
75
75
  { :method => @method, :path => @path },
76
76
  @params)
77
77
 
@@ -19,13 +19,15 @@ module Shoulda # :nodoc:
19
19
  @key = key.to_s
20
20
  end
21
21
 
22
- def to(value)
22
+ def to(value = nil, &block)
23
23
  @value = value
24
+ @value_block = block
24
25
  self
25
26
  end
26
27
 
27
28
  def matches?(controller)
28
29
  @controller = controller
30
+ @value = @context.instance_eval(&@value_block) if @value_block
29
31
  (assigned_value? && assigned_correct_value?) || cleared_value?
30
32
  end
31
33
 
@@ -43,6 +45,11 @@ module Shoulda # :nodoc:
43
45
  description
44
46
  end
45
47
 
48
+ def in_context(context)
49
+ @context = context
50
+ self
51
+ end
52
+
46
53
  private
47
54
 
48
55
  def assigned_value?
@@ -63,7 +70,11 @@ module Shoulda # :nodoc:
63
70
  end
64
71
 
65
72
  def session
66
- @controller.response.session.data
73
+ if @controller.request.respond_to?(:session)
74
+ @controller.request.session.to_hash
75
+ else
76
+ @controller.response.session.data
77
+ end
67
78
  end
68
79
 
69
80
  def expectation
@@ -60,7 +60,7 @@ module Shoulda # :nodoc:
60
60
  end
61
61
 
62
62
  def flash
63
- @controller.response.session['flash']
63
+ @controller.send(:flash)
64
64
  end
65
65
 
66
66
  def expectation
@@ -1,10 +1,13 @@
1
1
  require 'shoulda'
2
2
  require 'shoulda/action_mailer/assertions'
3
+ require 'shoulda/action_mailer/matchers'
3
4
 
4
5
  module Test # :nodoc: all
5
6
  module Unit
6
7
  class TestCase
7
8
  include Shoulda::ActionMailer::Assertions
9
+ include Shoulda::ActionMailer::Matchers
10
+ extend Shoulda::ActionMailer::Matchers
8
11
  end
9
12
  end
10
13
  end
@@ -16,6 +16,7 @@ module Shoulda # :nodoc:
16
16
  # 'none@none.com' as one of the recipients.
17
17
  #
18
18
  def assert_sent_email
19
+ ::ActiveSupport::Deprecation.warn("use: should have_sent_email")
19
20
  emails = ::ActionMailer::Base.deliveries
20
21
  assert !emails.empty?, "No emails were sent"
21
22
  if block_given?
@@ -24,10 +25,13 @@ module Shoulda # :nodoc:
24
25
  end
25
26
  end
26
27
 
28
+ # should have_sent_email.with_subject(/hi there/).to('none@none.com').from('noreply@example.com').with_body(/reach out/)
29
+
27
30
  # Asserts that no ActionMailer mails were delivered
28
31
  #
29
32
  # assert_did_not_send_email
30
33
  def assert_did_not_send_email
34
+ ::ActiveSupport::Deprecation.warn("use: should_not have_sent_email")
31
35
  msg = "Sent #{::ActionMailer::Base.deliveries.size} emails.\n"
32
36
  ::ActionMailer::Base.deliveries.each { |m| msg << " '#{m.subject}' sent to #{m.to.to_sentence}\n" }
33
37
  assert ::ActionMailer::Base.deliveries.empty?, msg
@@ -0,0 +1,22 @@
1
+ require 'shoulda/action_mailer/matchers/have_sent_email'
2
+
3
+ module Shoulda # :nodoc:
4
+ module ActionMailer # :nodoc:
5
+ # = Matchers for your mailers
6
+ #
7
+ # This matcher will test that email is sent properly
8
+ #
9
+ # describe User do
10
+ # it { should have_sent_email.with_subject(/is spam$/) }
11
+ # it { should have_sent_email.from('do-not-reply@example.com') }
12
+ # it { should have_sent_email.with_body(/is spam\./) }
13
+ # it { should have_sent_email.to('myself@me.com') }
14
+ # it { should have_sent_email.with_subject(/spam/).
15
+ # from('do-not-reply@example.com').
16
+ # with_body(/spam/).
17
+ # to('myself@me.com') }
18
+ # end
19
+ module Matchers
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,110 @@
1
+ module Shoulda # :nodoc:
2
+ module ActionMailer # :nodoc:
3
+ module Matchers
4
+
5
+ # The right email is sent.
6
+ #
7
+ # it { should have_sent_email.with_subject(/is spam$/) }
8
+ # it { should have_sent_email.from('do-not-reply@example.com') }
9
+ # it { should have_sent_email.with_body(/is spam\./) }
10
+ # it { should have_sent_email.to('myself@me.com') }
11
+ # it { should have_sent_email.with_subject(/spam/).
12
+ # from('do-not-reply@example.com').
13
+ # with_body(/spam/).
14
+ # to('myself@me.com') }
15
+ def have_sent_email
16
+ HaveSentEmailMatcher.new
17
+ end
18
+
19
+ class HaveSentEmailMatcher # :nodoc:
20
+
21
+ def initialize
22
+ end
23
+
24
+ def with_subject(email_subject)
25
+ @email_subject = email_subject
26
+ self
27
+ end
28
+
29
+ def from(sender)
30
+ @sender = sender
31
+ self
32
+ end
33
+
34
+ def with_body(body)
35
+ @body = body
36
+ self
37
+ end
38
+
39
+ def to(recipient)
40
+ @recipient = recipient
41
+ self
42
+ end
43
+
44
+ def matches?(subject)
45
+ ::ActionMailer::Base.deliveries.each do |mail|
46
+ @subject_failed = !regexp_or_string_match(mail.subject, @email_subject) if @email_subject
47
+ @body_failed = !regexp_or_string_match(mail.body, @body) if @body
48
+ @sender_failed = !regexp_or_string_match_in_array(mail.from, @sender) if @sender
49
+ @recipient_failed = !regexp_or_string_match_in_array(mail.to, @recipient) if @recipient
50
+ return true unless anything_failed?
51
+ end
52
+
53
+ false
54
+ end
55
+
56
+ def failure_message
57
+ "Expected #{expectation}"
58
+ end
59
+
60
+ def negative_failure_message
61
+ "Did not expect #{expectation}"
62
+ end
63
+
64
+ def description
65
+ "send an email"
66
+ end
67
+
68
+ private
69
+
70
+ def expectation
71
+ expectation = "sent email"
72
+ expectation << " with subject #{@email_subject.inspect}" if @subject_failed
73
+ expectation << " with body #{@body.inspect}" if @body_failed
74
+ expectation << " from #{@sender.inspect}" if @sender_failed
75
+ expectation << " to #{@recipient.inspect}" if @recipient_failed
76
+ expectation << "\nDeliveries:\n#{inspect_deliveries}"
77
+ end
78
+
79
+ def inspect_deliveries
80
+ ::ActionMailer::Base.deliveries.map do |delivery|
81
+ "#{delivery.subject.inspect} to #{delivery.to.inspect}"
82
+ end.join("\n")
83
+ end
84
+
85
+ def anything_failed?
86
+ @subject_failed || @body_failed || @sender_failed || @recipient_failed
87
+ end
88
+
89
+ def regexp_or_string_match(a_string, a_regexp_or_string)
90
+ case a_regexp_or_string
91
+ when Regexp
92
+ a_string =~ a_regexp_or_string
93
+ when String
94
+ a_string == a_regexp_or_string
95
+ end
96
+ end
97
+
98
+ def regexp_or_string_match_in_array(an_array, a_regexp_or_string)
99
+ case a_regexp_or_string
100
+ when Regexp
101
+ an_array.detect{|e| e =~ a_regexp_or_string}.any?
102
+ when String
103
+ an_array.include?(a_regexp_or_string)
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
110
+
@@ -2,8 +2,8 @@ module Shoulda # :nodoc:
2
2
  module ActiveRecord # :nodoc:
3
3
  module Helpers
4
4
  def pretty_error_messages(obj) # :nodoc:
5
- obj.errors.map do |a, m|
6
- msg = "#{a} #{m}"
5
+ obj.errors.map do |a, m|
6
+ msg = "#{a} #{m}"
7
7
  msg << " (#{obj.send(a).inspect})" unless a.to_sym == :base
8
8
  end
9
9
  end
@@ -17,7 +17,12 @@ module Shoulda # :nodoc:
17
17
  # default_error_message(:too_long, :count => 60)
18
18
  def default_error_message(key, values = {})
19
19
  if Object.const_defined?(:I18n) # Rails >= 2.2
20
- I18n.translate("activerecord.errors.messages.#{key}", values)
20
+ result = I18n.translate("activerecord.errors.messages.#{key}", values)
21
+ if result =~ /^translation missing/
22
+ I18n.translate("errors.messages.#{key}", values)
23
+ else
24
+ result
25
+ end
21
26
  else # Rails <= 2.1.x
22
27
  ::ActiveRecord::Errors.default_error_messages[key] % values[:count]
23
28
  end
@@ -23,6 +23,8 @@ module Shoulda # :nodoc:
23
23
  include Helpers
24
24
  include Matchers
25
25
 
26
+ # Deprecated: use ActiveRecord::Matchers#validate_presence_of instead.
27
+ #
26
28
  # Ensures that the model cannot be saved if one of the attributes listed is not present.
27
29
  #
28
30
  # Options:
@@ -33,21 +35,20 @@ module Shoulda # :nodoc:
33
35
  # should_validate_presence_of :name, :phone_number
34
36
  #
35
37
  def should_validate_presence_of(*attributes)
38
+ ::ActiveSupport::Deprecation.warn("use: should validate_presence_of")
36
39
  message = get_options!(attributes, :message)
37
40
 
38
41
  attributes.each do |attribute|
39
- matcher = validate_presence_of(attribute).with_message(message)
40
- should matcher.description do
41
- assert_accepts(matcher, subject)
42
- end
42
+ should validate_presence_of(attribute).with_message(message)
43
43
  end
44
44
  end
45
-
45
+
46
+ # Deprecated: use ActiveRecord::Matchers#validate_uniqueness_of instead.
47
+ #
46
48
  # Ensures that the model cannot be saved if one of the attributes listed is not unique.
47
49
  # Requires an existing record
48
50
  #
49
51
  # Options:
50
-
51
52
  # * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
52
53
  # Regexp or string. Default = <tt>I18n.translate('activerecord.errors.messages.taken')</tt>
53
54
  # * <tt>:scoped_to</tt> - field(s) to scope the uniqueness to.
@@ -62,6 +63,7 @@ module Shoulda # :nodoc:
62
63
  # should_validate_uniqueness_of :email, :case_sensitive => false
63
64
  #
64
65
  def should_validate_uniqueness_of(*attributes)
66
+ ::ActiveSupport::Deprecation.warn("use: should validate_uniqueness_of")
65
67
  message, scope, case_sensitive = get_options!(attributes, :message, :scoped_to, :case_sensitive)
66
68
  scope = [*scope].compact
67
69
  case_sensitive = true if case_sensitive.nil?
@@ -70,57 +72,57 @@ module Shoulda # :nodoc:
70
72
  matcher = validate_uniqueness_of(attribute).
71
73
  with_message(message).scoped_to(scope)
72
74
  matcher = matcher.case_insensitive unless case_sensitive
73
- should matcher.description do
74
- assert_accepts(matcher, subject)
75
- end
75
+ should matcher
76
76
  end
77
77
  end
78
78
 
79
+ # Deprecated: use ActiveRecord::Matchers#allow_mass_assignment_of instead.
80
+ #
79
81
  # Ensures that the attribute can be set on mass update.
80
82
  #
81
83
  # should_allow_mass_assignment_of :first_name, :last_name
82
84
  #
83
85
  def should_allow_mass_assignment_of(*attributes)
86
+ ::ActiveSupport::Deprecation.warn("use: should allow_mass_assignment_of")
84
87
  get_options!(attributes)
85
88
 
86
89
  attributes.each do |attribute|
87
- matcher = allow_mass_assignment_of(attribute)
88
- should matcher.description do
89
- assert_accepts matcher, subject
90
- end
90
+ should allow_mass_assignment_of(attribute)
91
91
  end
92
92
  end
93
93
 
94
+ # Deprecated: use ActiveRecord::Matchers#allow_mass_assignment_of instead.
95
+ #
94
96
  # Ensures that the attribute cannot be set on mass update.
95
97
  #
96
98
  # should_not_allow_mass_assignment_of :password, :admin_flag
97
99
  #
98
100
  def should_not_allow_mass_assignment_of(*attributes)
101
+ ::ActiveSupport::Deprecation.warn("use: should_not allow_mass_assignment_of")
99
102
  get_options!(attributes)
100
103
 
101
104
  attributes.each do |attribute|
102
- matcher = allow_mass_assignment_of(attribute)
103
- should "not #{matcher.description}" do
104
- assert_rejects matcher, subject
105
- end
105
+ should_not allow_mass_assignment_of(attribute)
106
106
  end
107
107
  end
108
108
 
109
+ # Deprecated: use ActiveRecord::Matchers#have_readonly_attribute instead.
110
+ #
109
111
  # Ensures that the attribute cannot be changed once the record has been created.
110
112
  #
111
113
  # should_have_readonly_attributes :password, :admin_flag
112
114
  #
113
115
  def should_have_readonly_attributes(*attributes)
116
+ ::ActiveSupport::Deprecation.warn("use: should have_readonly_attribute")
114
117
  get_options!(attributes)
115
118
 
116
119
  attributes.each do |attribute|
117
- matcher = have_readonly_attribute(attribute)
118
- should matcher.description do
119
- assert_accepts matcher, subject
120
- end
120
+ should have_readonly_attribute(attribute)
121
121
  end
122
122
  end
123
123
 
124
+ # Deprecated: use ActiveRecord::Matchers#allow_value instead.
125
+ #
124
126
  # Ensures that the attribute cannot be set to the given values
125
127
  #
126
128
  # Options:
@@ -132,30 +134,30 @@ module Shoulda # :nodoc:
132
134
  # should_not_allow_values_for :isbn, "bad 1", "bad 2"
133
135
  #
134
136
  def should_not_allow_values_for(attribute, *bad_values)
137
+ ::ActiveSupport::Deprecation.warn("use: should_not allow_value")
135
138
  message = get_options!(bad_values, :message)
136
139
  bad_values.each do |value|
137
- matcher = allow_value(value).for(attribute).with_message(message)
138
- should "not #{matcher.description}" do
139
- assert_rejects matcher, subject
140
- end
140
+ should_not allow_value(value).for(attribute).with_message(message)
141
141
  end
142
142
  end
143
143
 
144
+ # Deprecated: use ActiveRecord::Matchers#allow_value instead.
145
+ #
144
146
  # Ensures that the attribute can be set to the given values.
145
147
  #
146
148
  # Example:
147
149
  # should_allow_values_for :isbn, "isbn 1 2345 6789 0", "ISBN 1-2345-6789-0"
148
150
  #
149
151
  def should_allow_values_for(attribute, *good_values)
152
+ ::ActiveSupport::Deprecation.warn("use: should allow_value")
150
153
  get_options!(good_values)
151
154
  good_values.each do |value|
152
- matcher = allow_value(value).for(attribute)
153
- should matcher.description do
154
- assert_accepts matcher, subject
155
- end
155
+ should allow_value(value).for(attribute)
156
156
  end
157
157
  end
158
158
 
159
+ # Deprecated: use ActiveRecord::Matchers#ensure_length_of instead.
160
+ #
159
161
  # Ensures that the length of the attribute is in the given range
160
162
  #
161
163
  # Options:
@@ -168,20 +170,19 @@ module Shoulda # :nodoc:
168
170
  # should_ensure_length_in_range :password, (6..20)
169
171
  #
170
172
  def should_ensure_length_in_range(attribute, range, opts = {})
171
- short_message, long_message = get_options!([opts],
173
+ ::ActiveSupport::Deprecation.warn("use: should ensure_length_of.is_at_least.is_at_most")
174
+ short_message, long_message = get_options!([opts],
172
175
  :short_message,
173
176
  :long_message)
174
- matcher = ensure_length_of(attribute).
177
+ should ensure_length_of(attribute).
175
178
  is_at_least(range.first).
176
179
  with_short_message(short_message).
177
180
  is_at_most(range.last).
178
181
  with_long_message(long_message)
179
-
180
- should matcher.description do
181
- assert_accepts matcher, subject
182
- end
183
182
  end
184
183
 
184
+ # Deprecated: use ActiveRecord::Matchers#ensure_length_of instead.
185
+ #
185
186
  # Ensures that the length of the attribute is at least a certain length
186
187
  #
187
188
  # Options:
@@ -192,17 +193,16 @@ module Shoulda # :nodoc:
192
193
  # should_ensure_length_at_least :name, 3
193
194
  #
194
195
  def should_ensure_length_at_least(attribute, min_length, opts = {})
196
+ ::ActiveSupport::Deprecation.warn("use: should ensure_length_of.is_at_least")
195
197
  short_message = get_options!([opts], :short_message)
196
198
 
197
- matcher = ensure_length_of(attribute).
199
+ should ensure_length_of(attribute).
198
200
  is_at_least(min_length).
199
201
  with_short_message(short_message)
200
-
201
- should matcher.description do
202
- assert_accepts matcher, subject
203
- end
204
202
  end
205
203
 
204
+ # Deprecated: use ActiveRecord::Matchers#ensure_length_of instead.
205
+ #
206
206
  # Ensures that the length of the attribute is exactly a certain length
207
207
  #
208
208
  # Options:
@@ -213,16 +213,15 @@ module Shoulda # :nodoc:
213
213
  # should_ensure_length_is :ssn, 9
214
214
  #
215
215
  def should_ensure_length_is(attribute, length, opts = {})
216
+ ::ActiveSupport::Deprecation.warn("use: should ensure_length_of.is_equal_to")
216
217
  message = get_options!([opts], :message)
217
- matcher = ensure_length_of(attribute).
218
+ should ensure_length_of(attribute).
218
219
  is_equal_to(length).
219
220
  with_message(message)
220
-
221
- should matcher.description do
222
- assert_accepts matcher, subject
223
- end
224
221
  end
225
222
 
223
+ # Deprecated: use ActiveRecord::Matchers#ensure_inclusion_of instead.
224
+ #
226
225
  # Ensure that the attribute is in the range specified
227
226
  #
228
227
  # Options:
@@ -235,20 +234,20 @@ module Shoulda # :nodoc:
235
234
  # should_ensure_value_in_range :age, (0..100)
236
235
  #
237
236
  def should_ensure_value_in_range(attribute, range, opts = {})
237
+ ::ActiveSupport::Deprecation.warn("use: should ensure_inclusion_of.in_range")
238
238
  message, low_message, high_message = get_options!([opts],
239
239
  :message,
240
240
  :low_message,
241
241
  :high_message)
242
- matcher = ensure_inclusion_of(attribute).
242
+ should ensure_inclusion_of(attribute).
243
243
  in_range(range).
244
244
  with_message(message).
245
245
  with_low_message(low_message).
246
246
  with_high_message(high_message)
247
- should matcher.description do
248
- assert_accepts matcher, subject
249
- end
250
247
  end
251
248
 
249
+ # Deprecated: use ActiveRecord::Matchers#validate_numericality_of instead.
250
+ #
252
251
  # Ensure that the attribute is numeric
253
252
  #
254
253
  # Options:
@@ -259,16 +258,16 @@ module Shoulda # :nodoc:
259
258
  # should_validate_numericality_of :age
260
259
  #
261
260
  def should_validate_numericality_of(*attributes)
261
+ ::ActiveSupport::Deprecation.warn("use: should validate_numericality_of")
262
262
  message = get_options!(attributes, :message)
263
263
  attributes.each do |attribute|
264
- matcher = validate_numericality_of(attribute).
264
+ should validate_numericality_of(attribute).
265
265
  with_message(message)
266
- should matcher.description do
267
- assert_accepts matcher, subject
268
- end
269
266
  end
270
267
  end
271
268
 
269
+ # Deprecated: use ActiveRecord::Matchers#have_many instead.
270
+ #
272
271
  # Ensures that the has_many relationship exists. Will also test that the
273
272
  # associated table has the required columns. Works with polymorphic
274
273
  # associations.
@@ -283,15 +282,15 @@ module Shoulda # :nodoc:
283
282
  # should_have_many :enemies, :dependent => :destroy
284
283
  #
285
284
  def should_have_many(*associations)
285
+ ::ActiveSupport::Deprecation.warn("use: should have_many")
286
286
  through, dependent = get_options!(associations, :through, :dependent)
287
287
  associations.each do |association|
288
- matcher = have_many(association).through(through).dependent(dependent)
289
- should matcher.description do
290
- assert_accepts(matcher, subject)
291
- end
288
+ should have_many(association).through(through).dependent(dependent)
292
289
  end
293
290
  end
294
291
 
292
+ # Deprecated: use ActiveRecord::Matchers#have_one instead.
293
+ #
295
294
  # Ensure that the has_one relationship exists. Will also test that the
296
295
  # associated table has the required columns. Works with polymorphic
297
296
  # associations.
@@ -303,50 +302,51 @@ module Shoulda # :nodoc:
303
302
  # should_have_one :god # unless hindu
304
303
  #
305
304
  def should_have_one(*associations)
305
+ ::ActiveSupport::Deprecation.warn("use: should have_one")
306
306
  dependent, through = get_options!(associations, :dependent, :through)
307
307
  associations.each do |association|
308
- matcher = have_one(association).dependent(dependent).through(through)
309
- should matcher.description do
310
- assert_accepts(matcher, subject)
311
- end
308
+ should have_one(association).dependent(dependent).through(through)
312
309
  end
313
310
  end
314
311
 
312
+ # Deprecated: use ActiveRecord::Matchers#have_and_belong_to_many instead.
313
+ #
315
314
  # Ensures that the has_and_belongs_to_many relationship exists, and that the join
316
315
  # table is in place.
317
316
  #
318
317
  # should_have_and_belong_to_many :posts, :cars
319
318
  #
320
319
  def should_have_and_belong_to_many(*associations)
320
+ ::ActiveSupport::Deprecation.warn("use: should have_and_belong_to_many")
321
321
  get_options!(associations)
322
322
 
323
323
  associations.each do |association|
324
- matcher = have_and_belong_to_many(association)
325
- should matcher.description do
326
- assert_accepts(matcher, subject)
327
- end
324
+ should have_and_belong_to_many(association)
328
325
  end
329
326
  end
330
327
 
328
+ # Deprecated: use ActiveRecord::Matchers#belong_to instead.
329
+ #
331
330
  # Ensure that the belongs_to relationship exists.
332
331
  #
333
332
  # should_belong_to :parent
334
333
  #
335
334
  def should_belong_to(*associations)
335
+ ::ActiveSupport::Deprecation.warn("use: should belong_to")
336
336
  dependent = get_options!(associations, :dependent)
337
337
  associations.each do |association|
338
- matcher = belong_to(association).dependent(dependent)
339
- should matcher.description do
340
- assert_accepts(matcher, subject)
341
- end
338
+ should belong_to(association).dependent(dependent)
342
339
  end
343
340
  end
344
341
 
342
+ # Deprecated.
343
+ #
345
344
  # Ensure that the given class methods are defined on the model.
346
345
  #
347
346
  # should_have_class_methods :find, :destroy
348
347
  #
349
348
  def should_have_class_methods(*methods)
349
+ ::ActiveSupport::Deprecation.warn
350
350
  get_options!(methods)
351
351
  klass = described_type
352
352
  methods.each do |method|
@@ -356,11 +356,14 @@ module Shoulda # :nodoc:
356
356
  end
357
357
  end
358
358
 
359
+ # Deprecated.
360
+ #
359
361
  # Ensure that the given instance methods are defined on the model.
360
362
  #
361
363
  # should_have_instance_methods :email, :name, :name=
362
364
  #
363
365
  def should_have_instance_methods(*methods)
366
+ ::ActiveSupport::Deprecation.warn
364
367
  get_options!(methods)
365
368
  klass = described_type
366
369
  methods.each do |method|
@@ -370,9 +373,11 @@ module Shoulda # :nodoc:
370
373
  end
371
374
  end
372
375
 
376
+ # Deprecated: use ActiveRecord::Matchers#have_db_column instead.
377
+ #
373
378
  # Ensure that the given columns are defined on the models backing SQL table.
374
379
  # Also aliased to should_have_db_column for readability.
375
- # Takes the same options available in migrations:
380
+ # Takes the same options available in migrations:
376
381
  # :type, :precision, :limit, :default, :null, and :scale
377
382
  #
378
383
  # Examples:
@@ -384,23 +389,23 @@ module Shoulda # :nodoc:
384
389
  # should_have_db_column :admin, :default => false, :null => false
385
390
  #
386
391
  def should_have_db_columns(*columns)
387
- column_type, precision, limit, default, null, scale, sql_type =
392
+ ::ActiveSupport::Deprecation.warn("use: should have_db_column")
393
+ column_type, precision, limit, default, null, scale, sql_type =
388
394
  get_options!(columns, :type, :precision, :limit,
389
395
  :default, :null, :scale, :sql_type)
390
396
  columns.each do |name|
391
- matcher = have_db_column(name).
397
+ should have_db_column(name).
392
398
  of_type(column_type).
393
399
  with_options(:precision => precision, :limit => limit,
394
400
  :default => default, :null => null,
395
401
  :scale => scale, :sql_type => sql_type)
396
- should matcher.description do
397
- assert_accepts(matcher, subject)
398
- end
399
402
  end
400
403
  end
401
-
404
+
402
405
  alias_method :should_have_db_column, :should_have_db_columns
403
406
 
407
+ # Deprecated: use ActiveRecord::Matchers#have_db_index instead.
408
+ #
404
409
  # Ensures that there are DB indices on the given columns or tuples of columns.
405
410
  # Also aliased to should_have_db_index for readability
406
411
  #
@@ -418,32 +423,18 @@ module Shoulda # :nodoc:
418
423
  # should_have_db_index :ssn, :unique => true
419
424
  #
420
425
  def should_have_db_indices(*columns)
426
+ ::ActiveSupport::Deprecation.warn("use: should have_db_index")
421
427
  unique = get_options!(columns, :unique)
422
-
428
+
423
429
  columns.each do |column|
424
- matcher = have_db_index(column).unique(unique)
425
- should matcher.description do
426
- assert_accepts(matcher, subject)
427
- end
430
+ should have_db_index(column).unique(unique)
428
431
  end
429
432
  end
430
433
 
431
434
  alias_method :should_have_db_index, :should_have_db_indices
432
435
 
433
- # Deprecated. See should_have_db_index
434
- def should_have_index(*args)
435
- warn "[DEPRECATION] should_have_index is deprecated. " <<
436
- "Use should_have_db_index instead."
437
- should_have_db_index(*args)
438
- end
439
-
440
- # Deprecated. See should_have_db_indices
441
- def should_have_indices(*args)
442
- warn "[DEPRECATION] should_have_indices is deprecated. " <<
443
- "Use should_have_db_indices instead."
444
- should_have_db_indices(*args)
445
- end
446
-
436
+ # Deprecated: use ActiveRecord::Matchers#validate_acceptance_of instead.
437
+ #
447
438
  # Ensures that the model cannot be saved if one of the attributes listed is not accepted.
448
439
  #
449
440
  # Options:
@@ -454,57 +445,11 @@ module Shoulda # :nodoc:
454
445
  # should_validate_acceptance_of :eula
455
446
  #
456
447
  def should_validate_acceptance_of(*attributes)
448
+ ::ActiveSupport::Deprecation.warn("use: should validate_acceptance_of")
457
449
  message = get_options!(attributes, :message)
458
450
 
459
451
  attributes.each do |attribute|
460
- matcher = validate_acceptance_of(attribute).with_message(message)
461
- should matcher.description do
462
- assert_accepts matcher, subject
463
- end
464
- end
465
- end
466
-
467
- # Deprecated.
468
- #
469
- # Ensures that the model has a method named scope_name that returns a NamedScope object with the
470
- # proxy options set to the options you supply. scope_name can be either a symbol, or a method
471
- # call which will be evaled against the model. The eval'd method call has access to all the same
472
- # instance variables that a should statement would.
473
- #
474
- # Options: Any of the options that the named scope would pass on to find.
475
- #
476
- # Example:
477
- #
478
- # should_have_named_scope :visible, :conditions => {:visible => true}
479
- #
480
- # Passes for
481
- #
482
- # named_scope :visible, :conditions => {:visible => true}
483
- #
484
- # Or for
485
- #
486
- # def self.visible
487
- # scoped(:conditions => {:visible => true})
488
- # end
489
- #
490
- # You can test lambdas or methods that return ActiveRecord#scoped calls:
491
- #
492
- # should_have_named_scope 'recent(5)', :limit => 5
493
- # should_have_named_scope 'recent(1)', :limit => 1
494
- #
495
- # Passes for
496
- # named_scope :recent, lambda {|c| {:limit => c}}
497
- #
498
- # Or for
499
- #
500
- # def self.recent(c)
501
- # scoped(:limit => c)
502
- # end
503
- #
504
- def should_have_named_scope(scope_call, find_options = nil)
505
- matcher = have_named_scope(scope_call).finding(find_options)
506
- should matcher.description do
507
- assert_accepts matcher.in_context(self), subject
452
+ should validate_acceptance_of(attribute).with_message(message)
508
453
  end
509
454
  end
510
455
  end