rack-way 0.0.1 → 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: 016cf1e2d4ae57cf31b359733bf96c3510667bc9de887322c18a2118dcb54ba9
4
- data.tar.gz: b491da7388431e3d6b07a7b904af1d5d6b732b510c44904a0c93cd26978f0b07
3
+ metadata.gz: a49ebbc6df20d07f91d19e38ee194c6a2958d397c357b8ab6b262ba7ed256902
4
+ data.tar.gz: ef3a7824645ef0bea5b2f06a4ea3ca89c5cd5eb5daeea2e1f0028dcbee60676a
5
5
  SHA512:
6
- metadata.gz: c5948a9e5366dab3e86832df6f5fc66a9c837320689c3c6a2507c8f7b7a7c080272388159f44d464e07ba6ec1541377e9021ba83b33cb91958d0ff8005ba35de
7
- data.tar.gz: 1694ea321074055bdf57518e8dd6c16cf634b732c87561c4edd2f0a64af0c6ec714373acbfd9bdc59b6459ed9231a4c31f036b0151533aaaf26001ab79f9b538
6
+ metadata.gz: 48802c9548cbdeb967d28dc8a0d543841bcbc0fbb4fc6bdbe9976260df76795060abcc8dce9de3a500aea2dbba0bcdbd5ff55c5c30bc9df2afa65ea28e62049c
7
+ data.tar.gz: 50e8fb5a03bfdefaa88b5d3b0fabb73bb587b4c2e6c47fe01d787bd4e0898e80bb84e078a61938b0dd169e8ec650c4bbfa99c5e416724dc24f174440eb4b8a21
@@ -1,60 +1,156 @@
1
- require 'erubis'
1
+ # frozen_string_literal: true
2
+
3
+ require 'erubi'
2
4
  require 'json'
3
5
  require 'rack'
4
6
 
5
7
  module Rack
6
8
  class Way
7
9
  module Action
8
- def render(content, headers: {"Content-Type" => "text/html"}, status: 200)
9
- Rack::Way::Action.render(content, headers: headers, status: status)
10
+ def self.included(base)
11
+ base.class_eval do
12
+ attr_reader :route if self != Rack::Way
13
+
14
+ def initialize(route)
15
+ @route = route
16
+ end
17
+
18
+ def view_response(a_path, a_view_params = {}, status: 200)
19
+ Rack::Way::Action.view_response(
20
+ a_path,
21
+ a_view_params,
22
+ status: status, route: route
23
+ )
24
+ end
25
+
26
+ def view(
27
+ a_path, a_view_params = {}, status: 200, response_instance: false
28
+ )
29
+ Rack::Way::Action.view(
30
+ a_path,
31
+ a_view_params,
32
+ status: status, response_instance: response_instance, route: route
33
+ )
34
+ end
35
+ end
36
+ end
37
+
38
+ def html(content, status: 200)
39
+ Rack::Way::Action.html(content, status: status)
40
+ end
41
+
42
+ def html_response(content, status: 200)
43
+ Rack::Way::Action.html_response(content, status: status)
44
+ end
45
+
46
+ def json(content = {}, status: 200)
47
+ Rack::Way::Action.json(content, status: status)
48
+ end
49
+
50
+ def json_response(content = {}, status: 200)
51
+ Rack::Way::Action.json_response(content, status: status)
10
52
  end
11
53
 
12
- def render_erb(path, params = {}, status: 200)
13
- Rack::Way::Action.render_erb(path, params, status: status)
54
+ def text(content, status: 200)
55
+ Rack::Way::Action.text(content, status: status)
14
56
  end
15
57
 
16
- def render_json(content = {}, status: 200)
17
- Rack::Way::Action.render_json(content, status: status)
58
+ def text_response(content, status: 200)
59
+ Rack::Way::Action.text_response(content, status: status)
18
60
  end
19
61
 
20
- def erb(path, params = {})
21
- Rack::Way::Action.erb(path, params)
62
+ def erb(path, view_params = {})
63
+ Rack::Way::Action.erb(path, view_params)
22
64
  end
23
65
 
24
66
  def redirect_to(url)
25
67
  Rack::Way::Action.redirect_to(url)
26
68
  end
27
69
 
70
+ def response(body = nil, status = 200, headers = {})
71
+ Rack::Response.new(body, status, headers)
72
+ end
73
+
28
74
  class << self
29
- def render(content, headers: {"Content-Type" => "text/html"}, status: 200)
30
- [status, headers, [content]]
75
+ def html(content, status: 200)
76
+ [status, { 'Content-Type' => 'text/html' }, [content]]
77
+ end
78
+
79
+ def html_response(content, status: 200)
80
+ Rack::Response.new(content, status, { 'Content-Type' => 'text/html' })
31
81
  end
32
82
 
33
- def render_erb(paths, params = {}, status: 200)
34
- if paths.kind_of?(Array)
35
- erb =
36
- paths.map { |path| erb(path, params) }.join
37
- else
38
- erb = erb(paths, params)
83
+ def view_response(paths, view_params = {}, status: 200, route: nil)
84
+ view(
85
+ paths,
86
+ view_params,
87
+ status: status, response_instance: true,
88
+ route: route
89
+ )
90
+ end
91
+
92
+ def view(
93
+ paths,
94
+ view_params = {},
95
+ status: 200,
96
+ response_instance: false,
97
+ route: nil
98
+ )
99
+ erb = if paths.is_a?(Array)
100
+ paths.map { |path| erb("views/#{path}", route, view_params) }.join
101
+ else
102
+ erb("views/#{paths}", route, view_params)
103
+ end
104
+
105
+ if response_instance
106
+ return Rack::Response.new(
107
+ erb,
108
+ status,
109
+ { 'Content-Type' => 'text/html' }
110
+ )
39
111
  end
40
112
 
41
- [status, {"Content-Type" => "text/html"}, [erb]]
113
+ [status, { 'Content-Type' => 'text/html' }, [erb]]
114
+ end
115
+
116
+ def json(content = {}, status: 200)
117
+ [status, { 'Content-Type' => 'application/json' }, [content.to_json]]
118
+ end
119
+
120
+ def json_response(content = {}, status: 200)
121
+ Rack::Response.new(
122
+ content.to_json,
123
+ status,
124
+ { 'Content-Type' => 'application/json' }
125
+ )
126
+ end
127
+
128
+ def text(content, status: 200)
129
+ [status, { 'Content-Type' => 'text/plain' }, [content]]
42
130
  end
43
131
 
44
- def render_json(content = {}, status: 200)
45
- [status, {"Content-Type" => "application/json"}, [content.to_json]]
132
+ def text_response(content, status: 200)
133
+ Rack::Response.new(
134
+ content,
135
+ status,
136
+ { 'Content-Type' => 'text/plain' }
137
+ )
46
138
  end
47
139
 
48
- def erb(path, params = {})
49
- Erubis::FastEruby
50
- .load_file("#{path}.html.erb")
51
- .result(params)
140
+ def erb(path, _route, view_params = {})
141
+ @view = OpenStruct.new(view_params)
142
+
143
+ eval(Erubi::Engine.new(::File.read("#{path}.html.erb")).src)
52
144
  end
53
145
 
54
146
  def redirect_to(url)
55
- [302, {'Location' => url}, []]
147
+ [302, { 'Location' => url }, []]
148
+ end
149
+
150
+ def response(body = nil, status = 200, headers = {})
151
+ Rack::Response.new(body, status, headers)
56
152
  end
57
153
  end
58
154
  end
59
155
  end
60
- end
156
+ end
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Rack
2
4
  class Way
3
5
  class Router
4
- class RequestBuilder
6
+ class BuildRequest
5
7
  def initialize(env)
6
8
  @env = env
7
9
  end
@@ -10,7 +12,7 @@ module Rack
10
12
  request = Rack::Request.new(@env)
11
13
 
12
14
  return request if route.nil?
13
- return request unless route.has_params?
15
+ return request unless route.has_params
14
16
 
15
17
  update_request_params(request, route)
16
18
  end
@@ -45,4 +47,4 @@ module Rack
45
47
  end
46
48
  end
47
49
  end
48
- end
50
+ end
@@ -1,28 +1,25 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Rack
2
4
  class Way
3
5
  class Router
4
6
  class Route
5
- attr_reader :endpoint, :splitted_path
7
+ attr_reader :endpoint, :splitted_path, :has_params
6
8
 
7
9
  def initialize(path, endpoint)
8
10
  @path = path
9
11
  @splitted_path = @path.split('/')
10
12
  @endpoint = endpoint
11
13
  @params = fetch_params
14
+ @has_params = @params != []
12
15
  end
13
16
 
14
17
  def match?(env)
15
- if has_params?
16
- return match_with_params?(env)
17
- end
18
+ return match_with_params?(env) if @has_params
18
19
 
19
20
  env['REQUEST_PATH'] == @path
20
21
  end
21
22
 
22
- def has_params?
23
- @params != []
24
- end
25
-
26
23
  private
27
24
 
28
25
  def fetch_params
@@ -32,24 +29,22 @@ module Rack
32
29
  def match_with_params?(env)
33
30
  splitted_request_path = env['REQUEST_PATH'].split('/')
34
31
 
35
- if @splitted_path.size != splitted_request_path.size
36
- return false
37
- end
32
+ return false if @splitted_path.size != splitted_request_path.size
38
33
 
39
- matched =
34
+ matched_path_pieces =
40
35
  @splitted_path
41
- .map
42
- .with_index do |segment, i|
43
- if segment.start_with?(':')
44
- true
45
- else
46
- splitted_request_path[i] == segment
47
- end
36
+ .map
37
+ .with_index do |segment, i|
38
+ if segment.start_with?(':')
39
+ true
40
+ else
41
+ splitted_request_path[i] == segment
48
42
  end
43
+ end
49
44
 
50
- !matched.include?(false)
45
+ !matched_path_pieces.include?(false)
51
46
  end
52
47
  end
53
48
  end
54
49
  end
55
- end
50
+ end
@@ -1,64 +1,99 @@
1
- require_relative 'router/route.rb'
2
- require_relative 'router/request_builder.rb'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'router/route'
4
+ require_relative 'router/build_request'
3
5
 
4
6
  module Rack
5
7
  class Way
6
8
  class Router
9
+ class UndefinedNamedRoute < StandardError; end
10
+
7
11
  attr_writer :not_found
12
+ attr_reader :route
8
13
 
9
14
  def initialize
10
- @routes =
11
- {
12
- 'GET' => [],
13
- 'POST' => [],
14
- 'DELETE' => [],
15
- 'PUT' => [],
16
- 'PATCH' => []
17
- }
18
-
19
- @namespaces = []
20
-
15
+ @routes = {}
16
+ %w[GET POST DELETE PUT TRACE OPTIONS PATCH].each do |method|
17
+ @routes[method] = { __instances: [] }
18
+ end
19
+ @route = Hash.new do |_hash, key|
20
+ raise(UndefinedNamedRoute, "Undefined named route: '#{key}'")
21
+ end
22
+ @scopes = []
23
+ @error = proc { |_req, e| raise e }
21
24
  @not_found = proc { [404, {}, ['Not found']] }
22
25
  end
23
26
 
24
27
  def call(env)
25
- route = match_route(env)
26
- request_builder = RequestBuilder.new(env)
28
+ request_builder = BuildRequest.new(env)
29
+ env['REQUEST_METHOD'] = 'GET' if env['REQUEST_METHOD'] == 'HEAD'
30
+
31
+ route_instance = match_route(env)
27
32
 
28
- return render_not_found(request_builder.call) if route.nil?
33
+ return render_not_found(request_builder.call) if route_instance.nil?
29
34
 
30
- if route.endpoint.respond_to?(:call)
31
- return route.endpoint.call(request_builder.call(route))
35
+ if route_instance.endpoint.respond_to?(:call)
36
+ return route_instance.endpoint.call(request_builder.call(route_instance))
32
37
  end
33
38
 
34
- route.endpoint.new.call(request_builder.call(route))
39
+ if route_instance.endpoint.include?(Rack::Way::Action)
40
+ return route_instance.endpoint.new(@route).call(request_builder.call(route_instance))
41
+ end
42
+
43
+ route_instance.endpoint.new.call(request_builder.call(route_instance))
44
+ rescue Exception => e
45
+ @error.call(request_builder.call, e)
35
46
  end
36
47
 
37
- def add(method, path, endpoint)
38
- route =
39
- Route.new("/" + @namespaces.join('/') + put_path_slash(path), endpoint)
48
+ def add(method, path, endpoint, as = nil)
49
+ method = :get if method == :head
50
+
51
+ path_with_scopes = "/#{@scopes.join('/')}#{put_path_slash(path)}"
52
+ @route[as] = path_with_scopes if as
53
+
54
+ route_instance = Route.new(path_with_scopes, endpoint)
40
55
 
41
- @routes[method.to_s.upcase].push route
56
+ return push_to_scope(method.to_s.upcase, route_instance) if @scopes.size >= 1
57
+
58
+ @routes[method.to_s.upcase][:__instances].push(route_instance)
42
59
  end
43
60
 
44
61
  def add_not_found(endpoint)
45
62
  @not_found = endpoint
46
63
  end
47
64
 
48
- def append_namespace(name)
49
- @namespaces.push(name)
65
+ def add_error(endpoint)
66
+ @error = endpoint
67
+ end
68
+
69
+ def append_scope(name)
70
+ @scopes.push(name)
50
71
  end
51
72
 
52
- def clear_last_namespace
53
- @namespaces =
54
- @namespaces.first(@namespaces.size - 1)
73
+ def clear_last_scope
74
+ @scopes = @scopes.first(@scopes.size - 1)
55
75
  end
56
76
 
57
77
  private
58
78
 
79
+ def push_to_scope(method, route_instance)
80
+ scopes_with_slash = @scopes + [:__instances]
81
+ push_it(@routes[method], *scopes_with_slash, route_instance)
82
+ end
83
+
84
+ def push_it(h, first_key, *rest_keys, val)
85
+ if rest_keys.empty?
86
+ (h[first_key] ||= []) << val
87
+ else
88
+ h[first_key] = push_it(h[first_key] ||= {}, *rest_keys, val)
89
+ end
90
+ h
91
+ end
92
+
59
93
  def put_path_slash(path)
60
- return '' if (path == '/' || path == '') && @namespaces != []
61
- return '/' + path if @namespaces != []
94
+ return '' if ['/', ''].include?(path) && @scopes != []
95
+ return "/#{path}" if @scopes != []
96
+
62
97
  path
63
98
  end
64
99
 
@@ -68,9 +103,34 @@ module Rack
68
103
  @not_found.new.call(env)
69
104
  end
70
105
 
71
- def match_route(env)
72
- @routes[env["REQUEST_METHOD"]]
73
- .detect { |route| route.match?(env) }
106
+ def match_route(env, last_tail = nil, found_scopes = [])
107
+ routes =
108
+ if last_tail.nil?
109
+ last_tail = env['REQUEST_PATH'].split('/').drop(1)
110
+
111
+ @routes[env['REQUEST_METHOD']]
112
+ else
113
+ @routes[env['REQUEST_METHOD']].dig(*found_scopes)
114
+ end
115
+
116
+ segment, *tail = last_tail
117
+
118
+ routes.each do |scope, _v|
119
+ next if scope == :__instances
120
+
121
+ if segment == scope || scope.start_with?(':')
122
+ found_scopes.push(scope)
123
+ break
124
+ end
125
+ end
126
+
127
+ if tail.empty? || found_scopes == []
128
+ return @routes[env['REQUEST_METHOD']].dig(*(found_scopes << :__instances)).detect do |route_instance|
129
+ route_instance.match?(env)
130
+ end
131
+ end
132
+
133
+ match_route(env, tail, found_scopes)
74
134
  end
75
135
  end
76
136
  end
data/lib/rack-way.rb CHANGED
@@ -1,53 +1,57 @@
1
- require 'rack-way/router'
2
- require 'rack-way/action'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'rack-way/router'
4
+ require_relative 'rack-way/action'
3
5
 
4
6
  module Rack
5
7
  class Way
6
8
  include Action
7
9
 
8
- def initialize
9
- @router = Router.new
10
+ def initialize(router: Router.new)
11
+ @router = router
10
12
  end
11
13
 
12
- def draw_app(&block)
14
+ def http_router(&block)
13
15
  instance_eval(&block)
14
16
 
15
17
  @router
16
18
  end
17
19
 
18
- def namespace(name, &block)
19
- @router.append_namespace(name)
20
- instance_eval(&block)
21
-
22
- @router.clear_last_namespace
23
- end
24
-
25
- def root(endpoint)
26
- @router.add('GET', '', endpoint)
20
+ def route
21
+ @router.route
27
22
  end
28
23
 
29
- def not_found(endpoint)
30
- @router.add_not_found(endpoint)
31
- end
32
-
33
- def get(path, endpoint)
34
- @router.add('GET', path, endpoint)
35
- end
24
+ def scope(name, &block)
25
+ @router.append_scope(name)
26
+ instance_eval(&block)
36
27
 
37
- def post(path, endpoint)
38
- @router.add('POST', path, endpoint)
28
+ @router.clear_last_scope
39
29
  end
40
30
 
41
- def delete(path, endpoint)
42
- @router.add('DELETE', path, endpoint)
31
+ def not_found(endpoint = -> {}, &block)
32
+ if block_given?
33
+ @router.add_not_found(block)
34
+ else
35
+ @router.add_not_found(endpoint)
36
+ end
43
37
  end
44
38
 
45
- def put(path, endpoint)
46
- @router.add('PUT', path, endpoint)
39
+ def error(endpoint = -> {}, &block)
40
+ if block_given?
41
+ @router.add_error(block)
42
+ else
43
+ @router.add_error(endpoint)
44
+ end
47
45
  end
48
46
 
49
- def patch(path, endpoint)
50
- @router.add('PATCH', path, endpoint)
47
+ %w[GET POST DELETE PUT TRACE OPTIONS PATCH].each do |http_method|
48
+ define_method(http_method.downcase.to_sym) do |path = '', endpoint = -> {}, as: nil, &block|
49
+ if block.respond_to?(:call)
50
+ @router.add(http_method, path, block, as)
51
+ else
52
+ @router.add(http_method, path, endpoint, as)
53
+ end
54
+ end
51
55
  end
52
56
  end
53
57
  end
metadata CHANGED
@@ -1,45 +1,44 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-way
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
- - Henrique Fernandez
7
+ - Henrique F. Teixeira
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-04-21 00:00:00.000000000 Z
11
+ date: 2023-07-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: erubis
14
+ name: erubi
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '2.7'
19
+ version: '1.12'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '2.7'
26
+ version: '1.12'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rack
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '2.0'
33
+ version: '3.0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '2.0'
41
- description: A very little framework that encourages ruby developers to build 'pure
42
- Rack' applications when working in projects that need high performance.
40
+ version: '3.0'
41
+ description: A router and helper functions to build pure Rack projects.
43
42
  email: hriqueft@gmail.com
44
43
  executables: []
45
44
  extensions: []
@@ -48,7 +47,7 @@ files:
48
47
  - lib/rack-way.rb
49
48
  - lib/rack-way/action.rb
50
49
  - lib/rack-way/router.rb
51
- - lib/rack-way/router/request_builder.rb
50
+ - lib/rack-way/router/build_request.rb
52
51
  - lib/rack-way/router/route.rb
53
52
  homepage: https://github.com/henriquefernandez/rack-way
54
53
  licenses:
@@ -69,8 +68,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
69
68
  - !ruby/object:Gem::Version
70
69
  version: '0'
71
70
  requirements: []
72
- rubygems_version: 3.0.3
71
+ rubygems_version: 3.4.3
73
72
  signing_key:
74
73
  specification_version: 4
75
- summary: '"rack-way" come with a router and helper functions to build pure rack projects.'
74
+ summary: '"rack-way" come with a router and helper functions to build pure Rack projects.'
76
75
  test_files: []