bbserver 0.1.0 → 0.2.0
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/lib/bbserver/context_locals.rb +24 -0
- data/lib/bbserver/execution_stack.rb +26 -0
- data/lib/bbserver/handler.rb +15 -0
- data/lib/bbserver/handlers/not_found_handler.rb +14 -0
- data/lib/bbserver/http_context.rb +14 -0
- data/lib/bbserver/params.rb +17 -0
- data/lib/bbserver/request.rb +15 -0
- data/lib/bbserver/response.rb +31 -0
- data/lib/bbserver/route.rb +43 -0
- data/lib/bbserver/route_configuration_error.rb +5 -0
- data/lib/bbserver/route_not_found_error.rb +5 -0
- data/lib/bbserver/route_registry.rb +49 -0
- data/lib/bbserver/router.rb +52 -0
- data/lib/bbserver/server.rb +15 -7
- data/lib/bbserver/server_context.rb +16 -0
- data/lib/bbserver/version.rb +1 -1
- metadata +15 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 87cee3b4f4f872001b320d5aeb494e3496e903240c17f4b7601f2a34f14ead8b
|
|
4
|
+
data.tar.gz: 72304d3ba819dcfcac6d8202c8dadc7ae9c03dc6840d1d965ca13b118282d066
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 07b9b3986487dd38b9ae1dbd45dff2d5562a5f0e2c471d40841fc9a01e2853a7af55e0892402126961fefdcb2f819b4d651249fe8cbc90a89af7b4232aab1701
|
|
7
|
+
data.tar.gz: 48e22d0cbf53f2a30137cfac5757c6c957eff173ac8e93e8e1cff16301defc0b2adc7bcd91ab68f0adb83434063437e1dfe4edde1ac66182efe6f2dccfe62866
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BBServer
|
|
4
|
+
class ContextLocals
|
|
5
|
+
def initialize
|
|
6
|
+
@storage = {}
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def method_missing(name, *args, &block)
|
|
10
|
+
if name.to_s.end_with?('=')
|
|
11
|
+
key = name.to_s.chomp('=').to_sym
|
|
12
|
+
@storage[key] = args.first
|
|
13
|
+
elsif @storage.key?(name)
|
|
14
|
+
@storage[name]
|
|
15
|
+
else
|
|
16
|
+
super
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def respond_to_missing?(name, include_private = false)
|
|
21
|
+
@storage.key?(name.to_s.chomp('=').to_sym) || super
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BBServer
|
|
4
|
+
class ExecutionStack
|
|
5
|
+
def initialize(handler_class, middlewares)
|
|
6
|
+
@handler_class = handler_class
|
|
7
|
+
@middlewares = middlewares
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def execute(context)
|
|
11
|
+
chain = @middlewares.dup
|
|
12
|
+
|
|
13
|
+
process = proc do |ctx|
|
|
14
|
+
if chain.empty?
|
|
15
|
+
handler = @handler_class.new(ctx)
|
|
16
|
+
handler.handle
|
|
17
|
+
else
|
|
18
|
+
middleware = chain.shift
|
|
19
|
+
middleware.call(ctx, process)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
process.call(context)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BBServer::Handlers
|
|
4
|
+
class NotFoundHandler
|
|
5
|
+
def initialize(context)
|
|
6
|
+
@context = context
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def handle
|
|
10
|
+
@context.response.write_status 404
|
|
11
|
+
@context.response.write_body "Not Found"
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BBServer
|
|
4
|
+
class HttpContext
|
|
5
|
+
attr_reader :request, :response, :server_context, :params
|
|
6
|
+
|
|
7
|
+
def initialize(server_context, request, response, params)
|
|
8
|
+
@server_context = server_context
|
|
9
|
+
@request = request
|
|
10
|
+
@response = response
|
|
11
|
+
@params = params
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BBServer
|
|
4
|
+
class Response
|
|
5
|
+
def initialize
|
|
6
|
+
@status = 200
|
|
7
|
+
@headers = {}
|
|
8
|
+
@body = []
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def write_status(status)
|
|
12
|
+
@status = status
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def write_header(key, value)
|
|
16
|
+
@headers[key] = value
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def has_header?(key)
|
|
20
|
+
@headers.key?(key)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def write_body(body)
|
|
24
|
+
@body << body
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def to_rack
|
|
28
|
+
[@status, @headers, @body]
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BBServer
|
|
4
|
+
class Route
|
|
5
|
+
attr_reader :middlewares, :handler_proc
|
|
6
|
+
|
|
7
|
+
def self.any(middlewares = [])
|
|
8
|
+
new(method: nil, path: nil, middlewares: middlewares, any: true)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def initialize(method: nil, path: nil, middlewares: [], any: false)
|
|
12
|
+
raise ArgumentError, "Method and Path are required for non-ANY routes" unless any || (method && path)
|
|
13
|
+
|
|
14
|
+
@method = method
|
|
15
|
+
@path = path
|
|
16
|
+
@middlewares = middlewares
|
|
17
|
+
@any = any
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def method
|
|
21
|
+
raise RuntimeError, "Method is not defined for this route" if @method.nil?
|
|
22
|
+
@method
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def path
|
|
26
|
+
raise RuntimeError, "Path is not defined for this route" if @path.nil?
|
|
27
|
+
@path
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def any?
|
|
31
|
+
@any
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def use(&block)
|
|
35
|
+
@middlewares << block
|
|
36
|
+
self
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def call(&block)
|
|
40
|
+
@handler_proc = block
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BBServer
|
|
4
|
+
class RouteRegistry
|
|
5
|
+
def initialize
|
|
6
|
+
@routes = []
|
|
7
|
+
@middlewares = []
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def use(&block)
|
|
11
|
+
@middlewares << block
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def any
|
|
15
|
+
route = Route.new(method: nil, path: nil, middlewares: @middlewares.dup, any: true)
|
|
16
|
+
@routes << route
|
|
17
|
+
route
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def has_any?
|
|
21
|
+
@routes.any?(&:any?)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def get_any
|
|
25
|
+
@routes.find(&:any?)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
[:get, :post, :put, :delete, :patch, :head, :options].each do |http_verb|
|
|
29
|
+
define_method(http_verb) do |path|
|
|
30
|
+
raise RuntimeError, "Cannot register routes after ANY handler" if has_any?
|
|
31
|
+
route = Route.new(method: http_verb.to_s.upcase, path: path, middlewares: @middlewares.dup)
|
|
32
|
+
@routes << route
|
|
33
|
+
route
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def find(path)
|
|
38
|
+
@routes.find { |r| r.path == path }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def length
|
|
42
|
+
@routes.length
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def list
|
|
46
|
+
@routes
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
module BBServer
|
|
5
|
+
class Router
|
|
6
|
+
def initialize(routes)
|
|
7
|
+
@routes = routes
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def match(request)
|
|
11
|
+
path = request.instance_variable_get(:@env)["PATH_INFO"] || "/"
|
|
12
|
+
method = request.instance_variable_get(:@env)["REQUEST_METHOD"] || "GET"
|
|
13
|
+
|
|
14
|
+
route, params = find_route(path, method)
|
|
15
|
+
|
|
16
|
+
raise RouteNotFoundError, "No route found for #{method} #{path}" unless route
|
|
17
|
+
|
|
18
|
+
handler_class = route.handler_proc.call
|
|
19
|
+
stack = ExecutionStack.new(handler_class, route.middlewares)
|
|
20
|
+
|
|
21
|
+
[stack, Params.new(params || {})]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def find_route(path, method)
|
|
27
|
+
@routes.list.each do |route|
|
|
28
|
+
return [route, {}] if route.any?
|
|
29
|
+
|
|
30
|
+
next unless route.method == method
|
|
31
|
+
|
|
32
|
+
parts = route.path.split('/')
|
|
33
|
+
path_parts = path.split('/')
|
|
34
|
+
|
|
35
|
+
next unless parts.size == path_parts.size
|
|
36
|
+
|
|
37
|
+
params = {}
|
|
38
|
+
match = parts.each_with_index.all? do |part, i|
|
|
39
|
+
if part.start_with?(':')
|
|
40
|
+
params[part[1..-1].to_sym] = path_parts[i]
|
|
41
|
+
true
|
|
42
|
+
else
|
|
43
|
+
part == path_parts[i]
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
return [route, params] if match
|
|
48
|
+
end
|
|
49
|
+
nil
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
data/lib/bbserver/server.rb
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
|
|
2
|
-
|
|
2
|
+
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
+
module BBServer
|
|
4
5
|
class Server
|
|
6
|
+
def initialize(context)
|
|
7
|
+
@context = context
|
|
8
|
+
end
|
|
9
|
+
|
|
5
10
|
def call(env)
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
request = Request.new(env)
|
|
12
|
+
response = Response.new
|
|
13
|
+
|
|
14
|
+
router = Router.new(@context.routes)
|
|
15
|
+
stack, params = router.match(request)
|
|
16
|
+
http_context = HttpContext.new(@context, request, response, params)
|
|
17
|
+
stack.execute(http_context)
|
|
18
|
+
|
|
19
|
+
response.to_rack
|
|
11
20
|
end
|
|
12
21
|
end
|
|
13
|
-
|
|
14
22
|
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BBServer
|
|
4
|
+
class ServerContext
|
|
5
|
+
attr_reader :routes
|
|
6
|
+
|
|
7
|
+
def initialize
|
|
8
|
+
@routes = BBServer::RouteRegistry.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def set_routes(routes)
|
|
12
|
+
raise RouteConfigurationError, "Any handler is required" unless routes.has_any?
|
|
13
|
+
@routes = routes
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
data/lib/bbserver/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bbserver
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Juliano Soares da Silva
|
|
@@ -76,7 +76,21 @@ files:
|
|
|
76
76
|
- LICENSE
|
|
77
77
|
- README.md
|
|
78
78
|
- lib/bbserver.rb
|
|
79
|
+
- lib/bbserver/context_locals.rb
|
|
80
|
+
- lib/bbserver/execution_stack.rb
|
|
81
|
+
- lib/bbserver/handler.rb
|
|
82
|
+
- lib/bbserver/handlers/not_found_handler.rb
|
|
83
|
+
- lib/bbserver/http_context.rb
|
|
84
|
+
- lib/bbserver/params.rb
|
|
85
|
+
- lib/bbserver/request.rb
|
|
86
|
+
- lib/bbserver/response.rb
|
|
87
|
+
- lib/bbserver/route.rb
|
|
88
|
+
- lib/bbserver/route_configuration_error.rb
|
|
89
|
+
- lib/bbserver/route_not_found_error.rb
|
|
90
|
+
- lib/bbserver/route_registry.rb
|
|
91
|
+
- lib/bbserver/router.rb
|
|
79
92
|
- lib/bbserver/server.rb
|
|
93
|
+
- lib/bbserver/server_context.rb
|
|
80
94
|
- lib/bbserver/version.rb
|
|
81
95
|
homepage: https://github.com/bytebytebug/bbserver
|
|
82
96
|
licenses:
|