chespirito 0.0.2 → 0.0.4

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: c26d5cfd95f22fdb7fa89e0f16c36cc551f757c4009c42dbd36c95798f27c252
4
+ data.tar.gz: '09c340a8e1776bf4d33e578ba6475110d84703d2c5a0fc79b3bfff6f45859a75'
5
5
  SHA512:
6
- metadata.gz: 85db7c0ac953324ed3c0102ec757af300384d1614a99446ed693f376444cf94dfa713ecca0a4cde330be3c0fd7cbc07628d542b571808e17434893fa6ece2a69
7
- data.tar.gz: 0bf474e6e562247c38126250bf53b799c66f18a1aeeee451a43c6c5190c83ecc6e0b6156215fea01576269e67f22e9b42d1aa453f189bb8c3751f68fd9ec487f
6
+ metadata.gz: 75895b71b94768410da2bae31f1969dc7fde2b374c6d45ca9128049b97d7b3571163fe56ebb3f54a36f0f6c0b38cd178d9157dbba71abe403a30e8eeeb9c24d7
7
+ data.tar.gz: 21684e74e4478c61fe5f56b85c4a31d72e95489fb5a3ebb68a19cada1e46dca52b89e1aac2502632d15b85494cb66e6cc57b769196fe1b01f5649bfb2ea98617
data/README.md CHANGED
@@ -8,12 +8,13 @@
8
8
  [![Ruby Style Guide](https://img.shields.io/badge/code_style-rubocop-brightgreen.svg)](https://github.com/rubocop/rubocop)
9
9
  [![Ruby Style Guide](https://img.shields.io/badge/code_style-community-brightgreen.svg)](https://rubystyle.guide)
10
10
  ```
11
- ______ __ __ _______ _______..______ __ .______ __ .___________. ______
12
- / || | | | | ____| / || _ \ | | | _ \ | | | | / __ \
13
- | ,----'| |__| | | |__ | (----`| |_) | | | | |_) | | | `---| |----`| | | |
14
- | | | __ | | __| \ \ | ___/ | | | / | | | | | | | |
15
- | `----.| | | | | |____.----) | | | | | | |\ \----.| | | | | `--' |
16
- \______||__| |__| |_______|_______/ | _| |__| | _| `._____||__| |__| \______/
11
+ ( ) _ _ ( )_
12
+ ___ | |__ __ ___ _ _ (_) _ __ (_)| ,_) _
13
+ /'___)| _ `\ /'__`\/',__)( '_`\ | |( '__)| || | /'_`\
14
+ ( (___ | | | |( ___/\__, \| (_) )| || | | || |_ ( (_) )
15
+ `\____)(_) (_)`\____)(____/| ,__/'(_)(_) (_)`\__)`\___/'
16
+ | |
17
+ (_)
17
18
  ```
18
19
 
19
20
  [chespirito](https://rubygems.org/gems/chespirito) is a dead simple, yet Rack-compatible, web framework written in Ruby.
@@ -54,6 +55,7 @@ Usage: make <target>
54
55
  ## Boostrapping an application using Chespirito and Adelnor
55
56
 
56
57
  1. Install the gems:
58
+
57
59
  ```bash
58
60
  $ gem install chespirito adelnor
59
61
  ```
@@ -89,7 +91,7 @@ class HelloController < Chespirito::Controller
89
91
  end
90
92
  ```
91
93
 
92
- 4. Run the app using Adelnor (or you can choose other web server like Puma, Unicorn, etc):
94
+ 4. Run the app using Adelnor (or you can choose another web server like Puma, Unicorn, etc):
93
95
 
94
96
  ```ruby
95
97
  Adelnor::Server.run MyApp.application, 3000
@@ -99,4 +101,4 @@ Adelnor::Server.run MyApp.application, 3000
99
101
 
100
102
  ----
101
103
 
102
- [ASCII art generator](http://patorjk.com/software/taag/#p=display&f=Graffiti&t=Type%20Something%20)
104
+ [ASCII art generator](http://www.network-science.de/ascii/)
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.4'
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,23 +15,25 @@ 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
- request = ::Chespirito::Request.build(env)
28
- response = lookup(request)
29
-
30
- [
31
- response.status,
32
- response.headers,
33
- [response.body]
34
- ]
29
+ request = ::Chespirito::Request.build(env)
30
+ response = dispatch(request)
31
+
32
+ [
33
+ response.status,
34
+ response.headers,
35
+ [response.body]
36
+ ]
35
37
  end
36
38
  end
37
39
 
@@ -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 }
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'rack'
4
4
  require 'json'
5
+ require 'cgi'
5
6
 
6
7
  module Chespirito
7
8
  class Request
@@ -19,7 +20,9 @@ module Chespirito
19
20
  def self.build(env)
20
21
  rack_request = Rack::Request.new(env)
21
22
 
22
- body_params = rack_request.post? ? (JSON.parse(rack_request.body.read) rescue {}) : {}
23
+ body_params = rack_request.post? ? parse_body_params(rack_request.body.read,
24
+ rack_request.env['Content-Type']) : {}
25
+
23
26
  params = rack_request.params.merge(body_params)
24
27
 
25
28
  new(
@@ -30,5 +33,23 @@ module Chespirito
30
33
  cookies: rack_request.cookies
31
34
  )
32
35
  end
36
+
37
+ def self.parse_body_params(body_data, content_type)
38
+ case content_type
39
+ in 'application/json'; JSON.parse(body_data)
40
+ in 'application/x-www-form-urlencoded'
41
+ CGI.unescape(body_data).split('&').each_with_object({}) do |param, hash|
42
+ key, value = param.split('=')
43
+ hash[key] = value
44
+ end
45
+ else {}
46
+ end
47
+ end
48
+
49
+ def add_param!(name, value)
50
+ @params ||= {}
51
+
52
+ @params[name] = value
53
+ end
33
54
  end
34
55
  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.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Leandro Proença
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-05-23 00:00:00.000000000 Z
11
+ date: 2023-10-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -53,12 +53,15 @@ 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
60
63
  metadata: {}
61
- post_install_message:
64
+ post_install_message:
62
65
  rdoc_options: []
63
66
  require_paths:
64
67
  - lib
@@ -73,8 +76,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
73
76
  - !ruby/object:Gem::Version
74
77
  version: '0'
75
78
  requirements: []
76
- rubygems_version: 3.3.3
77
- signing_key:
79
+ rubygems_version: 3.4.10
80
+ signing_key:
78
81
  specification_version: 4
79
82
  summary: Chespirito Ruby web framework
80
83
  test_files: []
@@ -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