wouter 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/wouter.rb +100 -67
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8b80dbc3170d929c2d18d8dfd23513c2e834254de252d50daa55a197e79b3e7c
|
4
|
+
data.tar.gz: 1ff7108b371da999bb465b64a60b8621cba2d1ab90b4943f12eeef58e6e211d1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: df105c88fd3aba2c1747926041f08085f22ea7bfccbc896f35d280b49a578974d4b0e924b6385321cd88d05a931f7c89312cb8cfe2a1f4f002bd79d7bc7e2acb
|
7
|
+
data.tar.gz: fe5583ce266c4c10167e902f221283e37fd54d563f99d165323c9bdedf09e09e101f8f176ec0d9f90686da4a5ed41b245573cb4a9c03cdc202868d793763f0f6
|
data/lib/wouter.rb
CHANGED
@@ -3,53 +3,65 @@ Bundler.setup(:default)
|
|
3
3
|
require "rack"
|
4
4
|
|
5
5
|
class Wouter
|
6
|
+
# ========== Rack wrappers
|
7
|
+
class Request < Rack::Request; end
|
8
|
+
class Response < Rack::Response; end
|
6
9
|
|
7
|
-
#
|
8
|
-
class
|
9
|
-
|
10
|
+
# ========== Endpoint class to make life easier
|
11
|
+
class Endpoint
|
12
|
+
attr_accessor :req, :res
|
10
13
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
+
# @req : Request
|
15
|
+
# @res : Response
|
16
|
+
def initialize(req, res)
|
17
|
+
@req = req
|
18
|
+
@res = res
|
19
|
+
end
|
14
20
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
21
|
+
def self.call(env)
|
22
|
+
endpoint = new(Rack::Request.new(env), Rack::Response.new)
|
23
|
+
final_resp = endpoint.respond
|
24
|
+
# Return a `Rack::Response` or write to the body of the response if the return value of `response` is not `Rack::Response`
|
25
|
+
if final_resp.is_a?(Rack::Response)
|
26
|
+
final_resp
|
27
|
+
else
|
28
|
+
endpoint.res.write final_resp
|
29
|
+
endpoint.res
|
30
|
+
end
|
31
|
+
end
|
19
32
|
|
20
|
-
|
21
|
-
|
22
|
-
@
|
23
|
-
@params = nil
|
33
|
+
# Users of `Wouter::Endpoint` should implement their own `#response`
|
34
|
+
def respond
|
35
|
+
@res
|
24
36
|
end
|
25
37
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
@
|
30
|
-
r = respond
|
31
|
-
@response.write r
|
32
|
-
@response
|
38
|
+
## ~~~~~ Convience methods
|
39
|
+
|
40
|
+
def params
|
41
|
+
@req.params
|
33
42
|
end
|
34
43
|
|
35
44
|
def json(body)
|
36
|
-
@
|
37
|
-
body
|
45
|
+
@res.set_header('Content-Type', 'application/json')
|
46
|
+
@res.write body
|
38
47
|
end
|
39
48
|
|
40
49
|
def status(code)
|
41
|
-
@
|
42
|
-
""
|
50
|
+
@res.status = code
|
43
51
|
end
|
44
52
|
end
|
45
53
|
|
46
|
-
## Internal
|
54
|
+
## ========== Internal
|
55
|
+
|
56
|
+
def self.app
|
57
|
+
@app ||= Rack::Builder.new
|
58
|
+
end
|
47
59
|
|
48
60
|
def self.routes
|
49
61
|
@routes ||= []
|
50
62
|
end
|
51
63
|
|
52
|
-
## DSL
|
64
|
+
## ========== DSL
|
53
65
|
|
54
66
|
class <<self
|
55
67
|
%i[get post put delete].each do |m|
|
@@ -61,61 +73,82 @@ class Wouter
|
|
61
73
|
})
|
62
74
|
end
|
63
75
|
end
|
76
|
+
|
77
|
+
def middleware(klass, *args, &block)
|
78
|
+
app.use(klass, *args, &block)
|
79
|
+
end
|
64
80
|
end
|
65
81
|
|
66
|
-
## Rack
|
82
|
+
## ========== Build a Rack entry point
|
67
83
|
|
68
|
-
def self.
|
69
|
-
|
84
|
+
def self.build
|
85
|
+
app.run(Wrapper.new(routes))
|
86
|
+
app.to_app
|
87
|
+
end
|
70
88
|
|
71
|
-
|
89
|
+
class Wrapper
|
90
|
+
attr_reader :routes
|
72
91
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
if
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
route_params[n] = match_data[i+1]
|
87
|
-
end
|
88
|
-
true
|
92
|
+
def initialize(routes)
|
93
|
+
@routes = routes
|
94
|
+
end
|
95
|
+
|
96
|
+
def call(env)
|
97
|
+
request = Rack::Request.new(env)
|
98
|
+
|
99
|
+
route = routes.find do |route|
|
100
|
+
if route[:method] == request.request_method.to_sym
|
101
|
+
if parameterized_path?(route[:path])
|
102
|
+
split_path = route[:path].split("/")
|
103
|
+
path_regex = build_path_regex(split_path)
|
104
|
+
path_regex.match?(request.path)
|
89
105
|
else
|
90
|
-
|
106
|
+
route[:path] == request.path
|
91
107
|
end
|
92
|
-
else
|
93
|
-
route[:path] == request.path
|
94
108
|
end
|
95
109
|
end
|
96
|
-
end
|
97
110
|
|
98
|
-
|
99
|
-
|
100
|
-
|
111
|
+
if route
|
112
|
+
if parameterized_path?(route[:path])
|
113
|
+
split_path = route[:path].split("/")
|
114
|
+
path_parameter_data = build_path_regex(split_path).match(request.path)
|
115
|
+
path_parameter_names = find_parameter_names_in_path(split_path)
|
116
|
+
path_parameter_names.each_with_index do |parameter_name, i|
|
117
|
+
request.update_param(parameter_name, path_parameter_data[i+1])
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
resp = route[:route_class].call(request.env)
|
122
|
+
resp.finish
|
123
|
+
else
|
124
|
+
not_found
|
101
125
|
end
|
126
|
+
end
|
102
127
|
|
103
|
-
|
128
|
+
private
|
104
129
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
not_found.finish
|
130
|
+
# Does the path have a parameter in it? ex: "/user/:id"
|
131
|
+
def parameterized_path?(path)
|
132
|
+
path.include?(":")
|
109
133
|
end
|
110
|
-
end
|
111
134
|
|
112
|
-
|
135
|
+
# Find all the named parameters in the route, drop the ":" so we have the names: ":id" => "id"
|
136
|
+
def find_parameter_names_in_path(split_path)
|
137
|
+
split_path.find_all { |s| s.size > 1 ? s[0] == ":" : false }.map { |s| s[1..-1] }
|
138
|
+
end
|
113
139
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
end
|
140
|
+
# Turn the route into a regex: "/hello/:name" => "\/hello\/(\w*)"
|
141
|
+
def build_path_regex(split_path)
|
142
|
+
regex_string = split_path.map { |s| s[0] == ":" ? "(\\w*)" : s }.join("\/")
|
143
|
+
Regexp.new(regex_string)
|
144
|
+
end
|
120
145
|
|
146
|
+
# Return HTTP 404
|
147
|
+
def not_found
|
148
|
+
resp = Rack::Response.new
|
149
|
+
resp.status = 404
|
150
|
+
resp.write "Not Found"
|
151
|
+
resp
|
152
|
+
end
|
153
|
+
end
|
121
154
|
end
|