lennarb 1.3.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.
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.3.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-11-21 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,164 +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/plugin.rb
184
- - lib/lennarb/plugins/hooks.rb
185
- - lib/lennarb/plugins/mount.rb
226
+ - lib/lennarb/constansts.rb
186
227
  - lib/lennarb/request.rb
187
228
  - lib/lennarb/response.rb
188
229
  - lib/lennarb/route_node.rb
189
230
  - lib/lennarb/version.rb
190
231
  - license.md
232
+ - logo/lennarb.png
191
233
  - readme.md
192
234
  homepage: https://aristotelesbr.github.io/lennarb
193
235
  licenses:
@@ -198,7 +240,6 @@ metadata:
198
240
  homepage_uri: https://aristotelesbr.github.io/lennarb
199
241
  rubygems_mfa_required: 'true'
200
242
  source_code_uri: https://github.com/aristotelesbr/lennarb
201
- post_install_message:
202
243
  rdoc_options: []
203
244
  require_paths:
204
245
  - lib
@@ -206,15 +247,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
206
247
  requirements:
207
248
  - - ">="
208
249
  - !ruby/object:Gem::Version
209
- version: '3.1'
250
+ version: '0'
210
251
  required_rubygems_version: !ruby/object:Gem::Requirement
211
252
  requirements:
212
253
  - - ">="
213
254
  - !ruby/object:Gem::Version
214
255
  version: '0'
215
256
  requirements: []
216
- rubygems_version: 3.5.23
217
- signing_key:
257
+ rubygems_version: 3.6.2
218
258
  specification_version: 4
219
259
  summary: Lennarb provides a lightweight yet robust solution for web routing in Ruby,
220
260
  focusing on performance and simplicity.
@@ -1,49 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Lennarb
4
- module Plugin
5
- class Error < StandardError; end
6
-
7
- @registry = {}
8
- @defaults_loaded = false
9
-
10
- class << self
11
- attr_reader :registry
12
-
13
- def register(name, mod)
14
- registry[name.to_sym] = mod
15
- end
16
-
17
- def load(name)
18
- registry[name.to_sym] || raise(Error, "Plugin #{name} not found")
19
- end
20
-
21
- def load_defaults!
22
- return if @defaults_loaded
23
-
24
- # 1. Register default plugins
25
- plugins_path = File.expand_path('plugins', __dir__)
26
- load_plugins_from_directory(plugins_path)
27
-
28
- # # 2. Register custom plugins
29
- ENV.fetch('LENNARB_PLUGINS_PATH', nil)&.split(File::PATH_SEPARATOR)&.each do |path|
30
- load_plugins_from_directory(path)
31
- end
32
-
33
- @defaults_loaded = true
34
- end
35
-
36
- def load_defaults?
37
- ENV.fetch('LENNARB_AUTO_LOAD_DEFAULTS', 'true') == 'true'
38
- end
39
-
40
- private
41
-
42
- def load_plugins_from_directory(path)
43
- raise Error, "Plugin directory '#{path}' does not exist" unless File.directory?(path)
44
-
45
- Dir["#{path}/**/*.rb"].each { require _1 }
46
- end
47
- end
48
- end
49
- end
@@ -1,117 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Lennarb
4
- module Plugins
5
- module Hooks
6
- def self.configure(app)
7
- app.instance_variable_set(:@_before_hooks, {})
8
- app.instance_variable_set(:@_after_hooks, {})
9
- app.extend(ClassMethods)
10
- app.include(InstanceMethods)
11
- end
12
-
13
- module ClassMethods
14
- def before(paths = '*', &block)
15
- paths = Array(paths)
16
- @_before_hooks ||= {}
17
-
18
- paths.each do |path|
19
- @_before_hooks[path] ||= []
20
- @_before_hooks[path] << block
21
- end
22
- end
23
-
24
- def after(paths = '*', &block)
25
- paths = Array(paths)
26
- @_after_hooks ||= {}
27
-
28
- paths.each do |path|
29
- @_after_hooks[path] ||= []
30
- @_after_hooks[path] << block
31
- end
32
- end
33
-
34
- def inherited(subclass)
35
- super
36
- subclass.instance_variable_set(:@_before_hooks, @_before_hooks&.dup || {})
37
- subclass.instance_variable_set(:@_after_hooks, @_after_hooks&.dup || {})
38
- end
39
- end
40
-
41
- module InstanceMethods
42
- def call(env)
43
- catch(:halt) do
44
- req = Lennarb::Request.new(env)
45
- res = Lennarb::Response.new
46
-
47
- path = env[Rack::PATH_INFO]
48
-
49
- execute_hooks(self.class.instance_variable_get(:@_before_hooks), '*', req, res)
50
-
51
- execute_matching_hooks(self.class.instance_variable_get(:@_before_hooks), path, req, res)
52
-
53
- status, headers, body = super
54
- res.status = status
55
- headers.each { |k, v| res[k] = v }
56
- body.each { |chunk| res.write(chunk) }
57
-
58
- execute_matching_hooks(self.class.instance_variable_get(:@_after_hooks), path, req, res)
59
-
60
- execute_hooks(self.class.instance_variable_get(:@_after_hooks), '*', req, res)
61
-
62
- res.finish
63
- end
64
- rescue StandardError => e
65
- handle_error(e)
66
- end
67
-
68
- private
69
-
70
- def execute_hooks(hooks, path, req, res)
71
- return unless hooks&.key?(path)
72
-
73
- hooks[path].each do |hook|
74
- instance_exec(req, res, &hook)
75
- end
76
- end
77
-
78
- def execute_matching_hooks(hooks, current_path, req, res)
79
- return unless hooks
80
-
81
- hooks.each do |pattern, pattern_hooks|
82
- next if pattern == '*'
83
-
84
- next unless matches_pattern?(pattern, current_path)
85
-
86
- pattern_hooks.each do |hook|
87
- instance_exec(req, res, &hook)
88
- end
89
- end
90
- end
91
-
92
- def matches_pattern?(pattern, path)
93
- return true if pattern == path
94
-
95
- pattern_parts = pattern.split('/')
96
- path_parts = path.split('/')
97
-
98
- return false if pattern_parts.length != path_parts.length
99
-
100
- pattern_parts.zip(path_parts).all? do |pattern_part, path_part|
101
- pattern_part.start_with?(':') || pattern_part == path_part
102
- end
103
- end
104
-
105
- def handle_error(error)
106
- case error
107
- when ArgumentError
108
- [400, { 'Content-Type' => 'text/plain' }, ["Bad Request: #{error.message}"]]
109
- else
110
- [500, { 'Content-Type' => 'text/plain' }, ['Internal Server Error']]
111
- end
112
- end
113
- end
114
- end
115
- Lennarb::Plugin.register(:hooks, Hooks)
116
- end
117
- end
@@ -1,66 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Lennarb
4
- module Plugins
5
- module Mount
6
- def self.configure(app)
7
- app.instance_variable_set(:@_mounted_apps, {})
8
- app.extend(ClassMethods)
9
- app.include(InstanceMethods)
10
- end
11
-
12
- module ClassMethods
13
- def mount(app_class, at:)
14
- raise ArgumentError, 'Expected a Lennarb class' unless app_class.is_a?(Class) && app_class <= Lennarb
15
- raise ArgumentError, 'Mount path must start with /' unless at.start_with?('/')
16
-
17
- @_mounted_apps ||= {}
18
- normalized_path = normalize_mount_path(at)
19
-
20
- mounted_app = app_class.new
21
- mounted_app.freeze!
22
-
23
- @_mounted_apps[normalized_path] = mounted_app
24
- end
25
-
26
- private
27
-
28
- def normalize_mount_path(path)
29
- path.chomp('/')
30
- end
31
- end
32
-
33
- module InstanceMethods
34
- def call(env)
35
- path_info = env[Rack::PATH_INFO]
36
-
37
- self.class.instance_variable_get(:@_mounted_apps)&.each do |mount_path, app|
38
- next unless path_info.start_with?("#{mount_path}/") || path_info == mount_path
39
-
40
- env[Rack::PATH_INFO] = path_info[mount_path.length..]
41
- env[Rack::PATH_INFO] = '/' if env[Rack::PATH_INFO].empty?
42
- env[Rack::SCRIPT_NAME] = "#{env[Rack::SCRIPT_NAME]}#{mount_path}"
43
-
44
- return app.call(env)
45
- end
46
-
47
- super
48
- rescue StandardError => e
49
- handle_error(e)
50
- end
51
-
52
- private
53
-
54
- def handle_error(error)
55
- case error
56
- when ArgumentError
57
- [400, { 'content-type' => 'text/plain' }, ["Bad Request: #{error.message}"]]
58
- else
59
- [500, { 'content-type' => 'text/plain' }, ['Internal Server Error']]
60
- end
61
- end
62
- end
63
- end
64
- Lennarb::Plugin.register(:mount, Mount)
65
- end
66
- end