wouter 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/wouter.rb +100 -67
  3. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 83e0fd10fd5d4cfd564ab573dc0602bc7752f8fc9219e7b4ef988ce8879e0902
4
- data.tar.gz: 6e7613daede1879b938dbf481827b27ad15b52905a72c5742c1b16b8935f5ce0
3
+ metadata.gz: 8b80dbc3170d929c2d18d8dfd23513c2e834254de252d50daa55a197e79b3e7c
4
+ data.tar.gz: 1ff7108b371da999bb465b64a60b8621cba2d1ab90b4943f12eeef58e6e211d1
5
5
  SHA512:
6
- metadata.gz: d73792353400cd5de74b1da3b57eace57bba19e7cb517401a3d09416a8be22e5c3b6a36a6ab8090af85334282c8bf2d8aece9299fc79fc7135ee37f8235f4560
7
- data.tar.gz: ad2264f42d38ad8f02465a1e235125e3815306d868b53a37a7209880177b7a1844d85423f16879cbe5d50fc1b2f02f28a3287ea698bbe4ae7e05e55017ada17d
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
- # Incoming HTTP Request Wrapper
8
- class Request < Rack::Request
9
- end
10
+ # ========== Endpoint class to make life easier
11
+ class Endpoint
12
+ attr_accessor :req, :res
10
13
 
11
- # Outgoing HTTP Response Wrapper
12
- class Response < Rack::Response
13
- end
14
+ # @req : Request
15
+ # @res : Response
16
+ def initialize(req, res)
17
+ @req = req
18
+ @res = res
19
+ end
14
20
 
15
- # HTTP Endpoint Helper class
16
- class Endpoint
17
- attr_accessor :request, :response
18
- attr_reader :params
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
- def initialize
21
- @request = nil
22
- @response = nil
23
- @params = nil
33
+ # Users of `Wouter::Endpoint` should implement their own `#response`
34
+ def respond
35
+ @res
24
36
  end
25
37
 
26
- def call(req, res)
27
- @request = req
28
- @params = req.params
29
- @response = res
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
- @response.set_header('Content-Type', 'application/json')
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
- @response.status = code
42
- ""
50
+ @res.status = code
43
51
  end
44
52
  end
45
53
 
46
- ## Internal Data
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 API
82
+ ## ========== Build a Rack entry point
67
83
 
68
- def self.call(env)
69
- request = Request.new(env)
84
+ def self.build
85
+ app.run(Wrapper.new(routes))
86
+ app.to_app
87
+ end
70
88
 
71
- route_params = {}
89
+ class Wrapper
90
+ attr_reader :routes
72
91
 
73
- route = routes.find do |route|
74
- if route[:method] == request.request_method.to_sym
75
- if route[:path].include?(":")
76
- split_path = route[:path].split("/")
77
- # Find all the named parameters in the route, drop the ":" so we have the names: ":id" => "id"
78
- route_param_names = split_path.find_all { |s| s.size > 1 ? s[0] == ":" : false }.map { |s| s[1..-1] }
79
- # Turn the route into a regex: "/hello/:name" => "\/hello\/(\w*)"
80
- path_regex_string = split_path.map { |s| s[0] == ":" ? "(\\w*)" : s }.join("\/")
81
- r = Regexp.new(path_regex_string)
82
- if r.match?(request.path)
83
- match_data = r.match(request.path)
84
- # Match the match data with the named params, ex { "id" => 123 }
85
- route_param_names.each_with_index do |n, i|
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
- false
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
- if route
99
- route_params.each do |k, v|
100
- request.update_param(k, v)
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
- response = Response.new
128
+ private
104
129
 
105
- rack_response = route[:route_class].new.call(request, response)
106
- rack_response.finish
107
- else
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
- ### Helpers
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
- def self.not_found
115
- resp = Response.new
116
- resp.status = 404
117
- resp.write "Not Found"
118
- resp
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
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wouter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Peterson