lennarb 0.1.5 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
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