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,24 @@
1
+ <IfModule mod_ruby.c>
2
+ RubyRequire apache/ruby-run
3
+ RubySafeLevel 0
4
+
5
+ <Files *.rbx>
6
+ SetHandler ruby-object
7
+ RubyHandler Apache::RubyRun.instance
8
+ </Files>
9
+ </IfModule>
10
+
11
+
12
+ RewriteEngine On
13
+ RewriteRule ^fcgi/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/([0-9]+)$ /$1_controller.fcgi?action=$2&id=$3 [QSA]
14
+ RewriteRule ^fcgi/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)$ /$1_controller.fcgi?action=$2 [QSA]
15
+ RewriteRule ^fcgi/([-_a-zA-Z0-9]+)/$ /$1_controller.fcgi?action=index [QSA]
16
+
17
+ RewriteRule ^modruby/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/([0-9]+)$ /$1_controller.rbx?action=$2&id=$3 [QSA]
18
+ RewriteRule ^modruby/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)$ /$1_controller.rbx?action=$2 [QSA]
19
+ RewriteRule ^modruby/([-_a-zA-Z0-9]+)/$ /$1_controller.rbx?action=index [QSA]
20
+
21
+ RewriteRule ^([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/([0-9]+)$ /$1_controller.cgi?action=$2&id=$3 [QSA]
22
+ RewriteRule ^([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)$ /$1_controller.cgi?action=$2 [QSA]
23
+ RewriteRule ^([-_a-zA-Z0-9]+)/$ /$1_controller.cgi?action=index [QSA]
24
+
@@ -0,0 +1,33 @@
1
+ <h1>Address Book</h1>
2
+
3
+ <% if @people.empty? %>
4
+ <p>No people in the address book yet</p>
5
+ <% else %>
6
+ <table>
7
+ <tr><th>Name</th><th>Email Address</th><th>Phone Number</th></tr>
8
+ <% for person in @people %>
9
+ <tr><td><%= person.name %></td><td><%= person.email_address %></td><td><%= person.phone_number %></td></tr>
10
+ <% end %>
11
+ </table>
12
+ <% end %>
13
+
14
+ <form action="create_person">
15
+ <p>
16
+ Name:<br />
17
+ <input type="text" name="person[name]">
18
+ </p>
19
+
20
+ <p>
21
+ Email address:<br />
22
+ <input type="text" name="person[email_address]">
23
+ </p>
24
+
25
+ <p>
26
+ Phone number:<br />
27
+ <input type="text" name="person[phone_number]">
28
+ </p>
29
+
30
+ <p>
31
+ <input type="submit" value="Create Person">
32
+ </p>
33
+ </form>
@@ -0,0 +1,8 @@
1
+ <html>
2
+ <head>
3
+ <title><%= @title || "Untitled" %></title>
4
+ </head>
5
+ <body>
6
+ <%= @content_for_layout %>
7
+ </body>
8
+ </html>
@@ -0,0 +1,9 @@
1
+ #!/usr/local/bin/ruby
2
+
3
+ require "address_book_controller"
4
+
5
+ begin
6
+ AddressBookController.process_cgi(CGI.new)
7
+ rescue => e
8
+ CGI.new.out { "#{e.class}: #{e.message}" }
9
+ end
@@ -0,0 +1,6 @@
1
+ #!/usr/local/bin/ruby
2
+
3
+ require "address_book_controller"
4
+ require "fcgi"
5
+
6
+ FCGI.each_cgi { |cgi| AddressBookController.process_cgi(cgi) }
@@ -0,0 +1,52 @@
1
+ $:.unshift(File.dirname(__FILE__) + "/../lib")
2
+
3
+ require "action_controller"
4
+ require "action_controller/test_process"
5
+
6
+ Person = Struct.new("Person", :id, :name, :email_address, :phone_number)
7
+
8
+ class AddressBookService
9
+ attr_reader :people
10
+
11
+ def initialize() @people = [] end
12
+ def create_person(data) people.unshift(Person.new(next_person_id, data["name"], data["email_address"], data["phone_number"])) end
13
+ def find_person(topic_id) people.select { |person| person.id == person.to_i }.first end
14
+ def next_person_id() people.first.id + 1 end
15
+ end
16
+
17
+ class AddressBookController < ActionController::Base
18
+ layout "address_book/layout"
19
+
20
+ before_filter :initialize_session_storage
21
+
22
+ # Could also have used a proc
23
+ # before_filter proc { |c| c.instance_variable_set("@address_book", c.session["address_book"] ||= AddressBookService.new) }
24
+
25
+ def index
26
+ @title = "Address Book"
27
+ @people = @address_book.people
28
+ end
29
+
30
+ def person
31
+ @person = @address_book.find_person(@params["id"])
32
+ end
33
+
34
+ def create_person
35
+ @address_book.create_person(@params["person"])
36
+ redirect_to :action => "index"
37
+ end
38
+
39
+ private
40
+ def initialize_session_storage
41
+ @address_book = @session["address_book"] ||= AddressBookService.new
42
+ end
43
+ end
44
+
45
+ ActionController::Base.template_root = File.dirname(__FILE__)
46
+ # ActionController::Base.logger = Logger.new("debug.log") # Remove first comment to turn on logging in current dir
47
+
48
+ begin
49
+ AddressBookController.process_cgi(CGI.new) if $0 == __FILE__
50
+ rescue => e
51
+ CGI.new.out { "#{e.class}: #{e.message}" }
52
+ end
@@ -0,0 +1,4 @@
1
+ #!/usr/local/bin/ruby
2
+
3
+ require "address_book_controller"
4
+ AddressBookController.process_cgi(CGI.new)
@@ -0,0 +1,52 @@
1
+ $:.unshift(File.dirname(__FILE__) + "/../lib")
2
+
3
+ require "action_controller"
4
+ require 'action_controller/test_process'
5
+
6
+ Person = Struct.new("Person", :name, :address, :age)
7
+
8
+ class BenchmarkController < ActionController::Base
9
+ def message
10
+ render_text "hello world"
11
+ end
12
+
13
+ def list
14
+ @people = [ Person.new("David"), Person.new("Mary") ]
15
+ render_template "hello: <% for person in @people %>Name: <%= person.name %><% end %>"
16
+ end
17
+
18
+ def form_helper
19
+ @person = Person.new "david", "hyacintvej", 24
20
+ render_template(
21
+ "<% person = Person.new 'Mary', 'hyacintvej', 22 %> " +
22
+ "change the name <%= text_field 'person', 'name' %> and <%= text_field 'person', 'address' %> and <%= text_field 'person', 'age' %>"
23
+ )
24
+ end
25
+ end
26
+
27
+ #ActionController::Base.template_root = File.dirname(__FILE__)
28
+
29
+ require "benchmark"
30
+
31
+ RUNS = ARGV[0] ? ARGV[0].to_i : 50
32
+
33
+ require "profile" if ARGV[1]
34
+
35
+ runtime = Benchmark.measure {
36
+ RUNS.times { BenchmarkController.process_test(ActionController::TestRequest.new({ "action" => "list" })) }
37
+ }
38
+
39
+ puts "List: #{RUNS / runtime.real}"
40
+
41
+
42
+ runtime = Benchmark.measure {
43
+ RUNS.times { BenchmarkController.process_test(ActionController::TestRequest.new({ "action" => "message" })) }
44
+ }
45
+
46
+ puts "Message: #{RUNS / runtime.real}"
47
+
48
+ runtime = Benchmark.measure {
49
+ RUNS.times { BenchmarkController.process_test(ActionController::TestRequest.new({ "action" => "form_helper" })) }
50
+ }
51
+
52
+ puts "Form helper: #{RUNS / runtime.real}"
@@ -0,0 +1,89 @@
1
+ #!/usr/local/bin/ruby
2
+
3
+ begin
4
+
5
+ $:.unshift(File.dirname(__FILE__) + "/../lib")
6
+ $:.unshift(File.dirname(__FILE__) + "/../../../edge/activerecord/lib")
7
+
8
+ require 'fcgi'
9
+ require 'action_controller'
10
+ require 'action_controller/test_process'
11
+
12
+ require 'active_record'
13
+
14
+ class Post < ActiveRecord::Base; end
15
+
16
+ ActiveRecord::Base.establish_connection(:adapter => "mysql", :database => "basecamp")
17
+
18
+ SESSION_OPTIONS = { "database_manager" => CGI::Session::MemoryStore }
19
+
20
+ class TestController < ActionController::Base
21
+ def index
22
+ render_template <<-EOT
23
+ <% for post in Post.find_all(nil,nil,100) %>
24
+ <%= post.title %>
25
+ <% end %>
26
+ EOT
27
+ end
28
+
29
+ def show_one
30
+ render_template <<-EOT
31
+ <%= Post.find_first.title %>
32
+ EOT
33
+ end
34
+
35
+ def text
36
+ render_text "hello world"
37
+ end
38
+
39
+ def erb_text
40
+ render_template "hello <%= 'world' %>"
41
+ end
42
+
43
+ def erb_loop
44
+ render_template <<-EOT
45
+ <% for post in 1..100 %>
46
+ <%= post %>
47
+ <% end %>
48
+ EOT
49
+ end
50
+
51
+ def rescue_action(e) puts e.message + e.backtrace.join("\n") end
52
+ end
53
+
54
+ if ARGV.empty? && ENV["REQUEST_URI"]
55
+ FCGI.each_cgi do |cgi|
56
+ TestController.process(ActionController::CgiRequest.new(cgi, SESSION_OPTIONS), ActionController::CgiResponse.new(cgi)).out
57
+ end
58
+ else
59
+ if ARGV.empty?
60
+ cgi = CGI.new
61
+ end
62
+
63
+ require 'benchmark'
64
+ require 'profile' if ARGV[2] == "profile"
65
+
66
+ RUNS = ARGV[1] ? ARGV[1].to_i : 50
67
+
68
+ runtime = Benchmark::measure {
69
+ RUNS.times {
70
+ if ARGV.empty?
71
+ TestController.process(ActionController::CgiRequest.new(cgi, SESSION_OPTIONS), ActionController::CgiResponse.new(cgi))
72
+ else
73
+ response = TestController.process_test(
74
+ ActionController::TestRequest.new({"action" => ARGV[0]})
75
+ )
76
+ puts(response.body) if ARGV[2] == "show"
77
+ end
78
+ }
79
+ }
80
+
81
+ puts "Runs: #{RUNS}"
82
+ puts "Avg. runtime: #{runtime.real / RUNS}"
83
+ puts "Requests/second: #{RUNS / runtime.real}"
84
+ end
85
+
86
+ rescue Exception => e
87
+ # CGI.new.out { "<pre>" + e.message + e.backtrace.join("\n") + "</pre>" }
88
+ $stderr << e.message + e.backtrace.join("\n")
89
+ end
@@ -0,0 +1,53 @@
1
+ #!/usr/local/bin/ruby
2
+
3
+ $:.unshift(File.dirname(__FILE__) + "/../lib")
4
+
5
+ require "action_controller"
6
+
7
+ Post = Struct.new("Post", :title, :body)
8
+
9
+ class BlogController < ActionController::Base
10
+ before_filter :initialize_session_storage
11
+
12
+ def index
13
+ @posts = @session["posts"]
14
+
15
+ render_template <<-"EOF"
16
+ <html><body>
17
+ <%= @flash["alert"] %>
18
+ <h1>Posts</h1>
19
+ <% @posts.each do |post| %>
20
+ <p><b><%= post.title %></b><br /><%= post.body %></p>
21
+ <% end %>
22
+
23
+ <h1>Create post</h1>
24
+ <form action="create">
25
+ Title: <input type="text" name="post[title]"><br>
26
+ Body: <textarea name="post[body]"></textarea><br>
27
+ <input type="submit" value="save">
28
+ </form>
29
+
30
+ </body></html>
31
+ EOF
32
+ end
33
+
34
+ def create
35
+ @session["posts"].unshift(Post.new(@params["post"]["title"], @params["post"]["body"]))
36
+ flash["alert"] = "New post added!"
37
+ redirect_to :action => "index"
38
+ end
39
+
40
+ private
41
+ def initialize_session_storage
42
+ @session["posts"] = [] if @session["posts"].nil?
43
+ end
44
+ end
45
+
46
+ ActionController::Base.template_root = File.dirname(__FILE__)
47
+ # ActionController::Base.logger = Logger.new("debug.log") # Remove first comment to turn on logging in current dir
48
+
49
+ begin
50
+ BlogController.process_cgi(CGI.new) if $0 == __FILE__
51
+ rescue => e
52
+ CGI.new.out { "#{e.class}: #{e.message}" }
53
+ end
@@ -0,0 +1,14 @@
1
+ <html>
2
+ <body>
3
+ <h1>Topics</h1>
4
+
5
+ <%= link_to "New topic", :action => "new_topic" %>
6
+
7
+ <ul>
8
+ <% for topic in @topics %>
9
+ <li><%= link_to "#{topic.title} (#{topic.replies.length} replies)", :action => "topic", :path_params => { "id" => topic.id } %></li>
10
+ <% end %>
11
+ </ul>
12
+
13
+ </body>
14
+ </html>
@@ -0,0 +1,22 @@
1
+ <html>
2
+ <body>
3
+ <h1>New topic</h1>
4
+
5
+ <form action="<%= url_for(:action => "create_topic") %>" method="post">
6
+ <p>
7
+ Title:<br>
8
+ <input type="text" name="topic[title]">
9
+ </p>
10
+
11
+ <p>
12
+ Body:<br>
13
+ <textarea name="topic[body]" style="width: 200px; height: 200px"></textarea>
14
+ </p>
15
+
16
+ <p>
17
+ <input type="submit" value="Create topic">
18
+ </p>
19
+ </form>
20
+
21
+ </body>
22
+ </html>
@@ -0,0 +1,32 @@
1
+ <html>
2
+ <body>
3
+ <h1><%= @topic.title %></h1>
4
+
5
+ <p><%= @topic.body %></p>
6
+
7
+ <%= link_to "Back to topics", :action => "index" %>
8
+
9
+ <% unless @topic.replies.empty? %>
10
+ <h2>Replies</h2>
11
+ <ol>
12
+ <% for reply in @topic.replies %>
13
+ <li><%= reply.body %></li>
14
+ <% end %>
15
+ </ol>
16
+ <% end %>
17
+
18
+ <h2>Reply to this topic</h2>
19
+
20
+ <form action="<%= url_for(:action => "create_reply") %>" method="post">
21
+ <input type="hidden" name="reply[topic_id]" value="<%= @topic.id %>">
22
+ <p>
23
+ <textarea name="reply[body]" style="width: 200px; height: 200px"></textarea>
24
+ </p>
25
+
26
+ <p>
27
+ <input type="submit" value="Create reply">
28
+ </p>
29
+ </form>
30
+
31
+ </body>
32
+ </html>
@@ -0,0 +1,57 @@
1
+ #!/usr/local/bin/ruby
2
+
3
+ $:.unshift(File.dirname(__FILE__) + "/../lib")
4
+
5
+ require "action_controller"
6
+
7
+ Topic = Struct.new("Topic", :id, :title, :body, :replies)
8
+ Reply = Struct.new("Reply", :body)
9
+
10
+ class DebateService
11
+ attr_reader :topics
12
+
13
+ def initialize() @topics = [] end
14
+ def create_topic(data) topics.unshift(Topic.new(next_topic_id, data["title"], data["body"], [])) end
15
+ def create_reply(data) find_topic(data["topic_id"]).replies << Reply.new(data["body"]) end
16
+ def find_topic(topic_id) topics.select { |topic| topic.id == topic_id.to_i }.first end
17
+ def next_topic_id() topics.first.id + 1 end
18
+ end
19
+
20
+ class DebateController < ActionController::Base
21
+ before_filter :initialize_session_storage
22
+
23
+ def index
24
+ @topics = @debate.topics
25
+ end
26
+
27
+ def topic
28
+ @topic = @debate.find_topic(@params["id"])
29
+ end
30
+
31
+ # def new_topic() end <-- This is not needed as the template doesn't require any assigns
32
+
33
+ def create_topic
34
+ @debate.create_topic(@params["topic"])
35
+ redirect_to :action => "index"
36
+ end
37
+
38
+ def create_reply
39
+ @debate.create_reply(@params["reply"])
40
+ redirect_to :action => "topic", :path_params => { "id" => @params["reply"]["topic_id"] }
41
+ end
42
+
43
+ private
44
+ def initialize_session_storage
45
+ @session["debate"] = DebateService.new if @session["debate"].nil?
46
+ @debate = @session["debate"]
47
+ end
48
+ end
49
+
50
+ ActionController::Base.template_root = File.dirname(__FILE__)
51
+ # ActionController::Base.logger = Logger.new("debug.log") # Remove first comment to turn on logging in current dir
52
+
53
+ begin
54
+ DebateController.process_cgi(CGI.new) if $0 == __FILE__
55
+ rescue => e
56
+ CGI.new.out { "#{e.class}: #{e.message}" }
57
+ end