lennarb 0.1.7 → 0.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.
- checksums.yaml +4 -4
- data/changelog.md +48 -0
- data/exe/lenna +2 -4
- data/lib/lennarb/request.rb +37 -0
- data/lib/lennarb/response.rb +138 -0
- data/lib/lennarb/route_node.rb +73 -0
- data/lib/lennarb/version.rb +3 -3
- data/lib/lennarb.rb +120 -27
- data/license.md +2 -1
- data/readme.md +34 -13
- metadata +42 -57
- data/lib/lenna/application.rb +0 -53
- data/lib/lenna/cli/app.rb +0 -39
- data/lib/lenna/cli/commands/create_project.rb +0 -125
- data/lib/lenna/cli/commands/interface.rb +0 -20
- data/lib/lenna/cli/commands/start_server.rb +0 -143
- data/lib/lenna/cli/templates/application.erb +0 -11
- data/lib/lenna/cli/templates/config.ru.erb +0 -5
- data/lib/lenna/cli/templates/gemfile.erb +0 -14
- data/lib/lenna/middleware/app.rb +0 -118
- data/lib/lenna/middleware/default/error_handler.rb +0 -243
- data/lib/lenna/middleware/default/logging.rb +0 -93
- data/lib/lenna/middleware/default/reload.rb +0 -97
- data/lib/lenna/router/builder.rb +0 -124
- data/lib/lenna/router/cache.rb +0 -52
- data/lib/lenna/router/namespace_stack.rb +0 -77
- data/lib/lenna/router/request.rb +0 -141
- data/lib/lenna/router/response.rb +0 -509
- data/lib/lenna/router/route_matcher.rb +0 -68
- data/lib/lenna/router.rb +0 -206
- data/lib/lennarb/array_extensions.rb +0 -31
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9dfa4cf1e25284df8669a9fdd9faf45806575137b0b2a2cd131e4af205426176
|
4
|
+
data.tar.gz: 879b617cb51177961a055e2dfd069437e9cae0c7e781fb50aad410c14b271dd8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '087d53fc3627a7c61f028826f0af5ea8fc26e6fb02a2a461c54154852bbc9b71d9d65becf7faf5451e81612eeb9129b307002861aac49b3e85ecc1dab4e6a6de'
|
7
|
+
data.tar.gz: 74d0156c558d8619e66b2daa5d5449216d064b38c511efb01cea802397efc2323b149e71cb1a3756af591c58b10510aef48dcc77ec40e20cbbae6f2a350a38a7
|
data/changelog.md
CHANGED
@@ -5,6 +5,54 @@ All notable changes to this project will be documented in this file.
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
7
|
|
8
|
+
## [0.4.0] - 2024-07-02
|
9
|
+
|
10
|
+
### Added
|
11
|
+
|
12
|
+
- Add `Lennarb::ApplicationBase` class to be the base class of the `Lennarb` class. Now, the `Lennarb` class is a subclass of `Lennarb::ApplicationBase` class.
|
13
|
+
|
14
|
+
That permits to create a new application with the `Lennarb::ApplicationBase` class and use http methods to create the routes. Ex.
|
15
|
+
|
16
|
+
```rb
|
17
|
+
# app.rb
|
18
|
+
|
19
|
+
require 'lennarb'
|
20
|
+
|
21
|
+
class MyApp
|
22
|
+
include Lennarb::ApplicationBase
|
23
|
+
|
24
|
+
get '/hello' do |req, res|
|
25
|
+
res.html('Hello World')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
```
|
29
|
+
|
30
|
+
### Change
|
31
|
+
|
32
|
+
- Change the test/test_lenna.rb to test/test_lennarb.rb
|
33
|
+
- Change `add_route` method from `Lennarb` class to `__add_route` and remove from private section.
|
34
|
+
|
35
|
+
## [0.2.0] - 2024-08-01
|
36
|
+
|
37
|
+
### Removed
|
38
|
+
|
39
|
+
- Remove `zeitwerk` gem to load the files in the project.
|
40
|
+
- Remove `console` gem to print the logs in the console.
|
41
|
+
- Remove `Lenna` module. Now, the `Lennarb` class is the main class of the project.
|
42
|
+
- Remove `Middleware` module.
|
43
|
+
- Remove `CLI` module.
|
44
|
+
- Remove `Cache` module
|
45
|
+
|
46
|
+
### Changed
|
47
|
+
|
48
|
+
- Change `Lennarb::Application` class to `Lennarb` class.
|
49
|
+
- Request class and Response class now are in `Lennarb` class
|
50
|
+
- Change `Lennarb::Router` class to `Lennarb` class
|
51
|
+
|
52
|
+
### Fixed
|
53
|
+
|
54
|
+
- Improve performance of the RPS (Requests per second), memory and CPU usage. Now the performance is similar to the [Roda](https://github.com/jeremyevans/roda/tree/master).
|
55
|
+
|
8
56
|
## [0.1.7] - 2023-23-12
|
9
57
|
|
10
58
|
### Added
|
data/exe/lenna
CHANGED
@@ -0,0 +1,37 @@
|
|
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
|
+
class Request < Rack::Request
|
8
|
+
# Initialize the request object
|
9
|
+
#
|
10
|
+
# @parameter [Hash] env
|
11
|
+
# @parameter [Hash] route_params
|
12
|
+
#
|
13
|
+
# @returns [Request]
|
14
|
+
#
|
15
|
+
def initialize(env, route_params = {})
|
16
|
+
super(env)
|
17
|
+
@route_params = route_params
|
18
|
+
end
|
19
|
+
|
20
|
+
# Get the request body
|
21
|
+
#
|
22
|
+
# @returns [String]
|
23
|
+
def params
|
24
|
+
@params ||= super.merge(@route_params)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
# Get the query string
|
30
|
+
#
|
31
|
+
# @returns [String]
|
32
|
+
#
|
33
|
+
def query_params
|
34
|
+
@query_params ||= Rack::Utils.parse_nested_query(query_string)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,138 @@
|
|
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
|
+
class Response
|
8
|
+
# @!attribute [rw] status
|
9
|
+
# @returns [Integer]
|
10
|
+
#
|
11
|
+
attr_accessor :status
|
12
|
+
|
13
|
+
# @!attribute [r] body
|
14
|
+
# @returns [Array]
|
15
|
+
#
|
16
|
+
attr_reader :body
|
17
|
+
|
18
|
+
# @!attribute [r] headers
|
19
|
+
# @returns [Hash]
|
20
|
+
#
|
21
|
+
attr_reader :headers
|
22
|
+
|
23
|
+
# @!attribute [r] length
|
24
|
+
# @returns [Integer]
|
25
|
+
#
|
26
|
+
attr_reader :length
|
27
|
+
|
28
|
+
# Constants
|
29
|
+
#
|
30
|
+
LOCATION = 'location'
|
31
|
+
private_constant :LOCATION
|
32
|
+
|
33
|
+
CONTENT_TYPE = 'content-type'
|
34
|
+
private_constant :CONTENT_TYPE
|
35
|
+
|
36
|
+
CONTENT_LENGTH = 'content-length'
|
37
|
+
private_constant :CONTENT_LENGTH
|
38
|
+
|
39
|
+
ContentType = { HTML: 'text/html', TEXT: 'text/plain', JSON: 'application/json' }.freeze
|
40
|
+
private_constant :ContentType
|
41
|
+
|
42
|
+
# Initialize the response object
|
43
|
+
#
|
44
|
+
# @returns [Response]
|
45
|
+
#
|
46
|
+
def initialize
|
47
|
+
@status = 404
|
48
|
+
@headers = {}
|
49
|
+
@body = []
|
50
|
+
@length = 0
|
51
|
+
end
|
52
|
+
|
53
|
+
# Set the response header
|
54
|
+
#
|
55
|
+
# @parameter [String] key
|
56
|
+
#
|
57
|
+
# @returns [String] value
|
58
|
+
#
|
59
|
+
def [](key)
|
60
|
+
@headers[key]
|
61
|
+
end
|
62
|
+
|
63
|
+
# Get the response header
|
64
|
+
#
|
65
|
+
# @parameter [String] key
|
66
|
+
# @parameter [String] value
|
67
|
+
#
|
68
|
+
# @returns [String] value
|
69
|
+
#
|
70
|
+
def []=(key, value)
|
71
|
+
@headers[key] = value
|
72
|
+
end
|
73
|
+
|
74
|
+
# Write to the response body
|
75
|
+
#
|
76
|
+
# @parameter [String] str
|
77
|
+
#
|
78
|
+
# @returns [String] str
|
79
|
+
#
|
80
|
+
def write(str)
|
81
|
+
str = str.to_s
|
82
|
+
@length += str.bytesize
|
83
|
+
@headers[CONTENT_LENGTH] ||= @length.to_s
|
84
|
+
@body << str
|
85
|
+
end
|
86
|
+
|
87
|
+
# Set the response type to text
|
88
|
+
#
|
89
|
+
# @parameter [String] str
|
90
|
+
#
|
91
|
+
# @returns [String] str
|
92
|
+
#
|
93
|
+
def text(str)
|
94
|
+
@headers[CONTENT_TYPE] = ContentType[:TEXT]
|
95
|
+
write(str)
|
96
|
+
end
|
97
|
+
|
98
|
+
# Set the response type to html
|
99
|
+
#
|
100
|
+
# @parameter [String] str
|
101
|
+
#
|
102
|
+
# @returns [String] str
|
103
|
+
#
|
104
|
+
def html(str)
|
105
|
+
@headers[CONTENT_TYPE] = ContentType[:HTML]
|
106
|
+
write(str)
|
107
|
+
end
|
108
|
+
|
109
|
+
# Set the response type to json
|
110
|
+
#
|
111
|
+
# @parameter [String] str
|
112
|
+
#
|
113
|
+
# @returns [String] str
|
114
|
+
#
|
115
|
+
def json(str)
|
116
|
+
@headers[CONTENT_TYPE] = ContentType[:JSON]
|
117
|
+
write(str)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Redirect the response
|
121
|
+
#
|
122
|
+
# @parameter [String] path
|
123
|
+
# @parameter [Integer] status, default: 302
|
124
|
+
#
|
125
|
+
def redirect(path, status = 302)
|
126
|
+
@headers[LOCATION] = path
|
127
|
+
@status = status
|
128
|
+
end
|
129
|
+
|
130
|
+
# Finish the response
|
131
|
+
#
|
132
|
+
# @returns [Array] response
|
133
|
+
#
|
134
|
+
def finish
|
135
|
+
[@status, @headers, @body]
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,73 @@
|
|
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
|
+
class RouteNode
|
8
|
+
attr_accessor :children, :blocks, :param_key
|
9
|
+
|
10
|
+
# Initialize the route node
|
11
|
+
#
|
12
|
+
# @return [RouteNode]
|
13
|
+
#
|
14
|
+
def initialize
|
15
|
+
@children = {}
|
16
|
+
@blocks = {}
|
17
|
+
@param_key = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
# Add a route to the route node
|
21
|
+
#
|
22
|
+
# @parameter [Array] parts
|
23
|
+
# @parameter [String] http_method
|
24
|
+
# @parameter [Proc] block
|
25
|
+
#
|
26
|
+
# @return [void]
|
27
|
+
#
|
28
|
+
def add_route(parts, http_method, block)
|
29
|
+
current_node = self
|
30
|
+
|
31
|
+
parts.each do |part|
|
32
|
+
if part.start_with?(':')
|
33
|
+
key = :param
|
34
|
+
current_node.children[key] ||= RouteNode.new
|
35
|
+
current_node = current_node.children[key]
|
36
|
+
current_node.param_key = part[1..].to_sym
|
37
|
+
else
|
38
|
+
key = part
|
39
|
+
current_node.children[key] ||= RouteNode.new
|
40
|
+
current_node = current_node.children[key]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
current_node.blocks[http_method] = block
|
45
|
+
end
|
46
|
+
|
47
|
+
# Match a route to the route node
|
48
|
+
#
|
49
|
+
# @parameter [Array] parts
|
50
|
+
# @parameter [String] http_method
|
51
|
+
#
|
52
|
+
# @return [Array]
|
53
|
+
#
|
54
|
+
def match_route(parts, http_method)
|
55
|
+
current_node = self
|
56
|
+
params = {}
|
57
|
+
|
58
|
+
parts.each do |part|
|
59
|
+
return [nil, nil] unless current_node.children.key?(part) || current_node.children[:param]
|
60
|
+
|
61
|
+
if current_node.children.key?(part)
|
62
|
+
current_node = current_node.children[part]
|
63
|
+
else
|
64
|
+
param_node = current_node.children[:param]
|
65
|
+
params[param_node.param_key] = part
|
66
|
+
current_node = param_node
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
[current_node.blocks[http_method], params]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/lib/lennarb/version.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Released under the MIT License.
|
4
|
-
# Copyright, 2023, by Aristóteles Coutinho.
|
4
|
+
# Copyright, 2023-2024, by Aristóteles Coutinho.
|
5
5
|
|
6
|
-
|
7
|
-
VERSION = '0.
|
6
|
+
class Lennarb
|
7
|
+
VERSION = '0.4.0'
|
8
8
|
|
9
9
|
public_constant :VERSION
|
10
10
|
end
|
data/lib/lennarb.rb
CHANGED
@@ -1,46 +1,139 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Released under the MIT License.
|
4
|
-
# Copyright, 2023, by Aristóteles Coutinho.
|
4
|
+
# Copyright, 2023-2024, by Aristóteles Coutinho.
|
5
5
|
|
6
6
|
ENV['RACK_ENV'] ||= 'development'
|
7
7
|
|
8
|
-
#
|
8
|
+
# Core extensions
|
9
9
|
#
|
10
|
-
require '
|
10
|
+
require 'pathname'
|
11
|
+
require 'rack'
|
11
12
|
|
12
13
|
# Base class for Lennarb
|
13
14
|
#
|
14
|
-
|
15
|
-
|
15
|
+
require_relative 'lennarb/request'
|
16
|
+
require_relative 'lennarb/response'
|
17
|
+
require_relative 'lennarb/route_node'
|
18
|
+
require_relative 'lennarb/version'
|
16
19
|
|
17
|
-
|
18
|
-
#
|
19
|
-
|
20
|
+
class Lennarb
|
21
|
+
# Error class
|
22
|
+
#
|
23
|
+
class LennarbError < StandardError; end
|
20
24
|
|
21
|
-
#
|
22
|
-
#
|
23
|
-
|
25
|
+
# @attribute [r] root
|
26
|
+
# @returns [RouteNode]
|
27
|
+
#
|
28
|
+
attr_reader :root
|
24
29
|
|
25
|
-
#
|
26
|
-
#
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
30
|
+
# Initialize the application
|
31
|
+
#
|
32
|
+
# @yield { ... } The application
|
33
|
+
#
|
34
|
+
# @returns [Lennarb]
|
35
|
+
#
|
36
|
+
def initialize
|
37
|
+
@root = RouteNode.new
|
38
|
+
yield self if block_given?
|
39
|
+
end
|
32
40
|
|
33
|
-
#
|
34
|
-
#
|
35
|
-
|
36
|
-
|
41
|
+
# Split a path into parts
|
42
|
+
#
|
43
|
+
# @parameter [String] path
|
44
|
+
#
|
45
|
+
# @returns [Array] parts. Ex. ['users', ':id']
|
46
|
+
#
|
47
|
+
SplitPath = ->(path) { path.split('/').reject(&:empty?) }
|
48
|
+
private_constant :SplitPath
|
37
49
|
|
38
|
-
#
|
50
|
+
# Call the application
|
51
|
+
#
|
52
|
+
# @parameter [Hash] env
|
39
53
|
#
|
40
|
-
# @
|
54
|
+
# @returns [Array] response
|
41
55
|
#
|
42
|
-
def
|
43
|
-
|
44
|
-
|
56
|
+
def call(env)
|
57
|
+
http_method = env.fetch('REQUEST_METHOD').to_sym
|
58
|
+
parts = SplitPath[env.fetch('PATH_INFO')]
|
59
|
+
|
60
|
+
block, params = @root.match_route(parts, http_method)
|
61
|
+
return [404, { 'content-type' => 'text/plain' }, ['Not Found']] unless block
|
62
|
+
|
63
|
+
res = Response.new
|
64
|
+
req = Request.new(env, params)
|
65
|
+
instance_exec(req, res, &block)
|
66
|
+
|
67
|
+
res.finish
|
68
|
+
end
|
69
|
+
|
70
|
+
# Add a routes
|
71
|
+
#
|
72
|
+
# @parameter [String] path
|
73
|
+
# @parameter [Proc] block
|
74
|
+
#
|
75
|
+
# @returns [void]
|
76
|
+
#
|
77
|
+
def get(path, &block) = __add_route__(path, :GET, block)
|
78
|
+
def post(path, &block) = __add_route__(path, :POST, block)
|
79
|
+
def put(path, &block) = __add_route__(path, :PUT, block)
|
80
|
+
def patch(path, &block) = __add_route__(path, :PATCH, block)
|
81
|
+
def delete(path, &block) = __add_route__(path, :DELETE, block)
|
82
|
+
|
83
|
+
# Add a route
|
84
|
+
#
|
85
|
+
# @parameter [String] path
|
86
|
+
# @parameter [String] http_method
|
87
|
+
# @parameter [Proc] block
|
88
|
+
#
|
89
|
+
# @returns [void]
|
90
|
+
#
|
91
|
+
def __add_route__(path, http_method, block)
|
92
|
+
parts = SplitPath[path]
|
93
|
+
@root.add_route(parts, http_method, block)
|
94
|
+
end
|
95
|
+
|
96
|
+
# Base module for the application. The main purpose is to include the class methods
|
97
|
+
# and call the Lennarb instance.
|
98
|
+
#
|
99
|
+
module ApplicationBase
|
100
|
+
# Include the class methods
|
101
|
+
#
|
102
|
+
# @parameter [Class] base
|
103
|
+
#
|
104
|
+
# @returns [void]
|
105
|
+
#
|
106
|
+
def self.included(base) = base.extend(ClassMethods)
|
107
|
+
|
108
|
+
# Call the Lennarb instance
|
109
|
+
#
|
110
|
+
# @parameter [Hash] env
|
111
|
+
#
|
112
|
+
# @returns [Array]
|
113
|
+
#
|
114
|
+
def call(env) = self.class.lennarb_instance.call(env)
|
115
|
+
|
116
|
+
# Class methods
|
117
|
+
#
|
118
|
+
module ClassMethods
|
119
|
+
# Get the Lennarb instance
|
120
|
+
#
|
121
|
+
# @returns [Lennarb]
|
122
|
+
#
|
123
|
+
def lennarb_instance = @lennarb_instance ||= Lennarb.new
|
124
|
+
|
125
|
+
# Add a route
|
126
|
+
#
|
127
|
+
# @parameter [String] path
|
128
|
+
# @parameter [Proc] block
|
129
|
+
#
|
130
|
+
# @returns [void]
|
131
|
+
#
|
132
|
+
def get(path, &block) = lennarb_instance.__add_route__(path, :GET, block)
|
133
|
+
def put(path, &block) = lennarb_instance.__add_route__(path, :PUT, block)
|
134
|
+
def post(path, &block) = lennarb_instance.__add_route__(path, :POST, block)
|
135
|
+
def patch(path, &block) = lennarb_instance.__add_route__(path, :PATCH, block)
|
136
|
+
def delete(path, &block) = lennarb_instance.__add_route__(path, :DELETE, block)
|
137
|
+
end
|
45
138
|
end
|
46
139
|
end
|
data/license.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# MIT License
|
2
2
|
|
3
|
-
Copyright, 2023, by Aristóteles Coutinho.
|
3
|
+
Copyright, 2023-2024, by Aristóteles Coutinho.
|
4
|
+
Copyright, 2023, by aristotelesbr.
|
4
5
|
|
5
6
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
7
|
of this software and associated documentation files (the "Software"), to deal
|
data/readme.md
CHANGED
@@ -1,26 +1,47 @@
|
|
1
1
|
# Lennarb
|
2
2
|
|
3
|
-
Lennarb is a
|
3
|
+
Lennarb is a lightweight, fast, and modular web framework for Ruby based on Rack. The **Lennarb** supports Ruby (MRI) 3.0+
|
4
4
|
|
5
|
-
|
5
|
+
**Basic Usage**
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
require "lennarb"
|
9
|
+
|
10
|
+
Lennarb.new do |router|
|
11
|
+
router.get("/hello/:name") do |req, res|
|
12
|
+
name = req.params[:name]
|
13
|
+
res.html("Hello, #{name}!")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
```
|
17
|
+
|
18
|
+
## Performance
|
6
19
|
|
7
|
-
|
20
|
+
### 1. Requests per Second (RPS)
|
8
21
|
|
9
|
-
|
22
|
+

|
10
23
|
|
11
|
-
|
24
|
+
See all [graphs](https://github.com/aristotelesbr/lennarb/blob/main/benchmark)
|
12
25
|
|
13
|
-
|
26
|
+
| Position | Application | 10 RPS | 100 RPS | 1.000 RPS | 10.000 RPS |
|
27
|
+
| -------- | ----------- | ---------- | ---------- | --------- | ---------- |
|
28
|
+
| 1 | Lenna | 126.252,36 | 108.086,55 | 87.111,91 | 68.460,64 |
|
29
|
+
| 2 | Roda | 123.360,37 | 88.380,56 | 66.990,77 | 48.108,29 |
|
30
|
+
| 3 | Syro | 114.105,38 | 80.909,39 | 61.415,86 | 46.639,81 |
|
31
|
+
| 4 | Hanami-API | 68.089,18 | 52.851,88 | 40.801,78 | 27.996,00 |
|
32
|
+
|
33
|
+
This table ranks the routers by the number of requests they can process per second. Higher numbers indicate better performance.
|
34
|
+
|
35
|
+
Plese see [Performance](https://aristotelesbr.github.io/lennarb/guides/performance/index.html) for more information.
|
36
|
+
|
37
|
+
## Usage
|
14
38
|
|
15
|
-
|
39
|
+
- [Getting Started](https://aristotelesbr.github.io/lennarb/guides/getting-started/index) - This guide covers getting up and running with **Lennarb**.
|
16
40
|
|
17
|
-
|
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).
|
18
42
|
|
19
|
-
|
20
|
-
|
21
|
-
3. Commit your changes (`git commit -am 'Add some feature'`).
|
22
|
-
4. Push to the branch (`git push origin my-new-feature`).
|
23
|
-
5. Create new Pull Request.
|
43
|
+
- [Response](https://aristotelesbr.github.io/lennarb/guides/response/index.html) - This is the response guide.
|
44
|
+
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`.
|
24
45
|
|
25
46
|
### Developer Certificate of Origin
|
26
47
|
|