actionpack 0.9.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 (100) hide show
  1. data/CHANGELOG +604 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +418 -0
  4. data/RUNNING_UNIT_TESTS +14 -0
  5. data/examples/.htaccess +24 -0
  6. data/examples/address_book/index.rhtml +33 -0
  7. data/examples/address_book/layout.rhtml +8 -0
  8. data/examples/address_book_controller.cgi +9 -0
  9. data/examples/address_book_controller.fcgi +6 -0
  10. data/examples/address_book_controller.rb +52 -0
  11. data/examples/address_book_controller.rbx +4 -0
  12. data/examples/benchmark.rb +52 -0
  13. data/examples/benchmark_with_ar.fcgi +89 -0
  14. data/examples/blog_controller.cgi +53 -0
  15. data/examples/debate/index.rhtml +14 -0
  16. data/examples/debate/new_topic.rhtml +22 -0
  17. data/examples/debate/topic.rhtml +32 -0
  18. data/examples/debate_controller.cgi +57 -0
  19. data/install.rb +93 -0
  20. data/lib/action_controller.rb +47 -0
  21. data/lib/action_controller/assertions/action_pack_assertions.rb +166 -0
  22. data/lib/action_controller/assertions/active_record_assertions.rb +65 -0
  23. data/lib/action_controller/base.rb +626 -0
  24. data/lib/action_controller/benchmarking.rb +49 -0
  25. data/lib/action_controller/cgi_ext/cgi_ext.rb +43 -0
  26. data/lib/action_controller/cgi_ext/cgi_methods.rb +91 -0
  27. data/lib/action_controller/cgi_process.rb +123 -0
  28. data/lib/action_controller/filters.rb +279 -0
  29. data/lib/action_controller/flash.rb +65 -0
  30. data/lib/action_controller/layout.rb +143 -0
  31. data/lib/action_controller/request.rb +92 -0
  32. data/lib/action_controller/rescue.rb +94 -0
  33. data/lib/action_controller/response.rb +15 -0
  34. data/lib/action_controller/scaffolding.rb +183 -0
  35. data/lib/action_controller/session/active_record_store.rb +72 -0
  36. data/lib/action_controller/session/drb_server.rb +9 -0
  37. data/lib/action_controller/session/drb_store.rb +31 -0
  38. data/lib/action_controller/support/class_attribute_accessors.rb +57 -0
  39. data/lib/action_controller/support/class_inheritable_attributes.rb +37 -0
  40. data/lib/action_controller/support/clean_logger.rb +10 -0
  41. data/lib/action_controller/support/cookie_performance_fix.rb +121 -0
  42. data/lib/action_controller/support/inflector.rb +70 -0
  43. data/lib/action_controller/templates/rescues/_request_and_response.rhtml +28 -0
  44. data/lib/action_controller/templates/rescues/diagnostics.rhtml +22 -0
  45. data/lib/action_controller/templates/rescues/layout.rhtml +29 -0
  46. data/lib/action_controller/templates/rescues/missing_template.rhtml +2 -0
  47. data/lib/action_controller/templates/rescues/template_error.rhtml +26 -0
  48. data/lib/action_controller/templates/rescues/unknown_action.rhtml +2 -0
  49. data/lib/action_controller/templates/scaffolds/edit.rhtml +6 -0
  50. data/lib/action_controller/templates/scaffolds/layout.rhtml +29 -0
  51. data/lib/action_controller/templates/scaffolds/list.rhtml +24 -0
  52. data/lib/action_controller/templates/scaffolds/new.rhtml +5 -0
  53. data/lib/action_controller/templates/scaffolds/show.rhtml +9 -0
  54. data/lib/action_controller/test_process.rb +194 -0
  55. data/lib/action_controller/url_rewriter.rb +153 -0
  56. data/lib/action_view.rb +40 -0
  57. data/lib/action_view/base.rb +253 -0
  58. data/lib/action_view/helpers/active_record_helper.rb +171 -0
  59. data/lib/action_view/helpers/date_helper.rb +223 -0
  60. data/lib/action_view/helpers/debug_helper.rb +17 -0
  61. data/lib/action_view/helpers/form_helper.rb +176 -0
  62. data/lib/action_view/helpers/form_options_helper.rb +169 -0
  63. data/lib/action_view/helpers/tag_helper.rb +59 -0
  64. data/lib/action_view/helpers/text_helper.rb +129 -0
  65. data/lib/action_view/helpers/url_helper.rb +72 -0
  66. data/lib/action_view/partials.rb +61 -0
  67. data/lib/action_view/template_error.rb +84 -0
  68. data/lib/action_view/vendor/builder.rb +13 -0
  69. data/lib/action_view/vendor/builder/blankslate.rb +21 -0
  70. data/lib/action_view/vendor/builder/xmlbase.rb +143 -0
  71. data/lib/action_view/vendor/builder/xmlevents.rb +63 -0
  72. data/lib/action_view/vendor/builder/xmlmarkup.rb +288 -0
  73. data/rakefile +105 -0
  74. data/test/abstract_unit.rb +9 -0
  75. data/test/controller/action_pack_assertions_test.rb +295 -0
  76. data/test/controller/active_record_assertions_test.rb +118 -0
  77. data/test/controller/cgi_test.rb +142 -0
  78. data/test/controller/cookie_test.rb +38 -0
  79. data/test/controller/filters_test.rb +159 -0
  80. data/test/controller/flash_test.rb +69 -0
  81. data/test/controller/layout_test.rb +49 -0
  82. data/test/controller/redirect_test.rb +44 -0
  83. data/test/controller/render_test.rb +169 -0
  84. data/test/controller/url_test.rb +318 -0
  85. data/test/fixtures/layouts/builder.rxml +3 -0
  86. data/test/fixtures/layouts/standard.rhtml +1 -0
  87. data/test/fixtures/test/_customer.rhtml +1 -0
  88. data/test/fixtures/test/greeting.rhtml +1 -0
  89. data/test/fixtures/test/hello.rxml +4 -0
  90. data/test/fixtures/test/hello_world.rhtml +1 -0
  91. data/test/fixtures/test/hello_xml_world.rxml +11 -0
  92. data/test/fixtures/test/list.rhtml +1 -0
  93. data/test/template/active_record_helper_test.rb +76 -0
  94. data/test/template/date_helper_test.rb +103 -0
  95. data/test/template/form_helper_test.rb +115 -0
  96. data/test/template/form_options_helper_test.rb +174 -0
  97. data/test/template/tag_helper_test.rb +18 -0
  98. data/test/template/text_helper_test.rb +62 -0
  99. data/test/template/url_helper_test.rb +35 -0
  100. metadata +154 -0
@@ -0,0 +1,29 @@
1
+ <html>
2
+ <head>
3
+ <title>Action Controller: Exception caught</title>
4
+ <style>
5
+ body { background-color: #fff; color: #333; }
6
+
7
+ body, p, ol, ul, td {
8
+ font-family: verdana, arial, helvetica, sans-serif;
9
+ font-size: 13px;
10
+ line-height: 18px;
11
+ }
12
+
13
+ pre {
14
+ background-color: #eee;
15
+ padding: 10px;
16
+ font-size: 11px;
17
+ }
18
+
19
+ a { color: #000; }
20
+ a:visited { color: #666; }
21
+ a:hover { color: #fff; background-color:#000; }
22
+ </style>
23
+ </head>
24
+ <body>
25
+
26
+ <%= @contents %>
27
+
28
+ </body>
29
+ </html>
@@ -0,0 +1,2 @@
1
+ <h1>Template is missing</h1>
2
+ <p><%=h @exception.message %></p>
@@ -0,0 +1,26 @@
1
+ <%
2
+ base_dir = File.expand_path(File.dirname(__FILE__))
3
+
4
+ framework_trace = @exception.original_exception.backtrace.collect do |line|
5
+ line.gsub(base_dir, "").gsub("/../config/environments/../../", "")
6
+ end
7
+ %>
8
+
9
+ <h1>
10
+ <%=h @exception.original_exception.class.to_s %> in
11
+ <%=h @request.parameters["controller"].capitalize %>#<%=h @request.parameters["action"] %>
12
+ </h1>
13
+
14
+ <p>
15
+ Showing <i><%=h @exception.file_name %></i> where line <b>#<%=h @exception.line_number %></b> raised
16
+ <u><%=h @exception.message %></u>
17
+ </p>
18
+
19
+ <pre><code><%=h @exception.source_extract %></code></pre>
20
+
21
+ <p><%=h @exception.sub_template_message %></p>
22
+
23
+ <a href="#" onclick="document.getElementById('framework_trace').style.display='block'">Show template trace</a>
24
+ <pre id="framework_trace" style="display:none"><code><%=h framework_trace.join("\n") %></code></pre>
25
+
26
+ <%= render_file(@rescues_path + "/_request_and_response.rhtml", false) %>
@@ -0,0 +1,2 @@
1
+ <h1>Unknown action</h1>
2
+ <p><%=h @exception.message %></p>
@@ -0,0 +1,6 @@
1
+ <h1>Editing <%= @scaffold_singular_name %></h1>
2
+
3
+ <%= form(@scaffold_singular_name, :action => "../update" + @scaffold_suffix) %>
4
+
5
+ <%= link_to "Show", :action => "show#{@scaffold_suffix}", :id => instance_variable_get("@#{@scaffold_singular_name}").id %> |
6
+ <%= link_to "Back", :action => "list#{@scaffold_suffix}" %>
@@ -0,0 +1,29 @@
1
+ <html>
2
+ <head>
3
+ <title>Scaffolding</title>
4
+ <style>
5
+ body { background-color: #fff; color: #333; }
6
+
7
+ body, p, ol, ul, td {
8
+ font-family: verdana, arial, helvetica, sans-serif;
9
+ font-size: 13px;
10
+ line-height: 18px;
11
+ }
12
+
13
+ pre {
14
+ background-color: #eee;
15
+ padding: 10px;
16
+ font-size: 11px;
17
+ }
18
+
19
+ a { color: #000; }
20
+ a:visited { color: #666; }
21
+ a:hover { color: #fff; background-color:#000; }
22
+ </style>
23
+ </head>
24
+ <body>
25
+
26
+ <%= @content_for_layout %>
27
+
28
+ </body>
29
+ </html>
@@ -0,0 +1,24 @@
1
+ <h1>Listing <%= @scaffold_plural_name %></h1>
2
+
3
+ <table>
4
+ <tr>
5
+ <% for column in @scaffold_class.content_columns %>
6
+ <th><%= column.human_name %></th>
7
+ <% end %>
8
+ </tr>
9
+
10
+ <% for entry in instance_variable_get("@#{@scaffold_plural_name}") %>
11
+ <tr>
12
+ <% for column in @scaffold_class.content_columns %>
13
+ <td><%= entry.send(column.name) %></td>
14
+ <% end %>
15
+ <td><%= link_to "Show", :action => "show#{@scaffold_suffix}", :id => entry.id %></td>
16
+ <td><%= link_to "Edit", :action => "edit#{@scaffold_suffix}", :id => entry.id %></td>
17
+ <td><%= link_to "Destroy", :action => "destroy#{@scaffold_suffix}", :id => entry.id %></td>
18
+ </tr>
19
+ <% end %>
20
+ </table>
21
+
22
+ <br />
23
+
24
+ <%= link_to "New #{@scaffold_singular_name}", :action => "new#{@scaffold_suffix}" %>
@@ -0,0 +1,5 @@
1
+ <h1>New <%= @scaffold_singular_name %></h1>
2
+
3
+ <%= form(@scaffold_singular_name, :action => "create" + @scaffold_suffix) %>
4
+
5
+ <%= link_to "Back", :action => "list#{@scaffold_suffix}" %>
@@ -0,0 +1,9 @@
1
+ <% for column in @scaffold_class.content_columns %>
2
+ <p>
3
+ <b><%= column.human_name %>:</b>
4
+ <%= instance_variable_get("@#{@scaffold_singular_name}").send(column.name) %>
5
+ </p>
6
+ <% end %>
7
+
8
+ <%= link_to "Edit", :action => "edit#{@scaffold_suffix}", :id => instance_variable_get("@#{@scaffold_singular_name}").id %> |
9
+ <%= link_to "Back", :action => "list#{@scaffold_suffix}" %>
@@ -0,0 +1,194 @@
1
+ require File.dirname(__FILE__) + '/assertions/action_pack_assertions'
2
+ require File.dirname(__FILE__) + '/assertions/active_record_assertions'
3
+
4
+ module ActionController #:nodoc:
5
+ class Base
6
+ # Process a test request called with a +TestRequest+ object.
7
+ def self.process_test(request)
8
+ new.process_test(request)
9
+ end
10
+
11
+ def process_test(request) #:nodoc:
12
+ process(request, TestResponse.new)
13
+ end
14
+ end
15
+
16
+ class TestRequest < AbstractRequest #:nodoc:
17
+ attr_writer :cookies
18
+ attr_accessor :query_parameters, :request_parameters, :session, :env
19
+ attr_accessor :host, :path, :request_uri, :remote_addr
20
+
21
+ def initialize(query_parameters = nil, request_parameters = nil, session = nil)
22
+ @query_parameters = query_parameters || {}
23
+ @request_parameters = request_parameters || {}
24
+ @session = session || TestSession.new
25
+
26
+ initialize_containers
27
+ initialize_default_values
28
+
29
+ super()
30
+ end
31
+
32
+ def reset_session
33
+ @session = {}
34
+ end
35
+
36
+ def cookies
37
+ @cookies.freeze
38
+ end
39
+
40
+ def action=(action_name)
41
+ @query_parameters.update({ "action" => action_name })
42
+ @parameters = nil
43
+ end
44
+
45
+ def request_uri=(uri)
46
+ @request_uri = uri
47
+ @path = uri.split("?").first
48
+ end
49
+
50
+ private
51
+ def initialize_containers
52
+ @env, @cookies = {}, {}
53
+ end
54
+
55
+ def initialize_default_values
56
+ @host = "test.host"
57
+ @request_uri = "/"
58
+ @remote_addr = "127.0.0.1"
59
+ @env["SERVER_PORT"] = 80
60
+ end
61
+ end
62
+
63
+ class TestResponse < AbstractResponse #:nodoc:
64
+ # the class attribute ties a TestResponse to the assertions
65
+ class << self
66
+ attr_accessor :assertion_target
67
+ end
68
+
69
+ # initializer
70
+ def initialize
71
+ TestResponse.assertion_target=self# if TestResponse.assertion_target.nil?
72
+ super()
73
+ end
74
+
75
+ # the response code of the request
76
+ def response_code
77
+ headers['Status'][0,3].to_i rescue 0
78
+ end
79
+
80
+ # was the response successful?
81
+ def success?
82
+ response_code == 200
83
+ end
84
+
85
+ # was the URL not found?
86
+ def missing?
87
+ response_code == 404
88
+ end
89
+
90
+ # were we redirected?
91
+ def redirect?
92
+ (300..399).include?(response_code)
93
+ end
94
+
95
+ # was there a server-side error?
96
+ def server_error?
97
+ (500..599).include?(response_code)
98
+ end
99
+
100
+ # returns the redirection location or nil
101
+ def redirect_url
102
+ redirect? ? headers['location'] : nil
103
+ end
104
+
105
+ # does the redirect location match this regexp pattern?
106
+ def redirect_url_match?( pattern )
107
+ return false if redirect_url.nil?
108
+ p = Regexp.new(pattern) if pattern.class == String
109
+ p = pattern if pattern.class == Regexp
110
+ return false if p.nil?
111
+ p.match(redirect_url) != nil
112
+ end
113
+
114
+ # returns the template path of the file which was used to
115
+ # render this response (or nil)
116
+ def rendered_file(with_controller=false)
117
+ unless template.first_render.nil?
118
+ unless with_controller
119
+ template.first_render
120
+ else
121
+ template.first_render.split('/').last || template.first_render
122
+ end
123
+ end
124
+ end
125
+
126
+ # was this template rendered by a file?
127
+ def rendered_with_file?
128
+ !rendered_file.nil?
129
+ end
130
+
131
+ # a shortcut to the flash (or an empty hash if no flash.. hey! that rhymes!)
132
+ def flash
133
+ session['flash'] || {}
134
+ end
135
+
136
+ # do we have a flash?
137
+ def has_flash?
138
+ !session['flash'].nil?
139
+ end
140
+
141
+ # do we have a flash that has contents?
142
+ def has_flash_with_contents?
143
+ !flash.empty?
144
+ end
145
+
146
+ # does the specified flash object exist?
147
+ def has_flash_object?(name=nil)
148
+ !flash[name].nil?
149
+ end
150
+
151
+ # does the specified object exist in the session?
152
+ def has_session_object?(name=nil)
153
+ !session[name].nil?
154
+ end
155
+
156
+ # a shortcut to the template.assigns
157
+ def template_objects
158
+ template.assigns || {}
159
+ end
160
+
161
+ # does the specified template object exist?
162
+ def has_template_object?(name=nil)
163
+ !template_objects[name].nil?
164
+ end
165
+ end
166
+
167
+ class TestSession #:nodoc:
168
+ def initialize(attributes = {})
169
+ @attributes = attributes
170
+ end
171
+
172
+ def [](key)
173
+ @attributes[key]
174
+ end
175
+
176
+ def []=(key, value)
177
+ @attributes[key] = value
178
+ end
179
+
180
+ def update() end
181
+ def close() end
182
+ def delete() @attributes = {} end
183
+ end
184
+ end
185
+
186
+ class Test::Unit::TestCase #:nodoc:
187
+ private
188
+ # execute the request and set/volley the response
189
+ def process(action, parameters = {})
190
+ @request.action = action.to_s
191
+ @request.parameters.update(parameters)
192
+ @controller.process(@request, @response)
193
+ end
194
+ end
@@ -0,0 +1,153 @@
1
+ module ActionController
2
+ # Rewrites urls for Base.redirect_to and Base.url_for in the controller.
3
+ class UrlRewriter #:nodoc:
4
+ VALID_OPTIONS = [:action, :action_prefix, :action_suffix, :controller, :controller_prefix, :anchor, :params, :path_params, :id, :only_path, :overwrite_params ]
5
+
6
+ def initialize(request, controller, action)
7
+ @request, @controller, @action = request, controller, action
8
+ @rewritten_path = @request.path ? @request.path.dup : ""
9
+ end
10
+
11
+ def rewrite(options = {})
12
+ validate_options(VALID_OPTIONS, options.keys)
13
+
14
+ rewrite_url(
15
+ rewrite_path(@rewritten_path, options),
16
+ options
17
+ )
18
+ end
19
+
20
+ def to_s
21
+ to_str
22
+ end
23
+
24
+ def to_str
25
+ "#{@request.protocol}, #{@request.host_with_port}, #{@request.path}, #{@controller}, #{@action}, #{@request.parameters.inspect}"
26
+ end
27
+
28
+ private
29
+ def validate_options(valid_option_keys, supplied_option_keys)
30
+ unknown_option_keys = supplied_option_keys - valid_option_keys
31
+ raise(ActionController::ActionControllerError, "Unknown options: #{unknown_option_keys}") unless unknown_option_keys.empty?
32
+ end
33
+
34
+ def rewrite_url(path, options)
35
+ rewritten_url = ""
36
+ rewritten_url << @request.protocol unless options[:only_path]
37
+ rewritten_url << @request.host_with_port unless options[:only_path]
38
+
39
+ rewritten_url << path
40
+ rewritten_url << build_query_string(new_parameters(options)) if options[:params] || options[:overwrite_params]
41
+ rewritten_url << "##{options[:anchor]}" if options[:anchor]
42
+ return rewritten_url
43
+ end
44
+
45
+ def rewrite_path(path, options)
46
+ include_id_in_path_params(options)
47
+
48
+ path = rewrite_action(path, options) if options[:action] || options[:action_prefix]
49
+ path = rewrite_path_params(path, options) if options[:path_params]
50
+ path = rewrite_controller(path, options) if options[:controller] || options[:controller_prefix]
51
+ return path
52
+ end
53
+
54
+ def rewrite_path_params(path, options)
55
+ options[:path_params].inject(path) do |path, pair|
56
+ if options[:action].nil? && @request.parameters[pair.first]
57
+ path.sub(/\b#{@request.parameters[pair.first]}\b/, pair.last.to_s)
58
+ else
59
+ path += "/#{pair.last}"
60
+ end
61
+ end
62
+ end
63
+
64
+ def rewrite_action(path, options)
65
+ all, controller_prefix, action_prefix, action_suffix =
66
+ /^\/(.*)#{@controller}\/(.*)#{@action == "index" ? "" : @action}(.*)/.match(path).to_a
67
+
68
+ if @action == "index" && action_prefix && !action_prefix.empty?
69
+ path = path.sub(action_prefix, action_name(options, action_prefix))
70
+ elsif @action == "index"
71
+ path = path.sub(/#{@controller}\//, @controller + "/" + action_name(options))
72
+ else
73
+ path = path.sub((action_prefix || "") + @action + (action_suffix || ""), action_name(options, action_prefix))
74
+ end
75
+
76
+ if options[:controller_prefix] && !options[:controller]
77
+ ensure_slash_suffix(options, :controller_prefix)
78
+ if controller_prefix
79
+ path = path.sub(controller_prefix, options[:controller_prefix])
80
+ else
81
+ path = options[:controller_prefix] + path
82
+ end
83
+ end
84
+
85
+ return path
86
+ end
87
+
88
+ def rewrite_controller(path, options)
89
+ all, controller_prefix = /^\/(.*?)#{@controller}/.match(path).to_a
90
+ path = "/"
91
+ path << controller_name(options, controller_prefix)
92
+ path << action_name(options) if options[:action]
93
+ path << path_params_in_list(options) if options[:path_params]
94
+ return path
95
+ end
96
+
97
+ def action_name(options, action_prefix = nil, action_suffix = nil)
98
+ ensure_slash_suffix(options, :action_prefix)
99
+ ensure_slash_prefix(options, :action_suffix)
100
+
101
+ prefix = options[:action_prefix] || action_prefix || ""
102
+ suffix = options[:action] == "index" ? "" : (options[:action_suffix] || action_suffix || "")
103
+ name = (options[:action] == "index" ? "" : options[:action]) || ""
104
+
105
+ return prefix + name + suffix
106
+ end
107
+
108
+ def controller_name(options, controller_prefix)
109
+ ensure_slash_suffix(options, :controller_prefix)
110
+ controller_name = options[:controller_prefix] || controller_prefix || ""
111
+ controller_name << (options[:controller] + "/") if options[:controller]
112
+ return controller_name
113
+ end
114
+
115
+ def path_params_in_list(options)
116
+ options[:path_params].inject("") { |path, pair| path += "/#{pair.last}" }
117
+ end
118
+
119
+ def ensure_slash_suffix(options, key)
120
+ options[key] = options[key] + "/" if options[key] && !options[key].empty? && options[key][-1..-1] != "/"
121
+ end
122
+
123
+ def ensure_slash_prefix(options, key)
124
+ options[key] = "/" + options[key] if options[key] && !options[key].empty? && options[key][0..1] != "/"
125
+ end
126
+
127
+ def include_id_in_path_params(options)
128
+ options[:path_params] = (options[:path_params] || {}).merge({"id" => options[:id]}) if options[:id]
129
+ end
130
+
131
+ def new_parameters(options)
132
+ parameters = options[:params] || existing_parameters
133
+ parameters.update(options[:overwrite_params]) if options[:overwrite_params]
134
+ parameters.reject { |key,value| value.nil? }
135
+ end
136
+
137
+ def existing_parameters
138
+ @request.parameters.reject { |key, value| %w( id action controller).include?(key) }
139
+ end
140
+
141
+ # Returns a query string with escaped keys and values from the passed hash. If the passed hash contains an "id" it'll
142
+ # be added as a path element instead of a regular parameter pair.
143
+ def build_query_string(hash)
144
+ elements = []
145
+ query_string = ""
146
+
147
+ hash.each { |key, value| elements << "#{CGI.escape(key)}=#{CGI.escape(value.to_s)}" }
148
+ unless elements.empty? then query_string << ("?" + elements.join("&")) end
149
+
150
+ return query_string
151
+ end
152
+ end
153
+ end