wouter 0.0.2 → 0.0.3

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.
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