actionpack 2.2.3 → 2.3.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionpack might be problematic. Click here for more details.

Files changed (264) hide show
  1. data/CHANGELOG +433 -375
  2. data/MIT-LICENSE +1 -1
  3. data/README +21 -75
  4. data/Rakefile +1 -1
  5. data/lib/action_controller.rb +80 -43
  6. data/lib/action_controller/assertions/model_assertions.rb +1 -0
  7. data/lib/action_controller/assertions/response_assertions.rb +43 -16
  8. data/lib/action_controller/assertions/routing_assertions.rb +1 -1
  9. data/lib/action_controller/assertions/selector_assertions.rb +17 -12
  10. data/lib/action_controller/assertions/tag_assertions.rb +1 -4
  11. data/lib/action_controller/base.rb +153 -82
  12. data/lib/action_controller/benchmarking.rb +9 -9
  13. data/lib/action_controller/caching.rb +9 -11
  14. data/lib/action_controller/caching/actions.rb +11 -18
  15. data/lib/action_controller/caching/fragments.rb +28 -20
  16. data/lib/action_controller/caching/pages.rb +13 -15
  17. data/lib/action_controller/caching/sweeping.rb +2 -2
  18. data/lib/action_controller/cgi_ext.rb +0 -1
  19. data/lib/action_controller/cgi_ext/cookie.rb +2 -0
  20. data/lib/action_controller/cgi_process.rb +54 -162
  21. data/lib/action_controller/cookies.rb +13 -25
  22. data/lib/action_controller/dispatcher.rb +43 -122
  23. data/lib/action_controller/failsafe.rb +52 -0
  24. data/lib/action_controller/flash.rb +38 -47
  25. data/lib/action_controller/helpers.rb +13 -9
  26. data/lib/action_controller/http_authentication.rb +203 -23
  27. data/lib/action_controller/integration.rb +126 -70
  28. data/lib/action_controller/layout.rb +36 -39
  29. data/lib/action_controller/middleware_stack.rb +119 -0
  30. data/lib/action_controller/middlewares.rb +13 -0
  31. data/lib/action_controller/mime_responds.rb +19 -4
  32. data/lib/action_controller/mime_type.rb +8 -0
  33. data/lib/action_controller/params_parser.rb +71 -0
  34. data/lib/action_controller/performance_test.rb +0 -1
  35. data/lib/action_controller/polymorphic_routes.rb +36 -30
  36. data/lib/action_controller/reloader.rb +14 -0
  37. data/lib/action_controller/request.rb +107 -499
  38. data/lib/action_controller/request_forgery_protection.rb +7 -39
  39. data/lib/action_controller/rescue.rb +55 -35
  40. data/lib/action_controller/resources.rb +34 -31
  41. data/lib/action_controller/response.rb +99 -57
  42. data/lib/action_controller/rewindable_input.rb +28 -0
  43. data/lib/action_controller/routing.rb +7 -7
  44. data/lib/action_controller/routing/builder.rb +4 -1
  45. data/lib/action_controller/routing/optimisations.rb +1 -1
  46. data/lib/action_controller/routing/recognition_optimisation.rb +1 -2
  47. data/lib/action_controller/routing/route.rb +15 -5
  48. data/lib/action_controller/routing/route_set.rb +82 -35
  49. data/lib/action_controller/routing/segments.rb +35 -0
  50. data/lib/action_controller/session/abstract_store.rb +181 -0
  51. data/lib/action_controller/session/cookie_store.rb +197 -175
  52. data/lib/action_controller/session/mem_cache_store.rb +36 -83
  53. data/lib/action_controller/session_management.rb +26 -134
  54. data/lib/action_controller/streaming.rb +24 -7
  55. data/lib/action_controller/templates/rescues/diagnostics.erb +2 -2
  56. data/lib/action_controller/templates/rescues/template_error.erb +2 -2
  57. data/lib/action_controller/test_case.rb +87 -30
  58. data/lib/action_controller/test_process.rb +145 -104
  59. data/lib/action_controller/uploaded_file.rb +44 -0
  60. data/lib/action_controller/url_rewriter.rb +3 -6
  61. data/lib/action_controller/vendor/html-scanner.rb +16 -0
  62. data/lib/action_controller/vendor/html-scanner/html/selector.rb +1 -1
  63. data/lib/action_controller/vendor/rack-1.0/rack.rb +89 -0
  64. data/lib/action_controller/vendor/rack-1.0/rack/adapter/camping.rb +22 -0
  65. data/lib/action_controller/vendor/rack-1.0/rack/auth/abstract/handler.rb +37 -0
  66. data/lib/action_controller/vendor/rack-1.0/rack/auth/abstract/request.rb +37 -0
  67. data/lib/action_controller/vendor/rack-1.0/rack/auth/basic.rb +58 -0
  68. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/md5.rb +124 -0
  69. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/nonce.rb +51 -0
  70. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/params.rb +55 -0
  71. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/request.rb +40 -0
  72. data/lib/action_controller/vendor/rack-1.0/rack/auth/openid.rb +480 -0
  73. data/lib/action_controller/vendor/rack-1.0/rack/builder.rb +63 -0
  74. data/lib/action_controller/vendor/rack-1.0/rack/cascade.rb +36 -0
  75. data/lib/action_controller/vendor/rack-1.0/rack/chunked.rb +49 -0
  76. data/lib/action_controller/vendor/rack-1.0/rack/commonlogger.rb +61 -0
  77. data/lib/action_controller/vendor/rack-1.0/rack/conditionalget.rb +45 -0
  78. data/lib/action_controller/vendor/rack-1.0/rack/content_length.rb +29 -0
  79. data/lib/action_controller/vendor/rack-1.0/rack/content_type.rb +23 -0
  80. data/lib/action_controller/vendor/rack-1.0/rack/deflater.rb +85 -0
  81. data/lib/action_controller/vendor/rack-1.0/rack/directory.rb +153 -0
  82. data/lib/action_controller/vendor/rack-1.0/rack/file.rb +88 -0
  83. data/lib/action_controller/vendor/rack-1.0/rack/handler.rb +48 -0
  84. data/lib/action_controller/vendor/rack-1.0/rack/handler/cgi.rb +61 -0
  85. data/lib/action_controller/vendor/rack-1.0/rack/handler/evented_mongrel.rb +8 -0
  86. data/lib/action_controller/vendor/rack-1.0/rack/handler/fastcgi.rb +89 -0
  87. data/lib/action_controller/vendor/rack-1.0/rack/handler/lsws.rb +55 -0
  88. data/lib/action_controller/vendor/rack-1.0/rack/handler/mongrel.rb +84 -0
  89. data/lib/action_controller/vendor/rack-1.0/rack/handler/scgi.rb +59 -0
  90. data/lib/action_controller/vendor/rack-1.0/rack/handler/swiftiplied_mongrel.rb +8 -0
  91. data/lib/action_controller/vendor/rack-1.0/rack/handler/thin.rb +18 -0
  92. data/lib/action_controller/vendor/rack-1.0/rack/handler/webrick.rb +67 -0
  93. data/lib/action_controller/vendor/rack-1.0/rack/head.rb +19 -0
  94. data/lib/action_controller/vendor/rack-1.0/rack/lint.rb +462 -0
  95. data/lib/action_controller/vendor/rack-1.0/rack/lobster.rb +65 -0
  96. data/lib/action_controller/vendor/rack-1.0/rack/lock.rb +16 -0
  97. data/lib/action_controller/vendor/rack-1.0/rack/methodoverride.rb +27 -0
  98. data/lib/action_controller/vendor/rack-1.0/rack/mime.rb +204 -0
  99. data/lib/action_controller/vendor/rack-1.0/rack/mock.rb +160 -0
  100. data/lib/action_controller/vendor/rack-1.0/rack/recursive.rb +57 -0
  101. data/lib/action_controller/vendor/rack-1.0/rack/reloader.rb +64 -0
  102. data/lib/action_controller/vendor/rack-1.0/rack/request.rb +241 -0
  103. data/lib/action_controller/vendor/rack-1.0/rack/response.rb +179 -0
  104. data/lib/action_controller/vendor/rack-1.0/rack/session/abstract/id.rb +142 -0
  105. data/lib/action_controller/vendor/rack-1.0/rack/session/cookie.rb +91 -0
  106. data/lib/action_controller/vendor/rack-1.0/rack/session/memcache.rb +109 -0
  107. data/lib/action_controller/vendor/rack-1.0/rack/session/pool.rb +100 -0
  108. data/lib/action_controller/vendor/rack-1.0/rack/showexceptions.rb +349 -0
  109. data/lib/action_controller/vendor/rack-1.0/rack/showstatus.rb +106 -0
  110. data/lib/action_controller/vendor/rack-1.0/rack/static.rb +38 -0
  111. data/lib/action_controller/vendor/rack-1.0/rack/urlmap.rb +55 -0
  112. data/lib/action_controller/vendor/rack-1.0/rack/utils.rb +392 -0
  113. data/lib/action_controller/verification.rb +1 -1
  114. data/lib/action_pack.rb +1 -1
  115. data/lib/action_pack/version.rb +2 -2
  116. data/lib/action_view.rb +22 -17
  117. data/lib/action_view/base.rb +53 -79
  118. data/lib/action_view/erb/util.rb +38 -0
  119. data/lib/action_view/helpers.rb +24 -5
  120. data/lib/action_view/helpers/active_record_helper.rb +2 -2
  121. data/lib/action_view/helpers/asset_tag_helper.rb +81 -50
  122. data/lib/action_view/helpers/atom_feed_helper.rb +1 -1
  123. data/lib/action_view/helpers/benchmark_helper.rb +26 -5
  124. data/lib/action_view/helpers/date_helper.rb +82 -7
  125. data/lib/action_view/helpers/form_helper.rb +295 -64
  126. data/lib/action_view/helpers/form_options_helper.rb +160 -18
  127. data/lib/action_view/helpers/form_tag_helper.rb +2 -2
  128. data/lib/action_view/helpers/number_helper.rb +31 -18
  129. data/lib/action_view/helpers/prototype_helper.rb +2 -12
  130. data/lib/action_view/helpers/sanitize_helper.rb +0 -10
  131. data/lib/action_view/helpers/scriptaculous_helper.rb +1 -0
  132. data/lib/action_view/helpers/tag_helper.rb +3 -4
  133. data/lib/action_view/helpers/text_helper.rb +99 -122
  134. data/lib/action_view/helpers/translation_helper.rb +19 -1
  135. data/lib/action_view/helpers/url_helper.rb +25 -2
  136. data/lib/action_view/inline_template.rb +1 -1
  137. data/lib/action_view/locale/en.yml +19 -1
  138. data/lib/action_view/partials.rb +46 -9
  139. data/lib/action_view/paths.rb +28 -84
  140. data/lib/action_view/reloadable_template.rb +117 -0
  141. data/lib/action_view/renderable.rb +28 -35
  142. data/lib/action_view/renderable_partial.rb +3 -4
  143. data/lib/action_view/template.rb +172 -31
  144. data/lib/action_view/template_error.rb +8 -9
  145. data/lib/action_view/template_handler.rb +1 -1
  146. data/lib/action_view/template_handlers.rb +9 -6
  147. data/lib/action_view/template_handlers/erb.rb +2 -39
  148. data/lib/action_view/template_handlers/rjs.rb +1 -0
  149. data/lib/action_view/test_case.rb +27 -1
  150. data/test/abstract_unit.rb +23 -17
  151. data/test/active_record_unit.rb +5 -4
  152. data/test/activerecord/active_record_store_test.rb +139 -106
  153. data/test/activerecord/render_partial_with_record_identification_test.rb +5 -21
  154. data/test/controller/action_pack_assertions_test.rb +25 -23
  155. data/test/controller/addresses_render_test.rb +3 -6
  156. data/test/controller/assert_select_test.rb +83 -70
  157. data/test/controller/base_test.rb +11 -13
  158. data/test/controller/benchmark_test.rb +3 -3
  159. data/test/controller/caching_test.rb +34 -24
  160. data/test/controller/capture_test.rb +3 -6
  161. data/test/controller/content_type_test.rb +3 -6
  162. data/test/controller/cookie_test.rb +31 -66
  163. data/test/controller/deprecation/deprecated_base_methods_test.rb +9 -11
  164. data/test/controller/dispatcher_test.rb +23 -28
  165. data/test/controller/fake_models.rb +8 -0
  166. data/test/controller/filters_test.rb +6 -2
  167. data/test/controller/flash_test.rb +2 -6
  168. data/test/controller/helper_test.rb +15 -1
  169. data/test/controller/html-scanner/document_test.rb +1 -1
  170. data/test/controller/html-scanner/sanitizer_test.rb +1 -1
  171. data/test/controller/http_basic_authentication_test.rb +88 -0
  172. data/test/controller/http_digest_authentication_test.rb +178 -0
  173. data/test/controller/integration_test.rb +56 -52
  174. data/test/controller/layout_test.rb +46 -44
  175. data/test/controller/middleware_stack_test.rb +90 -0
  176. data/test/controller/mime_responds_test.rb +7 -11
  177. data/test/controller/mime_type_test.rb +9 -0
  178. data/test/controller/polymorphic_routes_test.rb +235 -151
  179. data/test/controller/rack_test.rb +52 -81
  180. data/test/controller/redirect_test.rb +6 -14
  181. data/test/controller/render_test.rb +273 -60
  182. data/test/controller/request/json_params_parsing_test.rb +45 -0
  183. data/test/controller/request/multipart_params_parsing_test.rb +223 -0
  184. data/test/controller/request/query_string_parsing_test.rb +120 -0
  185. data/test/controller/request/url_encoded_params_parsing_test.rb +184 -0
  186. data/test/controller/request/xml_params_parsing_test.rb +88 -0
  187. data/test/controller/request_forgery_protection_test.rb +17 -98
  188. data/test/controller/request_test.rb +45 -530
  189. data/test/controller/rescue_test.rb +45 -22
  190. data/test/controller/resources_test.rb +112 -37
  191. data/test/controller/routing_test.rb +1442 -1384
  192. data/test/controller/selector_test.rb +3 -3
  193. data/test/controller/send_file_test.rb +30 -3
  194. data/test/controller/session/cookie_store_test.rb +169 -240
  195. data/test/controller/session/mem_cache_store_test.rb +94 -148
  196. data/test/controller/session/test_session_test.rb +58 -0
  197. data/test/controller/test_test.rb +32 -13
  198. data/test/controller/url_rewriter_test.rb +54 -4
  199. data/test/controller/verification_test.rb +1 -1
  200. data/test/controller/view_paths_test.rb +15 -15
  201. data/test/controller/webservice_test.rb +178 -147
  202. data/test/fixtures/alternate_helpers/foo_helper.rb +3 -0
  203. data/test/fixtures/layout_tests/alt/layouts/alt.rhtml +0 -0
  204. data/test/fixtures/layouts/default_html.html.erb +1 -0
  205. data/test/fixtures/layouts/xhr.html.erb +2 -0
  206. data/test/fixtures/multipart/empty +10 -0
  207. data/test/fixtures/multipart/hello.txt +1 -0
  208. data/test/fixtures/multipart/none +9 -0
  209. data/test/fixtures/public/500.da.html +1 -0
  210. data/test/fixtures/quiz/questions/_question.html.erb +1 -0
  211. data/test/fixtures/replies.yml +1 -1
  212. data/test/fixtures/test/_one.html.erb +1 -0
  213. data/test/fixtures/test/_two.html.erb +1 -0
  214. data/test/fixtures/test/dont_pick_me +1 -0
  215. data/test/fixtures/test/hello.builder +1 -1
  216. data/test/fixtures/test/hello_world.da.html.erb +1 -0
  217. data/test/fixtures/test/hello_world.erb~ +1 -0
  218. data/test/fixtures/test/hello_world.pt-BR.html.erb +1 -0
  219. data/test/fixtures/test/malformed/malformed.en.html.erb~ +1 -0
  220. data/test/fixtures/test/malformed/malformed.erb~ +1 -0
  221. data/test/fixtures/test/malformed/malformed.html.erb~ +1 -0
  222. data/test/fixtures/test/render_explicit_html_template.js.rjs +1 -0
  223. data/test/fixtures/test/render_implicit_html_template.js.rjs +1 -0
  224. data/test/fixtures/test/render_implicit_html_template_from_xhr_request.da.html.erb +1 -0
  225. data/test/fixtures/test/render_implicit_html_template_from_xhr_request.html.erb +1 -0
  226. data/test/fixtures/test/render_implicit_js_template_without_layout.js.erb +1 -0
  227. data/test/fixtures/test/utf8.html.erb +2 -0
  228. data/test/template/active_record_helper_i18n_test.rb +31 -33
  229. data/test/template/active_record_helper_test.rb +34 -0
  230. data/test/template/asset_tag_helper_test.rb +52 -14
  231. data/test/template/atom_feed_helper_test.rb +3 -5
  232. data/test/template/benchmark_helper_test.rb +50 -24
  233. data/test/template/compiled_templates_test.rb +177 -33
  234. data/test/template/date_helper_i18n_test.rb +88 -81
  235. data/test/template/date_helper_test.rb +427 -43
  236. data/test/template/form_helper_test.rb +243 -44
  237. data/test/template/form_options_helper_test.rb +631 -565
  238. data/test/template/form_tag_helper_test.rb +9 -2
  239. data/test/template/javascript_helper_test.rb +0 -5
  240. data/test/template/number_helper_i18n_test.rb +60 -48
  241. data/test/template/number_helper_test.rb +1 -0
  242. data/test/template/render_test.rb +117 -35
  243. data/test/template/test_test.rb +4 -6
  244. data/test/template/text_helper_test.rb +129 -50
  245. data/test/template/translation_helper_test.rb +23 -19
  246. data/test/template/url_helper_test.rb +35 -2
  247. data/test/view/test_case_test.rb +8 -0
  248. metadata +197 -23
  249. data/lib/action_controller/assertions.rb +0 -69
  250. data/lib/action_controller/caching/sql_cache.rb +0 -18
  251. data/lib/action_controller/cgi_ext/session.rb +0 -53
  252. data/lib/action_controller/components.rb +0 -169
  253. data/lib/action_controller/rack_process.rb +0 -297
  254. data/lib/action_controller/request_profiler.rb +0 -169
  255. data/lib/action_controller/session/active_record_store.rb +0 -340
  256. data/lib/action_controller/session/drb_server.rb +0 -32
  257. data/lib/action_controller/session/drb_store.rb +0 -35
  258. data/test/controller/cgi_test.rb +0 -269
  259. data/test/controller/components_test.rb +0 -156
  260. data/test/controller/http_authentication_test.rb +0 -54
  261. data/test/controller/integration_upload_test.rb +0 -43
  262. data/test/controller/session_fixation_test.rb +0 -89
  263. data/test/controller/session_management_test.rb +0 -178
  264. data/test/fixtures/test/hello_world.js +0 -1
@@ -1,13 +1,17 @@
1
+ require 'active_support/dependencies'
2
+
1
3
  # FIXME: helper { ... } is broken on Ruby 1.9
2
4
  module ActionController #:nodoc:
3
5
  module Helpers #:nodoc:
4
- HELPERS_DIR = (defined?(RAILS_ROOT) ? "#{RAILS_ROOT}/app/helpers" : "app/helpers")
5
-
6
6
  def self.included(base)
7
7
  # Initialize the base module to aggregate its helpers.
8
8
  base.class_inheritable_accessor :master_helper_module
9
9
  base.master_helper_module = Module.new
10
10
 
11
+ # Set the default directory for helpers
12
+ base.class_inheritable_accessor :helpers_dir
13
+ base.helpers_dir = (defined?(RAILS_ROOT) ? "#{RAILS_ROOT}/app/helpers" : "app/helpers")
14
+
11
15
  # Extend base with class methods to declare helpers.
12
16
  base.extend(ClassMethods)
13
17
 
@@ -88,8 +92,8 @@ module ActionController #:nodoc:
88
92
  # When the argument is a module it will be included directly in the template class.
89
93
  # helper FooHelper # => includes FooHelper
90
94
  #
91
- # When the argument is the symbol <tt>:all</tt>, the controller will include all helpers from
92
- # <tt>app/helpers/**/*.rb</tt> under RAILS_ROOT.
95
+ # When the argument is the symbol <tt>:all</tt>, the controller will include all helpers beneath
96
+ # <tt>ActionController::Base.helpers_dir</tt> (defaults to <tt>app/helpers/**/*.rb</tt> under RAILS_ROOT).
93
97
  # helper :all
94
98
  #
95
99
  # Additionally, the +helper+ class method can receive and evaluate a block, making the methods defined available
@@ -159,9 +163,9 @@ module ActionController #:nodoc:
159
163
  def helper_method(*methods)
160
164
  methods.flatten.each do |method|
161
165
  master_helper_module.module_eval <<-end_eval
162
- def #{method}(*args, &block)
163
- controller.send(%(#{method}), *args, &block)
164
- end
166
+ def #{method}(*args, &block) # def current_user(*args, &block)
167
+ controller.send(%(#{method}), *args, &block) # controller.send(%(current_user), *args, &block)
168
+ end # end
165
169
  end_eval
166
170
  end
167
171
  end
@@ -213,8 +217,8 @@ module ActionController #:nodoc:
213
217
 
214
218
  # Extract helper names from files in app/helpers/**/*.rb
215
219
  def all_application_helpers
216
- extract = /^#{Regexp.quote(HELPERS_DIR)}\/?(.*)_helper.rb$/
217
- Dir["#{HELPERS_DIR}/**/*_helper.rb"].map { |file| file.sub extract, '\1' }
220
+ extract = /^#{Regexp.quote(helpers_dir)}\/?(.*)_helper.rb$/
221
+ Dir["#{helpers_dir}/**/*_helper.rb"].map { |file| file.sub extract, '\1' }
218
222
  end
219
223
  end
220
224
  end
@@ -1,42 +1,42 @@
1
1
  module ActionController
2
2
  module HttpAuthentication
3
3
  # Makes it dead easy to do HTTP Basic authentication.
4
- #
4
+ #
5
5
  # Simple Basic example:
6
- #
6
+ #
7
7
  # class PostsController < ApplicationController
8
8
  # USER_NAME, PASSWORD = "dhh", "secret"
9
- #
9
+ #
10
10
  # before_filter :authenticate, :except => [ :index ]
11
- #
11
+ #
12
12
  # def index
13
13
  # render :text => "Everyone can see me!"
14
14
  # end
15
- #
15
+ #
16
16
  # def edit
17
17
  # render :text => "I'm only accessible if you know the password"
18
18
  # end
19
- #
19
+ #
20
20
  # private
21
21
  # def authenticate
22
- # authenticate_or_request_with_http_basic do |user_name, password|
22
+ # authenticate_or_request_with_http_basic do |user_name, password|
23
23
  # user_name == USER_NAME && password == PASSWORD
24
24
  # end
25
25
  # end
26
26
  # end
27
- #
28
- #
29
- # Here is a more advanced Basic example where only Atom feeds and the XML API is protected by HTTP authentication,
27
+ #
28
+ #
29
+ # Here is a more advanced Basic example where only Atom feeds and the XML API is protected by HTTP authentication,
30
30
  # the regular HTML interface is protected by a session approach:
31
- #
31
+ #
32
32
  # class ApplicationController < ActionController::Base
33
33
  # before_filter :set_account, :authenticate
34
- #
34
+ #
35
35
  # protected
36
36
  # def set_account
37
37
  # @account = Account.find_by_url_name(request.subdomains.first)
38
38
  # end
39
- #
39
+ #
40
40
  # def authenticate
41
41
  # case request.format
42
42
  # when Mime::XML, Mime::ATOM
@@ -54,24 +54,55 @@ module ActionController
54
54
  # end
55
55
  # end
56
56
  # end
57
- #
58
- #
57
+ #
59
58
  # In your integration tests, you can do something like this:
60
- #
59
+ #
61
60
  # def test_access_granted_from_xml
62
61
  # get(
63
- # "/notes/1.xml", nil,
62
+ # "/notes/1.xml", nil,
64
63
  # :authorization => ActionController::HttpAuthentication::Basic.encode_credentials(users(:dhh).name, users(:dhh).password)
65
64
  # )
66
- #
65
+ #
67
66
  # assert_equal 200, status
68
67
  # end
69
- #
70
- #
68
+ #
69
+ # Simple Digest example:
70
+ #
71
+ # require 'digest/md5'
72
+ # class PostsController < ApplicationController
73
+ # REALM = "SuperSecret"
74
+ # USERS = {"dhh" => "secret", #plain text password
75
+ # "dap" => Digest:MD5::hexdigest(["dap",REALM,"secret"].join(":")) #ha1 digest password
76
+ #
77
+ # before_filter :authenticate, :except => [:index]
78
+ #
79
+ # def index
80
+ # render :text => "Everyone can see me!"
81
+ # end
82
+ #
83
+ # def edit
84
+ # render :text => "I'm only accessible if you know the password"
85
+ # end
86
+ #
87
+ # private
88
+ # def authenticate
89
+ # authenticate_or_request_with_http_digest(REALM) do |username|
90
+ # USERS[username]
91
+ # end
92
+ # end
93
+ # end
94
+ #
95
+ # NOTE: The +authenticate_or_request_with_http_digest+ block must return the user's password or the ha1 digest hash so the framework can appropriately
96
+ # hash to check the user's credentials. Returning +nil+ will cause authentication to fail.
97
+ # Storing the ha1 hash: MD5(username:realm:password), is better than storing a plain password. If
98
+ # the password file or database is compromised, the attacker would be able to use the ha1 hash to
99
+ # authenticate as the user at this +realm+, but would not have the user's password to try using at
100
+ # other sites.
101
+ #
71
102
  # On shared hosts, Apache sometimes doesn't pass authentication headers to
72
103
  # FCGI instances. If your environment matches this description and you cannot
73
104
  # authenticate, try this rule in your Apache setup:
74
- #
105
+ #
75
106
  # RewriteRule ^(.*)$ dispatch.fcgi [E=X-HTTP_AUTHORIZATION:%{HTTP:Authorization},QSA,L]
76
107
  module Basic
77
108
  extend self
@@ -99,14 +130,14 @@ module ActionController
99
130
  def user_name_and_password(request)
100
131
  decode_credentials(request).split(/:/, 2)
101
132
  end
102
-
133
+
103
134
  def authorization(request)
104
135
  request.env['HTTP_AUTHORIZATION'] ||
105
136
  request.env['X-HTTP_AUTHORIZATION'] ||
106
137
  request.env['X_HTTP_AUTHORIZATION'] ||
107
138
  request.env['REDIRECT_X_HTTP_AUTHORIZATION']
108
139
  end
109
-
140
+
110
141
  def decode_credentials(request)
111
142
  ActiveSupport::Base64.decode64(authorization(request).split.last || '')
112
143
  end
@@ -120,5 +151,154 @@ module ActionController
120
151
  controller.__send__ :render, :text => "HTTP Basic: Access denied.\n", :status => :unauthorized
121
152
  end
122
153
  end
154
+
155
+ module Digest
156
+ extend self
157
+
158
+ module ControllerMethods
159
+ def authenticate_or_request_with_http_digest(realm = "Application", &password_procedure)
160
+ authenticate_with_http_digest(realm, &password_procedure) || request_http_digest_authentication(realm)
161
+ end
162
+
163
+ # Authenticate with HTTP Digest, returns true or false
164
+ def authenticate_with_http_digest(realm = "Application", &password_procedure)
165
+ HttpAuthentication::Digest.authenticate(self, realm, &password_procedure)
166
+ end
167
+
168
+ # Render output including the HTTP Digest authentication header
169
+ def request_http_digest_authentication(realm = "Application", message = nil)
170
+ HttpAuthentication::Digest.authentication_request(self, realm, message)
171
+ end
172
+ end
173
+
174
+ # Returns false on a valid response, true otherwise
175
+ def authenticate(controller, realm, &password_procedure)
176
+ authorization(controller.request) && validate_digest_response(controller.request, realm, &password_procedure)
177
+ end
178
+
179
+ def authorization(request)
180
+ request.env['HTTP_AUTHORIZATION'] ||
181
+ request.env['X-HTTP_AUTHORIZATION'] ||
182
+ request.env['X_HTTP_AUTHORIZATION'] ||
183
+ request.env['REDIRECT_X_HTTP_AUTHORIZATION']
184
+ end
185
+
186
+ # Raises error unless the request credentials response value matches the expected value.
187
+ # First try the password as a ha1 digest password. If this fails, then try it as a plain
188
+ # text password.
189
+ def validate_digest_response(request, realm, &password_procedure)
190
+ credentials = decode_credentials_header(request)
191
+ valid_nonce = validate_nonce(request, credentials[:nonce])
192
+
193
+ if valid_nonce && realm == credentials[:realm] && opaque == credentials[:opaque]
194
+ password = password_procedure.call(credentials[:username])
195
+
196
+ [true, false].any? do |password_is_ha1|
197
+ expected = expected_response(request.env['REQUEST_METHOD'], request.env['REQUEST_URI'], credentials, password, password_is_ha1)
198
+ expected == credentials[:response]
199
+ end
200
+ end
201
+ end
202
+
203
+ # Returns the expected response for a request of +http_method+ to +uri+ with the decoded +credentials+ and the expected +password+
204
+ # Optional parameter +password_is_ha1+ is set to +true+ by default, since best practice is to store ha1 digest instead
205
+ # of a plain-text password.
206
+ def expected_response(http_method, uri, credentials, password, password_is_ha1=true)
207
+ ha1 = password_is_ha1 ? password : ha1(credentials, password)
208
+ ha2 = ::Digest::MD5.hexdigest([http_method.to_s.upcase, uri].join(':'))
209
+ ::Digest::MD5.hexdigest([ha1, credentials[:nonce], credentials[:nc], credentials[:cnonce], credentials[:qop], ha2].join(':'))
210
+ end
211
+
212
+ def ha1(credentials, password)
213
+ ::Digest::MD5.hexdigest([credentials[:username], credentials[:realm], password].join(':'))
214
+ end
215
+
216
+ def encode_credentials(http_method, credentials, password, password_is_ha1)
217
+ credentials[:response] = expected_response(http_method, credentials[:uri], credentials, password, password_is_ha1)
218
+ "Digest " + credentials.sort_by {|x| x[0].to_s }.inject([]) {|a, v| a << "#{v[0]}='#{v[1]}'" }.join(', ')
219
+ end
220
+
221
+ def decode_credentials_header(request)
222
+ decode_credentials(authorization(request))
223
+ end
224
+
225
+ def decode_credentials(header)
226
+ header.to_s.gsub(/^Digest\s+/,'').split(',').inject({}) do |hash, pair|
227
+ key, value = pair.split('=', 2)
228
+ hash[key.strip.to_sym] = value.to_s.gsub(/^"|"$/,'').gsub(/'/, '')
229
+ hash
230
+ end
231
+ end
232
+
233
+ def authentication_header(controller, realm)
234
+ controller.headers["WWW-Authenticate"] = %(Digest realm="#{realm}", qop="auth", algorithm=MD5, nonce="#{nonce}", opaque="#{opaque}")
235
+ end
236
+
237
+ def authentication_request(controller, realm, message = nil)
238
+ message ||= "HTTP Digest: Access denied.\n"
239
+ authentication_header(controller, realm)
240
+ controller.__send__ :render, :text => message, :status => :unauthorized
241
+ end
242
+
243
+ # Uses an MD5 digest based on time to generate a value to be used only once.
244
+ #
245
+ # A server-specified data string which should be uniquely generated each time a 401 response is made.
246
+ # It is recommended that this string be base64 or hexadecimal data.
247
+ # Specifically, since the string is passed in the header lines as a quoted string, the double-quote character is not allowed.
248
+ #
249
+ # The contents of the nonce are implementation dependent.
250
+ # The quality of the implementation depends on a good choice.
251
+ # A nonce might, for example, be constructed as the base 64 encoding of
252
+ #
253
+ # => time-stamp H(time-stamp ":" ETag ":" private-key)
254
+ #
255
+ # where time-stamp is a server-generated time or other non-repeating value,
256
+ # ETag is the value of the HTTP ETag header associated with the requested entity,
257
+ # and private-key is data known only to the server.
258
+ # With a nonce of this form a server would recalculate the hash portion after receiving the client authentication header and
259
+ # reject the request if it did not match the nonce from that header or
260
+ # if the time-stamp value is not recent enough. In this way the server can limit the time of the nonce's validity.
261
+ # The inclusion of the ETag prevents a replay request for an updated version of the resource.
262
+ # (Note: including the IP address of the client in the nonce would appear to offer the server the ability
263
+ # to limit the reuse of the nonce to the same client that originally got it.
264
+ # However, that would break proxy farms, where requests from a single user often go through different proxies in the farm.
265
+ # Also, IP address spoofing is not that hard.)
266
+ #
267
+ # An implementation might choose not to accept a previously used nonce or a previously used digest, in order to
268
+ # protect against a replay attack. Or, an implementation might choose to use one-time nonces or digests for
269
+ # POST or PUT requests and a time-stamp for GET requests. For more details on the issues involved see Section 4
270
+ # of this document.
271
+ #
272
+ # The nonce is opaque to the client. Composed of Time, and hash of Time with secret
273
+ # key from the Rails session secret generated upon creation of project. Ensures
274
+ # the time cannot be modifed by client.
275
+ def nonce(time = Time.now)
276
+ t = time.to_i
277
+ hashed = [t, secret_key]
278
+ digest = ::Digest::MD5.hexdigest(hashed.join(":"))
279
+ Base64.encode64("#{t}:#{digest}").gsub("\n", '')
280
+ end
281
+
282
+ # Might want a shorter timeout depending on whether the request
283
+ # is a PUT or POST, and if client is browser or web service.
284
+ # Can be much shorter if the Stale directive is implemented. This would
285
+ # allow a user to use new nonce without prompting user again for their
286
+ # username and password.
287
+ def validate_nonce(request, value, seconds_to_timeout=5*60)
288
+ t = Base64.decode64(value).split(":").first.to_i
289
+ nonce(t) == value && (t - Time.now.to_i).abs <= seconds_to_timeout
290
+ end
291
+
292
+ # Opaque based on random generation - but changing each request?
293
+ def opaque()
294
+ ::Digest::MD5.hexdigest(secret_key)
295
+ end
296
+
297
+ # Set in /initializers/session_store.rb, and loaded even if sessions are not in use.
298
+ def secret_key
299
+ ActionController::Base.session_options[:secret]
300
+ end
301
+
302
+ end
123
303
  end
124
304
  end
@@ -1,9 +1,6 @@
1
- require 'active_support/test_case'
2
- require 'action_controller/dispatcher'
3
- require 'action_controller/test_process'
4
-
5
1
  require 'stringio'
6
2
  require 'uri'
3
+ require 'active_support/test_case'
7
4
 
8
5
  module ActionController
9
6
  module Integration #:nodoc:
@@ -12,19 +9,26 @@ module ActionController
12
9
  # multiple sessions and run them side-by-side, you can also mimic (to some
13
10
  # limited extent) multiple simultaneous users interacting with your system.
14
11
  #
15
- # Typically, you will instantiate a new session using IntegrationTest#open_session,
16
- # rather than instantiating Integration::Session directly.
12
+ # Typically, you will instantiate a new session using
13
+ # IntegrationTest#open_session, rather than instantiating
14
+ # Integration::Session directly.
17
15
  class Session
18
16
  include Test::Unit::Assertions
19
- include ActionController::Assertions
17
+ include ActionController::TestCase::Assertions
20
18
  include ActionController::TestProcess
21
19
 
20
+ # Rack application to use
21
+ attr_accessor :application
22
+
22
23
  # The integer HTTP status code of the last request.
23
24
  attr_reader :status
24
25
 
25
26
  # The status message that accompanied the status code of the last request.
26
27
  attr_reader :status_message
27
28
 
29
+ # The body of the last request.
30
+ attr_reader :body
31
+
28
32
  # The URI of the last request.
29
33
  attr_reader :path
30
34
 
@@ -60,7 +64,8 @@ module ActionController
60
64
  end
61
65
 
62
66
  # Create and initialize a new Session instance.
63
- def initialize
67
+ def initialize(app = nil)
68
+ @application = app || ActionController::Dispatcher.new
64
69
  reset!
65
70
  end
66
71
 
@@ -79,11 +84,13 @@ module ActionController
79
84
 
80
85
  self.host = "www.example.com"
81
86
  self.remote_addr = "127.0.0.1"
82
- self.accept = "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"
87
+ self.accept = "text/xml,application/xml,application/xhtml+xml," +
88
+ "text/html;q=0.9,text/plain;q=0.8,image/png," +
89
+ "*/*;q=0.5"
83
90
 
84
91
  unless defined? @named_routes_configured
85
92
  # install the named routes in this session instance.
86
- klass = class<<self; self; end
93
+ klass = class << self; self; end
87
94
  Routing::Routes.install_helpers(klass)
88
95
 
89
96
  # the helpers are made protected by default--we make them public for
@@ -97,7 +104,7 @@ module ActionController
97
104
  #
98
105
  # session.https!
99
106
  # session.https!(false)
100
- def https!(flag=true)
107
+ def https!(flag = true)
101
108
  @https = flag
102
109
  end
103
110
 
@@ -122,7 +129,7 @@ module ActionController
122
129
  # performed on the location header.
123
130
  def follow_redirect!
124
131
  raise "not a redirect! #{@status} #{@status_message}" unless redirect?
125
- get(interpret_uri(headers['location'].first))
132
+ get(interpret_uri(headers['location']))
126
133
  status
127
134
  end
128
135
 
@@ -167,17 +174,21 @@ module ActionController
167
174
 
168
175
  # Performs a GET request with the given parameters.
169
176
  #
170
- # - +path+: The URI (as a String) on which you want to perform a GET request.
171
- # - +parameters+: The HTTP parameters that you want to pass. This may be +nil+,
177
+ # - +path+: The URI (as a String) on which you want to perform a GET
178
+ # request.
179
+ # - +parameters+: The HTTP parameters that you want to pass. This may
180
+ # be +nil+,
172
181
  # a Hash, or a String that is appropriately encoded
173
- # (<tt>application/x-www-form-urlencoded</tt> or <tt>multipart/form-data</tt>).
182
+ # (<tt>application/x-www-form-urlencoded</tt> or
183
+ # <tt>multipart/form-data</tt>).
174
184
  # - +headers+: Additional HTTP headers to pass, as a Hash. The keys will
175
185
  # automatically be upcased, with the prefix 'HTTP_' added if needed.
176
186
  #
177
- # This method returns an AbstractResponse object, which one can use to inspect
178
- # the details of the response. Furthermore, if this method was called from an
179
- # ActionController::IntegrationTest object, then that object's <tt>@response</tt>
180
- # instance variable will point to the same response object.
187
+ # This method returns an Response object, which one can use to
188
+ # inspect the details of the response. Furthermore, if this method was
189
+ # called from an ActionController::IntegrationTest object, then that
190
+ # object's <tt>@response</tt> instance variable will point to the same
191
+ # response object.
181
192
  #
182
193
  # You can also perform POST, PUT, DELETE, and HEAD requests with +post+,
183
194
  # +put+, +delete+, and +head+.
@@ -185,22 +196,26 @@ module ActionController
185
196
  process :get, path, parameters, headers
186
197
  end
187
198
 
188
- # Performs a POST request with the given parameters. See get() for more details.
199
+ # Performs a POST request with the given parameters. See get() for more
200
+ # details.
189
201
  def post(path, parameters = nil, headers = nil)
190
202
  process :post, path, parameters, headers
191
203
  end
192
204
 
193
- # Performs a PUT request with the given parameters. See get() for more details.
205
+ # Performs a PUT request with the given parameters. See get() for more
206
+ # details.
194
207
  def put(path, parameters = nil, headers = nil)
195
208
  process :put, path, parameters, headers
196
209
  end
197
210
 
198
- # Performs a DELETE request with the given parameters. See get() for more details.
211
+ # Performs a DELETE request with the given parameters. See get() for
212
+ # more details.
199
213
  def delete(path, parameters = nil, headers = nil)
200
214
  process :delete, path, parameters, headers
201
215
  end
202
216
 
203
- # Performs a HEAD request with the given parameters. See get() for more details.
217
+ # Performs a HEAD request with the given parameters. See get() for more
218
+ # details.
204
219
  def head(path, parameters = nil, headers = nil)
205
220
  process :head, path, parameters, headers
206
221
  end
@@ -215,8 +230,7 @@ module ActionController
215
230
  def xml_http_request(request_method, path, parameters = nil, headers = nil)
216
231
  headers ||= {}
217
232
  headers['X-Requested-With'] = 'XMLHttpRequest'
218
- headers['Accept'] ||= 'text/javascript, text/html, application/xml, text/xml, */*'
219
-
233
+ headers['Accept'] ||= [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ')
220
234
  process(request_method, path, parameters, headers)
221
235
  end
222
236
  alias xhr :xml_http_request
@@ -224,7 +238,9 @@ module ActionController
224
238
  # Returns the URL for the given options, according to the rules specified
225
239
  # in the application's routes.
226
240
  def url_for(options)
227
- controller ? controller.url_for(options) : generic_url_rewriter.rewrite(options)
241
+ controller ?
242
+ controller.url_for(options) :
243
+ generic_url_rewriter.rewrite(options)
228
244
  end
229
245
 
230
246
  private
@@ -250,17 +266,35 @@ module ActionController
250
266
  data = nil
251
267
  end
252
268
 
269
+ env["QUERY_STRING"] ||= ""
270
+
271
+ data = data.is_a?(IO) ? data : StringIO.new(data || '')
272
+
253
273
  env.update(
254
- "REQUEST_METHOD" => method.to_s.upcase,
274
+ "REQUEST_METHOD" => method.to_s.upcase,
275
+ "SERVER_NAME" => host,
276
+ "SERVER_PORT" => (https? ? "443" : "80"),
277
+ "HTTPS" => https? ? "on" : "off",
278
+ "rack.url_scheme" => https? ? "https" : "http",
279
+ "SCRIPT_NAME" => "",
280
+
255
281
  "REQUEST_URI" => path,
282
+ "PATH_INFO" => path,
256
283
  "HTTP_HOST" => host,
257
284
  "REMOTE_ADDR" => remote_addr,
258
- "SERVER_PORT" => (https? ? "443" : "80"),
259
285
  "CONTENT_TYPE" => "application/x-www-form-urlencoded",
260
286
  "CONTENT_LENGTH" => data ? data.length.to_s : nil,
261
287
  "HTTP_COOKIE" => encode_cookies,
262
- "HTTPS" => https? ? "on" : "off",
263
- "HTTP_ACCEPT" => accept
288
+ "HTTP_ACCEPT" => accept,
289
+
290
+ "rack.version" => [0,1],
291
+ "rack.input" => data,
292
+ "rack.errors" => StringIO.new,
293
+ "rack.multithread" => true,
294
+ "rack.multiprocess" => true,
295
+ "rack.run_once" => false,
296
+
297
+ "rack.test" => true
264
298
  )
265
299
 
266
300
  (headers || {}).each do |key, value|
@@ -269,54 +303,67 @@ module ActionController
269
303
  env[key] = value
270
304
  end
271
305
 
272
- unless ActionController::Base.respond_to?(:clear_last_instantiation!)
273
- ActionController::Base.module_eval { include ControllerCapture }
306
+ [ControllerCapture, ActionController::ProcessWithTest].each do |mod|
307
+ unless ActionController::Base < mod
308
+ ActionController::Base.class_eval { include mod }
309
+ end
274
310
  end
275
311
 
276
312
  ActionController::Base.clear_last_instantiation!
277
313
 
278
- env['rack.input'] = data.is_a?(IO) ? data : StringIO.new(data || '')
279
- @status, @headers, result_body = ActionController::Dispatcher.new.mark_as_test_request!.call(env)
280
- @request_count += 1
281
-
282
- @controller = ActionController::Base.last_instantiation
283
- @request = @controller.request
284
- @response = @controller.response
314
+ app = @application
315
+ # Rack::Lint doesn't accept String headers or bodies in Ruby 1.9
316
+ unless RUBY_VERSION >= '1.9.0' && Rack.release <= '0.9.0'
317
+ app = Rack::Lint.new(app)
318
+ end
285
319
 
286
- # Decorate the response with the standard behavior of the TestResponse
287
- # so that things like assert_response can be used in integration
288
- # tests.
289
- @response.extend(TestResponseBehavior)
320
+ status, headers, body = app.call(env)
321
+ @request_count += 1
290
322
 
291
323
  @html_document = nil
292
324
 
293
- # Inject status back in for backwords compatibility with CGI
294
- @headers['Status'] = @status
325
+ @status = status.to_i
326
+ @status_message = StatusCodes::STATUS_CODES[@status]
295
327
 
296
- @status, @status_message = @status.split(/ /)
297
- @status = @status.to_i
328
+ @headers = Rack::Utils::HeaderHash.new(headers)
298
329
 
299
- cgi_headers = Hash.new { |h,k| h[k] = [] }
300
- @headers.each do |key, value|
301
- cgi_headers[key.downcase] << value
302
- end
303
- cgi_headers['set-cookie'] = cgi_headers['set-cookie'].first
304
- @headers = cgi_headers
305
-
306
- @response.headers['cookie'] ||= []
307
- (@headers['set-cookie'] || []).each do |cookie|
330
+ (@headers['Set-Cookie'] || "").split("\n").each do |cookie|
308
331
  name, value = cookie.match(/^([^=]*)=([^;]*);/)[1,2]
309
332
  @cookies[name] = value
333
+ end
310
334
 
311
- # Fake CGI cookie header
312
- # DEPRECATE: Use response.headers["Set-Cookie"] instead
313
- @response.headers['cookie'] << CGI::Cookie::new("name" => name, "value" => value)
335
+ @body = ""
336
+ if body.is_a?(String)
337
+ @body << body
338
+ else
339
+ body.each { |part| @body << part }
314
340
  end
315
341
 
316
- return status
342
+ if @controller = ActionController::Base.last_instantiation
343
+ @request = @controller.request
344
+ @response = @controller.response
345
+ @controller.send(:set_test_assigns)
346
+ else
347
+ # Decorate responses from Rack Middleware and Rails Metal
348
+ # as an Response for the purposes of integration testing
349
+ @response = Response.new
350
+ @response.status = status.to_s
351
+ @response.headers.replace(@headers)
352
+ @response.body = @body
353
+ end
354
+
355
+ # Decorate the response with the standard behavior of the
356
+ # TestResponse so that things like assert_response can be
357
+ # used in integration tests.
358
+ @response.extend(TestResponseBehavior)
359
+
360
+ return @status
317
361
  rescue MultiPartNeededException
318
362
  boundary = "----------XnJLe9ZIbbGUYtzPQJ16u1"
319
- status = process(method, path, multipart_body(parameters, boundary), (headers || {}).merge({"CONTENT_TYPE" => "multipart/form-data; boundary=#{boundary}"}))
363
+ status = process(method, path,
364
+ multipart_body(parameters, boundary),
365
+ (headers || {}).merge(
366
+ {"CONTENT_TYPE" => "multipart/form-data; boundary=#{boundary}"}))
320
367
  return status
321
368
  end
322
369
 
@@ -338,7 +385,7 @@ module ActionController
338
385
  "SERVER_PORT" => https? ? "443" : "80",
339
386
  "HTTPS" => https? ? "on" : "off"
340
387
  }
341
- ActionController::UrlRewriter.new(ActionController::RackRequest.new(env), {})
388
+ UrlRewriter.new(Request.new(env), {})
342
389
  end
343
390
 
344
391
  def name_with_prefix(prefix, name)
@@ -352,9 +399,13 @@ module ActionController
352
399
  raise MultiPartNeededException
353
400
  elsif Hash === parameters
354
401
  return nil if parameters.empty?
355
- parameters.map { |k,v| requestify(v, name_with_prefix(prefix, k)) }.join("&")
402
+ parameters.map { |k,v|
403
+ requestify(v, name_with_prefix(prefix, k))
404
+ }.join("&")
356
405
  elsif Array === parameters
357
- parameters.map { |v| requestify(v, name_with_prefix(prefix, "")) }.join("&")
406
+ parameters.map { |v|
407
+ requestify(v, name_with_prefix(prefix, ""))
408
+ }.join("&")
358
409
  elsif prefix.nil?
359
410
  parameters
360
411
  else
@@ -380,7 +431,7 @@ module ActionController
380
431
  def multipart_body(params, boundary)
381
432
  multipart_requestify(params).map do |key, value|
382
433
  if value.respond_to?(:original_filename)
383
- File.open(value.path) do |f|
434
+ File.open(value.path, "rb") do |f|
384
435
  f.set_encoding(Encoding::BINARY) if f.respond_to?(:set_encoding)
385
436
 
386
437
  <<-EOF
@@ -460,8 +511,8 @@ EOF
460
511
  # By default, a single session is automatically created for you, but you
461
512
  # can use this method to open multiple sessions that ought to be tested
462
513
  # simultaneously.
463
- def open_session
464
- session = Integration::Session.new
514
+ def open_session(application = nil)
515
+ session = Integration::Session.new(application)
465
516
 
466
517
  # delegate the fixture accessors back to the test instance
467
518
  extras = Module.new { attr_accessor :delegate, :test_result }
@@ -469,12 +520,16 @@ EOF
469
520
  self.class.fixture_table_names.each do |table_name|
470
521
  name = table_name.tr(".", "_")
471
522
  next unless respond_to?(name)
472
- extras.__send__(:define_method, name) { |*args| delegate.send(name, *args) }
523
+ extras.__send__(:define_method, name) { |*args|
524
+ delegate.send(name, *args)
525
+ }
473
526
  end
474
527
  end
475
528
 
476
529
  # delegate add_assertion to the test case
477
- extras.__send__(:define_method, :add_assertion) { test_result.add_assertion }
530
+ extras.__send__(:define_method, :add_assertion) {
531
+ test_result.add_assertion
532
+ }
478
533
  session.extend(extras)
479
534
  session.delegate = self
480
535
  session.test_result = @_result
@@ -602,7 +657,8 @@ EOF
602
657
  # would potentially have to set their values for both Test::Unit::TestCase
603
658
  # ActionController::IntegrationTest, since by the time the value is set on
604
659
  # TestCase, IntegrationTest has already been defined and cannot inherit
605
- # changes to those variables. So, we make those two attributes copy-on-write.
660
+ # changes to those variables. So, we make those two attributes
661
+ # copy-on-write.
606
662
 
607
663
  class << self
608
664
  def use_transactional_fixtures=(flag) #:nodoc: