lennarb 0.5.0 → 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 +190 -181
- data/lib/lennarb/plugin.rb +20 -0
- data/lib/lennarb/version.rb +1 -1
- data/lib/lennarb.rb +12 -2
- metadata +3 -30
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
|
@@ -3,6 +3,8 @@
|
|
3
3
|
# Released under the MIT License.
|
4
4
|
# Copyright, 2023-2024, by Aristóteles Coutinho.
|
5
5
|
|
6
|
+
require 'colorize'
|
7
|
+
|
6
8
|
class Lennarb
|
7
9
|
module Application
|
8
10
|
class Base
|
@@ -30,207 +32,214 @@ class Lennarb
|
|
30
32
|
#
|
31
33
|
# @returns [Base]
|
32
34
|
#
|
33
|
-
def self.inherited(subclass)
|
34
|
-
subclass.instance_variable_set(:@_route, Lennarb.new)
|
35
|
-
subclass.instance_variable_set(:@_middlewares, [])
|
36
|
-
subclass.instance_variable_set(:@_global_after_hooks, [])
|
37
|
-
subclass.instance_variable_set(:@_global_before_hooks, [])
|
38
|
-
subclass.instance_variable_set(:@_after_hooks, Lennarb::RouteNode.new)
|
39
|
-
subclass.instance_variable_set(:@_before_hooks, Lennarb::RouteNode.new)
|
40
|
-
end
|
41
|
-
|
42
|
-
def self.get(...) = @_route.get(...)
|
43
|
-
def self.put(...) = @_route.put(...)
|
44
|
-
def self.post(...) = @_route.post(...)
|
45
|
-
def self.head(...) = @_route.head(...)
|
46
|
-
def self.match(...) = @_route.match(...)
|
47
|
-
def self.patch(...) = @_route.patch(...)
|
48
|
-
def self.delete(...) = @_route.delete(...)
|
49
|
-
def self.options(...) = @_route.options(...)
|
50
|
-
|
51
|
-
# @returns [Array] middlewares
|
52
|
-
def self.middlewares = @_middlewares
|
53
35
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
def self.use(middleware, *args, &block)
|
63
|
-
@_middlewares << [middleware, args, block]
|
64
|
-
end
|
65
|
-
|
66
|
-
# Add a before hook
|
67
|
-
#
|
68
|
-
# @parameter [String] path
|
69
|
-
# @parameter [Block] block
|
70
|
-
#
|
71
|
-
def self.before(path = nil, &block)
|
72
|
-
if path
|
73
|
-
parts = path.split('/').reject(&:empty?)
|
74
|
-
@_before_hooks.add_route(parts, :before, block)
|
75
|
-
else
|
76
|
-
@_global_before_hooks << block
|
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)
|
77
44
|
end
|
78
|
-
end
|
79
45
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
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]
|
91
68
|
end
|
92
|
-
end
|
93
69
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
res = @_route.call(env)
|
106
|
-
|
107
|
-
execute_hooks(@_after_hooks, env, :after)
|
108
|
-
res
|
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
|
109
81
|
end
|
110
|
-
|
111
|
-
case response
|
112
|
-
in [404 | 404, _, _] if html_request?(env) && File.exist?('public/404.html')
|
113
|
-
env['PATH_INFO'] = '/404.html'
|
114
|
-
Rack::Static.new(-> { response }, urls: ['/404.html'], root: 'public').call(env)
|
115
|
-
in [404 | 404, _, _] then response
|
116
|
-
else
|
117
|
-
response.is_a?(Array) ? response : response.finish
|
118
82
|
end
|
119
|
-
end
|
120
83
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
# - Rack::ContentLength
|
134
|
-
# - Rack::Static
|
135
|
-
#
|
136
|
-
def self.run!
|
137
|
-
stack = Rack::Builder.new
|
138
|
-
|
139
|
-
use Rack::ShowExceptions
|
140
|
-
use Rack::Lint
|
141
|
-
use Rack::MethodOverride
|
142
|
-
use Rack::Head
|
143
|
-
use Rack::ContentLength
|
144
|
-
use Rack::Static,
|
145
|
-
root: 'public',
|
146
|
-
urls: ['/404.html'],
|
147
|
-
header_rules: [
|
148
|
-
[200, %w[html], { 'content-type' => 'text/html; charset=utf-8' }]
|
149
|
-
]
|
150
|
-
|
151
|
-
middlewares.each do |(middleware, args, block)|
|
152
|
-
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
|
153
96
|
end
|
154
97
|
|
155
|
-
|
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
|
156
123
|
|
157
|
-
|
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
|
158
138
|
|
159
|
-
|
139
|
+
@_route.freeze!
|
160
140
|
|
161
|
-
|
162
|
-
|
141
|
+
stack.to_app
|
142
|
+
end
|
163
143
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
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
|
174
157
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
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
|
185
167
|
|
186
|
-
|
187
|
-
|
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
|
188
198
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
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
|
200
210
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
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
|
212
226
|
|
213
|
-
|
214
|
-
|
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')
|
215
242
|
end
|
216
|
-
|
217
|
-
# Parse the path
|
218
|
-
#
|
219
|
-
# @parameter [Hash] env
|
220
|
-
#
|
221
|
-
# @returns [Array] parts
|
222
|
-
#
|
223
|
-
def self.parse_path(env) = env[Rack::PATH_INFO]&.split('/')&.reject(&:empty?)
|
224
|
-
|
225
|
-
# Check if the request is a HTML request
|
226
|
-
#
|
227
|
-
# @parameter [Hash] env
|
228
|
-
#
|
229
|
-
# @returns [Boolean]
|
230
|
-
#
|
231
|
-
def self.html_request?(env) = env['HTTP_ACCEPT']&.include?('text/html')
|
232
|
-
|
233
|
-
private_class_method :execute_hooks, :execute_global_hooks, :execute_route_hooks, :parse_path, :html_request?
|
234
243
|
end
|
235
244
|
end
|
236
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
|
@@ -44,34 +44,6 @@ dependencies:
|
|
44
44
|
- - ">="
|
45
45
|
- !ruby/object:Gem::Version
|
46
46
|
version: 3.0.8
|
47
|
-
- !ruby/object:Gem::Dependency
|
48
|
-
name: rack-protection
|
49
|
-
requirement: !ruby/object:Gem::Requirement
|
50
|
-
requirements:
|
51
|
-
- - "~>"
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: '4.0'
|
54
|
-
type: :runtime
|
55
|
-
prerelease: false
|
56
|
-
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
requirements:
|
58
|
-
- - "~>"
|
59
|
-
- !ruby/object:Gem::Version
|
60
|
-
version: '4.0'
|
61
|
-
- !ruby/object:Gem::Dependency
|
62
|
-
name: rack-session
|
63
|
-
requirement: !ruby/object:Gem::Requirement
|
64
|
-
requirements:
|
65
|
-
- - "~>"
|
66
|
-
- !ruby/object:Gem::Version
|
67
|
-
version: '2.0'
|
68
|
-
type: :runtime
|
69
|
-
prerelease: false
|
70
|
-
version_requirements: !ruby/object:Gem::Requirement
|
71
|
-
requirements:
|
72
|
-
- - "~>"
|
73
|
-
- !ruby/object:Gem::Version
|
74
|
-
version: '2.0'
|
75
47
|
- !ruby/object:Gem::Dependency
|
76
48
|
name: bake
|
77
49
|
requirement: !ruby/object:Gem::Requirement
|
@@ -209,6 +181,7 @@ files:
|
|
209
181
|
- exe/lenna
|
210
182
|
- lib/lennarb.rb
|
211
183
|
- lib/lennarb/application/base.rb
|
184
|
+
- lib/lennarb/plugin.rb
|
212
185
|
- lib/lennarb/request.rb
|
213
186
|
- lib/lennarb/response.rb
|
214
187
|
- lib/lennarb/route_node.rb
|