lennarb 1.3.0 → 1.4.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.
@@ -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