lennarb 0.5.1 → 0.6.1

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: ff30294350acea0efb5cf2c074d256472f99300d46fee6fe0ea9cadfb375e151
4
- data.tar.gz: d96ea3d9ade277730f83fa0b011d3396d73be3ba8692229c5ad98cfd72f48ea4
3
+ metadata.gz: d9cfd70e5b40a64d96f5cd52b748c32a36b796c43e6d490b4df64bc5fae3c781
4
+ data.tar.gz: ffc4abf90906f7378879a0d342e74922c01c6ae9d6d59855128d4fd3ec11d40c
5
5
  SHA512:
6
- metadata.gz: a5aad4351361de62499992df5f53ac8ec5f8b42f3cd1b207d108ac137404ab6e4e103f394193ae58c847195cc97fe53d475d275e542840360b4d61dfe74474c4
7
- data.tar.gz: 55661804a4cb178b3365534c5df7a3c7653ecbe07e598b04ae4edfda64f0ada02edcd03ff08cc6f3004a519f5b1df80da4eccc1f4b2a6162d14166e6786f471e
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
- # @returns [Array] middlewares
54
- def self.middlewares = @_middlewares
55
-
56
- # Use a middleware
57
- #
58
- # @parameter [Object] middleware
59
- # @parameter [Array] args
60
- # @parameter [Block] block
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
- # Add a before hook
69
- #
70
- # @parameter [String] path
71
- # @parameter [Block] block
72
- #
73
- def self.before(path = nil, &block)
74
- if path
75
- parts = path.split('/').reject(&:empty?)
76
- @_before_hooks.add_route(parts, :before, block)
77
- else
78
- @_global_before_hooks << block
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
- # Add a after hook
83
- #
84
- # @parameter [String] path
85
- # @parameter [Block] block
86
- #
87
- def self.after(path = nil, &block)
88
- if path
89
- parts = path.split('/').reject(&:empty?)
90
- @_after_hooks.add_route(parts, :after, block)
91
- else
92
- @_global_after_hooks << block
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
- # Run the Application
97
- #
98
- # @returns [Base] self
99
- #
100
- # When you use this method, the application will be frozen. And you can't add more routes after that.
101
- # This method is used to run the application in a Rack server so, you can use the `rackup` command
102
- # to run the application.
103
- # Ex. rackup -p 3000
104
- # This command will use the following middleware:
105
- # - Rack::ShowExceptions
106
- # - Rack::Lint
107
- # - Rack::MethodOverride
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
- stack.run ->(env) do
134
- catch(:halt) do
135
- begin
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
- @_route.freeze!
139
+ @_route.freeze!
156
140
 
157
- stack.to_app
158
- end
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
- # Redirect to a path
185
- #
186
- # @parameter [String] path
187
- # @parameter [Integer] status default is 302
188
- #
189
- def self.redirect(path, status = 302) = throw :halt, [status, { 'location' => path }, []]
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
- # Execute the hooks
192
- #
193
- # @parameter [RouteNode] hook_route
194
- # @parameter [Hash] env
195
- # @parameter [Symbol] action
196
- #
197
- # @returns [void]
198
- #
199
- def self.execute_hooks(hook_route, env, action)
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
- execute_route_hooks(hook_route, env, action)
203
- end
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
- # Execute the global hooks
206
- #
207
- # @parameter [Hash] env
208
- # @parameter [Symbol] action
209
- #
210
- # @returns [void]
211
- #
212
- def self.execute_global_hooks(env, action)
213
- global_hooks = action == :before ? @_global_before_hooks : @_global_after_hooks
214
- global_hooks.each { |hook| hook.call(env) }
215
- end
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
- # Execute the route hooks
218
- #
219
- # @parameter [RouteNode] hook_route
220
- # @parameter [Hash] env
221
- # @parameter [Symbol] action
222
- #
223
- # @returns [void]
224
- #
225
- def self.execute_route_hooks(hook_route, env, action)
226
- parts = parse_path(env)
227
- return unless parts
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
- block, = hook_route.match_route(parts, action)
230
- block&.call(env)
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
@@ -4,7 +4,7 @@
4
4
  # Copyright, 2023-2024, by Aristóteles Coutinho.
5
5
 
6
6
  class Lennarb
7
- VERSION = '0.5.1'
7
+ VERSION = '0.6.1'
8
8
 
9
9
  public_constant :VERSION
10
10
  end
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.5.1
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-05 00:00:00.000000000 Z
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