chespirito 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5d3588983bf384783e2066d7bb71175b0fafca6a17c35212526dbbc46f6a5209
4
- data.tar.gz: a9a8a41c4bbe2113112cc81428b302427861c5dafab63344a6bb54339a270384
3
+ metadata.gz: 8c4d6e5d80eb4af70ff671777425f063aa79ea43125e68c453ddb1be96f14abd
4
+ data.tar.gz: 0bb3fcbd997da246fa75b009517a8b53c8e57dffd2cd539db9c925179c5ba33f
5
5
  SHA512:
6
- metadata.gz: 85db7c0ac953324ed3c0102ec757af300384d1614a99446ed693f376444cf94dfa713ecca0a4cde330be3c0fd7cbc07628d542b571808e17434893fa6ece2a69
7
- data.tar.gz: 0bf474e6e562247c38126250bf53b799c66f18a1aeeee451a43c6c5190c83ecc6e0b6156215fea01576269e67f22e9b42d1aa453f189bb8c3751f68fd9ec487f
6
+ metadata.gz: ed1632d57adc92b16534f172e79de97003a3a97bb1698d330d0517de467722cb495993b563a9ae203f51000d2a58ccd8f64514a86b02d5a2d882effce6ea2852
7
+ data.tar.gz: 1f850630a40f3da4f642d30f3ce4ee0b81143889ecd47ee3cad57aa11b587cce30c6e8c119305f3e638403cbdfae6238739dd135b80295c2636381397a918beb
data/chespirito.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = 'chespirito'
5
- spec.version = '0.0.2'
5
+ spec.version = '0.0.3'
6
6
  spec.summary = 'Chespirito Ruby web framework'
7
7
  spec.description = 'A dead simple, yet Rack-compatible, web framework written in Ruby'
8
8
  spec.authors = ['Leandro Proença']
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative './request'
4
- require_relative './router'
4
+ require_relative './routes/router'
5
5
 
6
6
  module Chespirito
7
7
  class App
@@ -15,17 +15,19 @@ module Chespirito
15
15
  new.tap { |app| yield(app) }
16
16
  end
17
17
 
18
- def register_route(*attrs)
19
- attrs => [verb, path, trait]
20
-
18
+ def register_route(verb, path, trait)
21
19
  @router.register_route(verb, path, trait)
22
20
  end
23
21
 
24
- def lookup(request) = @router.lookup(request)
22
+ def register_system_route(key, trait)
23
+ @router.register_system_route(key, trait)
24
+ end
25
+
26
+ def dispatch(request) = @router.dispatch(request)
25
27
 
26
28
  def call(env)
27
29
  request = ::Chespirito::Request.build(env)
28
- response = lookup(request)
30
+ response = dispatch(request)
29
31
 
30
32
  [
31
33
  response.status,
@@ -11,7 +11,7 @@ module Chespirito
11
11
  @response = ::Chespirito::Response.new
12
12
  end
13
13
 
14
- def self.dispatch(action, request)
14
+ def self.process(action, request)
15
15
  new(request)
16
16
  .tap { |controller| controller.send(action.to_sym) }
17
17
  .then { |controller| controller.response }
@@ -30,5 +30,11 @@ module Chespirito
30
30
  cookies: rack_request.cookies
31
31
  )
32
32
  end
33
+
34
+ def add_param!(name, value)
35
+ @params ||= {}
36
+
37
+ @params[name] = value
38
+ end
33
39
  end
34
40
  end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Chespirito
4
+ class Route
5
+ attr_reader :verb, :path, :controller_klass, :action
6
+
7
+ def initialize(*attrs)
8
+ @verb, @path, @trait = attrs
9
+ @controller_klass, @action = @trait
10
+ end
11
+
12
+ def key = "#{@verb} #{@path}"
13
+ end
14
+
15
+ class SystemRoute
16
+ attr_reader :key, :controller_klass, :action
17
+
18
+ def initialize(*attrs)
19
+ @key, @trait = attrs
20
+ @controller_klass, @action = @trait
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './route_utils'
4
+
5
+ module Chespirito
6
+ class RouteConstraintChecker
7
+ def initialize(request)
8
+ @request = request
9
+ end
10
+
11
+ def match_route?(route)
12
+ return false unless route.respond_to?(:path)
13
+ return false if route_constraints(route).empty?
14
+
15
+ route_constraints(route).size == request_constraints(route).size
16
+ end
17
+
18
+ def extract_params(route)
19
+ return {} unless route.respond_to?(:path)
20
+ return {} unless match_route?(route)
21
+
22
+ route_constraints(route)
23
+ .zip(request_constraints(route))
24
+ .to_h
25
+ end
26
+
27
+ def route_constraints(route) = RouteUtils.constraints(route.path)
28
+ def request_constraints(route) = request_parts - route_parts(route)
29
+
30
+ def route_parts(route) = RouteUtils.parts(route.path)
31
+ def request_parts = RouteUtils.words(@request.path)
32
+ end
33
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Chespirito
4
+ class RouteUtils
5
+ class << self
6
+ def words(path) = path.split("/").delete_if(&:empty?)
7
+ def constraints(path) = words(path).select(&method(:constraint?)).map(&method(:remove_colon))
8
+ def parts(path) = words(path).select(&method(:part?))
9
+ def part?(word) = !constraint?(word)
10
+ def constraint?(word) = word.start_with?(":")
11
+ def remove_colon(word) = word.gsub(":", '')
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './route'
4
+ require_relative './route_constraint_checker'
5
+ require_relative '../response'
6
+
7
+ module Chespirito
8
+ class Router
9
+ def initialize
10
+ @routes = {}
11
+ end
12
+
13
+ def register_route(*attrs)
14
+ route = Route.new(*attrs)
15
+
16
+ @routes[route.key] = route
17
+ end
18
+
19
+ def register_system_route(*attrs)
20
+ route = SystemRoute.new(*attrs)
21
+
22
+ @routes[route.key] = route
23
+ end
24
+
25
+ def dispatch(request)
26
+ route = route_for(request)
27
+ return not_found_response unless route
28
+
29
+ route
30
+ .controller_klass
31
+ .process(route.action, request)
32
+ end
33
+
34
+ def route_for(request)
35
+ simple_route(request) || constraint_route(request) || not_found_route
36
+ end
37
+
38
+ def simple_route(request)
39
+ @routes["#{request.verb} #{request.path}"]
40
+ end
41
+
42
+ def constraint_route(request)
43
+ constraint_checker = RouteConstraintChecker.new(request)
44
+
45
+ route = @routes.values.find(&constraint_checker.method(:match_route?))
46
+ return unless route
47
+
48
+ route.tap do
49
+ constraint_checker
50
+ .extract_params(route)
51
+ .each { |(name, value)| request.add_param!(name, value) }
52
+ end
53
+ end
54
+
55
+ def not_found_route = @routes['404'] || @routes[:not_found]
56
+
57
+ def not_found_response
58
+ ::Chespirito::Response.new.tap do |response|
59
+ response.status = 404
60
+ response.headers = {}
61
+ response.body = ''
62
+ end
63
+ end
64
+ end
65
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chespirito
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
  - Leandro Proença
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-05-23 00:00:00.000000000 Z
11
+ date: 2022-05-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -53,7 +53,10 @@ files:
53
53
  - lib/chespirito/controller.rb
54
54
  - lib/chespirito/request.rb
55
55
  - lib/chespirito/response.rb
56
- - lib/chespirito/router.rb
56
+ - lib/chespirito/routes/route.rb
57
+ - lib/chespirito/routes/route_constraint_checker.rb
58
+ - lib/chespirito/routes/route_utils.rb
59
+ - lib/chespirito/routes/router.rb
57
60
  homepage: https://github.com/leandronsp/chespirito
58
61
  licenses:
59
62
  - MIT
@@ -1,34 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative './request'
4
- require_relative './response'
5
-
6
- module Chespirito
7
- class Router
8
- def initialize
9
- @routes = {}
10
- end
11
-
12
- def register_route(verb, path, trait)
13
- @routes[route_key(verb, path)] = trait
14
- end
15
-
16
- def lookup(request)
17
- controller_klass, action = @routes[route_key(request.verb, request.path)]
18
-
19
- return not_found_response unless controller_klass
20
-
21
- controller_klass.dispatch(action, request)
22
- end
23
-
24
- def route_key(verb, path) = "#{verb} #{path}"
25
-
26
- def not_found_response
27
- ::Chespirito::Response.new.tap do |response|
28
- response.status = 404
29
- response.headers = {}
30
- response.body = ''
31
- end
32
- end
33
- end
34
- end