lennarb 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,99 +1,124 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # Released under the MIT License.
4
+ # Copyright, 2023, by Aristóteles Coutinho.
5
+
3
6
  module Lenna
4
- class Router
5
- # The Route::Builder class is responsible for building the tree of routes.
6
- #
7
- # The tree of routes is built by adding routes to the tree. Each route is
8
- # represented by a node in the tree and each node has a path and an
9
- # endpoint. The path is the path of the route and the endpoint is then
10
- # action to be executed when the route is matched.
11
- #
12
- # Those nodes are stored in a cache to avoid rebuilding the tree of routes
13
- # for each request.
14
- #
15
- # The tree use `Trie` data structures to optimize the search for a route.
16
- # The trie is a tree where each node is a character of the path.
17
- # This way, the search for a route is O(n) where n is the length of the
18
- # path.
19
- #
20
- class Builder
21
- def initialize(root_node) = @root_node = root_node
7
+ class Router
8
+ # The Route::Builder class is responsible for building the tree of routes.
9
+ #
10
+ # The tree of routes is built by adding routes to the tree. Each route is
11
+ # represented by a node in the tree and each node has a path and an
12
+ # endpoint. The path is the path of the route and the endpoint is then
13
+ # action to be executed when the route is matched.
14
+ #
15
+ # Those nodes are stored in a cache to avoid rebuilding the tree of routes
16
+ # for each request.
17
+ #
18
+ # The tree use `Trie` data structures to optimize the search for a route.
19
+ # The trie is a tree where each node is a character of the path.
20
+ # This way, the search for a route is O(n) where n is the length of the
21
+ # path.
22
+ #
23
+ # @private
24
+ #
25
+ class Builder
26
+ def initialize(root_node) = @root_node = root_node
22
27
 
23
- # @param method [String] the HTTP method
24
- # @param path [String] the path to be matched
25
- # @param action [Proc] the action to be executed
26
- # @param cache [Cache] the cache to be used
27
- # @return [void]
28
- def call(method, path, action, cache)
29
- path_key = cache.cache_key(method, path)
28
+ # This method will add a route to the tree of routes.
29
+ #
30
+ # @parameter method [String] the HTTP method
31
+ # @parameter path [String] the path to be matched
32
+ # @parameter action [Proc] the action to be executed
33
+ # @parameter cache [Cache] the cache to be used
34
+ #
35
+ # @return [void]
36
+ #
37
+ def call(method, path, action, cache)
38
+ path_key = cache.cache_key(method, path)
30
39
 
31
- return if cache.exist?(path_key)
40
+ return if cache.exist?(path_key)
32
41
 
33
- current_node = find_or_create_route_node(path)
34
- setup_endpoint(current_node, method, action)
42
+ current_node = find_or_create_route_node(path)
43
+ setup_endpoint(current_node, method, action)
35
44
 
36
- cache.add(path_key, current_node)
37
- end
45
+ cache.add(path_key, current_node)
46
+ end
38
47
 
39
- private
48
+ private
40
49
 
41
- # This method will create routes that are missing.
42
- # @param path [String] the path to be matched
43
- # @return [Node] the node that matches the path
44
- def find_or_create_route_node(path)
45
- current_node = @root_node
46
- split_path(path).each do |part|
47
- current_node = find_or_create_node(current_node, part)
48
- end
49
- current_node
50
- end
50
+ # This method will create routes that are missing.
51
+ # @parameter path [String] the path to be matched
52
+ #
53
+ # @return [Node] the node that matches the path
54
+ #
55
+ def find_or_create_route_node(path)
56
+ current_node = @root_node
57
+ split_path(path).each do |part|
58
+ current_node = find_or_create_node(current_node, part)
59
+ end
60
+ current_node
61
+ end
51
62
 
52
- # @param current_node [Node] the current node
53
- # @param part [String] the part of the path
54
- # @return [Node] the node that matches the part of the path
55
- # @note This method will create the nodes that are missing.
56
- # This way, the tree of routes is built.
57
- # @example Given the part ':id' and the tree bellow:
58
- # root
59
- # └── users
60
- # └── :id
61
- # The method will return the node :id.
62
- # If the node :id does not exist, it will be created.
63
- # The tree will be:
64
- # root
65
- # └── users
66
- # └── :id
67
- def find_or_create_node(current_node, part)
68
- if part.start_with?(':')
69
- # If it is a placeholder, then we just create or update
70
- # the placeholder node with the placeholder name.
71
- placeholder_name = part[1..].to_sym
72
- current_node.children[:placeholder] ||= Node.new(
73
- {},
74
- nil,
75
- placeholder_name
76
- )
77
- else
78
- current_node.children[part] ||= Node.new
79
- end
80
- current_node.children[part.start_with?(':') ? :placeholder : part]
81
- end
63
+ # This method will create the nodes that are missing.
64
+ #
65
+ # @parameter current_node [Node] the current node
66
+ # @parameter part [String] the part of the path
67
+ #
68
+ # @return [Node] the node that matches the part of the path
69
+ #
70
+ # This way, the tree of routes is built.
71
+ # @example Given the part ':id' and the tree bellow:
72
+ # root
73
+ # └── users
74
+ # └── :id
75
+ # The method will return the node :id.
76
+ # If the node :id does not exist, it will be created.
77
+ # The tree will be:
78
+ # root
79
+ # └── users
80
+ # └── :id
81
+ #
82
+ def find_or_create_node(current_node, part)
83
+ if part.start_with?(':')
84
+ # If it is a placeholder, then we just create or update
85
+ # the placeholder node with the placeholder name.
86
+ placeholder_name = part[1..].to_sym
87
+ current_node.children[:placeholder] ||= Node.new(
88
+ {},
89
+ nil,
90
+ placeholder_name
91
+ )
92
+ else
93
+ current_node.children[part] ||= Node.new
94
+ end
95
+ current_node.children[part.start_with?(':') ? :placeholder : part]
96
+ end
82
97
 
83
- # @param current_node [Node] the current node
84
- # @param method [String] the HTTP method
85
- # @param action [Proc] the action to be executed
86
- def setup_endpoint(current_node, method, action)
87
- current_node.endpoint ||= {}
88
- current_node.endpoint[method] = action
89
- end
98
+ # This method will setup the endpoint of the current node.
99
+ #
100
+ # @parameter current_node [Node] the current node
101
+ # @parameter method [String] the HTTP method
102
+ # @parameter action [Proc] the action to be executed
103
+ #
104
+ # @return [void]
105
+ #
106
+ def setup_endpoint(current_node, method, action)
107
+ current_node.endpoint ||= {}
108
+ current_node.endpoint[method] = action
109
+ end
90
110
 
91
- # @param path [String] the path to be split
92
- # @return [Array] the splitted path
93
- # @todo: Move this to a separate file and require it here.
94
- # Maybe utils or something like that.
95
- # Use Rack::Utils.split_path_info instead.
96
- def split_path(path) = path.split('/').reject(&:empty?)
97
- end
98
- end
111
+ # This method will split the path into parts.
112
+ #
113
+ # @parameter path [String] the path to be split
114
+ #
115
+ # @return [Array] the splitted path
116
+ #
117
+ # TODO: Move this to a separate file and require it here.
118
+ # Maybe utils or something like that.
119
+ # Use Rack::Utils.split_path_info instead.
120
+ #
121
+ def split_path(path) = path.split('/').reject(&:empty?)
122
+ end
123
+ end
99
124
  end
@@ -1,38 +1,52 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # Released under the MIT License.
4
+ # Copyright, 2023, by Aristóteles Coutinho.
5
+
3
6
  module Lenna
4
- class Router
5
- # @api public
6
- # @note This class is used to cache the routes.
7
- class Cache
8
- def initialize = @cache = {}
7
+ class Router
8
+ # This class is used to cache the routes.
9
+ #
10
+ # @private
11
+ #
12
+ class Cache
13
+ def initialize = @cache = {}
9
14
 
10
- # @api public
11
- # @param [String] method
12
- # @param [String] path
13
- # @return [String]
14
- # @note This method is used to generate a key for the cache.
15
- def cache_key(method, path) = "#{method} #{path}"
15
+ # This method is used to generate a key for the cache.
16
+ #
17
+ # @parameter [String] method
18
+ # @parameter [String] path
19
+ #
20
+ # @return [String]
21
+ #
22
+ def cache_key(method, path) = "#{method} #{path}"
16
23
 
17
- # @api public
18
- # @param route_key [String] The key for the route.
19
- # @param node [Lenna::Route::Node] The node for the route.
20
- # @return [Lenna::Route::Node]
21
- # @note This method is used to add a route to the cache.
22
- def add(route_key, node) = @cache[route_key] = node
24
+ # This method is used to add a route to the cache.
25
+ #
26
+ # @parameter route_key [String] The key for the route.
27
+ # @parameter node [Lenna::Route::Node] The node for the route.
28
+ #
29
+ # @return [Lenna::Route::Node]
30
+ #
31
+ def add(route_key, node) = @cache[route_key] = node
23
32
 
24
- # @api public
25
- # @param route_key [String] The key for the route.
26
- # @return [Lenna::Route::Node]
27
- # @note This method is used to get a route from the cache.
28
- def get(route_key) = @cache[route_key]
33
+ # This method is used to get a route from the cache.
34
+ #
35
+ # @parameter route_key [String] The key for the route.
36
+ #
37
+ # @return [Lenna::Route::Node]
38
+ #
39
+ def get(route_key) = @cache[route_key]
29
40
 
30
- # @api public
31
- # @param route_key [String] The key for the route.
32
- # @return [Boolean]
33
- # @note This method is used to check if a route exists
34
- # in the cache.
35
- def exist?(route_key) = @cache.key?(route_key)
36
- end
37
- end
41
+ # This method is used to check if a route is in the cache.
42
+ #
43
+ # @api public
44
+ #
45
+ # @parameter route_key [String] The key for the route.
46
+ #
47
+ # @return [Boolean]
48
+ #
49
+ def exist?(route_key) = @cache.key?(route_key)
50
+ end
51
+ end
38
52
  end
@@ -1,73 +1,77 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # Released under the MIT License.
4
+ # Copyright, 2023, by Aristóteles Coutinho.
5
+
3
6
  module Lenna
4
- class Router
5
- # This class is used to manage the namespaces.
6
- #
7
- # @api private
8
- class NamespaceStack
9
- # @return [Array] The stack of namespaces
10
- #
11
- # @api private
12
- attr_reader :stack
7
+ class Router
8
+ # This class is used to manage the namespaces.
9
+ #
10
+ # @private `Since v0.1.0`
11
+ #
12
+ class NamespaceStack
13
+ # @return [Array] The stack of namespaces
14
+ #
15
+ # @private
16
+ #
17
+ attr_reader :stack
13
18
 
14
- # @return [void]
15
- #
16
- # @api private
17
- def initialize = @stack = ['']
19
+ # The initialize method is used to initialize the stack of namespaces.
20
+ #
21
+ # @private
22
+ #
23
+ # @attibute stack [Array] The stack of namespaces
24
+ #
25
+ # @return [void]
26
+ #
27
+ def initialize = @stack = ['']
18
28
 
19
- # This method is used to push a prefix to the stack.
20
- #
21
- # @param prefix [String] The prefix to be pushed
22
- # @return [void]
23
- #
24
- # @example:
25
- #
26
- # stack = NamespaceStack.new
27
- # stack.push('/users')
28
- # stack.current_prefix # => '/users'
29
- #
30
- # @see #resolve_prefix
31
- #
32
- # @api private
33
- def push(prefix)
34
- @stack.push(resolve_prefix(prefix))
35
- end
29
+ # This method is used to push a prefix to the stack.
30
+ #
31
+ # @parameter prefix [String] The prefix to be pushed
32
+ #
33
+ # @return [void]
34
+ #
35
+ # ex.
36
+ #
37
+ # stack = NamespaceStack.new
38
+ # stack.push('/users')
39
+ # stack.current_prefix # => '/users'
40
+ #
41
+ # @see #resolve_prefix
42
+ #
43
+ def push(prefix)
44
+ @stack.push(resolve_prefix(prefix))
45
+ end
36
46
 
37
- # @return [String] The popped prefix
38
- #
39
- # @api private
40
- def pop
41
- @stack.pop unless @stack.size == 1
42
- end
47
+ # This method is used to remove the last prefix from the stack.
48
+ #
49
+ # @return [String] The popped prefix
50
+ #
51
+ def pop
52
+ @stack.pop unless @stack.size == 1
53
+ end
43
54
 
44
- # @return [String] The current prefix
45
- #
46
- # @api private
47
- #
48
- # @since 0.1.0
49
- def current_prefix = @stack.last
55
+ # @return [String] The current prefix
56
+ #
57
+ def current_prefix = @stack.last
50
58
 
51
- # The to_s method is used to return the current prefix.
52
- #
53
- # @return [String] The current prefix
54
- #
55
- # @api private
56
- def to_s = current_prefix
59
+ # The to_s method is used to return the current prefix.
60
+ #
61
+ # @return [String] The current prefix
62
+ #
63
+ def to_s = current_prefix
57
64
 
58
- private
65
+ private
59
66
 
60
- # The resolve_prefix method is used to resolve the prefix.
61
- #
62
- # @param prefix [String] The prefix to be resolved
63
- # @return [String] The resolved prefix
64
- #
65
- # @see #current_prefix
66
- #
67
- # @since 0.1.0
68
- def resolve_prefix(prefix)
69
- current_prefix + prefix
70
- end
71
- end
72
- end
67
+ # The resolve_prefix method is used to resolve the prefix.
68
+ #
69
+ # @parameter prefix [String] The prefix to be resolved
70
+ # @return [String] The resolved prefix
71
+ #
72
+ def resolve_prefix(prefix)
73
+ current_prefix + prefix
74
+ end
75
+ end
76
+ end
73
77
  end