chespirito 0.0.2 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
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