goofy 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gems +4 -0
- data/.gitignore +2 -0
- data/CHANGELOG +47 -0
- data/CONTRIBUTING +19 -0
- data/Gemfile +4 -0
- data/LICENSE +23 -0
- data/README.md +67 -0
- data/app/.rspec +2 -0
- data/app/Gemfile +13 -0
- data/app/app/controllers/application_controller.rb +3 -0
- data/app/app/services/.keep +0 -0
- data/app/config.ru +4 -0
- data/app/config/environment.rb +9 -0
- data/app/config/initializers/.keep +0 -0
- data/app/config/routes.rb +7 -0
- data/app/config/settings.rb +0 -0
- data/app/spec/helpers.rb +2 -0
- data/app/spec/helpers/goofy.rb +11 -0
- data/app/spec/spec_helper.rb +107 -0
- data/benchmark/measure.rb +35 -0
- data/bin/check_its_goofy.rb +15 -0
- data/bin/goofy +61 -0
- data/bin/goofy_generator.rb +357 -0
- data/bin/goofy_instance_creator.rb +40 -0
- data/examples/config.ru +18 -0
- data/examples/measure.rb +17 -0
- data/examples/rack-response.ru +21 -0
- data/examples/views/home.mote +7 -0
- data/examples/views/layout.mote +11 -0
- data/goofy.gemspec +26 -0
- data/lib/goofy.rb +405 -0
- data/lib/goofy/capybara.rb +13 -0
- data/lib/goofy/controller.rb +14 -0
- data/lib/goofy/controller/base.rb +21 -0
- data/lib/goofy/controller/callbacks.rb +19 -0
- data/lib/goofy/render.rb +63 -0
- data/lib/goofy/router.rb +9 -0
- data/lib/goofy/safe.rb +23 -0
- data/lib/goofy/safe/csrf.rb +47 -0
- data/lib/goofy/safe/secure_headers.rb +40 -0
- data/lib/goofy/test.rb +11 -0
- data/makefile +4 -0
- data/test/accept.rb +32 -0
- data/test/captures.rb +162 -0
- data/test/composition.rb +69 -0
- data/test/controller.rb +29 -0
- data/test/cookie.rb +34 -0
- data/test/csrf.rb +139 -0
- data/test/extension.rb +21 -0
- data/test/helper.rb +11 -0
- data/test/host.rb +29 -0
- data/test/integration.rb +114 -0
- data/test/match.rb +86 -0
- data/test/middleware.rb +46 -0
- data/test/number.rb +36 -0
- data/test/on.rb +157 -0
- data/test/param.rb +66 -0
- data/test/path.rb +86 -0
- data/test/plugin.rb +68 -0
- data/test/rack.rb +22 -0
- data/test/redirect.rb +21 -0
- data/test/render.rb +128 -0
- data/test/root.rb +83 -0
- data/test/run.rb +23 -0
- data/test/safe.rb +74 -0
- data/test/segment.rb +45 -0
- data/test/session.rb +21 -0
- data/test/settings.rb +52 -0
- data/test/views/about.erb +1 -0
- data/test/views/about.str +1 -0
- data/test/views/content-yield.erb +1 -0
- data/test/views/custom/abs_path.mote +1 -0
- data/test/views/frag.mote +1 -0
- data/test/views/home.erb +2 -0
- data/test/views/home.mote +1 -0
- data/test/views/home.str +2 -0
- data/test/views/layout-alternative.erb +2 -0
- data/test/views/layout-yield.erb +3 -0
- data/test/views/layout.erb +2 -0
- data/test/views/layout.mote +2 -0
- data/test/views/layout.str +2 -0
- data/test/views/test.erb +1 -0
- data/test/with.rb +42 -0
- metadata +271 -0
data/test/match.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
require File.expand_path("helper", File.dirname(__FILE__))
|
2
|
+
|
3
|
+
setup do
|
4
|
+
{ "SCRIPT_NAME" => "/", "PATH_INFO" => "/posts/123" }
|
5
|
+
end
|
6
|
+
|
7
|
+
test "text-book example" do |env|
|
8
|
+
Goofy.define do
|
9
|
+
on "posts/:id" do |id|
|
10
|
+
res.write id
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
_, _, resp = Goofy.call(env)
|
15
|
+
|
16
|
+
assert_response resp, ["123"]
|
17
|
+
end
|
18
|
+
|
19
|
+
test "multi-param" do |env|
|
20
|
+
Goofy.define do
|
21
|
+
on "u/:uid/posts/:id" do |uid, id|
|
22
|
+
res.write uid
|
23
|
+
res.write id
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
env["PATH_INFO"] = "/u/jdoe/posts/123"
|
28
|
+
|
29
|
+
_, _, resp = Goofy.call(env)
|
30
|
+
|
31
|
+
assert_response resp, ["jdoe", "123"]
|
32
|
+
end
|
33
|
+
|
34
|
+
test "regex nesting" do |env|
|
35
|
+
Goofy.define do
|
36
|
+
on(/u\/(\w+)/) do |uid|
|
37
|
+
res.write uid
|
38
|
+
|
39
|
+
on(/posts\/(\d+)/) do |id|
|
40
|
+
res.write id
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
env["PATH_INFO"] = "/u/jdoe/posts/123"
|
46
|
+
|
47
|
+
_, _, resp = Goofy.call(env)
|
48
|
+
|
49
|
+
assert_response resp, ["jdoe", "123"]
|
50
|
+
end
|
51
|
+
|
52
|
+
test "regex nesting colon param style" do |env|
|
53
|
+
Goofy.define do
|
54
|
+
on(/u:(\w+)/) do |uid|
|
55
|
+
res.write uid
|
56
|
+
|
57
|
+
on(/posts:(\d+)/) do |id|
|
58
|
+
res.write id
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
env["PATH_INFO"] = "/u:jdoe/posts:123"
|
64
|
+
|
65
|
+
_, _, resp = Goofy.call(env)
|
66
|
+
|
67
|
+
assert_response resp, ["jdoe", "123"]
|
68
|
+
end
|
69
|
+
|
70
|
+
test "symbol matching" do |env|
|
71
|
+
Goofy.define do
|
72
|
+
on "user", :id do |uid|
|
73
|
+
res.write uid
|
74
|
+
|
75
|
+
on "posts", :pid do |id|
|
76
|
+
res.write id
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
env["PATH_INFO"] = "/user/jdoe/posts/123"
|
82
|
+
|
83
|
+
_, _, resp = Goofy.call(env)
|
84
|
+
|
85
|
+
assert_response resp, ["jdoe", "123"]
|
86
|
+
end
|
data/test/middleware.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require File.expand_path("helper", File.dirname(__FILE__))
|
2
|
+
|
3
|
+
class Shrimp
|
4
|
+
def initialize(app)
|
5
|
+
@app = app
|
6
|
+
end
|
7
|
+
|
8
|
+
def call(env)
|
9
|
+
status, headers, resp = @app.call(env)
|
10
|
+
|
11
|
+
arr = []
|
12
|
+
resp.each { |e| arr << e }
|
13
|
+
|
14
|
+
[status, headers, arr.reverse]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
test do
|
19
|
+
class API < Goofy
|
20
|
+
use Shrimp
|
21
|
+
|
22
|
+
define do
|
23
|
+
on "v1/test" do
|
24
|
+
res.write "OK"
|
25
|
+
res.write "1"
|
26
|
+
res.write "2"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
Goofy.define do
|
32
|
+
on "api" do
|
33
|
+
run API
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
_, _, body = Goofy.call({ "PATH_INFO" => "/api/v1/test", "SCRIPT_NAME" => "/" })
|
38
|
+
|
39
|
+
arr = []
|
40
|
+
|
41
|
+
body.each do |line|
|
42
|
+
arr << line
|
43
|
+
end
|
44
|
+
|
45
|
+
assert_equal ["2", "1", "OK"], arr
|
46
|
+
end
|
data/test/number.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require File.expand_path("helper", File.dirname(__FILE__))
|
2
|
+
|
3
|
+
setup do
|
4
|
+
{ "SCRIPT_NAME" => "/", "PATH_INFO" => "/about/1/2" }
|
5
|
+
end
|
6
|
+
|
7
|
+
test "paths and numbers" do |env|
|
8
|
+
Goofy.define do
|
9
|
+
on "about" do
|
10
|
+
on :one, :two do |one, two|
|
11
|
+
res.write one
|
12
|
+
res.write two
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
_, _, resp = Goofy.call(env)
|
18
|
+
|
19
|
+
assert_response resp, ["1", "2"]
|
20
|
+
end
|
21
|
+
|
22
|
+
test "paths and decimals" do |env|
|
23
|
+
Goofy.define do
|
24
|
+
on "about" do
|
25
|
+
on(/(\d+)/) do |one|
|
26
|
+
res.write one
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
env["PATH_INFO"] = "/about/1.2"
|
32
|
+
|
33
|
+
_, _, resp = Goofy.call(env)
|
34
|
+
|
35
|
+
assert_response resp, []
|
36
|
+
end
|
data/test/on.rb
ADDED
@@ -0,0 +1,157 @@
|
|
1
|
+
require File.expand_path("helper", File.dirname(__FILE__))
|
2
|
+
|
3
|
+
test "executes on true" do
|
4
|
+
Goofy.define do
|
5
|
+
on true do
|
6
|
+
res.write "+1"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
_, _, resp = Goofy.call({})
|
11
|
+
|
12
|
+
assert_response resp, ["+1"]
|
13
|
+
end
|
14
|
+
|
15
|
+
test "executes on non-false" do
|
16
|
+
Goofy.define do
|
17
|
+
on "123" do
|
18
|
+
res.write "+1"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
_, _, resp = Goofy.call({ "PATH_INFO" => "/123", "SCRIPT_NAME" => "/" })
|
23
|
+
|
24
|
+
assert_response resp, ["+1"]
|
25
|
+
end
|
26
|
+
|
27
|
+
test "ensures SCRIPT_NAME and PATH_INFO are reverted" do
|
28
|
+
Goofy.define do
|
29
|
+
on lambda { env["SCRIPT_NAME"] = "/hello"; false } do
|
30
|
+
res.write "Unreachable"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
env = { "SCRIPT_NAME" => "/", "PATH_INFO" => "/hello" }
|
35
|
+
|
36
|
+
_, _, resp = Goofy.call(env)
|
37
|
+
|
38
|
+
assert_equal "/", env["SCRIPT_NAME"]
|
39
|
+
assert_equal "/hello", env["PATH_INFO"]
|
40
|
+
assert_response resp, []
|
41
|
+
end
|
42
|
+
|
43
|
+
test "skips consecutive matches" do
|
44
|
+
Goofy.define do
|
45
|
+
on true do
|
46
|
+
env["foo"] = "foo"
|
47
|
+
|
48
|
+
res.write "foo"
|
49
|
+
end
|
50
|
+
|
51
|
+
on true do
|
52
|
+
env["bar"] = "bar"
|
53
|
+
|
54
|
+
res.write "bar"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
env = {}
|
59
|
+
|
60
|
+
_, _, resp = Goofy.call(env)
|
61
|
+
|
62
|
+
assert_equal "foo", env["foo"]
|
63
|
+
assert_response resp, ["foo"]
|
64
|
+
|
65
|
+
assert ! env["bar"]
|
66
|
+
end
|
67
|
+
|
68
|
+
test "finds first match available" do
|
69
|
+
Goofy.define do
|
70
|
+
on false do
|
71
|
+
res.write "foo"
|
72
|
+
end
|
73
|
+
|
74
|
+
on true do
|
75
|
+
res.write "bar"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
_, _, resp = Goofy.call({})
|
80
|
+
|
81
|
+
assert_response resp, ["bar"]
|
82
|
+
end
|
83
|
+
|
84
|
+
test "reverts a half-met matcher" do
|
85
|
+
Goofy.define do
|
86
|
+
on "post", false do
|
87
|
+
res.write "Should be unmet"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
env = { "PATH_INFO" => "/post", "SCRIPT_NAME" => "/" }
|
92
|
+
_, _, resp = Goofy.call(env)
|
93
|
+
|
94
|
+
assert_response resp, []
|
95
|
+
assert_equal "/post", env["PATH_INFO"]
|
96
|
+
assert_equal "/", env["SCRIPT_NAME"]
|
97
|
+
end
|
98
|
+
|
99
|
+
test "responds 404 if conditions are not met" do
|
100
|
+
Goofy.define do
|
101
|
+
on root do
|
102
|
+
res.write("Should be unmet")
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
env = { "PATH_INFO" => "/notexists", "SCRIPT_NAME" => "/" }
|
107
|
+
status, _, body = Goofy.call(env)
|
108
|
+
|
109
|
+
assert_equal 404, status
|
110
|
+
assert body.empty?
|
111
|
+
end
|
112
|
+
|
113
|
+
test "responds 404 if nested conditions are not met" do
|
114
|
+
Goofy.define do
|
115
|
+
on get do
|
116
|
+
on root do
|
117
|
+
res.write("Should be unmet")
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
on default do
|
122
|
+
res.write("Should be unmet")
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
env = {
|
127
|
+
"REQUEST_METHOD" => "GET",
|
128
|
+
"PATH_INFO" => "/notexists",
|
129
|
+
"SCRIPT_NAME" => "/"
|
130
|
+
}
|
131
|
+
|
132
|
+
status, _, body = Goofy.call(env)
|
133
|
+
|
134
|
+
assert_equal 404, status
|
135
|
+
assert body.empty?
|
136
|
+
end
|
137
|
+
|
138
|
+
test "responds 200 even with an empty body if status is set" do
|
139
|
+
Goofy.define do
|
140
|
+
on get do
|
141
|
+
on root do
|
142
|
+
res.status = 200
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
env = {
|
148
|
+
"REQUEST_METHOD" => "GET",
|
149
|
+
"PATH_INFO" => "/",
|
150
|
+
"SCRIPT_NAME" => "/"
|
151
|
+
}
|
152
|
+
|
153
|
+
status, _, body = Goofy.call(env)
|
154
|
+
|
155
|
+
assert_equal 200, status
|
156
|
+
assert body.empty?
|
157
|
+
end
|
data/test/param.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
require File.expand_path("helper", File.dirname(__FILE__))
|
2
|
+
require "stringio"
|
3
|
+
|
4
|
+
prepare do
|
5
|
+
Goofy.define do
|
6
|
+
on get, "signup", param("email") do |email|
|
7
|
+
res.write email
|
8
|
+
end
|
9
|
+
|
10
|
+
on get, "login", param("username", "guest") do |username|
|
11
|
+
res.write username
|
12
|
+
end
|
13
|
+
|
14
|
+
on default do
|
15
|
+
res.write "No email"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
test "yields a param" do
|
21
|
+
env = { "REQUEST_METHOD" => "GET", "PATH_INFO" => "/signup",
|
22
|
+
"SCRIPT_NAME" => "/", "rack.input" => StringIO.new,
|
23
|
+
"QUERY_STRING" => "email=john@doe.com" }
|
24
|
+
|
25
|
+
_, _, resp = Goofy.call(env)
|
26
|
+
|
27
|
+
assert_response resp, ["john@doe.com"]
|
28
|
+
end
|
29
|
+
|
30
|
+
test "doesn't yield a missing param" do
|
31
|
+
env = { "REQUEST_METHOD" => "GET", "PATH_INFO" => "/signup",
|
32
|
+
"SCRIPT_NAME" => "/", "rack.input" => StringIO.new,
|
33
|
+
"QUERY_STRING" => "" }
|
34
|
+
|
35
|
+
_, _, resp = Goofy.call(env)
|
36
|
+
|
37
|
+
assert_response resp, ["No email"]
|
38
|
+
end
|
39
|
+
|
40
|
+
test "doesn't yield an empty param" do
|
41
|
+
env = { "REQUEST_METHOD" => "GET", "PATH_INFO" => "/signup",
|
42
|
+
"SCRIPT_NAME" => "/", "rack.input" => StringIO.new,
|
43
|
+
"QUERY_STRING" => "email=" }
|
44
|
+
|
45
|
+
_, _, resp = Goofy.call(env)
|
46
|
+
|
47
|
+
assert_response resp, ["No email"]
|
48
|
+
end
|
49
|
+
|
50
|
+
test "yields a default param" do
|
51
|
+
env = { "REQUEST_METHOD" => "GET", "PATH_INFO" => "/login",
|
52
|
+
"SCRIPT_NAME" => "/", "rack.input" => StringIO.new,
|
53
|
+
"QUERY_STRING" => "username=john" }
|
54
|
+
|
55
|
+
_, _, resp = Goofy.call(env)
|
56
|
+
|
57
|
+
assert_response resp, ["john"]
|
58
|
+
|
59
|
+
env = { "REQUEST_METHOD" => "GET", "PATH_INFO" => "/login",
|
60
|
+
"SCRIPT_NAME" => "/", "rack.input" => StringIO.new,
|
61
|
+
"QUERY_STRING" => "" }
|
62
|
+
|
63
|
+
_, _, resp = Goofy.call(env)
|
64
|
+
|
65
|
+
assert_response resp, ["guest"]
|
66
|
+
end
|
data/test/path.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
require File.expand_path("helper", File.dirname(__FILE__))
|
2
|
+
|
3
|
+
setup do
|
4
|
+
{ "SCRIPT_NAME" => "/", "PATH_INFO" => "/about" }
|
5
|
+
end
|
6
|
+
|
7
|
+
test "one level path" do |env|
|
8
|
+
Goofy.define do
|
9
|
+
on "about" do
|
10
|
+
res.write "About"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
_, _, resp = Goofy.call(env)
|
15
|
+
|
16
|
+
assert_response resp, ["About"]
|
17
|
+
end
|
18
|
+
|
19
|
+
test "two level nested paths" do |env|
|
20
|
+
Goofy.define do
|
21
|
+
on "about" do
|
22
|
+
on "1" do
|
23
|
+
res.write "+1"
|
24
|
+
end
|
25
|
+
|
26
|
+
on "2" do
|
27
|
+
res.write "+2"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
env["PATH_INFO"] = "/about/1"
|
33
|
+
|
34
|
+
_, _, resp = Goofy.call(env)
|
35
|
+
|
36
|
+
assert_response resp, ["+1"]
|
37
|
+
|
38
|
+
env["PATH_INFO"] = "/about/2"
|
39
|
+
|
40
|
+
_, _, resp = Goofy.call(env)
|
41
|
+
|
42
|
+
assert_response resp, ["+2"]
|
43
|
+
end
|
44
|
+
|
45
|
+
test "two level inlined paths" do |env|
|
46
|
+
Goofy.define do
|
47
|
+
on "a/b" do
|
48
|
+
res.write "a"
|
49
|
+
res.write "b"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
env["PATH_INFO"] = "/a/b"
|
54
|
+
|
55
|
+
_, _, resp = Goofy.call(env)
|
56
|
+
|
57
|
+
assert_response resp, ["a", "b"]
|
58
|
+
end
|
59
|
+
|
60
|
+
test "a path with some regex captures" do |env|
|
61
|
+
Goofy.define do
|
62
|
+
on "user(\\d+)" do |uid|
|
63
|
+
res.write uid
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
env["PATH_INFO"] = "/user123"
|
68
|
+
|
69
|
+
_, _, resp = Goofy.call(env)
|
70
|
+
|
71
|
+
assert_response resp, ["123"]
|
72
|
+
end
|
73
|
+
|
74
|
+
test "matching the root" do |env|
|
75
|
+
Goofy.define do
|
76
|
+
on "" do
|
77
|
+
res.write "Home"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
env["PATH_INFO"] = "/"
|
82
|
+
|
83
|
+
_, _, resp = Goofy.call(env)
|
84
|
+
|
85
|
+
assert_response resp, ["Home"]
|
86
|
+
end
|