lennarb 1.2.0 → 1.4.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.
data/readme.md CHANGED
@@ -1,8 +1,19 @@
1
- # Lennarb
1
+ <div align="center">
2
+ <picture>
3
+ <img alt="Lennarb" src="logo/lennarb.png" width="250">
4
+ </picture>
2
5
 
3
- Lennarb is a lightweight, fast, and modular web framework for Ruby based on Rack. The **Lennarb** supports Ruby (MRI) 3.0+
6
+ ---
4
7
 
5
- **Basic Usage**
8
+ A lightweight, fast, and modular web framework for Ruby based on Rack. The **Lennarb** supports Ruby (MRI) 3.4+
9
+
10
+ [![Tests](https://github.com/aristotelesbr/lennarb/workflows/rubyby-tests/badge.svg)](https://github.com/aristotelesbr/lennarb)
11
+ [![Gem](https://img.shields.io/gem/v/lennarb.svg)](https://rubygems.org/gems/lennarb)
12
+ [![Gem](https://img.shields.io/gem/dt/lennarb.svg)](https://rubygems.org/gems/lennarb)
13
+ [![MIT License](https://img.shields.io/:License-MIT-blue.svg)](https://tldrlegal.com/license/mit-license)
14
+ </div>
15
+
16
+ ## Basic Usage
6
17
 
7
18
  ```ruby
8
19
  require "lennarb"
@@ -36,13 +47,13 @@ Plese see [Performance](https://aristotelesbr.github.io/lennarb/guides/performan
36
47
 
37
48
  ## Usage
38
49
 
39
- - [Getting Started](https://aristotelesbr.github.io/lennarb/guides/getting-started/index) - This guide covers getting up and running with **Lennarb**.
50
+ - [Getting Started](https://aristotelesbr.github.io/lennarb/guides/getting-started/index) - This guide covers getting up and running with **Lennarb**.
40
51
 
41
- - [Performance](https://aristotelesbr.github.io/lennarb/guides/performance/index.html) - The **Lennarb** is very fast. The following benchmarks were performed on a MacBook Pro (Retina, 13-inch, Early 2013) with 2,7 GHz Intel Core i7 and 8 GB 1867 MHz DDR3. Based on [jeremyevans/r10k](https://github.com/jeremyevans/r10k) using the following [template build](static/r10k/build/lennarb.rb).
52
+ - [Performance](https://aristotelesbr.github.io/lennarb/guides/performance/index.html) - The **Lennarb** is very fast. The following benchmarks were performed on a MacBook Pro (Retina, 13-inch, Early 2013) with 2,7 GHz Intel Core i7 and 8 GB 1867 MHz DDR3. Based on [jeremyevans/r10k](https://github.com/jeremyevans/r10k) using the following [template build](static/r10k/build/lennarb.rb).
42
53
 
43
- - [Plugin](https://aristotelesbr.github.io/lennarb/guides/plugin/index.html) - You can create your plugins to extend the functionality of the framework.
54
+ - [Plugin](https://aristotelesbr.github.io/lennarb/guides/plugin/index.html) - You can create your plugins to extend the functionality of the framework.
44
55
 
45
- - [Response](https://aristotelesbr.github.io/lennarb/guides/response/index.html) - This is the response guide.
56
+ - [Response](https://aristotelesbr.github.io/lennarb/guides/response/index.html) - This is the response guide.
46
57
  The `res` object is used to send a response to the client. The Lennarb use a custom response object to send responses to the client. The `res` object is an instance of `Lennarb::Response`.
47
58
 
48
59
  ### Developer Certificate of Origin
metadata CHANGED
@@ -1,15 +1,28 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lennarb
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aristóteles Coutinho
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2024-10-09 00:00:00.000000000 Z
10
+ date: 2025-02-09 00:00:00.000000000 Z
12
11
  dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: bigdecimal
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
13
26
  - !ruby/object:Gem::Dependency
14
27
  name: colorize
15
28
  requirement: !ruby/object:Gem::Requirement
@@ -30,163 +43,193 @@ dependencies:
30
43
  requirements:
31
44
  - - "~>"
32
45
  - !ruby/object:Gem::Version
33
- version: '3.0'
34
- - - ">="
35
- - !ruby/object:Gem::Version
36
- version: 3.0.8
46
+ version: '3.1'
37
47
  type: :runtime
38
48
  prerelease: false
39
49
  version_requirements: !ruby/object:Gem::Requirement
40
50
  requirements:
41
51
  - - "~>"
42
52
  - !ruby/object:Gem::Version
43
- version: '3.0'
53
+ version: '3.1'
54
+ - !ruby/object:Gem::Dependency
55
+ name: bundler
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
44
58
  - - ">="
45
59
  - !ruby/object:Gem::Version
46
- version: 3.0.8
60
+ version: '0'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
47
68
  - !ruby/object:Gem::Dependency
48
- name: bake
69
+ name: covered
49
70
  requirement: !ruby/object:Gem::Requirement
50
71
  requirements:
51
- - - "~>"
72
+ - - ">="
52
73
  - !ruby/object:Gem::Version
53
- version: 0.18.2
74
+ version: '0'
54
75
  type: :development
55
76
  prerelease: false
56
77
  version_requirements: !ruby/object:Gem::Requirement
57
78
  requirements:
58
- - - "~>"
79
+ - - ">="
59
80
  - !ruby/object:Gem::Version
60
- version: 0.18.2
81
+ version: '0'
61
82
  - !ruby/object:Gem::Dependency
62
- name: bundler
83
+ name: simplecov
63
84
  requirement: !ruby/object:Gem::Requirement
64
85
  requirements:
65
- - - "~>"
86
+ - - ">="
66
87
  - !ruby/object:Gem::Version
67
- version: '2.2'
88
+ version: '0'
68
89
  type: :development
69
90
  prerelease: false
70
91
  version_requirements: !ruby/object:Gem::Requirement
71
92
  requirements:
72
- - - "~>"
93
+ - - ">="
73
94
  - !ruby/object:Gem::Version
74
- version: '2.2'
95
+ version: '0'
75
96
  - !ruby/object:Gem::Dependency
76
- name: covered
97
+ name: minitest
77
98
  requirement: !ruby/object:Gem::Requirement
78
99
  requirements:
79
- - - "~>"
100
+ - - ">="
80
101
  - !ruby/object:Gem::Version
81
- version: 0.25.1
102
+ version: '0'
82
103
  type: :development
83
104
  prerelease: false
84
105
  version_requirements: !ruby/object:Gem::Requirement
85
106
  requirements:
86
- - - "~>"
107
+ - - ">="
87
108
  - !ruby/object:Gem::Version
88
- version: 0.25.1
109
+ version: '0'
89
110
  - !ruby/object:Gem::Dependency
90
- name: minitest
111
+ name: rack-test
91
112
  requirement: !ruby/object:Gem::Requirement
92
113
  requirements:
93
- - - "~>"
114
+ - - ">="
94
115
  - !ruby/object:Gem::Version
95
- version: '5.20'
116
+ version: '0'
96
117
  type: :development
97
118
  prerelease: false
98
119
  version_requirements: !ruby/object:Gem::Requirement
99
120
  requirements:
100
- - - "~>"
121
+ - - ">="
101
122
  - !ruby/object:Gem::Version
102
- version: '5.20'
123
+ version: '0'
103
124
  - !ruby/object:Gem::Dependency
104
- name: puma
125
+ name: rake
105
126
  requirement: !ruby/object:Gem::Requirement
106
127
  requirements:
107
- - - "~>"
128
+ - - ">="
108
129
  - !ruby/object:Gem::Version
109
- version: '6.4'
130
+ version: '0'
110
131
  type: :development
111
132
  prerelease: false
112
133
  version_requirements: !ruby/object:Gem::Requirement
113
134
  requirements:
114
- - - "~>"
135
+ - - ">="
115
136
  - !ruby/object:Gem::Version
116
- version: '6.4'
137
+ version: '0'
117
138
  - !ruby/object:Gem::Dependency
118
- name: rack-test
139
+ name: standard
119
140
  requirement: !ruby/object:Gem::Requirement
120
141
  requirements:
121
- - - "~>"
142
+ - - ">="
122
143
  - !ruby/object:Gem::Version
123
- version: '2.1'
144
+ version: '0'
124
145
  type: :development
125
146
  prerelease: false
126
147
  version_requirements: !ruby/object:Gem::Requirement
127
148
  requirements:
128
- - - "~>"
149
+ - - ">="
129
150
  - !ruby/object:Gem::Version
130
- version: '2.1'
151
+ version: '0'
131
152
  - !ruby/object:Gem::Dependency
132
- name: rake
153
+ name: standard-custom
133
154
  requirement: !ruby/object:Gem::Requirement
134
155
  requirements:
135
- - - "~>"
156
+ - - ">="
136
157
  - !ruby/object:Gem::Version
137
- version: '13.1'
158
+ version: '0'
138
159
  type: :development
139
160
  prerelease: false
140
161
  version_requirements: !ruby/object:Gem::Requirement
141
162
  requirements:
142
- - - "~>"
163
+ - - ">="
143
164
  - !ruby/object:Gem::Version
144
- version: '13.1'
165
+ version: '0'
145
166
  - !ruby/object:Gem::Dependency
146
- name: rubocop
167
+ name: standard-performance
147
168
  requirement: !ruby/object:Gem::Requirement
148
169
  requirements:
149
- - - "~>"
170
+ - - ">="
150
171
  - !ruby/object:Gem::Version
151
- version: '1.59'
172
+ version: '0'
152
173
  type: :development
153
174
  prerelease: false
154
175
  version_requirements: !ruby/object:Gem::Requirement
155
176
  requirements:
156
- - - "~>"
177
+ - - ">="
157
178
  - !ruby/object:Gem::Version
158
- version: '1.59'
179
+ version: '0'
159
180
  - !ruby/object:Gem::Dependency
160
- name: rubocop-minitest
181
+ name: m
161
182
  requirement: !ruby/object:Gem::Requirement
162
183
  requirements:
163
- - - "~>"
184
+ - - ">="
164
185
  - !ruby/object:Gem::Version
165
- version: 0.33.0
186
+ version: '0'
166
187
  type: :development
167
188
  prerelease: false
168
189
  version_requirements: !ruby/object:Gem::Requirement
169
190
  requirements:
170
- - - "~>"
191
+ - - ">="
171
192
  - !ruby/object:Gem::Version
172
- version: 0.33.0
173
- description:
174
- email:
193
+ version: '0'
175
194
  executables:
176
195
  - lenna
177
196
  extensions: []
178
197
  extra_rdoc_files: []
179
198
  files:
199
+ - ".devcontainer/Dockerfile"
200
+ - ".devcontainer/devcontainer.json"
201
+ - ".editorconfig"
202
+ - ".github/workflows/coverage.yaml"
203
+ - ".github/workflows/documentation.yaml"
204
+ - ".github/workflows/main.yaml"
205
+ - ".github/workflows/test.yaml"
206
+ - ".gitignore"
207
+ - ".standard.yml"
208
+ - ".tool-versions"
209
+ - LICENCE
210
+ - Rakefile
211
+ - benchmark/memory.png
212
+ - benchmark/rps.png
213
+ - benchmark/runtime_with_startup.png
214
+ - bin/console
215
+ - bin/release
216
+ - bin/setup
180
217
  - changelog.md
181
218
  - exe/lenna
219
+ - gems.rb
220
+ - guides/getting-started/readme.md
221
+ - guides/links.yaml
222
+ - guides/performance/readme.md
223
+ - guides/response/readme.md
224
+ - lennarb.gemspec
182
225
  - lib/lennarb.rb
183
- - lib/lennarb/application/base.rb
184
- - lib/lennarb/plugin.rb
226
+ - lib/lennarb/constansts.rb
185
227
  - lib/lennarb/request.rb
186
228
  - lib/lennarb/response.rb
187
229
  - lib/lennarb/route_node.rb
188
230
  - lib/lennarb/version.rb
189
231
  - license.md
232
+ - logo/lennarb.png
190
233
  - readme.md
191
234
  homepage: https://aristotelesbr.github.io/lennarb
192
235
  licenses:
@@ -197,7 +240,6 @@ metadata:
197
240
  homepage_uri: https://aristotelesbr.github.io/lennarb
198
241
  rubygems_mfa_required: 'true'
199
242
  source_code_uri: https://github.com/aristotelesbr/lennarb
200
- post_install_message:
201
243
  rdoc_options: []
202
244
  require_paths:
203
245
  - lib
@@ -205,15 +247,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
205
247
  requirements:
206
248
  - - ">="
207
249
  - !ruby/object:Gem::Version
208
- version: '3.1'
250
+ version: '0'
209
251
  required_rubygems_version: !ruby/object:Gem::Requirement
210
252
  requirements:
211
253
  - - ">="
212
254
  - !ruby/object:Gem::Version
213
255
  version: '0'
214
256
  requirements: []
215
- rubygems_version: 3.5.11
216
- signing_key:
257
+ rubygems_version: 3.6.2
217
258
  specification_version: 4
218
259
  summary: Lennarb provides a lightweight yet robust solution for web routing in Ruby,
219
260
  focusing on performance and simplicity.
@@ -1,283 +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
- class << self
36
- def inherited(subclass)
37
- super
38
- _applications << subclass
39
- subclass.instance_variable_set(:@_route, Lennarb.new)
40
- subclass.instance_variable_set(:@_middlewares, [])
41
- subclass.instance_variable_set(:@_global_after_hooks, [])
42
- subclass.instance_variable_set(:@_global_before_hooks, [])
43
- subclass.instance_variable_set(:@_after_hooks, Lennarb::RouteNode.new)
44
- subclass.instance_variable_set(:@_before_hooks, Lennarb::RouteNode.new)
45
- end
46
-
47
- def get(...) = @_route.get(...)
48
- def put(...) = @_route.put(...)
49
- def post(...) = @_route.post(...)
50
- def head(...) = @_route.head(...)
51
- def match(...) = @_route.match(...)
52
- def patch(...) = @_route.patch(...)
53
- def delete(...) = @_route.delete(...)
54
- def options(...) = @_route.options(...)
55
-
56
- # @returns [Array] middlewares
57
- #
58
- def _middlewares = @_middlewares ||= []
59
-
60
- # @returns [Array] applications
61
- #
62
- def _applications = @_applications ||= []
63
-
64
- # Mount a controller
65
- #
66
- # @parameter [Class] controller
67
- #
68
- def mount(controller_class)
69
- _applications << controller_class
70
- puts "Mounted controller: #{controller_class}"
71
- end
72
-
73
- # Use a middleware
74
- #
75
- # @parameter [Object] middleware
76
- # @parameter [Array] args
77
- # @parameter [Block] block
78
- #
79
- # @returns [Array] middlewares
80
- #
81
- def use(middleware, *args, &block)
82
- @_middlewares << [middleware, args, block]
83
- end
84
-
85
- # Add a before hook
86
- #
87
- # @parameter [String] path
88
- # @parameter [Block] block
89
- #
90
- def before(path = nil, &block)
91
- if path
92
- parts = path.split('/').reject(&:empty?)
93
- @_before_hooks.add_route(parts, :before, block)
94
- else
95
- @_global_before_hooks << block
96
- end
97
- end
98
-
99
- # Add a after hook
100
- #
101
- # @parameter [String] path
102
- # @parameter [Block] block
103
- #
104
- def after(path = nil, &block)
105
- if path
106
- parts = path.split('/').reject(&:empty?)
107
- @_after_hooks.add_route(parts, :after, block)
108
- else
109
- @_global_after_hooks << block
110
- end
111
- end
112
-
113
- # Run the Application
114
- #
115
- # @returns [Base] self
116
- #
117
- # When you use this method, the application will be frozen. And you can't add more routes after that.
118
- # This method is used to run the application in a Rack server so, you can use the `rackup` command
119
- # to run the application.
120
- # Ex. rackup -p 3000
121
- # This command will use the following middleware:
122
- # - Rack::ShowExceptions
123
- # - Rack::MethodOverride
124
- # - Rack::Head
125
- # - Rack::ContentLength
126
- #
127
- def run!
128
- stack = Rack::Builder.new
129
-
130
- use Rack::ShowExceptions if test? || development?
131
- use Rack::MethodOverride
132
- use Rack::Head
133
- use Rack::ContentLength
134
-
135
- _middlewares.each do |(middleware, args, block)|
136
- stack.use(middleware, *args, &block)
137
- end
138
-
139
- _applications.each do |app|
140
- app_route = app.instance_variable_get(:@_route)
141
-
142
- app_after_hooks = app.instance_variable_get(:@_after_hooks)
143
- app_before_hooks = app.instance_variable_get(:@_before_hooks)
144
- global_after_hooks = app.instance_variable_get(:@_global_after_hooks)
145
- global_before_hooks = app.instance_variable_get(:@_global_before_hooks)
146
-
147
- @_route.merge!(app_route)
148
- @_before_hooks.merge!(app_before_hooks)
149
- @_after_hooks.merge!(app_after_hooks)
150
-
151
- @_global_before_hooks.concat(global_before_hooks)
152
- @_global_after_hooks.concat(global_after_hooks)
153
- end
154
-
155
- stack.run ->(env) do
156
- catch(:halt) do
157
- execute_hooks(@_before_hooks, env, :before)
158
- res = @_route.call(env)
159
- execute_hooks(@_after_hooks, env, :after)
160
- res
161
- rescue StandardError => e
162
- render_error if production?
163
-
164
- puts e.message.red
165
- puts e.backtrace
166
- raise e
167
- end
168
- end
169
-
170
- @_route.freeze!
171
- stack.to_app
172
- end
173
-
174
- def test? = ENV['RACK_ENV'] == 'test' || ENV['LENNARB_ENV'] == 'test'
175
- def production? = ENV['RACK_ENV'] == 'production' || ENV['LENNARB_ENV'] == 'production'
176
- def development? = ENV['RACK_ENV'] == 'development' || ENV['LENNARB_ENV'] == 'development'
177
-
178
- # Render a not found
179
- #
180
- # @returns [void]
181
- #
182
- def render_not_found(content = nil)
183
- default = File.exist?('public/404.html')
184
- body = content || default || 'Not Found'
185
- throw :halt, [404, { 'content-type' => 'text/html' }, [body]]
186
- end
187
-
188
- # Render an error
189
- #
190
- # @returns [void]
191
- #
192
- def render_error(content = nil)
193
- default = File.exist?('public/500.html')
194
- body = content || default || 'Internal Server Error'
195
- throw :halt, [500, { 'content-type' => 'text/html' }, [body]]
196
- end
197
-
198
- # Redirect to a path
199
- #
200
- # @parameter [String] path
201
- # @parameter [Integer] status default is 302
202
- #
203
- def redirect(path, status = 302) = throw :halt, [status, { 'location' => path }, []]
204
-
205
- # Include a plugin in the application
206
- #
207
- # @parameter [String] plugin_name
208
- # @parameter [Array] args
209
- # @parameter [Block] block
210
- #
211
- # @returns [void]
212
- #
213
- def plugin(plugin_name, *, &)
214
- @_route.plugin(plugin_name, *, &)
215
- plugin_module = @_route.class::Plugin.load(plugin_name)
216
-
217
- include plugin_module::InstanceMethods if plugin_module.const_defined?(:InstanceMethods)
218
- extend plugin_module::ClassMethods if plugin_module.const_defined?(:ClassMethods)
219
- end
220
-
221
- private
222
-
223
- # Execute the hooks
224
- #
225
- # @parameter [RouteNode] hook_route
226
- # @parameter [Hash] env
227
- # @parameter [Symbol] action
228
- #
229
- # @returns [void]
230
- #
231
- def execute_hooks(hook_route, env, action)
232
- execute_global_hooks(env, action)
233
-
234
- execute_route_hooks(hook_route, env, action)
235
- end
236
-
237
- # Execute the global hooks
238
- #
239
- # @parameter [Hash] env
240
- # @parameter [Symbol] action
241
- #
242
- # @returns [void]
243
- #
244
- def execute_global_hooks(env, action)
245
- global_hooks = action == :before ? @_global_before_hooks : @_global_after_hooks
246
- global_hooks.each { |hook| hook.call(env) }
247
- end
248
-
249
- # Execute the route hooks
250
- #
251
- # @parameter [RouteNode] hook_route
252
- # @parameter [Hash] env
253
- # @parameter [Symbol] action
254
- #
255
- # @returns [void]
256
- #
257
- def execute_route_hooks(hook_route, env, action)
258
- parts = parse_path(env)
259
- return unless parts
260
-
261
- block, = hook_route.match_route(parts, action)
262
- block&.call(env)
263
- end
264
-
265
- # Parse the path
266
- #
267
- # @parameter [Hash] env
268
- #
269
- # @returns [Array] parts
270
- #
271
- def parse_path(env) = env[Rack::PATH_INFO]&.split('/')&.reject(&:empty?)
272
-
273
- # Check if the request is a HTML request
274
- #
275
- # @parameter [Hash] env
276
- #
277
- # @returns [Boolean]
278
- #
279
- def html_request?(env) = env['HTTP_ACCEPT']&.include?('text/html')
280
- end
281
- end
282
- end
283
- end
@@ -1,35 +0,0 @@
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
- # Register a plugin
11
- #
12
- # @parameter [String] name
13
- # @parameter [Module] mod
14
- #
15
- # @returns [void]
16
- #
17
- def self.register(name, mod)
18
- @plugins[name] = mod
19
- end
20
-
21
- # Load a plugin
22
- #
23
- # @parameter [String] name
24
- #
25
- # @returns [Module] plugin
26
- #
27
- def self.load(name)
28
- @plugins[name] || raise(LennarbError, "Plugin #{name} did not register itself correctly")
29
- end
30
-
31
- # @returns [Hash] plugins
32
- #
33
- def self.plugins = @plugins
34
- end
35
- end