lennarb 0.1.5 → 0.1.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 59a236423ff7acaaeec6bf3b3b2a7dd42bfbc704eac97f7e2c7aa0539ebc0f45
4
- data.tar.gz: 19b0a12ce5aa48f252c1ff342987b3c4e42073fe80a584dd983c3739321b316c
3
+ metadata.gz: b3b1fe759bb5de90ef757201a4023c441a9c40146f31a318aecc5c5c08cd04bb
4
+ data.tar.gz: 8137ee838ca5636d7013cbfa5aa5f7e83d66e3b28d3387255b702d82becd884a
5
5
  SHA512:
6
- metadata.gz: 4df198f477ac2fcb3c09efb95ad9ea2699d6a12051cc9bcacd56c65adfe6d7778eed6cc1e920d6df35141d4dbbbb5aab4dfcc4aaea00483666e836b114b9e5e3
7
- data.tar.gz: 03a57883380017a70be1974bd98cdd6df3bd851c1944f787db4d97aec1ddc0f8947f3fc8a3179d817585d5a8ce877454f52a539ab8b77403bafe4cdd0321d7c1
6
+ metadata.gz: 3216bc56c89485d3292b621dcdfb26082957bea1ecfc622107b2f631f86508d7eb5318ce5bc43889ccf0db59775dcefd34e7e4ac00f5b023f34c4f371bab83b9
7
+ data.tar.gz: 944b432173eeeee78c2fc8d546ee74f6768ab3581a61babfdad27f8e54969afd96581259d8866126a3e6e26c2418f92355af8cc07d3aa215b0f9fb9a6bceccc0
data/changelog.md ADDED
@@ -0,0 +1,210 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.1.7] - 2023-23-12
9
+
10
+ ### Added
11
+
12
+ - Add `console` gem to print the logs in the console.
13
+
14
+ - Add CLI module to:
15
+ - Create a new project with `lennarb new` command.
16
+ - Run the server with `lennarb server` command.
17
+
18
+ - Add simple guide to create and run a project with Lennarb. See [guides/command-line/readme.md](guides/command-line/readme.md) for more details.
19
+
20
+ - Add `Reload` middleware to reload the application in development environment. You can import and use this middleware in your application. Ex.
21
+
22
+ ```rb
23
+ # app.rb
24
+
25
+ require 'lenna/middleware/default/reload'
26
+
27
+ app = Lenna::Application.new
28
+
29
+ app.use Lenna::Middleware::Default::Reload
30
+ ```
31
+
32
+ In the next version, this middleware will be available by default in development environment.
33
+
34
+ - Add `root` method to `Lennarb` module to get the root path of the project. Ex.
35
+
36
+ ```rb
37
+ # app.rb
38
+
39
+ Lennarb.root.join('app.rb')
40
+ # => /home/user/project/app.rb
41
+ ```
42
+
43
+ - Add `zeitwerk` gem to load the files in the project.
44
+
45
+ ### Remove
46
+
47
+ - Remove `Logging` and `ErrorHandling` middlewares from any environment. Now, theses middlewares are only available in development environment.
48
+
49
+ ### Changed
50
+
51
+ - Change log level to `fatal` in test environment.
52
+
53
+ ## [0.1.6] - 2023-21-12
54
+
55
+ ### Changed
56
+
57
+ - Update `README.md` with the new features. Move examples to `guides` folder.
58
+ - Replace `rubocop` to `standard` gem to lint the code.
59
+ - Move `puma` gem to development dependencies.
60
+ - Use tabs instead of spaces to indent the code.
61
+ - Add default middlewares to `Lennarb::Router` class. Now, the `Lennarb::Router` class has the following middlewares by default:
62
+
63
+ - `Lennarb::Middleware::Default::Logging`
64
+ - `Lennarb::Middleware::Default::ErrorHandling`
65
+
66
+ - Replace `assign_status` to `=` on Response
67
+
68
+ ```rb
69
+ response.status = 200
70
+ ```
71
+
72
+ - Rename `Lenna::Base` to `Lenna::Application` and accept a block to build the routes. Ex.
73
+
74
+ ```rb
75
+ Lenna::Application.new do |app|
76
+ app.get '/hello' do |req, res|
77
+ res.status = 200
78
+ res['Content-Type'] = 'text/plain'
79
+ res.body = 'Hello World'
80
+ end
81
+ app.post '/hello' do |req, res|
82
+ res.status = 200
83
+ res['Content-Type'] = 'text/plain'
84
+ res.body = 'Hello World'
85
+ end
86
+ end
87
+ ```
88
+
89
+ - The Middleware app now implements [Singleton](https://ruby-doc.org/stdlib-2.5.1/libdoc/singleton/rdoc/Singleton.html) pattern to manager state.
90
+
91
+ ### Added
92
+
93
+ - Add `standard` gem to lint the code.
94
+ - Add `maintenance` gropu to `Gemfile` with:
95
+ - Add `bake-gem` gem to run the tasks.
96
+ - Add `bake-modernize` gem to update the code to the latest Ruby version.
97
+ - Add `utopia-project` gem to generate the project.
98
+ - Add `bake-github-pages` to generate the GitHub Pages.
99
+ - Add `bake` gem to run the tasks.
100
+ - Add `puma` gem to run the development server.
101
+ - Add alias to `assign_header` to `[]=` on Response. Now, you can use:
102
+
103
+ ```rb
104
+ response['Content-Type'] = 'application/json'
105
+ ```
106
+
107
+ - Add alias to `assign_body` to `:body=` on Response. Now, you can use:
108
+
109
+ ```rb
110
+ response.body = 'Hello World'
111
+ ```
112
+
113
+ - Add alias to `assign_params` to `:params=` on Request. Now, you can use:
114
+
115
+ ```rb
116
+ request.params = { name: 'John' }
117
+ ```
118
+
119
+ ### Removed
120
+
121
+ - Remove `listen` method to run development server. Now, you must be use `.config.ru` file to run the development server. Ex.
122
+
123
+ ```rb
124
+ # .config.ru
125
+
126
+ require 'lennarb'
127
+
128
+ app = Lennarb::Application.new do |app|
129
+ app.get '/hello' do |req, res|
130
+ res.status = 200
131
+ res['Content-Type'] = 'text/plain'
132
+ res.body = 'Hello World'
133
+ end
134
+ app.post '/hello' do |req, res|
135
+ res.status = 200
136
+ res['Content-Type'] = 'text/plain'
137
+ res.body = 'Hello World'
138
+ end
139
+ end
140
+
141
+ run app
142
+ ```
143
+
144
+ - Remove Rakefile. Now, you must be use `bake` gem to run the tasks. Ex.
145
+
146
+ ```sh
147
+ bundle exec bake test
148
+ ```
149
+
150
+ ## Bug Fixes
151
+
152
+ - Fix default middlewares to `Lennarb::Router` class. Now, the `Lennarb::Router` class has the following middlewares by default:
153
+ - `Lennarb::Middleware::Default::Logging`
154
+ - `Lennarb::Middleware::Default::ErrorHandling`
155
+
156
+ ## [0.1.5] - 2023-25-11
157
+
158
+ ### Added
159
+
160
+ - Add `assign_params` method to Request class
161
+
162
+ ## [0.1.4] - 2023-25-11
163
+
164
+ ### Fixed
165
+
166
+ - Internal docmentation methods
167
+ - Fix `post_params` from Resquest router class
168
+
169
+ ### Added
170
+
171
+ - Add basic documentation for usage. See [README.md](README.md) for more details.
172
+
173
+ ## [0.1.3] - 2023-24-11
174
+
175
+ ## [0.1.2] - 2023-23-11
176
+
177
+ ### Added
178
+
179
+ - Implemented a specific error handler for Content-Type related errors, enhancing the system's ability to respond appropriately based on whether the request Content-Type is JSON or HTML.
180
+
181
+ ### Removed
182
+
183
+ - Removed the debug gem from development dependencies, streamlining the development environment setup.
184
+
185
+ ### Fixed
186
+
187
+ - Fixed a bug that prevented the correct reading of the Content-Type header in requests, ensuring proper handling of content types.
188
+
189
+ ## [0.1.1] - 2023-23-11
190
+
191
+ ### Added
192
+
193
+ - Introduced `Array.wrap` extension to the `Array` class for more reliable conversion of objects to arrays within the Lennarb router environment. This method ensures consistent array wrapping of single objects and `nil` values.
194
+
195
+ ### Changed
196
+
197
+ - Refactored the `put_header` method to use the `Array.wrap` method for more predictable header value handling.
198
+ - Renamed methods to have a consistent `assign_` prefix to standardize the API interface:
199
+ - `put_header` to `assign_header`
200
+ - `write_body` to `assign_body`
201
+ - `set_params` to `assign_params`
202
+ - `update_status` to `assign_status`
203
+
204
+ ### Deprecated
205
+
206
+ ### Removed
207
+
208
+ ### Fixed
209
+
210
+ ### Security
data/exe/lenna ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Released under the MIT License.
5
+ # Copyright, 2023, by Aristóteles Coutinho.
6
+
7
+ # Require the main file
8
+ #
9
+ # @private `Since v0.1`
10
+ #
11
+ require 'lennarb'
12
+
13
+ # Call the CLI to start the server
14
+ #
15
+ # @private `Since v0.1`
16
+ #
17
+ Lenna::Cli::App.run!(ARGV)
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2023, by Aristóteles Coutinho.
5
+
6
+ # Internal dependencies
7
+ #
8
+ require 'lenna/middleware/default/error_handler'
9
+ require 'lenna/middleware/default/logging'
10
+ require 'lenna/router'
11
+
12
+ # The Lenna module is used to namespace the framework.
13
+ #
14
+ # @public
15
+ #
16
+ module Lenna
17
+ # The base class is used to start the server.
18
+ #
19
+ # @public
20
+ #
21
+ class Application < Router
22
+ # Initialize the base class
23
+ #
24
+ # @yield { ... } the block to be evaluated in the context of the instance.
25
+ #
26
+ # @return [void | Application] Returns the instance if a block is given.
27
+ #
28
+ def initialize
29
+ super
30
+ yield self if block_given?
31
+ end
32
+ end
33
+
34
+ # The base module is used to include the base class.
35
+ #
36
+ # @public
37
+ #
38
+ module Base
39
+ def self.included(base)
40
+ base.extend(ClassMethods)
41
+ end
42
+
43
+ module ClassMethods
44
+ # Initialize the base module
45
+ #
46
+ # @return [Lenna::Application] Returns the instance.
47
+ #
48
+ # @public
49
+ #
50
+ def app = @app ||= Lenna::Application.new
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2023, by Aristóteles Coutinho.
5
+
6
+ module Lenna
7
+ module Cli
8
+ # Mediator class for CLI
9
+ #
10
+ # @private `Since v0.1.0`
11
+ #
12
+ module App
13
+ extend self
14
+ # Execute the command
15
+ #
16
+ # @return [void]
17
+ #
18
+ def run!(args)
19
+ subcommand = args.shift
20
+
21
+ strategy = parse_options(subcommand, args)
22
+
23
+ strategy.is_a?(Lenna::Cli::Commands::Interface) or fail ::ArgumentError
24
+
25
+ strategy.call
26
+ end
27
+
28
+ private
29
+
30
+ def parse_options(command, args)
31
+ case command
32
+ in 'new' | 'start' then Lenna::Cli::Commands::CreateProject.new(args)
33
+ in 'server' | 's' then Lenna::Cli::Commands::StartServer.new(args)
34
+ else 'help'
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2023, by Aristóteles Coutinho.
5
+
6
+ require 'console'
7
+ require 'erb'
8
+ require 'fileutils'
9
+
10
+ module Lenna
11
+ module Cli
12
+ module Commands
13
+ # Command for creating a new app
14
+ #
15
+ # @private `Since v0.1.0`
16
+ #
17
+ class CreateProject
18
+ include ::Lenna::Cli::Commands::Interface
19
+
20
+ # @!attribute [r] app_name
21
+ #
22
+ private attr_accessor :app_name
23
+
24
+ # Initialize the command
25
+ #
26
+ # @parameter app_name [Array<String>] The name of the app
27
+ #
28
+ def initialize(app_name)
29
+ self.app_name = app_name[0]
30
+ end
31
+
32
+ # Execute the command
33
+ #
34
+ # @parameter app_name [String] The name of the app
35
+ #
36
+ # @return [void]
37
+ #
38
+ def call
39
+ return puts 'Please specify an app name'.red if app_name.nil?
40
+
41
+ create_app(app_name) do
42
+ create_gemfile
43
+ create_config_ru
44
+ create_app_directory
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ # Create a directory for the app
51
+ #
52
+ # @parameter app_name [String] The name of the app
53
+ #
54
+ # @yield { ... } The block to be executed after the directory
55
+ #
56
+ # @return [void]
57
+ #
58
+ def create_app(app_name)
59
+ ::Console.info("Creating a new app named #{app_name}")
60
+
61
+ ::FileUtils.mkdir_p(app_name)
62
+
63
+ ::FileUtils.cd(app_name).tap { yield app_name } if block_given?
64
+
65
+ app_name
66
+ end
67
+
68
+ # Create a new Gemfile for the app. This will be use template
69
+ # file in the `templates` directory.
70
+ #
71
+ # @parameter app_name [String] The name of the app
72
+ #
73
+ # @return [void]
74
+ #
75
+ def create_gemfile
76
+ { version: Lennarb::VERSION }.then { create_template('gemfile', _1, 'Gemfile') }
77
+ end
78
+
79
+ # Create a new config.ru for the app. This will be use template
80
+ # file in the `templates` directory.
81
+ #
82
+ # @return [void]
83
+ #
84
+ def create_config_ru
85
+ create_template('config.ru', {})
86
+ end
87
+
88
+ # Create a new application.rb for the app. This will be use template
89
+ # file in the `templates` directory.
90
+ #
91
+ # @return [void]
92
+ #
93
+ # @See #create_template
94
+ # @See lenna/cli/templates/application
95
+ #
96
+ def create_app_directory
97
+ simple_template = <<~HTML.strip
98
+ '<h2>Hello, welcome to Lenna! #{Lennarb::VERSION}</h1>'
99
+ HTML
100
+ create_template('application', { simple_template: }, 'app/application.rb')
101
+ end
102
+
103
+ # Method for creating file based on a template
104
+ #
105
+ # @parameter template_name [String] The name of the template
106
+ # @parameter template_data [Hash] The data to be used in the template
107
+ #
108
+ # @return [void]
109
+ #
110
+ def create_template(template_name, template_data, file_name = template_name)
111
+ Lennarb # rubocop:disable Lint
112
+ .root
113
+ .join("lib/lenna/cli/templates/#{template_name}.erb")
114
+ .then { ::File.read(_1) }
115
+ .then { ::ERB.new(_1).result_with_hash(template_data) }
116
+ .then do |content|
117
+ return ::File.write(file_name, content) unless file_name.include?('/')
118
+
119
+ ::FileUtils.mkdir_p(::File.dirname(file_name)) && ::File.write(file_name, content)
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2023, by Aristóteles Coutinho.
5
+
6
+ module Lenna
7
+ module Cli
8
+ module Commands
9
+ module Interface
10
+ def new(args)
11
+ raise NotImplementedError
12
+ end
13
+
14
+ def call
15
+ raise NotImplementedError
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2023, by Aristóteles Coutinho.
5
+
6
+ require 'console'
7
+ require 'optparse'
8
+
9
+ module Lenna
10
+ module Cli
11
+ module Commands
12
+ # Command for creating a new app
13
+ #
14
+ # @private `Since v0.1.0`
15
+ #
16
+ class StartServer
17
+ include Lenna::Cli::Commands::Interface
18
+
19
+ # @!attribute [rw] port
20
+ # @return [Integer] Port to start the server
21
+ #
22
+ private attr_accessor :port
23
+ # @!attribute [rw] server
24
+ # @return [String] Server to start
25
+ #
26
+ private attr_accessor :server
27
+ # @!attribute [rw] command
28
+ # @return [String] Command to execute
29
+ #
30
+ private attr_accessor :command
31
+
32
+ def initialize(args)
33
+ self.command = args.shift
34
+
35
+ options = parse_options!(args)
36
+
37
+ self.port = options[:port]
38
+ self.server = options[:server]
39
+ end
40
+
41
+ # Execute the command
42
+ #
43
+ # @return [void]
44
+ #
45
+ def call
46
+ ::Console.debug("Starting server on port #{port}...")
47
+
48
+ case server
49
+ in 'puma' | 'falcon' => server then start_server(port:, server:)
50
+ else fail ::ArgumentError, ::Console.error("The server '#{server}' is not supported yet.")
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ # Parse the options
57
+ #
58
+ # @parameter args [Array<String>] The arguments
59
+ #
60
+ # @return [Hash] The options
61
+ #
62
+ def parse_options!(args)
63
+ options = { port: 4000, server: 'puma' }
64
+
65
+ ::OptionParser.new do |opts|
66
+ opts.banner = "Usage: lenna #{command} [options]"
67
+
68
+ opts.on('-p', '--port [PORT]', Integer, 'Port to start the server') do |port|
69
+ options[:port] = port
70
+ end
71
+
72
+ opts.on('-s', '--server [SERVER]', String, 'Server to start') do |server|
73
+ options[:server] = server
74
+ end
75
+ end.parse!(args)
76
+
77
+ options
78
+ end
79
+
80
+ # Start the server
81
+ #
82
+ # @paramaeter port [Integer] Port to start the server
83
+ # @paramaeter server [String] Server to start
84
+ #
85
+ # @return [void]
86
+ #
87
+ def start_server(port:, server:)
88
+ return warn_not_installed(server) unless instaled_gem?(server)
89
+
90
+ ::File.exist?(config_file) or fail ::StandardError, ::Console.error("'config.ru' not found in #{poroject_name}.")
91
+
92
+ system("bundle exec #{server} #{config_file} --port #{port}", chdir: current_path)
93
+ rescue ::ArgumentError
94
+ ::Console.error("The server '#{server}' is not supported yet.")
95
+ rescue ::Interrupt
96
+ ::Console.info("\nServer stopped.")
97
+ rescue ::StandardError => e
98
+ ::Console.error(self, e.message)
99
+ end
100
+
101
+ # Check if the gem is installed
102
+ #
103
+ # @parameter name [String] Name of the gem
104
+ #
105
+ # @return [Boolean]
106
+ #
107
+ def instaled_gem?(name)
108
+ ::Gem::Specification.find_by_name(name)
109
+ rescue ::Gem::LoadError
110
+ false
111
+ end
112
+
113
+ # Get the name of the project
114
+ #
115
+ # @return [String] Name of the project
116
+ #
117
+ def poroject_name = @current_path.split('/').last
118
+
119
+ # Get the path of the project
120
+ #
121
+ # @return [String] Path of the project
122
+ #
123
+ def current_path = @current_path ||= ::Dir.pwd
124
+
125
+ # Get the path of the config file
126
+ #
127
+ # @return [String] Path of the config file
128
+ #
129
+ def config_file = "#{current_path}/config.ru"
130
+
131
+ # Warn the user that the gem is not installed
132
+ #
133
+ # @parameter name [String] Name of the gem
134
+ #
135
+ # @return [void]
136
+ #
137
+ def warn_not_installed(name)
138
+ ::Console.warn("The gem '#{name}' is not installed. Please install it and try again.")
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'lennarb'
4
+
5
+ class Application
6
+ include Lenna::Base
7
+
8
+ app.get '/' do |req, res|
9
+ res.html(<%= simple_template %>)
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'app/application'
4
+
5
+ run Application.app
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # [https://rubygems.org/gems/lennarb]
6
+ # Lenna is a lightweight and experimental web framework for Ruby. It's designed
7
+ # to be modular and easy to use. Also, that's how I affectionately call my wife.
8
+ gem 'lennarb', '~> <%= version %>'
9
+ # [https://rubygems.org/gems/puma]
10
+ # Puma is a simple, fast, threaded, and highly parallel HTTP 1.1 server for Ruby/Rack applications.
11
+ gem 'puma', '~> 6.4'
12
+
13
+ group :development, :test do
14
+ end