goofy 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +7 -0
  2. data/.gems +4 -0
  3. data/.gitignore +2 -0
  4. data/CHANGELOG +47 -0
  5. data/CONTRIBUTING +19 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE +23 -0
  8. data/README.md +67 -0
  9. data/app/.rspec +2 -0
  10. data/app/Gemfile +13 -0
  11. data/app/app/controllers/application_controller.rb +3 -0
  12. data/app/app/services/.keep +0 -0
  13. data/app/config.ru +4 -0
  14. data/app/config/environment.rb +9 -0
  15. data/app/config/initializers/.keep +0 -0
  16. data/app/config/routes.rb +7 -0
  17. data/app/config/settings.rb +0 -0
  18. data/app/spec/helpers.rb +2 -0
  19. data/app/spec/helpers/goofy.rb +11 -0
  20. data/app/spec/spec_helper.rb +107 -0
  21. data/benchmark/measure.rb +35 -0
  22. data/bin/check_its_goofy.rb +15 -0
  23. data/bin/goofy +61 -0
  24. data/bin/goofy_generator.rb +357 -0
  25. data/bin/goofy_instance_creator.rb +40 -0
  26. data/examples/config.ru +18 -0
  27. data/examples/measure.rb +17 -0
  28. data/examples/rack-response.ru +21 -0
  29. data/examples/views/home.mote +7 -0
  30. data/examples/views/layout.mote +11 -0
  31. data/goofy.gemspec +26 -0
  32. data/lib/goofy.rb +405 -0
  33. data/lib/goofy/capybara.rb +13 -0
  34. data/lib/goofy/controller.rb +14 -0
  35. data/lib/goofy/controller/base.rb +21 -0
  36. data/lib/goofy/controller/callbacks.rb +19 -0
  37. data/lib/goofy/render.rb +63 -0
  38. data/lib/goofy/router.rb +9 -0
  39. data/lib/goofy/safe.rb +23 -0
  40. data/lib/goofy/safe/csrf.rb +47 -0
  41. data/lib/goofy/safe/secure_headers.rb +40 -0
  42. data/lib/goofy/test.rb +11 -0
  43. data/makefile +4 -0
  44. data/test/accept.rb +32 -0
  45. data/test/captures.rb +162 -0
  46. data/test/composition.rb +69 -0
  47. data/test/controller.rb +29 -0
  48. data/test/cookie.rb +34 -0
  49. data/test/csrf.rb +139 -0
  50. data/test/extension.rb +21 -0
  51. data/test/helper.rb +11 -0
  52. data/test/host.rb +29 -0
  53. data/test/integration.rb +114 -0
  54. data/test/match.rb +86 -0
  55. data/test/middleware.rb +46 -0
  56. data/test/number.rb +36 -0
  57. data/test/on.rb +157 -0
  58. data/test/param.rb +66 -0
  59. data/test/path.rb +86 -0
  60. data/test/plugin.rb +68 -0
  61. data/test/rack.rb +22 -0
  62. data/test/redirect.rb +21 -0
  63. data/test/render.rb +128 -0
  64. data/test/root.rb +83 -0
  65. data/test/run.rb +23 -0
  66. data/test/safe.rb +74 -0
  67. data/test/segment.rb +45 -0
  68. data/test/session.rb +21 -0
  69. data/test/settings.rb +52 -0
  70. data/test/views/about.erb +1 -0
  71. data/test/views/about.str +1 -0
  72. data/test/views/content-yield.erb +1 -0
  73. data/test/views/custom/abs_path.mote +1 -0
  74. data/test/views/frag.mote +1 -0
  75. data/test/views/home.erb +2 -0
  76. data/test/views/home.mote +1 -0
  77. data/test/views/home.str +2 -0
  78. data/test/views/layout-alternative.erb +2 -0
  79. data/test/views/layout-yield.erb +3 -0
  80. data/test/views/layout.erb +2 -0
  81. data/test/views/layout.mote +2 -0
  82. data/test/views/layout.str +2 -0
  83. data/test/views/test.erb +1 -0
  84. data/test/with.rb +42 -0
  85. metadata +271 -0
@@ -0,0 +1,69 @@
1
+ require File.expand_path("helper", File.dirname(__FILE__))
2
+
3
+ test "composing on top of a PATH" do
4
+ Services = Goofy.new {
5
+ on "services/:id" do |id|
6
+ res.write "View #{id}"
7
+ end
8
+ }
9
+
10
+ Goofy.define do
11
+ on "provider" do
12
+ run Services
13
+ end
14
+ end
15
+
16
+ env = { "SCRIPT_NAME" => "/", "PATH_INFO" => "/provider/services/101" }
17
+
18
+ _, _, resp = Goofy.call(env)
19
+
20
+ assert_response resp, ["View 101"]
21
+ end
22
+
23
+ test "redefining not_found" do
24
+ class Users < Goofy
25
+ def not_found
26
+ res.status = 404
27
+ res.write "Not found!"
28
+ end
29
+
30
+ define do
31
+ on root do
32
+ res.write "Users"
33
+ end
34
+ end
35
+ end
36
+
37
+ class Goofy
38
+ def not_found
39
+ res.status = 404
40
+ res.write "Error 404"
41
+ end
42
+ end
43
+
44
+ Goofy.define do
45
+ on "users" do
46
+ run Users
47
+ end
48
+ end
49
+
50
+ env = { "SCRIPT_NAME" => "/", "PATH_INFO" => "/users" }
51
+
52
+ _, _, resp = Goofy.call(env)
53
+
54
+ assert_response resp, ["Users"]
55
+
56
+ env = { "SCRIPT_NAME" => "/", "PATH_INFO" => "/users/42" }
57
+
58
+ status, _, resp = Goofy.call(env)
59
+
60
+ assert_response resp, ["Not found!"]
61
+ assert_equal status, 404
62
+
63
+ env = { "SCRIPT_NAME" => "/", "PATH_INFO" => "/guests" }
64
+
65
+ status, _, resp = Goofy.call(env)
66
+
67
+ assert_response resp, ["Error 404"]
68
+ assert_equal status, 404
69
+ end
@@ -0,0 +1,29 @@
1
+ require_relative "helper"
2
+
3
+ require "goofy/controller"
4
+
5
+ scope do
6
+ setup do
7
+ @@___stack_ = []
8
+ class HomeControlelr < Goofy::Controller
9
+ before_response -> { @message = "before_response_from_controller"; @@___stack_ << @message }
10
+ around_response -> { @around = "around_from_controller"; @@___stack_ << @around }
11
+ after_response -> { @after = "after_from_controller"; @@___stack_ << @after }
12
+ def response
13
+ res.write(@message)
14
+ end
15
+ end
16
+ Goofy.define do
17
+ on "home" do
18
+ controller HomeControlelr
19
+ end
20
+ end
21
+ end
22
+
23
+ test "response" do
24
+ _, _, body = Goofy.call({ "PATH_INFO" => "/home", "SCRIPT_NAME" => "/" })
25
+
26
+ assert_response body, ["before_response_from_controller"]
27
+ assert_equal ["before_response_from_controller", "around_from_controller", "around_from_controller", "after_from_controller"], @@___stack_
28
+ end
29
+ end
@@ -0,0 +1,34 @@
1
+ require File.expand_path("helper", File.dirname(__FILE__))
2
+
3
+ test "set cookie" do
4
+ Goofy.define do
5
+ on default do
6
+ res.set_cookie("foo", "bar")
7
+ res.set_cookie("bar", "baz")
8
+ res.write "Hello"
9
+ end
10
+ end
11
+
12
+ env = { "SCRIPT_NAME" => "/", "PATH_INFO" => "/" }
13
+
14
+ _, headers, body = Goofy.call(env)
15
+
16
+ assert_equal "foo=bar\nbar=baz", headers["Set-Cookie"]
17
+ end
18
+
19
+ test "delete cookie" do
20
+ Goofy.define do
21
+ on default do
22
+ res.set_cookie("foo", "bar")
23
+ res.delete_cookie("foo")
24
+ res.write "Hello"
25
+ end
26
+ end
27
+
28
+ env = { "SCRIPT_NAME" => "/", "PATH_INFO" => "/" }
29
+
30
+ _, headers, body = Goofy.call(env)
31
+
32
+ assert_equal "foo=; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 -0000",
33
+ headers["Set-Cookie"]
34
+ end
@@ -0,0 +1,139 @@
1
+ require_relative "helper"
2
+ require "goofy/safe/csrf"
3
+ require "goofy/test"
4
+
5
+ def assert_no_raise
6
+ yield
7
+ success
8
+ end
9
+
10
+ class UnsafeRequest < RuntimeError; end
11
+
12
+ scope do
13
+ setup do
14
+ Goofy.reset!
15
+
16
+ Goofy.use(Rack::Session::Cookie, secret: "_this_must_be_secret")
17
+ Goofy.plugin(Goofy::Safe::CSRF)
18
+ end
19
+
20
+ test "safe http methods" do
21
+ Goofy.define do
22
+ raise UnsafeRequest if csrf.unsafe?
23
+ end
24
+
25
+ assert_no_raise do
26
+ get "/"
27
+ head "/"
28
+ end
29
+ end
30
+
31
+ test "invalid csrf param" do
32
+ Goofy.define do
33
+ if csrf.unsafe?
34
+ csrf.reset!
35
+ end
36
+
37
+ res.write(csrf.token)
38
+ end
39
+
40
+ get "/"
41
+
42
+ old_token = last_response.body
43
+
44
+ post "/", "csrf_token" => "nonsense"
45
+
46
+ new_token = last_response.body
47
+
48
+ assert(old_token != new_token)
49
+ end
50
+
51
+ test "valid csrf param" do
52
+ Goofy.define do
53
+ raise unless csrf.safe?
54
+
55
+ on get do
56
+ res.write(csrf.token)
57
+ end
58
+
59
+ on post do
60
+ res.write("safe")
61
+ end
62
+ end
63
+
64
+ get "/"
65
+
66
+ csrf_token = last_response.body
67
+
68
+ assert(!csrf_token.empty?)
69
+
70
+ assert_no_raise do
71
+ post "/", "csrf_token" => csrf_token
72
+ end
73
+ end
74
+
75
+ test "http header" do
76
+ csrf_token = SecureRandom.hex(32)
77
+
78
+ Goofy.define do
79
+ session[:csrf_token] = csrf_token
80
+ raise if csrf.unsafe?
81
+ end
82
+
83
+ assert_no_raise do
84
+ post "/", {}, { "HTTP_X_CSRF_TOKEN" => csrf_token }
85
+ end
86
+ end
87
+
88
+ test "sub app raises too" do
89
+ class App < Goofy
90
+ define do
91
+ on post do
92
+ res.write("unsafe")
93
+ end
94
+ end
95
+ end
96
+
97
+ Goofy.define do
98
+ raise UnsafeRequest unless csrf.safe?
99
+
100
+ on "app" do
101
+ run(App)
102
+ end
103
+ end
104
+
105
+ assert_raise(UnsafeRequest) do
106
+ post "/app"
107
+ end
108
+ end
109
+
110
+ test "only sub app" do
111
+ class App < Goofy
112
+ define do
113
+ raise UnsafeRequest unless csrf.safe?
114
+
115
+ on post do
116
+ res.write("unsafe")
117
+ end
118
+ end
119
+ end
120
+
121
+ Goofy.define do
122
+ on "app" do
123
+ run(App)
124
+ end
125
+
126
+ on default do
127
+ res.write("safe")
128
+ end
129
+ end
130
+
131
+ assert_no_raise do
132
+ post "/"
133
+ end
134
+
135
+ assert_raise(UnsafeRequest) do
136
+ post "/app"
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,21 @@
1
+ require File.expand_path("helper", File.dirname(__FILE__))
2
+
3
+ setup do
4
+ Goofy.define do
5
+ on "styles" do
6
+ on extension("css") do |file|
7
+ res.write file
8
+ end
9
+ end
10
+ end
11
+
12
+ { "SCRIPT_NAME" => "/", "PATH_INFO" => "/styles" }
13
+ end
14
+
15
+ test "/styles/reset.css" do |env|
16
+ env["PATH_INFO"] += "/reset.css"
17
+
18
+ _, _, resp = Goofy.call(env)
19
+
20
+ assert_response resp, ["reset"]
21
+ end
@@ -0,0 +1,11 @@
1
+ $:.unshift(File.expand_path("../lib", File.dirname(__FILE__)))
2
+ require "goofy"
3
+
4
+ prepare { Goofy.reset! }
5
+
6
+ def assert_response(body, expected)
7
+ arr = body.map { |line| line.strip }
8
+
9
+ flunk "#{arr.inspect} != #{expected.inspect}" unless arr == expected
10
+ print "."
11
+ end
@@ -0,0 +1,29 @@
1
+ require File.expand_path("helper", File.dirname(__FILE__))
2
+
3
+ test "matches a host" do
4
+ Goofy.define do
5
+ on host("example.com") do
6
+ res.write "worked"
7
+ end
8
+ end
9
+
10
+ env = { "HTTP_HOST" => "example.com" }
11
+
12
+ _, _, resp = Goofy.call(env)
13
+
14
+ assert_response resp, ["worked"]
15
+ end
16
+
17
+ test "matches a host with a regexp" do
18
+ Goofy.define do
19
+ on host(/example/) do
20
+ res.write "worked"
21
+ end
22
+ end
23
+
24
+ env = { "HTTP_HOST" => "example.com" }
25
+
26
+ _, _, resp = Goofy.call(env)
27
+
28
+ assert_response resp, ["worked"]
29
+ end
@@ -0,0 +1,114 @@
1
+ require File.expand_path("helper", File.dirname(__FILE__))
2
+
3
+ test "resetting" do
4
+ old = Goofy.app
5
+ assert old.object_id == Goofy.app.object_id
6
+
7
+ Goofy.reset!
8
+ assert old.object_id != Goofy.app.object_id
9
+ end
10
+
11
+ class Middle
12
+ def initialize(app, first, second, &block)
13
+ @app, @first, @second, @block = app, first, second, block
14
+ end
15
+
16
+ def call(env)
17
+ env["m.first"] = @first
18
+ env["m.second"] = @second
19
+ env["m.block"] = @block.call
20
+
21
+ @app.call(env)
22
+ end
23
+ end
24
+
25
+ test "use passes in the arguments and block" do
26
+ Goofy.use Middle, "First", "Second" do
27
+ "this is the block"
28
+ end
29
+
30
+ Goofy.define do
31
+ on get do
32
+ on "hello" do
33
+ "Default"
34
+ end
35
+ end
36
+ end
37
+
38
+ env = { "REQUEST_METHOD" => "GET", "PATH_INFO" => "/hello",
39
+ "SCRIPT_NAME" => "/" }
40
+
41
+ Goofy.call(env)
42
+
43
+ assert "First" == env["m.first"]
44
+ assert "Second" == env["m.second"]
45
+ assert "this is the block" == env["m.block"]
46
+ end
47
+
48
+ test "reset and use" do
49
+ Goofy.use Middle, "First", "Second" do
50
+ "this is the block"
51
+ end
52
+
53
+ Goofy.define do
54
+ on get do
55
+ on "hello" do
56
+ res.write "Default"
57
+ end
58
+ end
59
+ end
60
+
61
+ Goofy.reset!
62
+
63
+ Goofy.use Middle, "1", "2" do
64
+ "3"
65
+ end
66
+
67
+ Goofy.define do
68
+ on get do
69
+ on "hello" do
70
+ res.write "2nd Default"
71
+ end
72
+ end
73
+ end
74
+
75
+ env = { "REQUEST_METHOD" => "GET", "PATH_INFO" => "/hello",
76
+ "SCRIPT_NAME" => "/" }
77
+
78
+ status, headers, resp = Goofy.call(env)
79
+
80
+ assert_equal 200, status
81
+ assert "text/html; charset=utf-8" == headers["Content-Type"]
82
+ assert_response resp, ["2nd Default"]
83
+
84
+ assert "1" == env["m.first"]
85
+ assert "2" == env["m.second"]
86
+ assert "3" == env["m.block"]
87
+ end
88
+
89
+ test "custom response" do
90
+ class MyResponse < Goofy::Response
91
+ def foobar
92
+ write "Default"
93
+ end
94
+ end
95
+
96
+ Goofy.settings[:res] = MyResponse
97
+
98
+ Goofy.define do
99
+ on get do
100
+ on "hello" do
101
+ res.foobar
102
+ end
103
+ end
104
+ end
105
+
106
+ env = { "REQUEST_METHOD" => "GET", "PATH_INFO" => "/hello",
107
+ "SCRIPT_NAME" => "/" }
108
+
109
+ status, headers, resp = Goofy.call(env)
110
+
111
+ assert 200 == status
112
+ assert "text/html; charset=utf-8" == headers["Content-Type"]
113
+ assert_response resp, ["Default"]
114
+ end