rackal 0.0.2 → 0.0.3
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/LICENSE +17 -13
- data/README.md +126 -13
- data/lib/rackal.rb +20 -0
- data/lib/rackal/internal/application.rb +8 -25
- data/lib/rackal/internal/database_configuration.rb +1 -0
- data/lib/rackal/internal/rack_environment.rb +1 -1
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9b8aeffe0440b8e7bc48ffa1cfb8cb4192896da0230e46fc2d900ff002a32889
|
4
|
+
data.tar.gz: 2384ea484c8f6a50460efefa32f11630a336c88b77b31c7f5591f987783049e3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3c7c8ad588cb2a63806cf3117e93d88a1e2924937bf7e850618b370b8ef554faba7cf86818eeac6d93ad21a8eb1a300d8de4d685c9e8cfd1d5ae48cf03eee0bf
|
7
|
+
data.tar.gz: 23e739d63c605079ba3a977294fb857835f87b5df42313822450ed5d84762943263c442410fb0101eb15d3b3c712ff91a2a83034a6f6cf8205f67e2d0a422d79
|
data/LICENSE
CHANGED
@@ -1,17 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
1
3
|
Copyright (c) 2021 Richard Newman
|
2
4
|
|
3
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
-
software and associated documentation files (the "Software"), to deal
|
5
|
-
without restriction, including without limitation the rights
|
6
|
-
publish, distribute, sublicense, and/or sell
|
7
|
-
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
8
11
|
|
9
|
-
The above copyright notice and this permission notice shall be included in all
|
10
|
-
substantial portions of the Software.
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
11
14
|
|
12
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
13
|
-
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
14
|
-
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
15
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
16
|
-
|
17
|
-
OR OTHER DEALINGS IN THE
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# Rackal
|
2
2
|
|
3
|
-
|
3
|
+
[](https://badge.fury.io/rb/rackal)
|
4
|
+
|
5
|
+
The `rackal` gem provides convenience helpers when configuring Rack applications.
|
4
6
|
|
5
7
|
The main intent is abstract away some common boilerplate and reduce hardcoded details in
|
6
8
|
application configuration, especially in `config.ru`, in a way that still allows some
|
@@ -8,13 +10,16 @@ direct control of how it is applied.
|
|
8
10
|
|
9
11
|
Rackal was originally developed to simplify set up of Roda apps but is intended to not
|
10
12
|
assume or depend on Roda. As of this writing, no testing with Sinatra or bare Rack apps has
|
11
|
-
been performed, so milage may vary. This gem is still considered experimental
|
13
|
+
been performed, so milage may vary. This gem is still considered experimental (at least
|
14
|
+
until version number is updated to at least 0.1.0).
|
12
15
|
|
13
16
|
## Features
|
14
17
|
* Environment aware: "production", "staging", "test", and "development" are recognized (based on ENV['RACK_ENV'])
|
15
|
-
* Database configuration: easy access to database configuration (based on YAML)
|
16
|
-
* Application metadata: easy access to application details (trivial YAML configuration)
|
17
|
-
* Application protection: easy use of Refrigerator gem
|
18
|
+
* Database configuration: easy access to database configuration (based on YAML configuration file)
|
19
|
+
* Application metadata: easy access to application details (trivial YAML configuration file)
|
20
|
+
* Application protection: easy use of [Refrigerator](https://github.com/jeremyevans/ruby-refrigerator) gem (when available)
|
21
|
+
|
22
|
+
Easy setup for application logging is being considered for inclusion in Rackal.
|
18
23
|
|
19
24
|
## Example `config.ru`
|
20
25
|
```
|
@@ -32,15 +37,110 @@ Gem.ruby
|
|
32
37
|
|
33
38
|
# these output lines demonstrate some use
|
34
39
|
puts "Starting #{Rackal.application.name} in #{Rackal.environment.env} environment."
|
35
|
-
|
36
|
-
puts "(root directory is #{Rackal.
|
37
|
-
|
40
|
+
# => Starting MyApp in production environment.
|
41
|
+
puts "(root directory is \"#{Rackal.root}\")"
|
42
|
+
# => (root directory is "/home/someuser/src/my_app")
|
38
43
|
|
39
44
|
run(Rackal.application.main_class.freeze.app) # main_class is the driving class of the application
|
40
45
|
|
41
46
|
Rackal.protect! # applies Refrigerator if gem is present in production settings
|
42
47
|
```
|
43
48
|
|
49
|
+
An demonstration application using Rackal will be provided in a later version.
|
50
|
+
|
51
|
+
## Main interface
|
52
|
+
Available as namespaced methods:
|
53
|
+
|
54
|
+
* `Rackal.application` returns an object allowing access to various application metadata
|
55
|
+
* `Rackal.root` returns the inferred root directory of the application (same as `Rackal.appliation.root`)
|
56
|
+
* `Rackal.database_parameters` returns Hash of database connection attributes (see below)
|
57
|
+
* `Rackal.environment` returns an object allowing access to various runtime environment (e.g., "production") metadata
|
58
|
+
* `Rackal.env` convenience use of `ENV` array (with caching) (e.g., `Rackal.env("RACK_ENV")` == `ENV["RACK_ENV"]`)
|
59
|
+
* `Rackal.protect!` applies [Refrigerator](https://github.com/jeremyevans/ruby-refrigerator) gem (if available) to lock/freeze the application during run time. Merely returns `false` if gem is not available.
|
60
|
+
|
61
|
+
If `ENV["RACK_ENV"]` is `nil` for whatever reason, Rackal will assume a development environment.
|
62
|
+
|
63
|
+
## Configuration
|
64
|
+
Two configuration files, written in YAML, will be assumed to be under `/config` directory for
|
65
|
+
the application: `database.yml` and `rackal.yml`
|
66
|
+
|
67
|
+
### Twelve-factor app
|
68
|
+
If adhering to the [twelve-factor app](https://12factor.net/config) standard, recall that
|
69
|
+
deploy-level configuration should not included in code, but application configuration can
|
70
|
+
be.
|
71
|
+
|
72
|
+
Rackal does not interfere with use of tools like [dotenv](https://github.com/bkeepers/dotenv)
|
73
|
+
or [figaro](https://github.com/laserlemon/figaro) to support deploy-level environment variable.
|
74
|
+
Merely add that to the application startup (e.g., `config.ru`) in the usual way before
|
75
|
+
calling any Rackal methods.
|
76
|
+
|
77
|
+
Since the YAML files used for Rackal's configuration support ERB, those files can then
|
78
|
+
follow the environment variables supplied dynamically when wanted, while leaving
|
79
|
+
application-level directly supplied. The `database.yml` example below shows such a use
|
80
|
+
for credentials.
|
81
|
+
|
82
|
+
### `database.yml`
|
83
|
+
|
84
|
+
The `database.yml` file is just to collect, by runtime environment, the parameters for
|
85
|
+
connecting to the database.
|
86
|
+
|
87
|
+
If `Rackal.database_parameters` is never called, this YAML file need not be present.
|
88
|
+
|
89
|
+
Example (for Sequel using Postgres):
|
90
|
+
```
|
91
|
+
default: &default
|
92
|
+
adapter: 'postgres'
|
93
|
+
# host: 'some_db_url'
|
94
|
+
# port: '5432'
|
95
|
+
database: 'myapp'
|
96
|
+
max_connections: 10
|
97
|
+
username: <%= Rackal.env('MYAPP_DATABASE_USERNAME') %>
|
98
|
+
password: <%= Rackal.env('MYAPP_DATABASE_PASSWORD') %>
|
99
|
+
|
100
|
+
development:
|
101
|
+
<<: *default
|
102
|
+
host: 'localhost'
|
103
|
+
database: 'myapp_dev'
|
104
|
+
|
105
|
+
test:
|
106
|
+
<<: *default
|
107
|
+
host: 'localhost'
|
108
|
+
database: 'myapp_test'
|
109
|
+
|
110
|
+
staging:
|
111
|
+
<<: *default
|
112
|
+
|
113
|
+
production:
|
114
|
+
<<: *default
|
115
|
+
```
|
116
|
+
|
117
|
+
For the given runtime environment, the configured parameters are available in code via
|
118
|
+
`Rackal.database_parameters` which provides a Hash (using symbols as keys):
|
119
|
+
```
|
120
|
+
Rackal.database_parameters[:database]
|
121
|
+
# => "myapp_test" if ENV['RACK_ENV'] == "test"
|
122
|
+
```
|
123
|
+
|
124
|
+
### `rackal.yml`
|
125
|
+
|
126
|
+
The `rackal.yml` file is for any specifics to inform Rackal of assumptions it can make.
|
127
|
+
|
128
|
+
Presently, only the name of the application is configured to support inference of how
|
129
|
+
to refer to it in the boilerplate it abstracts away (e.g., class name, source file name).
|
130
|
+
|
131
|
+
If neither `Rackal.root` nor `Rackal.application` are ever called (unlikely), this YAML file
|
132
|
+
need not be present.
|
133
|
+
|
134
|
+
Example:
|
135
|
+
```
|
136
|
+
rackal:
|
137
|
+
app_main: 'SomeApp' # note that this is the class name, provided as a string
|
138
|
+
```
|
139
|
+
|
140
|
+
* `app_main`: class name of the main class used to drive the application.
|
141
|
+
* The string, as given, is available in code as `Rackal.application.name`
|
142
|
+
* The class, as a constant, is available in case as `Rackal.application.main_class`
|
143
|
+
|
44
144
|
## Performance
|
45
145
|
Given that one key feature of Roda is its performance and memory footprint, care was taken
|
46
146
|
to avoid interferring with that. Any cost is constrained as much as possible to only
|
@@ -56,16 +156,29 @@ Since a Gemfile is used for testing and development conveniences without polluti
|
|
56
156
|
gem itself, be sure to `bundle install`. RSpec, simplecov, and rubocop are assumed, but
|
57
157
|
only RSpec itself is required.
|
58
158
|
|
59
|
-
The provided RSpec tests have strong coverage
|
60
|
-
|
159
|
+
The provided RSpec tests have strong coverage for regression testing. Mutation testing
|
160
|
+
will be attempted soon.
|
61
161
|
|
62
162
|
Further development is invited to better support Roda applications, extensions and
|
63
163
|
generalization for non-Roda Rack applications, and performance improvements.
|
64
164
|
|
65
165
|
## Acknowledgements
|
66
|
-
Jeremy Evans's `roda-sequel-stack` [repository](https://github.com/jeremyevans/roda-sequel-stack)
|
67
|
-
|
68
|
-
|
166
|
+
Jeremy Evans's `roda-sequel-stack` [repository](https://github.com/jeremyevans/roda-sequel-stack)
|
167
|
+
was used as an original reference for boilerplate (though the "up"/"down" mechanics for
|
168
|
+
database migrations are not considered in Rackal).
|
169
|
+
|
170
|
+
Some application metadata concepts were inspired by Rails (for instance, `Rackal.root`),
|
171
|
+
though with a much lighter (and so less robust) approach taken in Rackal.
|
172
|
+
|
173
|
+
## Limitations
|
174
|
+
* Rackal (primarily `Rackal.root`) assumes use in a Linux style OS and so use of `/` as a
|
175
|
+
path delimiter.
|
176
|
+
* Right now, `Rackal.database_parameters` has only been tested with Sequel ORM for database
|
177
|
+
connections, though the use of YAML to produce the Hash should be universally capable.
|
178
|
+
* (As stated in the introduction to this notes,) Rackal has not been tested with a bare
|
179
|
+
Rack application or with a Sinatra application.
|
180
|
+
|
181
|
+
Please [report issues or bugs](https://github.com/rdnewman/rackal/issues).
|
69
182
|
|
70
183
|
## License
|
71
184
|
Rackal is released under the [MIT License](https://opensource.org/licenses/MIT).
|
data/lib/rackal.rb
CHANGED
@@ -16,6 +16,12 @@ module Rackal
|
|
16
16
|
@environment = Internal::RackEnvironment.new(options)
|
17
17
|
end
|
18
18
|
|
19
|
+
# Retrieves database connection parameters from configuration file
|
20
|
+
# Requires `config/database.yml`.
|
21
|
+
#
|
22
|
+
# @param [Hash] options
|
23
|
+
# @option options [true, false] :reset If true, resets cache and ensure fresh retrieval (defaults to: false)
|
24
|
+
# @return [Hash]
|
19
25
|
def self.database_parameters(options = {})
|
20
26
|
reload = options.delete(:reload) || false
|
21
27
|
@database_parameters = nil if reload
|
@@ -23,6 +29,11 @@ module Rackal
|
|
23
29
|
@database_parameters ||= Internal::DatabaseConfiguration.parameters
|
24
30
|
end
|
25
31
|
|
32
|
+
# Retrieves OS environment values (`ENV`)
|
33
|
+
#
|
34
|
+
# @param [Hash] options
|
35
|
+
# @option options [true, false] :reset If true, resets cache and ensure fresh retrieval (defaults to: false)
|
36
|
+
# @return [String]
|
26
37
|
def self.env(key, options = {})
|
27
38
|
reload = options.delete(:reload) || false
|
28
39
|
@env = nil if reload
|
@@ -32,14 +43,23 @@ module Rackal
|
|
32
43
|
@env[key] || (@env[key] = ENV.fetch(key.to_s, nil))
|
33
44
|
end
|
34
45
|
|
46
|
+
# Retrieves application details. Requires `config/rackal.yml`.
|
47
|
+
#
|
48
|
+
# @return [Object] an object
|
35
49
|
def self.application
|
36
50
|
@application ||= Internal::Application.new
|
37
51
|
end
|
38
52
|
|
53
|
+
# Applies Refrigerator gem (if available) in protected Rack environments
|
54
|
+
#
|
55
|
+
# @return [true, false] true if gem available and in protected environment; otherwise, false
|
39
56
|
def self.protect!
|
40
57
|
Internal::Protection.apply
|
41
58
|
end
|
42
59
|
|
60
|
+
# Returns root directory (inferred) for the application. Requires `config/rackal.yml`.
|
61
|
+
#
|
62
|
+
# @return [String] top (root) directory for the application
|
43
63
|
def self.root
|
44
64
|
@root ||= application.root
|
45
65
|
end
|
@@ -5,11 +5,7 @@ module Rackal
|
|
5
5
|
class Application
|
6
6
|
include ConfigurationFile
|
7
7
|
|
8
|
-
#
|
9
|
-
def self.root
|
10
|
-
new.root
|
11
|
-
end
|
12
|
-
|
8
|
+
# @api private
|
13
9
|
def initialize
|
14
10
|
@config = parse
|
15
11
|
end
|
@@ -18,16 +14,17 @@ module Rackal
|
|
18
14
|
@config[:app_main]
|
19
15
|
end
|
20
16
|
|
21
|
-
# only supports bare class names (not under a namespace)
|
22
17
|
def main_class
|
18
|
+
# only supports bare class names (not under a namespace)
|
23
19
|
raise NameError unless name
|
24
20
|
|
25
21
|
@main_class ||= Object.const_get(name)
|
26
22
|
end
|
27
23
|
|
28
|
-
# lightly inspired by Rails implementation in
|
29
|
-
# railties/lib/rails/engine.rb#find_root_with_flag
|
30
24
|
def root
|
25
|
+
# lightly inspired by Rails implementation in
|
26
|
+
# railties/lib/rails/engine.rb#find_root_with_flag
|
27
|
+
|
31
28
|
return @root if defined?(@root) && @root
|
32
29
|
|
33
30
|
paths = potential_root_paths
|
@@ -51,24 +48,12 @@ module Rackal
|
|
51
48
|
@parse = read_configuration('rackal') { |content| content.fetch('rackal') }
|
52
49
|
end
|
53
50
|
|
54
|
-
# only works in linux style OS (assumes path delimiter "/")
|
55
51
|
def potential_root_paths
|
52
|
+
# only works in linux style OS (assumes path delimiter "/")
|
53
|
+
|
56
54
|
appname = main_class_rb_filename
|
57
55
|
|
58
56
|
caller_locations.lazy.map { |location| assess_location(location, appname) }
|
59
|
-
# assess_location
|
60
|
-
# path = location.absolute_path || location.path
|
61
|
-
# dirname = File.dirname(path)
|
62
|
-
|
63
|
-
# {
|
64
|
-
# dirname: dirname,
|
65
|
-
# configru: File.directory?(dirname) && File.exist?("#{dirname}/config.ru"),
|
66
|
-
# app: appname && (File.directory?(dirname) && File.exist?("#{dirname}/#{appname}")),
|
67
|
-
# # configru: File.directory?(path) && File.exist?("#{path}/config.ru"),
|
68
|
-
# # app: appname && (File.directory?(path) && File.exist?("#{path}/#{appname}")),
|
69
|
-
# lib: dirname.match?(/.*\/lib\/\z/)
|
70
|
-
# }
|
71
|
-
# end
|
72
57
|
end
|
73
58
|
|
74
59
|
def assess_location(location, appname)
|
@@ -79,8 +64,6 @@ module Rackal
|
|
79
64
|
dirname: dirname,
|
80
65
|
configru: File.directory?(dirname) && File.exist?("#{dirname}/config.ru"),
|
81
66
|
app: appname && (File.directory?(dirname) && File.exist?("#{dirname}/#{appname}")),
|
82
|
-
# configru: File.directory?(path) && File.exist?("#{path}/config.ru"),
|
83
|
-
# app: appname && (File.directory?(path) && File.exist?("#{path}/#{appname}")),
|
84
67
|
lib: dirname.match?(/.*\/lib\/\z/)
|
85
68
|
}
|
86
69
|
end
|
@@ -88,7 +71,7 @@ module Rackal
|
|
88
71
|
def main_class_rb_filename
|
89
72
|
return nil unless name
|
90
73
|
|
91
|
-
#
|
74
|
+
# based on Rails ActiveSupport (but simpler)
|
92
75
|
word = name.gsub(/([A-Z\d]+)(?=[A-Z][a-z])|([a-z\d])(?=[A-Z])/) do
|
93
76
|
(Regexp.last_match(1) || Regexp.last_match(2)) << '_'
|
94
77
|
end
|
@@ -33,7 +33,7 @@ module Rackal
|
|
33
33
|
!supported?
|
34
34
|
end
|
35
35
|
|
36
|
-
# return Array list environments treated as protected (e.g., :production)
|
36
|
+
# @return Array list environments treated as protected (e.g., :production)
|
37
37
|
def protected
|
38
38
|
@protected ||= self.class.supported -
|
39
39
|
(@protect_test ? [:development] : [:development, :test])
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rackal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Richard Newman
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-07-
|
11
|
+
date: 2021-07-11 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: 'Rack application helpers
|
14
14
|
|
@@ -31,7 +31,9 @@ files:
|
|
31
31
|
homepage: https://rubygems.org/gems/rackal
|
32
32
|
licenses:
|
33
33
|
- MIT
|
34
|
-
metadata:
|
34
|
+
metadata:
|
35
|
+
source_code_uri: https://github.com/rdnewman/rackal
|
36
|
+
bug_tracker_uri: https://github.com/rdnewman/rackal/issues
|
35
37
|
post_install_message:
|
36
38
|
rdoc_options: []
|
37
39
|
require_paths:
|
@@ -47,7 +49,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
47
49
|
- !ruby/object:Gem::Version
|
48
50
|
version: '0'
|
49
51
|
requirements: []
|
50
|
-
rubygems_version: 3.
|
52
|
+
rubygems_version: 3.2.23
|
51
53
|
signing_key:
|
52
54
|
specification_version: 4
|
53
55
|
summary: Rackal
|