tynn 1.4.0 → 2.0.0.alpha
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 +4 -4
- data/LICENSE +1 -1
- data/README.md +540 -25
- data/lib/tynn.rb +50 -103
- data/lib/tynn/base.rb +97 -0
- data/lib/tynn/default_headers.rb +50 -0
- data/lib/tynn/environment.rb +54 -28
- data/lib/tynn/json.rb +7 -18
- data/lib/tynn/render.rb +16 -12
- data/lib/tynn/request.rb +54 -38
- data/lib/tynn/response.rb +33 -173
- data/lib/tynn/secure_headers.rb +28 -31
- data/lib/tynn/session.rb +68 -34
- data/lib/tynn/settings.rb +56 -27
- data/lib/tynn/ssl.rb +78 -70
- data/lib/tynn/static.rb +12 -21
- data/lib/tynn/test.rb +51 -78
- data/lib/tynn/version.rb +4 -7
- data/test/default_headers_test.rb +21 -9
- data/test/environment_test.rb +57 -16
- data/test/helper.rb +4 -6
- data/test/json_test.rb +48 -10
- data/test/middleware_test.rb +63 -54
- data/test/plugin_test.rb +121 -0
- data/test/render_test.rb +56 -65
- data/test/request_headers_test.rb +33 -0
- data/test/routing_test.rb +111 -0
- data/test/secure_headers_test.rb +29 -17
- data/test/session_test.rb +44 -11
- data/test/settings_test.rb +53 -0
- data/test/ssl_test.rb +107 -35
- data/test/static_test.rb +25 -6
- metadata +33 -38
- data/lib/tynn/all_methods.rb +0 -50
- data/lib/tynn/hmote.rb +0 -34
- data/lib/tynn/not_found.rb +0 -20
- data/lib/tynn/protection.rb +0 -45
- data/test/all_methods_test.rb +0 -16
- data/test/core_test.rb +0 -65
- data/test/hmote_test.rb +0 -78
- data/test/not_found_test.rb +0 -19
- data/test/protection_test.rb +0 -36
data/test/middleware_test.rb
CHANGED
@@ -1,79 +1,88 @@
|
|
1
|
-
|
2
|
-
def initialize(app)
|
3
|
-
@app = app
|
4
|
-
end
|
1
|
+
# frozen_string_literal: true
|
5
2
|
|
6
|
-
|
7
|
-
status, headers, body = @app.call(env)
|
3
|
+
require_relative "helper"
|
8
4
|
|
9
|
-
|
10
|
-
|
11
|
-
|
5
|
+
class MiddlewareTest < Minitest::Test
|
6
|
+
class Shrimp
|
7
|
+
def initialize(app)
|
8
|
+
@app = app
|
9
|
+
end
|
12
10
|
|
13
|
-
|
14
|
-
|
11
|
+
def call(env)
|
12
|
+
status, headers, body = @app.call(env)
|
15
13
|
|
16
|
-
|
17
|
-
get do
|
18
|
-
res.write("1")
|
19
|
-
res.write("2")
|
14
|
+
[status, headers, body.reverse]
|
20
15
|
end
|
21
16
|
end
|
22
17
|
|
23
|
-
|
24
|
-
|
18
|
+
def test_middleware_works
|
19
|
+
app = Class.new(Tynn)
|
25
20
|
|
26
|
-
|
27
|
-
assert_equal "21", app.res.body
|
28
|
-
end
|
21
|
+
app.use(Shrimp)
|
29
22
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
run(API)
|
23
|
+
app.define do
|
24
|
+
get do
|
25
|
+
res.write("1")
|
26
|
+
res.write("2")
|
27
|
+
end
|
36
28
|
end
|
37
|
-
end
|
38
29
|
|
39
|
-
|
30
|
+
ts = Tynn::Test.new(app)
|
31
|
+
ts.get("/")
|
32
|
+
|
33
|
+
assert_equal 200, ts.res.status
|
34
|
+
assert_equal "21", ts.res.body
|
40
35
|
end
|
41
36
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
37
|
+
def test_middleware_with_composition
|
38
|
+
app = Class.new(Tynn)
|
39
|
+
api = Class.new(Tynn)
|
40
|
+
|
41
|
+
app.use(Shrimp)
|
42
|
+
|
43
|
+
app.define do
|
44
|
+
on("api") do
|
45
|
+
run(api)
|
46
|
+
end
|
46
47
|
end
|
47
|
-
end
|
48
48
|
|
49
|
-
|
50
|
-
|
49
|
+
api.define do
|
50
|
+
get do
|
51
|
+
res.write("1")
|
52
|
+
res.write("2")
|
53
|
+
end
|
54
|
+
end
|
51
55
|
|
52
|
-
|
53
|
-
|
54
|
-
end
|
56
|
+
ts = Tynn::Test.new(app)
|
57
|
+
ts.get("/api")
|
55
58
|
|
56
|
-
|
57
|
-
|
58
|
-
use(Shrimp)
|
59
|
+
assert_equal 200, ts.res.status
|
60
|
+
assert_equal "21", ts.res.body
|
59
61
|
end
|
60
62
|
|
61
|
-
|
62
|
-
|
63
|
-
|
63
|
+
def test_middleware_for_sub_application
|
64
|
+
app = Class.new(Tynn)
|
65
|
+
api = Class.new(Tynn)
|
66
|
+
|
67
|
+
api.use(Shrimp)
|
68
|
+
|
69
|
+
app.define do
|
70
|
+
on("api") do
|
71
|
+
run(api)
|
72
|
+
end
|
64
73
|
end
|
65
|
-
end
|
66
74
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
75
|
+
api.define do
|
76
|
+
get do
|
77
|
+
res.write("1")
|
78
|
+
res.write("2")
|
79
|
+
end
|
71
80
|
end
|
72
|
-
end
|
73
81
|
|
74
|
-
|
75
|
-
|
82
|
+
ts = Tynn::Test.new(app)
|
83
|
+
ts.get("/api")
|
76
84
|
|
77
|
-
|
78
|
-
|
85
|
+
assert_equal 200, ts.res.status
|
86
|
+
assert_equal "21", ts.res.body
|
87
|
+
end
|
79
88
|
end
|
data/test/plugin_test.rb
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "helper"
|
4
|
+
|
5
|
+
class PluginTest < Minitest::Test
|
6
|
+
def setup
|
7
|
+
@app = Class.new(Tynn)
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_class_methods
|
11
|
+
mod = Module.new do
|
12
|
+
def foo
|
13
|
+
"foo"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
plugin = Module.new
|
18
|
+
plugin.const_set(:ClassMethods, mod)
|
19
|
+
|
20
|
+
@app.plugin(plugin)
|
21
|
+
|
22
|
+
assert_equal "foo", @app.foo
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_instance_methods
|
26
|
+
mod = Module.new do
|
27
|
+
def bar
|
28
|
+
"bar"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
plugin = Module.new
|
33
|
+
plugin.const_set(:InstanceMethods, mod)
|
34
|
+
|
35
|
+
@app.plugin(plugin)
|
36
|
+
|
37
|
+
assert_equal "bar", @app.new(proc {}).bar
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_setup
|
41
|
+
plugin = Module.new
|
42
|
+
|
43
|
+
def plugin.run?
|
44
|
+
@run
|
45
|
+
end
|
46
|
+
|
47
|
+
def plugin.setup(_)
|
48
|
+
@run = true
|
49
|
+
end
|
50
|
+
|
51
|
+
@app.plugin(plugin)
|
52
|
+
|
53
|
+
assert_equal true, plugin.run?
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_setup_passes_app
|
57
|
+
plugin = Module.new
|
58
|
+
|
59
|
+
def plugin.app
|
60
|
+
@__app
|
61
|
+
end
|
62
|
+
|
63
|
+
def plugin.setup(app)
|
64
|
+
@__app = app
|
65
|
+
end
|
66
|
+
|
67
|
+
@app.plugin(plugin)
|
68
|
+
|
69
|
+
assert_equal @app, plugin.app
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_setup_with_arguments
|
73
|
+
plugin = Module.new
|
74
|
+
|
75
|
+
def plugin.args
|
76
|
+
@args
|
77
|
+
end
|
78
|
+
|
79
|
+
def plugin.setup(_, foo, bar)
|
80
|
+
@args = [foo, bar]
|
81
|
+
end
|
82
|
+
|
83
|
+
@app.plugin(plugin, "foo", "bar")
|
84
|
+
|
85
|
+
assert_equal %w(foo bar), plugin.args
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_setup_with_keyword_arguments
|
89
|
+
plugin = Module.new
|
90
|
+
|
91
|
+
def plugin.args
|
92
|
+
@args
|
93
|
+
end
|
94
|
+
|
95
|
+
def plugin.setup(_, foo:, bar: "bar")
|
96
|
+
@args = [foo, bar]
|
97
|
+
end
|
98
|
+
|
99
|
+
@app.plugin(plugin, foo: "foo")
|
100
|
+
|
101
|
+
assert_equal %w(foo bar), plugin.args
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_setup_with_block
|
105
|
+
plugin = Module.new
|
106
|
+
|
107
|
+
def plugin.block
|
108
|
+
@block
|
109
|
+
end
|
110
|
+
|
111
|
+
def plugin.setup(_, &block)
|
112
|
+
@block = block
|
113
|
+
end
|
114
|
+
|
115
|
+
@app.plugin(plugin) do
|
116
|
+
"foo"
|
117
|
+
end
|
118
|
+
|
119
|
+
assert_equal "foo", plugin.block.call
|
120
|
+
end
|
121
|
+
end
|
data/test/render_test.rb
CHANGED
@@ -1,92 +1,83 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "helper"
|
2
4
|
require_relative "../lib/tynn/render"
|
5
|
+
require "tilt/erubis"
|
3
6
|
|
4
|
-
|
5
|
-
|
7
|
+
class RenderTest < Minitest::Test
|
8
|
+
VIEWS_PATH = File.expand_path("views", __dir__)
|
6
9
|
|
7
|
-
|
8
|
-
|
10
|
+
def setup
|
11
|
+
@app = Class.new(Tynn)
|
9
12
|
|
10
|
-
|
11
|
-
Tynn.define do
|
12
|
-
on "partial" do
|
13
|
-
res.write(partial("partial", name: "erb"))
|
14
|
-
end
|
13
|
+
@app.plugin(Tynn::Render, views: VIEWS_PATH)
|
15
14
|
end
|
16
15
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
test "view" do |app|
|
23
|
-
Tynn.define do
|
24
|
-
on "view" do
|
25
|
-
res.write(view("view", title: "tynn", name: "erb"))
|
16
|
+
def test_partial
|
17
|
+
@app.define do
|
18
|
+
on("partial") do
|
19
|
+
res.write(partial("partial", name: "alice"))
|
20
|
+
end
|
26
21
|
end
|
27
|
-
end
|
28
|
-
|
29
|
-
app.get("/view")
|
30
22
|
|
31
|
-
|
32
|
-
|
23
|
+
ts = Tynn::Test.new(@app)
|
24
|
+
ts.get("/partial")
|
33
25
|
|
34
|
-
|
35
|
-
Tynn.define do
|
36
|
-
on "render" do
|
37
|
-
render("view", title: "tynn", name: "erb")
|
38
|
-
end
|
26
|
+
assert_equal "alice", ts.res.body.strip
|
39
27
|
end
|
40
28
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
end
|
29
|
+
def test_view
|
30
|
+
@app.define do
|
31
|
+
on("view") do
|
32
|
+
res.write(view("view", title: "welcome", name: "alice"))
|
33
|
+
end
|
34
|
+
end
|
47
35
|
|
48
|
-
|
49
|
-
|
50
|
-
on "404" do
|
51
|
-
res.status = 404
|
36
|
+
ts = Tynn::Test.new(@app)
|
37
|
+
ts.get("/view")
|
52
38
|
|
53
|
-
|
54
|
-
end
|
39
|
+
assert_equal "welcome / alice", ts.res.body.strip
|
55
40
|
end
|
56
41
|
|
57
|
-
|
42
|
+
def test_render
|
43
|
+
@app.define do
|
44
|
+
on("render") do
|
45
|
+
render("view", title: "welcome", name: "alice")
|
46
|
+
end
|
47
|
+
end
|
58
48
|
|
59
|
-
|
60
|
-
|
61
|
-
assert_equal "tynn / erb", app.res.body.strip
|
62
|
-
end
|
49
|
+
ts = Tynn::Test.new(@app)
|
50
|
+
ts.get("/render")
|
63
51
|
|
64
|
-
|
65
|
-
|
66
|
-
set :layout, "custom_layout"
|
52
|
+
assert_equal "text/html", ts.res.content_type
|
53
|
+
assert_equal "welcome / alice", ts.res.body.strip
|
67
54
|
end
|
68
55
|
|
69
|
-
|
70
|
-
|
71
|
-
|
56
|
+
def test_escaping
|
57
|
+
@app.define do
|
58
|
+
on("escape") do
|
59
|
+
res.write(partial("partial", name: "<a></a>"))
|
60
|
+
end
|
72
61
|
end
|
73
|
-
end
|
74
62
|
|
75
|
-
|
76
|
-
|
63
|
+
ts = Tynn::Test.new(@app)
|
64
|
+
ts.get("/escape")
|
77
65
|
|
78
|
-
|
79
|
-
end
|
66
|
+
assert_equal "<a></a>", ts.res.body.strip
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_custom_layout
|
70
|
+
@app.set(:render, layout: "custom_layout")
|
80
71
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
72
|
+
@app.define do
|
73
|
+
get do
|
74
|
+
render("view", title: "welcome", name: "alice")
|
75
|
+
end
|
85
76
|
end
|
86
|
-
end
|
87
77
|
|
88
|
-
|
89
|
-
|
78
|
+
ts = Tynn::Test.new(@app)
|
79
|
+
ts.get("/")
|
90
80
|
|
91
|
-
|
81
|
+
assert_equal "custom / welcome / alice", ts.res.body.strip
|
82
|
+
end
|
92
83
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "helper"
|
4
|
+
|
5
|
+
class RequestHeadersTest < Minitest::Test
|
6
|
+
def setup
|
7
|
+
env = { "HTTP_HOST" => "127.0.0.1", "CONTENT_TYPE" => "text/plain" }
|
8
|
+
request = Tynn::Request.new(env)
|
9
|
+
|
10
|
+
@headers = Tynn::Request::Headers.new(request)
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_get_header
|
14
|
+
assert_equal "127.0.0.1", @headers["Host"]
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_check_if_key_exists
|
18
|
+
assert @headers.key?("Host")
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_fetch
|
22
|
+
assert_equal "text/plain", @headers.fetch("content-type")
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_fetch_raises_if_key_not_exists
|
26
|
+
assert_raises(KeyError) { @headers.fetch("not-exists") }
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_fetch_with_default
|
30
|
+
assert_equal "not exists", @headers.fetch("not-exists", "not exists")
|
31
|
+
assert_equal "not exists", @headers.fetch("not-exists") { "not exists" }
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "helper"
|
4
|
+
|
5
|
+
class RoutingTest < Minitest::Test
|
6
|
+
def setup
|
7
|
+
@app = Class.new(Tynn)
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_raise_if_not_handler
|
11
|
+
assert_raises { @app.call({}) }
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_path_matching
|
15
|
+
@app.define do
|
16
|
+
on "hello" do
|
17
|
+
res.write("hello")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
ts = Tynn::Test.new(@app)
|
22
|
+
ts.get("/")
|
23
|
+
|
24
|
+
assert_equal 404, ts.res.status
|
25
|
+
|
26
|
+
ts.get("/hello")
|
27
|
+
|
28
|
+
assert_equal 200, ts.res.status
|
29
|
+
assert_equal "hello", ts.res.body
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_http_methods
|
33
|
+
methods = %i(get post put patch delete head options)
|
34
|
+
|
35
|
+
methods.each do |method|
|
36
|
+
@app.define do
|
37
|
+
send(method) { res.write(method) }
|
38
|
+
end
|
39
|
+
|
40
|
+
ts = Tynn::Test.new(@app)
|
41
|
+
ts.send(method, "/")
|
42
|
+
|
43
|
+
assert_equal 200, ts.res.status
|
44
|
+
assert_equal method.to_s, ts.res.body
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_capturing_path
|
49
|
+
@app.define do
|
50
|
+
on(:foo) do |foo|
|
51
|
+
on(:bar) do |bar|
|
52
|
+
res.write(sprintf("%s/%s", foo, bar))
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
ts = Tynn::Test.new(@app)
|
58
|
+
ts.get("/john/doe")
|
59
|
+
|
60
|
+
assert_equal 200, ts.res.status
|
61
|
+
assert_equal "john/doe", ts.res.body
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_composition
|
65
|
+
foo = Class.new(@app)
|
66
|
+
|
67
|
+
@app.define do
|
68
|
+
on("foo") do
|
69
|
+
run(foo, foo: 42)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
foo.define do
|
74
|
+
get do
|
75
|
+
res.write(inbox[:foo])
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
ts = Tynn::Test.new(@app)
|
80
|
+
ts.get("/foo")
|
81
|
+
|
82
|
+
assert_equal 200, ts.res.status
|
83
|
+
assert_equal "42", ts.res.body
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_request_class
|
87
|
+
@app.define do
|
88
|
+
get do
|
89
|
+
res.write(req.class.name)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
ts = Tynn::Test.new(@app)
|
94
|
+
ts.get("/")
|
95
|
+
|
96
|
+
assert_equal Tynn::Request.name, ts.res.body
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_response_class
|
100
|
+
@app.define do
|
101
|
+
get do
|
102
|
+
res.write(res.class.name)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
ts = Tynn::Test.new(@app)
|
107
|
+
ts.get("/")
|
108
|
+
|
109
|
+
assert_equal Tynn::Response.name, ts.res.body
|
110
|
+
end
|
111
|
+
end
|