rackr 0.0.63 → 0.0.65

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: 0e5510a8382fb76e2ecd76fb38f024753d2bece6771aeac87f4fa8f000e14bb7
4
- data.tar.gz: 48e121278f8b5dc8eac591883e9e40d6ecc43f6116dd4ee6abe3130da8956186
3
+ metadata.gz: 5d146e39fc587acb31017ef9e5b093aba6a8cecadf8fe8beb038ab7804425015
4
+ data.tar.gz: '04787fa986d2d6f4033114d5bf6a134bd6451e2e7cb0c957ef063ddf7fbb9cf3'
5
5
  SHA512:
6
- metadata.gz: cbcfc075222a1f7b7b39a2106f6bff6192616f76879bc05515b53db3654ca9733b9003cc8c6fa637b57ac3e0daff4b00489589176ece200820249fae4d8fbe4f
7
- data.tar.gz: 4f3314ff137706612f7f0f8e5484236794c65772a4a063c2e327642e6ff4ce7c6dfc8ed1d5a023420f16c77431c4443cb36e0cc559837e4d5d86d654d85aa0a0
6
+ metadata.gz: 57661323fb8e596afd2833f24145716090db3bd1024bf465ae2388f48c5a2c9cbff4384331368d69337a08f7fd977b5f33dcb275421324748eb783f33d6a877e
7
+ data.tar.gz: b524b6414b3218cca05f134f81ce03583fac97d38eb4e754c27a754b50fd0d2eaa969b4728304ce6aafe08a45c370ffde59a68d21d76f72634cc43fc74925b9b
data/lib/rackr/action.rb CHANGED
@@ -6,16 +6,35 @@ require 'rack'
6
6
 
7
7
  class Rackr
8
8
  module Action
9
- RENDER = {
9
+ @@default_headers_for = lambda { |content_type, headers, content|
10
+ {
11
+ 'content-type' => content_type,
12
+ 'content-length' => content.bytesize.to_s
13
+ }.merge(headers)
14
+ }
15
+
16
+ @@render = {
10
17
  html: lambda do |val, status: 200, headers: {}, html: nil|
11
- [status, { 'content-type' => 'text/html', 'content-length' => val.bytesize.to_s }.merge(headers), [val]]
18
+ [
19
+ status,
20
+ @@default_headers_for.call('text/html; charset=utf-8', headers, val),
21
+ [val]
22
+ ]
12
23
  end,
13
24
  text: lambda do |val, status: 200, headers: {}, text: nil|
14
- [status, { 'content-type' => 'text/plain', 'content-length' => val.bytesize.to_s }.merge(headers), [val]]
25
+ [
26
+ status,
27
+ @@default_headers_for.call('text/plain', headers, val),
28
+ [val]
29
+ ]
15
30
  end,
16
31
  json: lambda do |val, status: 200, headers: {}, json: nil|
17
32
  val = Oj.dump(val, mode: :compat) unless val.is_a?(String)
18
- [status, { 'content-type' => 'application/json', 'content-length' => val.bytesize.to_s }.merge(headers), [val]]
33
+ [
34
+ status,
35
+ @@default_headers_for.call('application/json', headers, val),
36
+ [val]
37
+ ]
19
38
  end,
20
39
  res: lambda do |val, status: nil, headers: nil, res: nil|
21
40
  val.status = status if status
@@ -31,19 +50,20 @@ class Rackr
31
50
 
32
51
  def self.included(base)
33
52
  base.class_eval do
34
- attr_reader :routes, :config, :db if self != Rackr
53
+ attr_reader :routes, :config, :deps, :db if self != Rackr
35
54
 
36
55
  def initialize(routes: nil, config: nil)
37
56
  @routes = routes
38
57
  @config = config
39
- @db = config[:db]
58
+ @deps = config[:deps]
59
+ @db = config.dig(:deps, :db)
40
60
  end
41
61
 
42
62
  def render(**opts)
43
63
  type = opts.keys.first
44
64
  content = opts[type]
45
65
 
46
- Rackr::Action::RENDER[type]&.call(content, **opts) || _render_view(content, **opts)
66
+ @@render[type]&.call(content, **opts) || _render_view(content, **opts)
47
67
  end
48
68
 
49
69
  def view_response(
@@ -98,12 +118,15 @@ class Rackr
98
118
  return Rack::Response.new(
99
119
  parsed_erb,
100
120
  status,
101
- { 'content-type' => 'text/html' }.merge(headers)
121
+ @@default_headers_for.call('text/html; charset=utf-8', headers, parsed_erb)
102
122
  )
103
123
  end
104
124
 
105
- [status, { 'content-type' => 'text/html', 'content-length' => parsed_erb.bytesize.to_s }.merge(headers),
106
- [parsed_erb]]
125
+ [status, @@default_headers_for.call('text/html; charset=utf-8', headers, parsed_erb), [parsed_erb]]
126
+ end
127
+
128
+ def not_found!
129
+ raise Rackr::NotFound
107
130
  end
108
131
 
109
132
  def load_json(val)
@@ -113,25 +136,16 @@ class Rackr
113
136
  end
114
137
 
115
138
  def html_response(content = '', status: 200, headers: {})
116
- Rack::Response.new(content, status,
117
- { 'content-type' => 'text/html', 'content-length' => content.bytesize.to_s }.merge(headers))
139
+ Rack::Response.new(content, status, @@default_headers_for.call('text/html; charset=utf-8', headers, content))
118
140
  end
119
141
 
120
142
  def json_response(content = {}, status: 200, headers: {})
121
143
  content = Oj.dump(content, mode: :compat) unless content.is_a?(String)
122
- Rack::Response.new(
123
- content,
124
- status,
125
- { 'content-type' => 'application/json', 'content-length' => content.bytesize.to_s }.merge(headers)
126
- )
144
+ Rack::Response.new(content, status, @@default_headers_for.call('application/json', headers, content))
127
145
  end
128
146
 
129
147
  def text_response(content, status: 200, headers: {})
130
- Rack::Response.new(
131
- content,
132
- status,
133
- { 'content-type' => 'text/plain', 'content-length' => content.bytesize.to_s }.merge(headers)
134
- )
148
+ Rack::Response.new(content, status, @@default_headers_for.call('text/plain', headers, content))
135
149
  end
136
150
 
137
151
  def load_erb(content, binding_context: nil)
@@ -50,7 +50,7 @@ class Rackr
50
50
 
51
51
  def backtrace(env)
52
52
  first, *tail = env['error'].backtrace
53
- traceback = String.new("<h2>Traceback <span>(innermost first)</span></h2>")
53
+ traceback = String.new('<h2>Traceback <span>(innermost first)</span></h2>')
54
54
  traceback << "<p class=\"first-p\">#{first}</p><br/>"
55
55
 
56
56
  line_number = extract_line_number(first)
@@ -61,7 +61,7 @@ class Rackr
61
61
  traceback << "<pre>#{slice_around_index(lines, line_number).join('')}</pre>"
62
62
  end
63
63
 
64
- traceback << "<p>#{tail.join("<br>")}</p>"
64
+ traceback << "<p>#{tail.join('<br>')}</p>"
65
65
  traceback
66
66
  end
67
67
 
@@ -4,39 +4,22 @@ class Rackr
4
4
  class Router
5
5
  class Route
6
6
  attr_reader :endpoint,
7
- :splitted_path,
8
- :has_params,
9
- :has_befores,
10
7
  :befores,
11
- :has_afters,
12
- :afters
8
+ :has_befores,
9
+ :afters,
10
+ :has_afters
13
11
 
14
- def initialize(path, endpoint, befores: [], afters: [], wildcard: false)
15
- @path = path
16
- @splitted_path = @path.split('/')
12
+ def initialize(endpoint, befores: [], afters: [])
17
13
  @endpoint = endpoint
18
- @params = fetch_params
19
- @has_params = @params != []
20
14
  @befores = befores
21
15
  @has_befores = befores != []
22
16
  @afters = afters
23
17
  @has_afters = afters != []
24
- @path_regex = /\A#{path.gsub(/(:\w+)/, '([^/]+)')}\z/
25
- @wildcard = wildcard
26
18
  end
27
19
 
28
- def match?(path_info)
29
- return path_info.match?(@path_regex) if @has_params
30
- return true if @wildcard
31
-
32
- path_info == @path
33
- end
34
-
35
- private
36
-
37
- def fetch_params
38
- @splitted_path.select { |value| value.start_with? ':' }
39
- end
20
+ def match? = true
21
+ def splitted_path = []
22
+ def has_params = false
40
23
  end
41
24
  end
42
25
  end
data/lib/rackr/router.rb CHANGED
@@ -1,19 +1,27 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'router/utils'
3
4
  require_relative 'router/errors'
5
+ require_relative 'router/endpoint'
4
6
  require_relative 'router/route'
7
+ require_relative 'router/path_route'
5
8
  require_relative 'router/build_request'
6
9
 
7
10
  class Rackr
8
11
  class Router
9
- attr_writer :not_found
10
- attr_reader :routes, :config
12
+ include Utils
13
+
14
+ attr_writer :default_not_found
15
+ attr_reader :routes, :config, :not_found_instances, :error_instances
11
16
 
12
17
  def initialize(config = {}, before: [], after: [])
13
- @instance_routes = {}
18
+ @path_routes_instances = {}
14
19
  %w[GET POST DELETE PUT TRACE OPTIONS PATCH].each do |method|
15
- @instance_routes[method] = { __instances: [] }
20
+ @path_routes_instances[method] = { __instances: [] }
16
21
  end
22
+ @not_found_instances = {}
23
+ @error_instances = {}
24
+
17
25
  http_methods = HTTP_METHODS.map { |m| m.downcase.to_sym }
18
26
  @routes = Struct.new(*http_methods).new
19
27
  http_methods.each do |method|
@@ -28,8 +36,8 @@ class Rackr
28
36
  @scopes_befores = {}
29
37
  @afters = ensure_array(after)
30
38
  @scopes_afters = {}
31
- @error = proc { |_req, e| raise e }
32
- @not_found = proc { [404, {}, ['Not found']] }
39
+ @default_error = Route.new(proc { |_req, e| raise e })
40
+ @default_not_found = Route.new(proc { [404, {}, ['Not found']] })
33
41
  @splitted_request_path_info = []
34
42
  @current_request_path_info = nil
35
43
  end
@@ -44,39 +52,36 @@ class Rackr
44
52
  request_builder = BuildRequest.new(env, @splitted_request_path_info)
45
53
  env['REQUEST_METHOD'] = 'GET' if env['REQUEST_METHOD'] == 'HEAD'
46
54
 
47
- route_instance = match_route(env['REQUEST_METHOD'])
48
- return call_endpoint(@not_found, request_builder.call) if route_instance.nil?
49
-
55
+ route_instance, found_scopes = match_path_route(env['REQUEST_METHOD'])
50
56
  rack_request = request_builder.call(route_instance)
51
-
52
57
  befores = route_instance.befores
53
58
  before_result = nil
54
- i = 0
55
- while i < befores.size
56
- before_result = call_endpoint(befores[i], rack_request)
57
- return before_result unless before_result.is_a?(Rack::Request)
58
59
 
59
- rack_request = before_result
60
+ begin
61
+ i = 0
62
+ while i < befores.size
63
+ before_result = Endpoint.call(befores[i], rack_request)
64
+ return before_result unless before_result.is_a?(Rack::Request)
60
65
 
61
- i += 1
62
- end
66
+ rack_request = before_result
63
67
 
64
- endpoint_result = call_endpoint(route_instance.endpoint, before_result || rack_request)
68
+ i += 1
69
+ end
65
70
 
66
- afters = route_instance.afters
67
- i = 0
68
- while i < afters.size
69
- call_endpoint(afters[i], endpoint_result)
70
- i += 1
71
+ endpoint_result = Endpoint.call(route_instance.endpoint, before_result || rack_request)
72
+
73
+ call_afters(route_instance, endpoint_result)
74
+ rescue Rackr::NotFound
75
+ return not_found_fallback(found_scopes, route_instance, before_result || rack_request)
76
+ rescue Exception => e
77
+ if !@dev_mode || ENV['RACKR_ERROR_DEV']
78
+ return error_fallback(found_scopes, route_instance, before_result || rack_request, e)
79
+ end
80
+
81
+ return Endpoint.call(Errors::DevHtml, env.merge({ 'error' => e }))
71
82
  end
72
83
 
73
84
  endpoint_result
74
- rescue Rackr::NotFound
75
- call_endpoint(@not_found, request_builder.call)
76
- rescue Exception => e
77
- return @error.call(request_builder.call, e) if !@dev_mode || ENV['RACKR_ERROR_DEV']
78
-
79
- call_endpoint(Errors::DevHtml, env.merge({ 'error' => e }))
80
85
  end
81
86
 
82
87
  def add(method, path, endpoint, as: nil, route_befores: [], route_afters: [])
@@ -94,7 +99,7 @@ class Rackr
94
99
  add_named_route(method, path_with_scopes, as)
95
100
 
96
101
  route_instance =
97
- Route.new(
102
+ PathRoute.new(
98
103
  path_with_scopes,
99
104
  endpoint,
100
105
  befores: @befores + ensure_array(route_befores),
@@ -104,19 +109,51 @@ class Rackr
104
109
 
105
110
  return push_to_scope(method.to_s.upcase, route_instance) if @scopes.size >= 1
106
111
 
107
- @instance_routes[method.to_s.upcase][:__instances].push(route_instance)
112
+ @path_routes_instances[method.to_s.upcase][:__instances].push(route_instance)
108
113
  end
109
114
 
110
- def add_not_found(endpoint)
111
- Errors.check_endpoint(endpoint, 'not_found')
115
+ %i[error not_found].each do |v|
116
+ define_method("add_#{v}") do |endpoint|
117
+ Errors.check_endpoint(endpoint, v)
112
118
 
113
- @not_found = endpoint
114
- end
119
+ route_instance =
120
+ Route.new(
121
+ endpoint,
122
+ befores: @befores,
123
+ afters: @afters
124
+ )
125
+
126
+ return set_to_scope(send("#{v}_instances"), route_instance) if @scopes.size >= 1
115
127
 
116
- def add_error(endpoint)
117
- Errors.check_endpoint(endpoint, 'error')
128
+ instance_variable_set("@default_#{v}", route_instance)
129
+ end
130
+
131
+ define_method("#{v}_fallback") do |found_scopes, route_instance, request, error = nil|
132
+ args = [
133
+ match_route(
134
+ found_scopes,
135
+ send("#{v}_instances"),
136
+ instance_variable_get("@default_#{v}")
137
+ ).endpoint,
138
+ request
139
+ ]
140
+ args << error if error
141
+
142
+ endpoint_result = Endpoint.call(*args)
143
+
144
+ call_afters(route_instance, endpoint_result)
145
+
146
+ endpoint_result
147
+ end
148
+ end
118
149
 
119
- @error = endpoint
150
+ def call_afters(route_instance, endpoint_result)
151
+ afters = route_instance.afters
152
+ i = 0
153
+ while i < afters.size
154
+ Endpoint.call(afters[i], endpoint_result)
155
+ i += 1
156
+ end
120
157
  end
121
158
 
122
159
  def append_scope(name, scope_befores: [], scope_afters: [])
@@ -146,23 +183,6 @@ class Rackr
146
183
 
147
184
  private
148
185
 
149
- def call_endpoint(endpoint, content)
150
- return endpoint.call(content) if endpoint.respond_to?(:call)
151
-
152
- if endpoint < Rackr::Action || endpoint < Rackr::Callback
153
- return endpoint.new(routes: @routes, config: @config).call(content)
154
- end
155
-
156
- endpoint.new.call(content)
157
- end
158
-
159
- def ensure_array(list)
160
- return [] if list.nil?
161
- return list if list.is_a?(Array)
162
-
163
- [list]
164
- end
165
-
166
186
  def add_named_route(method, path_with_scopes, as)
167
187
  return @routes.send(method.downcase)[:root] = path_with_scopes if path_with_scopes == '/'
168
188
  return @routes.send(method.downcase)[as] = path_with_scopes unless as.nil?
@@ -172,17 +192,11 @@ class Rackr
172
192
  end
173
193
 
174
194
  def push_to_scope(method, route_instance)
175
- scopes_with_slash = not_empty_scopes + %i[__instances]
176
- push_it(@instance_routes[method], *scopes_with_slash, route_instance)
195
+ deep_hash_push(@path_routes_instances[method], *(not_empty_scopes + %i[__instances]), route_instance)
177
196
  end
178
197
 
179
- def push_it(hash, first_key, *rest_keys, val)
180
- if rest_keys.empty?
181
- (hash[first_key] ||= []) << val
182
- else
183
- hash[first_key] = push_it(hash[first_key] ||= {}, *rest_keys, val)
184
- end
185
- hash
198
+ def set_to_scope(instances, route_instance)
199
+ deep_hash_set(instances, (not_empty_scopes + %i[__instance]), route_instance)
186
200
  end
187
201
 
188
202
  def put_path_slash(path)
@@ -199,9 +213,9 @@ class Rackr
199
213
  @scopes.reject { |v| (v == '') }
200
214
  end
201
215
 
202
- def match_route(request_method)
216
+ def match_path_route(request_method)
203
217
  find_instance_in_scope = proc do |request_method, found_scopes|
204
- @instance_routes[request_method].dig(
218
+ @path_routes_instances[request_method].dig(
205
219
  *(found_scopes + [:__instances])
206
220
  )&.detect { |route_instance| route_instance.match?(@current_request_path_info) }
207
221
  end
@@ -209,38 +223,58 @@ class Rackr
209
223
  last_tail = @splitted_request_path_info.drop(1)
210
224
  found_scopes = []
211
225
 
212
- instance_routes = @instance_routes[request_method]
226
+ path_routes_instances = @path_routes_instances[request_method]
213
227
 
214
228
  while last_tail && !last_tail.empty?
215
229
  segment = last_tail.shift
216
230
  found_route = nil
217
231
 
218
- instance_routes.each_key do |scope|
232
+ path_routes_instances.each_key do |scope|
219
233
  next if scope == :__instances
220
234
 
221
235
  if segment == scope
222
236
  found_scopes << scope
223
- instance_routes = @instance_routes[request_method].dig(*found_scopes)
237
+ path_routes_instances = @path_routes_instances[request_method].dig(*found_scopes)
224
238
  break
225
239
  elsif scope.start_with?(':')
226
- found_route = find_instance_in_scope.(request_method, found_scopes)
240
+ found_route = find_instance_in_scope.call(request_method, found_scopes)
227
241
  return found_route if found_route
228
242
 
229
243
  found_scopes << scope
230
- instance_routes = @instance_routes[request_method].dig(*found_scopes)
244
+ path_routes_instances = @path_routes_instances[request_method].dig(*found_scopes)
231
245
  break
232
246
  end
233
247
  end
234
248
  end
235
249
 
236
- result_route = find_instance_in_scope.(request_method, found_scopes)
250
+ result_route = find_instance_in_scope.call(request_method, found_scopes)
251
+
252
+ if result_route.nil? && !found_scopes.empty?
253
+ result_route = find_instance_in_scope.call(request_method, found_scopes[..-2])
254
+ end
255
+
256
+ if result_route.nil?
257
+ result_route = match_route(
258
+ found_scopes,
259
+ @not_found_instances,
260
+ @default_not_found
261
+ )
262
+ end
263
+
264
+ [result_route, found_scopes]
265
+ end
266
+
267
+ def match_route(found_scopes, instances, default_instance)
268
+ route_instance = nil
237
269
 
238
- if result_route == nil && !found_scopes.empty?
239
- found_scopes.shift
240
- result_route = find_instance_in_scope.(request_method, found_scopes)
270
+ while route_instance.nil? && found_scopes != []
271
+ route_instance = instances&.dig(*(found_scopes + [:__instance]))
272
+ found_scopes.pop
241
273
  end
242
274
 
243
- result_route
275
+ return default_instance if route_instance.nil?
276
+
277
+ route_instance
244
278
  end
245
279
  end
246
280
  end
data/lib/rackr.rb CHANGED
@@ -18,11 +18,11 @@ class Rackr
18
18
 
19
19
  def call(&block)
20
20
  instance_eval(&block)
21
- puts "\n= Routes =============="
22
- routes.each_pair { |v| p v }
23
- puts "\n= Config =============="
24
- puts config
25
- puts "\n"
21
+ #puts "\n= Routes =============="
22
+ #routes.each_pair { |v| p v }
23
+ #puts "\n= Config =============="
24
+ #puts config
25
+ #puts "\n"
26
26
 
27
27
  @router
28
28
  end
@@ -35,8 +35,12 @@ class Rackr
35
35
  @router.config
36
36
  end
37
37
 
38
+ def deps
39
+ @router.config[:deps]
40
+ end
41
+
38
42
  def db
39
- @router.config[:db]
43
+ @router.config.dig(:deps, :db)
40
44
  end
41
45
 
42
46
  def scope(name = '', before: [], after: [], &block)
metadata CHANGED
@@ -1,13 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rackr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.63
4
+ version: 0.0.65
5
5
  platform: ruby
6
6
  authors:
7
7
  - Henrique F. Teixeira
8
+ autorequire:
8
9
  bindir: bin
9
10
  cert_chain: []
10
- date: 2025-10-14 00:00:00.000000000 Z
11
+ date: 2025-12-14 00:00:00.000000000 Z
11
12
  dependencies:
12
13
  - !ruby/object:Gem::Dependency
13
14
  name: erubi
@@ -57,7 +58,7 @@ dependencies:
57
58
  - - "<"
58
59
  - !ruby/object:Gem::Version
59
60
  version: '4.0'
60
- description: A complete, simple and easy web micro-framework.
61
+ description: A friendly web micro-framework.
61
62
  email: hriqueft@gmail.com
62
63
  executables: []
63
64
  extensions: []
@@ -75,6 +76,7 @@ homepage: https://github.com/henrique-ft/rackr
75
76
  licenses:
76
77
  - MIT
77
78
  metadata: {}
79
+ post_install_message:
78
80
  rdoc_options: []
79
81
  require_paths:
80
82
  - lib
@@ -89,7 +91,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
89
91
  - !ruby/object:Gem::Version
90
92
  version: '0'
91
93
  requirements: []
92
- rubygems_version: 3.6.2
94
+ rubygems_version: 3.3.3
95
+ signing_key:
93
96
  specification_version: 4
94
- summary: A complete, simple and easy web micro-framework.
97
+ summary: A friendly web micro-framework.
95
98
  test_files: []