lennarb 0.5.1 → 0.6.1
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 +8 -0
- data/lib/lennarb/application/base.rb +179 -186
- data/lib/lennarb/plugin.rb +20 -0
- data/lib/lennarb/version.rb +1 -1
- data/lib/lennarb.rb +12 -2
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d9cfd70e5b40a64d96f5cd52b748c32a36b796c43e6d490b4df64bc5fae3c781
|
4
|
+
data.tar.gz: ffc4abf90906f7378879a0d342e74922c01c6ae9d6d59855128d4fd3ec11d40c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6d1e7a05a3e931a3163b4103d9900c36163e72e738e0435bc4396fb5f3aeb3c6d044edbdfd8a7fde7512265df91d86dc01a719b7b58ffdf7dc10698a69c1016c
|
7
|
+
data.tar.gz: 75c64ac16b3fd3599e78c6a9dd04c951137d11b64b11685af4f9d7d0626331aa554564d8786914d129b93e128ebaa54015f0098b75626e5c74bd347e7ece2861
|
data/changelog.md
CHANGED
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
7
7
|
|
8
8
|
## [Unreleased]
|
9
9
|
|
10
|
+
## [0.6.1] - 2024-05-17
|
11
|
+
|
12
|
+
### Added
|
13
|
+
|
14
|
+
- Add `Lennarb::Plugin` module to manage the plugins in the project. Now, the `Lennarb` class is the main class of the project.
|
15
|
+
- Add `Lennarb::Plugin::Base` class to be the base class of the plugins in the project.
|
16
|
+
- Add simple guide to use `Lenn` plugins. See [guides/plugins/readme.md](guides/plugins/readme.md) for more details.
|
17
|
+
|
10
18
|
## [0.4.4] - 2024-04-02
|
11
19
|
|
12
20
|
### Added
|
@@ -32,107 +32,97 @@ class Lennarb
|
|
32
32
|
#
|
33
33
|
# @returns [Base]
|
34
34
|
#
|
35
|
-
def self.inherited(subclass)
|
36
|
-
subclass.instance_variable_set(:@_route, Lennarb.new)
|
37
|
-
subclass.instance_variable_set(:@_middlewares, [])
|
38
|
-
subclass.instance_variable_set(:@_global_after_hooks, [])
|
39
|
-
subclass.instance_variable_set(:@_global_before_hooks, [])
|
40
|
-
subclass.instance_variable_set(:@_after_hooks, Lennarb::RouteNode.new)
|
41
|
-
subclass.instance_variable_set(:@_before_hooks, Lennarb::RouteNode.new)
|
42
|
-
end
|
43
|
-
|
44
|
-
def self.get(...) = @_route.get(...)
|
45
|
-
def self.put(...) = @_route.put(...)
|
46
|
-
def self.post(...) = @_route.post(...)
|
47
|
-
def self.head(...) = @_route.head(...)
|
48
|
-
def self.match(...) = @_route.match(...)
|
49
|
-
def self.patch(...) = @_route.patch(...)
|
50
|
-
def self.delete(...) = @_route.delete(...)
|
51
|
-
def self.options(...) = @_route.options(...)
|
52
35
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
# @returns [Array] middlewares
|
63
|
-
#
|
64
|
-
def self.use(middleware, *args, &block)
|
65
|
-
@_middlewares << [middleware, args, block]
|
66
|
-
end
|
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
|
67
45
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
46
|
+
def get(path, &) = @_route.get(path, &)
|
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]
|
79
68
|
end
|
80
|
-
end
|
81
69
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
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
|
93
82
|
end
|
94
|
-
end
|
95
83
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
# - Rack::Head
|
109
|
-
# - Rack::ContentLength
|
110
|
-
# - Rack::Static
|
111
|
-
#
|
112
|
-
def self.run!
|
113
|
-
stack = Rack::Builder.new
|
114
|
-
|
115
|
-
use Rack::ShowExceptions
|
116
|
-
use Rack::Lint
|
117
|
-
use Rack::MethodOverride
|
118
|
-
use Rack::Head
|
119
|
-
use Rack::ContentLength
|
120
|
-
use Rack::Static,
|
121
|
-
root: 'public',
|
122
|
-
urls: ['/404.html', '/500.html'],
|
123
|
-
header_rules: [
|
124
|
-
[200, %w[html], { 'content-type' => 'text/html; charset=utf-8' }],
|
125
|
-
[400, %w[html], { 'content-type' => 'text/html; charset=utf-8' }],
|
126
|
-
[500, %w[html], { 'content-type' => 'text/html; charset=utf-8' }]
|
127
|
-
]
|
128
|
-
|
129
|
-
middlewares.each do |(middleware, args, block)|
|
130
|
-
stack.use(middleware, *args, &block)
|
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
|
131
96
|
end
|
132
97
|
|
133
|
-
|
134
|
-
|
135
|
-
|
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
|
136
126
|
execute_hooks(@_before_hooks, env, :before)
|
137
127
|
res = @_route.call(env)
|
138
128
|
execute_hooks(@_after_hooks, env, :after)
|
@@ -143,110 +133,113 @@ class Lennarb
|
|
143
133
|
puts e.message.red
|
144
134
|
puts e.backtrace
|
145
135
|
raise e
|
146
|
-
end.then do |response|
|
147
|
-
case response
|
148
|
-
in [400..499, _, _] then render_not_found
|
149
|
-
else response
|
150
|
-
end
|
151
136
|
end
|
152
137
|
end
|
153
|
-
end
|
154
138
|
|
155
|
-
|
139
|
+
@_route.freeze!
|
156
140
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
def self.test? = ENV['RACK_ENV'] == 'test' || ENV['LENNARB_ENV'] == 'test'
|
161
|
-
def self.production? = ENV['RACK_ENV'] == 'production' || ENV['LENNARB_ENV'] == 'production'
|
162
|
-
def self.development? = ENV['RACK_ENV'] == 'development' || ENV['LENNARB_ENV'] == 'development'
|
163
|
-
|
164
|
-
# Render a not found
|
165
|
-
#
|
166
|
-
# @returns [void]
|
167
|
-
#
|
168
|
-
def self.render_not_found(content = nil)
|
169
|
-
default = File.exist?('public/404.html')
|
170
|
-
body = content || default || 'Not Found'
|
171
|
-
throw :halt, [404, { 'content-type' => 'text/html' }, [body]]
|
172
|
-
end
|
173
|
-
|
174
|
-
# Render an error
|
175
|
-
#
|
176
|
-
# @returns [void]
|
177
|
-
#
|
178
|
-
def self.render_error(content = nil)
|
179
|
-
default = File.exist?('public/500.html')
|
180
|
-
body = content || default || 'Internal Server Error'
|
181
|
-
throw :halt, [500, { 'content-type' => 'text/html' }, [body]]
|
182
|
-
end
|
141
|
+
stack.to_app
|
142
|
+
end
|
183
143
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
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
|
190
157
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
execute_global_hooks(env, action)
|
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
|
201
167
|
|
202
|
-
|
203
|
-
|
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
|
+
# To use a plugin
|
176
|
+
#
|
177
|
+
# @parameter [String | Symbol] plugin_name
|
178
|
+
#
|
179
|
+
# @returns [void]
|
180
|
+
#
|
181
|
+
def plugin(plugin_name) = @_route.plugin(plugin_name)
|
182
|
+
|
183
|
+
private
|
184
|
+
|
185
|
+
# Execute the hooks
|
186
|
+
#
|
187
|
+
# @parameter [RouteNode] hook_route
|
188
|
+
# @parameter [Hash] env
|
189
|
+
# @parameter [Symbol] action
|
190
|
+
#
|
191
|
+
# @returns [void]
|
192
|
+
#
|
193
|
+
def execute_hooks(hook_route, env, action)
|
194
|
+
execute_global_hooks(env, action)
|
195
|
+
|
196
|
+
execute_route_hooks(hook_route, env, action)
|
197
|
+
end
|
204
198
|
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
199
|
+
# Execute the global hooks
|
200
|
+
#
|
201
|
+
# @parameter [Hash] env
|
202
|
+
# @parameter [Symbol] action
|
203
|
+
#
|
204
|
+
# @returns [void]
|
205
|
+
#
|
206
|
+
def execute_global_hooks(env, action)
|
207
|
+
global_hooks = action == :before ? @_global_before_hooks : @_global_after_hooks
|
208
|
+
global_hooks.each { |hook| hook.call(env) }
|
209
|
+
end
|
216
210
|
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
211
|
+
# Execute the route hooks
|
212
|
+
#
|
213
|
+
# @parameter [RouteNode] hook_route
|
214
|
+
# @parameter [Hash] env
|
215
|
+
# @parameter [Symbol] action
|
216
|
+
#
|
217
|
+
# @returns [void]
|
218
|
+
#
|
219
|
+
def execute_route_hooks(hook_route, env, action)
|
220
|
+
parts = parse_path(env)
|
221
|
+
return unless parts
|
222
|
+
|
223
|
+
block, = hook_route.match_route(parts, action)
|
224
|
+
block&.call(env)
|
225
|
+
end
|
228
226
|
|
229
|
-
|
230
|
-
|
227
|
+
# Parse the path
|
228
|
+
#
|
229
|
+
# @parameter [Hash] env
|
230
|
+
#
|
231
|
+
# @returns [Array] parts
|
232
|
+
#
|
233
|
+
def parse_path(env) = env[Rack::PATH_INFO]&.split('/')&.reject(&:empty?)
|
234
|
+
|
235
|
+
# Check if the request is a HTML request
|
236
|
+
#
|
237
|
+
# @parameter [Hash] env
|
238
|
+
#
|
239
|
+
# @returns [Boolean]
|
240
|
+
#
|
241
|
+
def html_request?(env) = env['HTTP_ACCEPT']&.include?('text/html')
|
231
242
|
end
|
232
|
-
|
233
|
-
# Parse the path
|
234
|
-
#
|
235
|
-
# @parameter [Hash] env
|
236
|
-
#
|
237
|
-
# @returns [Array] parts
|
238
|
-
#
|
239
|
-
def self.parse_path(env) = env[Rack::PATH_INFO]&.split('/')&.reject(&:empty?)
|
240
|
-
|
241
|
-
# Check if the request is a HTML request
|
242
|
-
#
|
243
|
-
# @parameter [Hash] env
|
244
|
-
#
|
245
|
-
# @returns [Boolean]
|
246
|
-
#
|
247
|
-
def self.html_request?(env) = env['HTTP_ACCEPT']&.include?('text/html')
|
248
|
-
|
249
|
-
private_class_method :execute_hooks, :execute_global_hooks, :execute_route_hooks, :parse_path, :html_request?
|
250
243
|
end
|
251
244
|
end
|
252
245
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2023-2024, by Aristóteles Coutinho.
|
5
|
+
|
6
|
+
class Lennarb
|
7
|
+
module Plugin
|
8
|
+
@plugins = {}
|
9
|
+
|
10
|
+
def self.register(name, mod)
|
11
|
+
@plugins[name] = mod
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.load(name)
|
15
|
+
@plugins[name] || raise("Plugin #{name} did not register itself correctly")
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.plugins = @plugins
|
19
|
+
end
|
20
|
+
end
|
data/lib/lennarb/version.rb
CHANGED
data/lib/lennarb.rb
CHANGED
@@ -3,8 +3,6 @@
|
|
3
3
|
# Released under the MIT License.
|
4
4
|
# Copyright, 2023-2024, by Aristóteles Coutinho.
|
5
5
|
|
6
|
-
ENV['RACK_ENV'] ||= 'development'
|
7
|
-
|
8
6
|
# Core extensions
|
9
7
|
#
|
10
8
|
require 'pathname'
|
@@ -13,6 +11,7 @@ require 'rack'
|
|
13
11
|
# Base class for Lennarb
|
14
12
|
#
|
15
13
|
require_relative 'lennarb/application/base'
|
14
|
+
require_relative 'lennarb/plugin'
|
16
15
|
require_relative 'lennarb/request'
|
17
16
|
require_relative 'lennarb/response'
|
18
17
|
require_relative 'lennarb/route_node'
|
@@ -91,6 +90,17 @@ class Lennarb
|
|
91
90
|
def delete(path, &block) = add_route(path, :DELETE, block)
|
92
91
|
def options(path, &block) = add_route(path, :OPTIONS, block)
|
93
92
|
|
93
|
+
# Register a plugin
|
94
|
+
#
|
95
|
+
# @parameter [String | Symbol] plugin_name
|
96
|
+
#
|
97
|
+
# @returns [void]
|
98
|
+
#
|
99
|
+
def plugin(plugin_name)
|
100
|
+
plugin_module = Lennarb::Plugin.load(plugin_name)
|
101
|
+
extend plugin_module
|
102
|
+
end
|
103
|
+
|
94
104
|
private
|
95
105
|
|
96
106
|
# Add a route
|
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: 0.
|
4
|
+
version: 0.6.1
|
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-05-
|
11
|
+
date: 2024-05-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colorize
|
@@ -181,6 +181,7 @@ files:
|
|
181
181
|
- exe/lenna
|
182
182
|
- lib/lennarb.rb
|
183
183
|
- lib/lennarb/application/base.rb
|
184
|
+
- lib/lennarb/plugin.rb
|
184
185
|
- lib/lennarb/request.rb
|
185
186
|
- lib/lennarb/response.rb
|
186
187
|
- lib/lennarb/route_node.rb
|