rack-way 0.0.1 → 0.0.3

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: 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: []