actionpack 1.4.0 → 1.5.0

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 (84) hide show
  1. data/CHANGELOG +66 -0
  2. data/README +94 -64
  3. data/install.rb +1 -20
  4. data/lib/action_controller.rb +15 -7
  5. data/lib/action_controller/assertions/action_pack_assertions.rb +56 -3
  6. data/lib/action_controller/base.rb +137 -64
  7. data/lib/action_controller/caching.rb +11 -11
  8. data/lib/action_controller/cgi_ext/cgi_ext.rb +2 -2
  9. data/lib/action_controller/cgi_ext/raw_post_data_fix.rb +4 -4
  10. data/lib/action_controller/cgi_process.rb +9 -1
  11. data/lib/action_controller/components.rb +73 -0
  12. data/lib/action_controller/cookies.rb +1 -1
  13. data/lib/action_controller/dependencies.rb +6 -1
  14. data/lib/action_controller/filters.rb +1 -1
  15. data/lib/action_controller/flash.rb +3 -3
  16. data/lib/action_controller/helpers.rb +17 -21
  17. data/lib/action_controller/layout.rb +2 -2
  18. data/lib/action_controller/request.rb +16 -6
  19. data/lib/action_controller/rescue.rb +15 -3
  20. data/lib/action_controller/routing.rb +304 -0
  21. data/lib/action_controller/scaffolding.rb +10 -12
  22. data/lib/action_controller/session/active_record_store.rb +4 -7
  23. data/lib/action_controller/session/mem_cache_store.rb +2 -2
  24. data/lib/action_controller/templates/rescues/_request_and_response.rhtml +9 -1
  25. data/lib/action_controller/templates/rescues/diagnostics.rhtml +1 -1
  26. data/lib/action_controller/templates/rescues/routing_error.rhtml +8 -0
  27. data/lib/action_controller/test_process.rb +29 -7
  28. data/lib/action_controller/url_rewriter.rb +28 -112
  29. data/lib/action_view.rb +1 -1
  30. data/lib/action_view/base.rb +44 -17
  31. data/lib/action_view/helpers/active_record_helper.rb +1 -1
  32. data/lib/action_view/helpers/asset_tag_helper.rb +59 -0
  33. data/lib/action_view/helpers/date_helper.rb +24 -13
  34. data/lib/action_view/helpers/form_helper.rb +6 -1
  35. data/lib/action_view/helpers/form_options_helper.rb +87 -9
  36. data/lib/action_view/helpers/form_tag_helper.rb +80 -0
  37. data/lib/action_view/helpers/tag_helper.rb +0 -23
  38. data/lib/action_view/helpers/text_helper.rb +26 -1
  39. data/lib/action_view/helpers/url_helper.rb +29 -35
  40. data/lib/action_view/partials.rb +2 -2
  41. data/lib/action_view/vendor/builder/xmlbase.rb +3 -3
  42. data/rakefile +5 -2
  43. data/test/abstract_unit.rb +3 -1
  44. data/test/controller/action_pack_assertions_test.rb +29 -1
  45. data/test/controller/active_record_assertions_test.rb +109 -101
  46. data/test/controller/base_tests.rb +72 -0
  47. data/test/controller/components_test.rb +74 -0
  48. data/test/controller/cookie_test.rb +0 -9
  49. data/test/controller/custom_handler_test.rb +33 -0
  50. data/test/controller/filters_test.rb +36 -0
  51. data/test/controller/helper_test.rb +27 -10
  52. data/test/controller/redirect_test.rb +23 -31
  53. data/test/controller/render_test.rb +81 -66
  54. data/test/controller/request_test.rb +22 -0
  55. data/test/controller/routing_tests.rb +490 -0
  56. data/test/controller/{url_test.rb → url_obsolete.rb} +24 -14
  57. data/test/controller/url_obsolete.rb.rej +747 -0
  58. data/test/fixtures/fun/games/hello_world.rhtml +1 -0
  59. data/test/fixtures/helpers/fun/games_helper.rb +3 -0
  60. data/test/template/asset_tag_helper_test.rb +45 -0
  61. data/test/template/form_options_helper_test.rb +161 -1
  62. data/test/template/form_tag_helper_test.rb +22 -0
  63. data/test/template/text_helper_test.rb +7 -0
  64. data/test/template/url_helper_test.rb +5 -2
  65. data/test/template/url_helper_test.rb.rej +105 -0
  66. metadata +32 -27
  67. data/lib/action_controller/support/binding_of_caller.rb +0 -83
  68. data/lib/action_controller/support/breakpoint.rb +0 -518
  69. data/lib/action_controller/support/class_attribute_accessors.rb +0 -57
  70. data/lib/action_controller/support/class_inheritable_attributes.rb +0 -117
  71. data/lib/action_controller/support/clean_logger.rb +0 -10
  72. data/lib/action_controller/support/core_ext.rb +0 -1
  73. data/lib/action_controller/support/core_ext/hash.rb +0 -5
  74. data/lib/action_controller/support/core_ext/hash/keys.rb +0 -35
  75. data/lib/action_controller/support/core_ext/numeric.rb +0 -7
  76. data/lib/action_controller/support/core_ext/numeric/bytes.rb +0 -33
  77. data/lib/action_controller/support/core_ext/numeric/time.rb +0 -59
  78. data/lib/action_controller/support/core_ext/object_and_class.rb +0 -24
  79. data/lib/action_controller/support/core_ext/string.rb +0 -5
  80. data/lib/action_controller/support/core_ext/string/inflections.rb +0 -45
  81. data/lib/action_controller/support/dependencies.rb +0 -63
  82. data/lib/action_controller/support/inflector.rb +0 -84
  83. data/lib/action_controller/support/misc.rb +0 -8
  84. data/lib/action_controller/support/module_attribute_accessors.rb +0 -57
data/CHANGELOG CHANGED
@@ -1,3 +1,69 @@
1
+ *1.5.0* (24th February, 2005)
2
+
3
+ * Added Routing as a replacement for mod_rewrite pretty urls [Nicholas Seckar]. Read more in ActionController::Base.url_for and on http://manuals.rubyonrails.com/read/book/9
4
+
5
+ * Added components that allows you to call other actions for their rendered response while execution another action. You can either delegate the entire response rendering or you can mix a partial response in with your other content. Read more on http://manuals.rubyonrails.com/read/book/14
6
+
7
+ * Fixed that proxy IPs do not follow all RFC1918 nets #251 [caleb@aei-tech.com]
8
+
9
+ * Added Base#render_to_string to parse a template and get the result back as a string #479
10
+
11
+ * Fixed that send_file/data can work even if render* has been called before in action processing to render the content of a file to be send for example #601
12
+
13
+ * Added FormOptionsHelper#time_zone_select and FormOptionsHelper#time_zone_options_for_select to work with the new value object TimeZone in Active Support #688 [Jamis Buck]
14
+
15
+ * Added FormHelper#file_field and FormTagHelper#file_field_tag for creating file upload fields
16
+
17
+ * Added :order option for date_select that allows control over the order in which the date dropdowns is used and which of them should be used #619 [Tim Bates]. Examples:
18
+
19
+ date_select("post", "written_on", :order => [:day, :month, :year])
20
+ date_select("user", "birthday", :order => [:month, :day])
21
+
22
+ * Added ActionView::Base.register_template_handler for easy integration of an alternative template language to ERb and Builder. See test/controller/custom_handler_test.rb for a usage example #656 [Jamis Buck]
23
+
24
+ * Added AssetTagHelper that provides methods for linking a HTML page together with other assets, such as javascripts, stylesheets, and feeds.
25
+
26
+ * Added FormTagHelper that provides a number of methods for creating form tags that doesn't rely on conventions with an object assigned to the template like FormHelper does. With the FormTagHelper, you provide the names and values yourself.
27
+
28
+ * Added Afghanistan, Iran, and Irak to the countries list used by FormOptions#country_select and FormOptions#country_options_for_select
29
+
30
+ * Renamed link_to_image to link_image_to (since thats what it actually does) -- kept alias for the old method name
31
+
32
+ * Fixed textilize for RedCloth3 to keep doing hardbreaks
33
+
34
+ * Fixed that assert_template_xpath_matches did not indicate when a path was not found #658 [Eric Hodel]
35
+
36
+ * Added TextHelper#auto_link to turn email addresses and urls into ahrefs
37
+
38
+ * Fixed that on validation errors, scaffold couldn't find template #654 [mindel]
39
+
40
+ * Added Base#hide_action(*names) to hide public methods from a controller that would otherwise have been callable through the URL. For the majority of cases, its preferred just to make the methods you don't want to expose protected or private (so they'll automatically be hidden) -- but if you must have a public method, this is a way to make it uncallable. Base#hidden_actions retrieve the list of all hidden actions for the controller #644 [Nicholas Seckar]
41
+
42
+ * Fixed that a bunch of methods from ActionController::Base was accessible as actions (callable through a URL) when they shouldn't have been #644 [Nicholas Seckar]
43
+
44
+ * Added UrlHelper#current_page?(options) method to check if the url_for options passed corresponds to the current page
45
+
46
+ * Fixed https handling on other ports than 443 [Alan Gano]
47
+
48
+ * Added follow_redirect method for functional tests that'll get-request the redirect that was made. Example:
49
+
50
+ def test_create_post
51
+ post :create, "post" => { "title" => "Exciting!" }
52
+ assert_redirected_to :action => "show"
53
+
54
+ follow_redirect
55
+ assert_rendered_file "post/show"
56
+ end
57
+
58
+ Limitation: Only works for redirects to other actions within the same controller.
59
+
60
+ * Fixed double requiring of models with the same name as the controller
61
+
62
+ * Fixed that query params could be forced to nil on a POST due to the raw post fix #562 [moriq@moriq.com]
63
+
64
+ * Fixed that cookies shouldn't be frozen in TestRequest #571 [Eric Hodel]
65
+
66
+
1
67
  *1.4.0* (January 25th, 2005)
2
68
 
3
69
  * Fixed problems with ActiveRecordStore under the development environment in Rails
data/README CHANGED
@@ -50,7 +50,7 @@ A short rundown of the major features:
50
50
  def find_customer() Customer.find(@params["id"]) end
51
51
  end
52
52
 
53
- Learn more in link:classes/ActionController/Base.html
53
+ {Learn more}[link:classes/ActionController/Base.html]
54
54
 
55
55
 
56
56
  * Embedded Ruby for templates (no new "easy" template language)
@@ -65,30 +65,32 @@ A short rundown of the major features:
65
65
  Not for clients to see...
66
66
  <% end %>
67
67
 
68
- Learn more in link:classes/ActionView.html
68
+ {Learn more}[link:classes/ActionView.html]
69
69
 
70
70
 
71
71
  * Builder-based templates (great for XML content, like RSS)
72
72
 
73
- xml.rss("version" => "2.0") do
74
- xml.channel do
75
- xml.title(@feed_title)
76
- xml.link(@url)
77
- xml.description "Basecamp: Recent items"
78
- xml.language "en-us"
79
- xml.ttl "40"
80
-
81
- for item in @recent_items
82
- xml.item do
83
- xml.title(item_title(item))
84
- xml.description(item_description(item))
85
- xml.pubDate(item_pubDate(item))
86
- xml.guid(@recent_items.url(item))
87
- xml.link(@recent_items.url(item))
73
+ xml.rss("version" => "2.0") do
74
+ xml.channel do
75
+ xml.title(@feed_title)
76
+ xml.link(@url)
77
+ xml.description "Basecamp: Recent items"
78
+ xml.language "en-us"
79
+ xml.ttl "40"
80
+
81
+ for item in @recent_items
82
+ xml.item do
83
+ xml.title(item_title(item))
84
+ xml.description(item_description(item))
85
+ xml.pubDate(item_pubDate(item))
86
+ xml.guid(@recent_items.url(item))
87
+ xml.link(@recent_items.url(item))
88
+ end
88
89
  end
89
90
  end
90
91
  end
91
- end
92
+
93
+ {Learn more}[link:classes/ActionView/Base.html]
92
94
 
93
95
 
94
96
  * Filters for pre and post processing of the response (as methods, procs, and classes)
@@ -113,7 +115,7 @@ A short rundown of the major features:
113
115
  end
114
116
  end
115
117
 
116
- Learn more in link:classes/ActionController/Filters/ClassMethods.html
118
+ {Learn more}[link:classes/ActionController/Filters/ClassMethods.html]
117
119
 
118
120
 
119
121
  * Helpers for forms, dates, action links, and text
@@ -123,7 +125,7 @@ A short rundown of the major features:
123
125
  <%= link_to "New post", :controller => "post", :action => "new" %>
124
126
  <%= truncate(post.title, 25) %>
125
127
 
126
- Learn more in link:classes/ActionView/Helpers.html
128
+ {Learn more}[link:classes/ActionView/Helpers.html]
127
129
 
128
130
 
129
131
  * Layout sharing for template reuse (think simple version of Struts
@@ -145,28 +147,25 @@ A short rundown of the major features:
145
147
  Result of running hello_world action:
146
148
  <html><body><h1>Hello world</h1></body></html>
147
149
 
148
- Learn more in link:classes/ActionController/Layout/ClassMethods.html
150
+ {Learn more}[link:classes/ActionController/Layout/ClassMethods.html]
149
151
 
150
152
 
151
- * Advanced redirection that makes pretty urls easy
153
+ * Routing makes pretty urls incredibly easy
152
154
 
153
- RewriteRule ^/library/books/([A-Z]+)([0-9]+)/([-_a-zA-Z0-9]+)$ \
154
- /books_controller.cgi?action=$3&type=$1&code=$2 [QSA] [L]
155
+ map.connect 'clients/:client_name/:project_name/:controller/:action'
155
156
 
156
- Accessing /library/books/ISBN/0743536703/show calls BooksController#show
157
+ Accessing /clients/37signals/basecamp/project/dash calls ProjectController#dash with
158
+ { "client_name" => "37signals", "project_name" => "basecamp" } in @params["params"]
157
159
 
158
160
  From that URL, you can rewrite the redirect in a number of ways:
159
161
 
160
162
  redirect_to(:action => "edit") =>
161
- /library/books/ISBN/0743536703/edit
162
-
163
- redirect_to(:path_params => { "type" => "XTC", "code" => "12354345" }) =>
164
- /library/books/XTC/12354345/show
163
+ /clients/37signals/basecamp/project/dash
165
164
 
166
- redirect_to(:controller_prefix => "admin", :controller => "accounts") =>
167
- /admin/accounts/
165
+ redirect_to(:client_name => "nextangle", :project_name => "rails") =>
166
+ /clients/nextangle/rails/project/dash
168
167
 
169
- Learn more in link:classes/ActionController/Base.html
168
+ {Learn more}[link:classes/ActionController/Base.html]
170
169
 
171
170
 
172
171
  * Easy testing of both controller and template result through TestRequest/Response
@@ -185,7 +184,7 @@ A short rundown of the major features:
185
184
  end
186
185
  end
187
186
 
188
- Learn more in link:classes/ActionController/TestRequest.html
187
+ {Learn more}[link:classes/ActionController/TestRequest.html]
189
188
 
190
189
 
191
190
  * Automated benchmarking and integrated logging
@@ -211,6 +210,58 @@ A short rundown of the major features:
211
210
  ActionController::Base.logger = Log4r::Logger.new("Application Log")
212
211
 
213
212
 
213
+ * Caching at three levels of granularity (page, action, fragment)
214
+
215
+ class WeblogController < ActionController::Base
216
+ caches_page :show
217
+ caches_action :account
218
+
219
+ def show
220
+ # the output of the method will be cached as
221
+ # ActionController::Base.page_cache_directory + "/weblog/show/n.html"
222
+ # and the web server will pick it up without even hitting Rails
223
+ end
224
+
225
+ def account
226
+ # the output of the method will be cached in the fragment store
227
+ # but Rails is hit to retrieve it, so filters are run
228
+ end
229
+
230
+ def update
231
+ List.update(@params["list"]["id"], @params["list"])
232
+ expire_page :action => "show", :id => @params["list"]["id"]
233
+ expire_action :action => "account"
234
+ redirect_to :action => "show", :id => @params["list"]["id"]
235
+ end
236
+ end
237
+
238
+ {Learn more}[link:classes/ActionController/Caching.html]
239
+
240
+
241
+ * Component requests from one controller to another
242
+
243
+ class WeblogController < ActionController::Base
244
+ # Performs a method and then lets hello_world output its render
245
+ def delegate_action
246
+ do_other_stuff_before_hello_world
247
+ render_component :controller => "greeter", :action => "hello_world"
248
+ end
249
+ end
250
+
251
+ class GreeterController < ActionController::Base
252
+ def hello_world
253
+ render_text "Hello World!"
254
+ end
255
+ end
256
+
257
+ The same can be done in a view to do a partial rendering:
258
+
259
+ Let's see a greeting:
260
+ <%= render_component :controller => "greeter", :action => "hello_world" %>
261
+
262
+ {Learn more}[link:classes/ActionController/Components.html]
263
+
264
+
214
265
  * Powerful debugging mechanism for local requests
215
266
 
216
267
  All exceptions raised on actions performed on the request of a local user
@@ -218,7 +269,7 @@ A short rundown of the major features:
218
269
  message, stack trace, request parameters, session contents, and the
219
270
  half-finished response.
220
271
 
221
- Learn more in link:classes/ActionController/Rescue.html
272
+ {Learn more}[link:classes/ActionController/Rescue.html]
222
273
 
223
274
 
224
275
  * Scaffolding for Action Record model objects
@@ -231,7 +282,7 @@ A short rundown of the major features:
231
282
  The AccountController now has the full CRUD range of actions and default
232
283
  templates: list, show, destroy, new, create, edit, update
233
284
 
234
- Learn more in link:classes/ActionController/Scaffolding/ClassMethods.html
285
+ {Learn more}link:classes/ActionController/Scaffolding/ClassMethods.html
235
286
 
236
287
 
237
288
  * Form building for Active Record model objects
@@ -272,42 +323,21 @@ A short rundown of the major features:
272
323
  end
273
324
  end
274
325
 
275
- Learn more in link:classes/ActionView/Helpers/ActiveRecordHelper.html
276
-
326
+ {Learn more}[link:classes/ActionView/Helpers/ActiveRecordHelper.html]
277
327
 
278
- * Automated mapping of URLs to controller/action pairs through Apache's
279
- mod_rewrite
280
328
 
281
- Requesting /blog/display/5 will call BlogController#display and
282
- make 5 available as an instance variable through @params["id"]
283
-
284
-
285
- * Runs on top of CGI, FCGI, and mod_ruby
286
-
287
- See the address_book_controller example for all three forms
329
+ * Runs on top of WEBrick, CGI, FCGI, and mod_ruby
288
330
 
289
331
 
290
332
  == Simple example
291
333
 
292
334
  This example will implement a simple weblog system using inline templates and
293
- an Active Record model. The first thing we need to do is setup an .htaccess to
294
- interpret pretty URLs into something the controller can use. Let's use the
295
- simplest form for starters:
296
-
297
- RewriteRule ^weblog/([-_a-zA-Z0-9]+)/([0-9]+)$ \
298
- /weblog_controller.cgi?action=$2&id=$3 [QSA]
299
- RewriteRule ^weblog/([-_a-zA-Z0-9]+)$ \
300
- /weblog_controller.cgi?action=$2 [QSA]
301
- RewriteRule ^weblog/$ \
302
- /weblog_controller.cgi?action=index [QSA]
303
-
304
- Now we'll be able to access URLs like weblog/display/5 and have
305
- WeblogController#display called with { "id" => 5 } in the @params array
306
- available for the action. So let's build that WeblogController with just a few
335
+ an Active Record model. So let's build that WeblogController with just a few
307
336
  methods:
308
337
 
309
338
  require 'action_controller'
310
339
  require 'post'
340
+
311
341
  class WeblogController < ActionController::Base
312
342
  layout "weblog/layout"
313
343
 
@@ -362,7 +392,7 @@ which is called by accessing /weblog/. It uses the form builder for the Active
362
392
  Record model to make the new screen, which in turns hand everything over to
363
393
  the create action (that's the default target for the form builder when given a
364
394
  new model). After creating the post, it'll redirect to the display page using
365
- an URL such as /weblog/display/5 (where 5 is the id of the post.
395
+ an URL such as /weblog/display/5 (where 5 is the id of the post).
366
396
 
367
397
 
368
398
  == Examples
@@ -386,7 +416,7 @@ The latest version of Action Pack can be found at
386
416
 
387
417
  Documentation can be found at
388
418
 
389
- * http://actionpack.rubyonrails.org
419
+ * http://ap.rubyonrails.com
390
420
 
391
421
 
392
422
  == Installation
@@ -400,12 +430,12 @@ from its distribution directory.
400
430
 
401
431
  == License
402
432
 
403
- Action Pack is released under the same license as Ruby.
433
+ Action Pack is released under the MIT license.
404
434
 
405
435
 
406
436
  == Support
407
437
 
408
- The Action Pack homepage is http://actionpack.rubyonrails.org. You can find
438
+ The Action Pack homepage is http://www.rubyonrails.com. You can find
409
439
  the Action Pack RubyForge page at http://rubyforge.org/projects/actionpack.
410
440
  And as Jim from Rake says:
411
441
 
data/install.rb CHANGED
@@ -19,8 +19,7 @@ unless $sitedir
19
19
  end
20
20
 
21
21
  makedirs = %w{ action_controller/assertions action_controller/cgi_ext
22
- action_controller/session action_controller/support action_controller/support/core_ext
23
- action_controller/support/core_ext/hash action_controller/support/core_ext/numeric action_controller/support/core_ext/string
22
+ action_controller/session action_controller/support
24
23
  action_controller/templates action_controller/templates/rescues
25
24
  action_controller/templates/scaffolds
26
25
  action_view/helpers action_view/vendor action_view/vendor/builder
@@ -60,24 +59,6 @@ files = %w-
60
59
  action_controller/session/drb_store.rb
61
60
  action_controller/session/mem_cache_store.rb
62
61
  action_controller/session.rb
63
- action_controller/support/class_inheritable_attributes.rb
64
- action_controller/support/class_attribute_accessors.rb
65
- action_controller/support/clean_logger.rb
66
- action_controller/support/core_ext/hash/keys.rb
67
- action_controller/support/core_ext/hash.rb
68
- action_controller/support/core_ext/object_and_class.rb
69
- action_controller/support/core_ext/numeric/bytes.rb
70
- action_controller/support/core_ext/numeric/time.rb
71
- action_controller/support/core_ext/numeric.rb
72
- action_controller/support/core_ext/string/inflections.rb
73
- action_controller/support/core_ext/string.rb
74
- active_record/support/core_ext.rb
75
- action_controller/support/inflector.rb
76
- action_controller/support/binding_of_caller.rb
77
- action_controller/support/breakpoint.rb
78
- action_controller/support/dependencies.rb
79
- action_controller/support/misc.rb
80
- action_controller/support/module_attribute_accessors.rb
81
62
  action_controller/templates/rescues/_request_and_response.rhtml
82
63
  action_controller/templates/rescues/diagnostics.rhtml
83
64
  action_controller/templates/rescues/layout.rhtml
@@ -23,10 +23,16 @@
23
23
 
24
24
  $:.unshift(File.dirname(__FILE__))
25
25
 
26
- require 'action_controller/support/core_ext'
27
- require 'action_controller/support/clean_logger'
28
- require 'action_controller/support/misc'
29
- require 'action_controller/support/dependencies'
26
+ begin
27
+ require 'active_support'
28
+ rescue LoadError
29
+ begin
30
+ require File.dirname(__FILE__) + '/../../activesupport/lib/active_support'
31
+ rescue LoadError
32
+ require 'rubygems'
33
+ require_gem 'activesupport'
34
+ end
35
+ end
30
36
 
31
37
  require 'action_controller/base'
32
38
  require 'action_controller/rescue'
@@ -41,6 +47,10 @@ require 'action_controller/helpers'
41
47
  require 'action_controller/cookies'
42
48
  require 'action_controller/cgi_process'
43
49
  require 'action_controller/caching'
50
+ require 'action_controller/components'
51
+
52
+ require 'action_view'
53
+ ActionController::Base.template_class = ActionView::Base
44
54
 
45
55
  ActionController::Base.class_eval do
46
56
  include ActionController::Filters
@@ -54,7 +64,5 @@ ActionController::Base.class_eval do
54
64
  include ActionController::Cookies
55
65
  include ActionController::Session
56
66
  include ActionController::Caching
67
+ include ActionController::Components
57
68
  end
58
-
59
- require 'action_view'
60
- ActionController::Base.template_class = ActionView::Base
@@ -99,7 +99,7 @@ module Test #:nodoc:
99
99
  assert_block(msg) { !response.has_flash? }
100
100
  end
101
101
 
102
- # ensure the flash is empty but existant
102
+ # ensure the flash is empty but existent
103
103
  def assert_flash_empty(message=nil)
104
104
  response = acquire_assertion_target
105
105
  msg = build_message(message, "the flash is not empty <?>", response.flash)
@@ -141,7 +141,7 @@ module Test #:nodoc:
141
141
  end
142
142
  end
143
143
  end
144
-
144
+
145
145
  # ensure our redirection url is an exact match
146
146
  def assert_redirect_url(url=nil, message=nil)
147
147
  assert_redirect(message)
@@ -158,6 +158,53 @@ module Test #:nodoc:
158
158
  assert_block(msg) { response.redirect_url_match?(pattern) }
159
159
  end
160
160
 
161
+ # -- routing assertions --------------------------------------------------
162
+
163
+ # Asserts that the routing of the given path is handled correctly and that the parsed options match.
164
+ def assert_recognizes(expected_options, path, extras={}, message=nil)
165
+ # Load routes.rb if it hasn't been loaded.
166
+ ActionController::Routing::Routes.reload if ActionController::Routing::Routes.empty?
167
+
168
+ # Assume given controller
169
+ request = ActionController::TestRequest.new({}, {}, nil)
170
+ request.path = path
171
+ ActionController::Routing::Routes.recognize!(request)
172
+
173
+ expected_options = expected_options.clone
174
+ extras.each_key { |key| expected_options.delete key } unless extras.nil?
175
+
176
+ msg = build_message(message, "The recognized options <?> did not match <?>",
177
+ request.path_parameters, expected_options)
178
+ assert_block(msg) { request.path_parameters == expected_options }
179
+ end
180
+
181
+ # Asserts that the provided options can be used to generate the provided path.
182
+ def assert_generates(expected_path, options, defaults={}, extras = {}, message=nil)
183
+ # Load routes.rb if it hasn't been loaded.
184
+ ActionController::Routing::Routes.reload if ActionController::Routing::Routes.empty?
185
+
186
+ # Assume given controller
187
+ request = ActionController::TestRequest.new({}, {}, nil)
188
+ request.path_parameters = (defaults or {}).clone
189
+ request.path_parameters[:controller] ||= options[:controller]
190
+
191
+ generated_path, found_extras = ActionController::Routing::Routes.generate(options, request)
192
+ generated_path = generated_path.join('/')
193
+ msg = build_message(message, "found extras <?>, not <?>", found_extras, extras)
194
+ assert_block(msg) { found_extras == extras }
195
+
196
+ msg = build_message(message, "The generated path <?> did not match <?>", generated_path,
197
+ expected_path)
198
+ assert_block(msg) { expected_path == generated_path }
199
+ end
200
+
201
+ # asserts that path and options match both ways, in other words, the URL generated from
202
+ # options is same as path, and also that the options recognized from path are same as options
203
+ def assert_routing(path, options, defaults={}, extras={}, message=nil)
204
+ assert_recognizes(options, path, extras, message)
205
+ assert_generates(path, options, defaults, extras, message)
206
+ end
207
+
161
208
  # -- template assertions ------------------------------------------------
162
209
 
163
210
  # ensure that a template object with the given name exists
@@ -187,7 +234,13 @@ module Test #:nodoc:
187
234
  response = acquire_assertion_target
188
235
  xml, matches = REXML::Document.new(response.body), []
189
236
  xml.elements.each(expression) { |e| matches << e.text }
190
- matches = matches.first if matches.length < 2
237
+ if matches.empty? then
238
+ msg = build_message(message, "<?> not found in document", expression)
239
+ flunk(msg)
240
+ return
241
+ elsif matches.length < 2 then
242
+ matches = matches.first
243
+ end
191
244
 
192
245
  msg = build_message(message, "<?> found <?>, not <?>", expression, matches, expected)
193
246
  assert_block(msg) { matches == expected }