lennarb 1.1.0 → 1.3.0
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 +4 -4
- data/changelog.md +20 -0
- data/lib/lennarb/plugin.rb +45 -31
- data/lib/lennarb/plugins/hooks.rb +117 -0
- data/lib/lennarb/plugins/mount.rb +66 -0
- data/lib/lennarb/request.rb +76 -37
- data/lib/lennarb/response.rb +133 -133
- data/lib/lennarb/route_node.rb +50 -56
- data/lib/lennarb/version.rb +2 -2
- data/lib/lennarb.rb +140 -114
- data/license.md +1 -2
- metadata +5 -4
- data/lib/lennarb/application/base.rb +0 -253
data/license.md
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# MIT License
|
2
2
|
|
3
|
-
Copyright
|
4
|
-
Copyright, 2023, by aristotelesbr.
|
3
|
+
Copyright (c) 2023-2025 Aristótels Coutinho
|
5
4
|
|
6
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
6
|
of this software and associated documentation files (the "Software"), to deal
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lennarb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aristóteles Coutinho
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-11-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colorize
|
@@ -180,8 +180,9 @@ files:
|
|
180
180
|
- changelog.md
|
181
181
|
- exe/lenna
|
182
182
|
- lib/lennarb.rb
|
183
|
-
- lib/lennarb/application/base.rb
|
184
183
|
- lib/lennarb/plugin.rb
|
184
|
+
- lib/lennarb/plugins/hooks.rb
|
185
|
+
- lib/lennarb/plugins/mount.rb
|
185
186
|
- lib/lennarb/request.rb
|
186
187
|
- lib/lennarb/response.rb
|
187
188
|
- lib/lennarb/route_node.rb
|
@@ -212,7 +213,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
212
213
|
- !ruby/object:Gem::Version
|
213
214
|
version: '0'
|
214
215
|
requirements: []
|
215
|
-
rubygems_version: 3.5.
|
216
|
+
rubygems_version: 3.5.23
|
216
217
|
signing_key:
|
217
218
|
specification_version: 4
|
218
219
|
summary: Lennarb provides a lightweight yet robust solution for web routing in Ruby,
|
@@ -1,253 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Released under the MIT License.
|
4
|
-
# Copyright, 2023-2024, by Aristóteles Coutinho.
|
5
|
-
|
6
|
-
require 'colorize'
|
7
|
-
|
8
|
-
class Lennarb
|
9
|
-
module Application
|
10
|
-
class Base
|
11
|
-
# @attribute [r] _route
|
12
|
-
# @returns [RouteNode]
|
13
|
-
#
|
14
|
-
# @attribute [r] _middlewares
|
15
|
-
# @returns [Array]
|
16
|
-
#
|
17
|
-
# @attribute [r] _global_after_hooks
|
18
|
-
# @returns [Array]
|
19
|
-
#
|
20
|
-
# @attribute [r] _global_before_hooks
|
21
|
-
# @returns [Array]
|
22
|
-
#
|
23
|
-
# @attribute [r] _after_hooks
|
24
|
-
# @returns [RouteNode]
|
25
|
-
#
|
26
|
-
# @attribute [r] _before_hooks
|
27
|
-
# @returns [RouteNode]
|
28
|
-
#
|
29
|
-
attr_accessor :_route, :_global_after_hooks, :_global_before_hooks, :_after_hooks, :_before_hooks
|
30
|
-
|
31
|
-
# Initialize the Application
|
32
|
-
#
|
33
|
-
# @returns [Base]
|
34
|
-
#
|
35
|
-
|
36
|
-
class << self
|
37
|
-
def inherited(subclass)
|
38
|
-
subclass.instance_variable_set(:@_route, Lennarb.new)
|
39
|
-
subclass.instance_variable_set(:@_middlewares, [])
|
40
|
-
subclass.instance_variable_set(:@_global_after_hooks, [])
|
41
|
-
subclass.instance_variable_set(:@_global_before_hooks, [])
|
42
|
-
subclass.instance_variable_set(:@_after_hooks, Lennarb::RouteNode.new)
|
43
|
-
subclass.instance_variable_set(:@_before_hooks, Lennarb::RouteNode.new)
|
44
|
-
end
|
45
|
-
|
46
|
-
def get(...) = @_route.get(...)
|
47
|
-
def put(...) = @_route.put(...)
|
48
|
-
def post(...) = @_route.post(...)
|
49
|
-
def head(...) = @_route.head(...)
|
50
|
-
def match(...) = @_route.match(...)
|
51
|
-
def patch(...) = @_route.patch(...)
|
52
|
-
def delete(...) = @_route.delete(...)
|
53
|
-
def options(...) = @_route.options(...)
|
54
|
-
|
55
|
-
# @returns [Array] middlewares
|
56
|
-
def middlewares = @_middlewares
|
57
|
-
|
58
|
-
# Use a middleware
|
59
|
-
#
|
60
|
-
# @parameter [Object] middleware
|
61
|
-
# @parameter [Array] args
|
62
|
-
# @parameter [Block] block
|
63
|
-
#
|
64
|
-
# @returns [Array] middlewares
|
65
|
-
#
|
66
|
-
def use(middleware, *args, &block)
|
67
|
-
@_middlewares << [middleware, args, block]
|
68
|
-
end
|
69
|
-
|
70
|
-
# Add a before hook
|
71
|
-
#
|
72
|
-
# @parameter [String] path
|
73
|
-
# @parameter [Block] block
|
74
|
-
#
|
75
|
-
def before(path = nil, &block)
|
76
|
-
if path
|
77
|
-
parts = path.split('/').reject(&:empty?)
|
78
|
-
@_before_hooks.add_route(parts, :before, block)
|
79
|
-
else
|
80
|
-
@_global_before_hooks << block
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
# Add a after hook
|
85
|
-
#
|
86
|
-
# @parameter [String] path
|
87
|
-
# @parameter [Block] block
|
88
|
-
#
|
89
|
-
def after(path = nil, &block)
|
90
|
-
if path
|
91
|
-
parts = path.split('/').reject(&:empty?)
|
92
|
-
@_after_hooks.add_route(parts, :after, block)
|
93
|
-
else
|
94
|
-
@_global_after_hooks << block
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
# Run the Application
|
99
|
-
#
|
100
|
-
# @returns [Base] self
|
101
|
-
#
|
102
|
-
# When you use this method, the application will be frozen. And you can't add more routes after that.
|
103
|
-
# This method is used to run the application in a Rack server so, you can use the `rackup` command
|
104
|
-
# to run the application.
|
105
|
-
# Ex. rackup -p 3000
|
106
|
-
# This command will use the following middleware:
|
107
|
-
# - Rack::ShowExceptions
|
108
|
-
# - Rack::MethodOverride
|
109
|
-
# - Rack::Head
|
110
|
-
# - Rack::ContentLength
|
111
|
-
#
|
112
|
-
def run!
|
113
|
-
stack = Rack::Builder.new
|
114
|
-
|
115
|
-
use Rack::ShowExceptions if test? || development?
|
116
|
-
use Rack::MethodOverride
|
117
|
-
use Rack::Head
|
118
|
-
use Rack::ContentLength
|
119
|
-
|
120
|
-
middlewares.each do |(middleware, args, block)|
|
121
|
-
stack.use(middleware, *args, &block)
|
122
|
-
end
|
123
|
-
|
124
|
-
stack.run ->(env) do
|
125
|
-
catch(:halt) do
|
126
|
-
execute_hooks(@_before_hooks, env, :before)
|
127
|
-
res = @_route.call(env)
|
128
|
-
execute_hooks(@_after_hooks, env, :after)
|
129
|
-
res
|
130
|
-
rescue StandardError => e
|
131
|
-
render_error if production?
|
132
|
-
|
133
|
-
puts e.message.red
|
134
|
-
puts e.backtrace
|
135
|
-
raise e
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
@_route.freeze!
|
140
|
-
|
141
|
-
stack.to_app
|
142
|
-
end
|
143
|
-
|
144
|
-
def test? = ENV['RACK_ENV'] == 'test' || ENV['LENNARB_ENV'] == 'test'
|
145
|
-
def production? = ENV['RACK_ENV'] == 'production' || ENV['LENNARB_ENV'] == 'production'
|
146
|
-
def development? = ENV['RACK_ENV'] == 'development' || ENV['LENNARB_ENV'] == 'development'
|
147
|
-
|
148
|
-
# Render a not found
|
149
|
-
#
|
150
|
-
# @returns [void]
|
151
|
-
#
|
152
|
-
def render_not_found(content = nil)
|
153
|
-
default = File.exist?('public/404.html')
|
154
|
-
body = content || default || 'Not Found'
|
155
|
-
throw :halt, [404, { 'content-type' => 'text/html' }, [body]]
|
156
|
-
end
|
157
|
-
|
158
|
-
# Render an error
|
159
|
-
#
|
160
|
-
# @returns [void]
|
161
|
-
#
|
162
|
-
def render_error(content = nil)
|
163
|
-
default = File.exist?('public/500.html')
|
164
|
-
body = content || default || 'Internal Server Error'
|
165
|
-
throw :halt, [500, { 'content-type' => 'text/html' }, [body]]
|
166
|
-
end
|
167
|
-
|
168
|
-
# Redirect to a path
|
169
|
-
#
|
170
|
-
# @parameter [String] path
|
171
|
-
# @parameter [Integer] status default is 302
|
172
|
-
#
|
173
|
-
def redirect(path, status = 302) = throw :halt, [status, { 'location' => path }, []]
|
174
|
-
|
175
|
-
# Include a plugin in the application
|
176
|
-
#
|
177
|
-
# @parameter [String] plugin_name
|
178
|
-
# @parameter [Array] args
|
179
|
-
# @parameter [Block] block
|
180
|
-
#
|
181
|
-
# @returns [void]
|
182
|
-
#
|
183
|
-
def plugin(plugin_name, *, &)
|
184
|
-
@_route.plugin(plugin_name, *, &)
|
185
|
-
plugin_module = @_route.class::Plugin.load(plugin_name)
|
186
|
-
|
187
|
-
include plugin_module::InstanceMethods if plugin_module.const_defined?(:InstanceMethods)
|
188
|
-
extend plugin_module::ClassMethods if plugin_module.const_defined?(:ClassMethods)
|
189
|
-
end
|
190
|
-
|
191
|
-
private
|
192
|
-
|
193
|
-
# Execute the hooks
|
194
|
-
#
|
195
|
-
# @parameter [RouteNode] hook_route
|
196
|
-
# @parameter [Hash] env
|
197
|
-
# @parameter [Symbol] action
|
198
|
-
#
|
199
|
-
# @returns [void]
|
200
|
-
#
|
201
|
-
def execute_hooks(hook_route, env, action)
|
202
|
-
execute_global_hooks(env, action)
|
203
|
-
|
204
|
-
execute_route_hooks(hook_route, env, action)
|
205
|
-
end
|
206
|
-
|
207
|
-
# Execute the global hooks
|
208
|
-
#
|
209
|
-
# @parameter [Hash] env
|
210
|
-
# @parameter [Symbol] action
|
211
|
-
#
|
212
|
-
# @returns [void]
|
213
|
-
#
|
214
|
-
def execute_global_hooks(env, action)
|
215
|
-
global_hooks = action == :before ? @_global_before_hooks : @_global_after_hooks
|
216
|
-
global_hooks.each { |hook| hook.call(env) }
|
217
|
-
end
|
218
|
-
|
219
|
-
# Execute the route hooks
|
220
|
-
#
|
221
|
-
# @parameter [RouteNode] hook_route
|
222
|
-
# @parameter [Hash] env
|
223
|
-
# @parameter [Symbol] action
|
224
|
-
#
|
225
|
-
# @returns [void]
|
226
|
-
#
|
227
|
-
def execute_route_hooks(hook_route, env, action)
|
228
|
-
parts = parse_path(env)
|
229
|
-
return unless parts
|
230
|
-
|
231
|
-
block, = hook_route.match_route(parts, action)
|
232
|
-
block&.call(env)
|
233
|
-
end
|
234
|
-
|
235
|
-
# Parse the path
|
236
|
-
#
|
237
|
-
# @parameter [Hash] env
|
238
|
-
#
|
239
|
-
# @returns [Array] parts
|
240
|
-
#
|
241
|
-
def parse_path(env) = env[Rack::PATH_INFO]&.split('/')&.reject(&:empty?)
|
242
|
-
|
243
|
-
# Check if the request is a HTML request
|
244
|
-
#
|
245
|
-
# @parameter [Hash] env
|
246
|
-
#
|
247
|
-
# @returns [Boolean]
|
248
|
-
#
|
249
|
-
def html_request?(env) = env['HTTP_ACCEPT']&.include?('text/html')
|
250
|
-
end
|
251
|
-
end
|
252
|
-
end
|
253
|
-
end
|