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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0ead58575158b4ee56a407d2dc1efc3b9ca7dbe00fef20cfd2f6151fbc1a6585
4
- data.tar.gz: 2b325e4277a93d86795c280acd6e3d83b4ec8090322e2f198889379d5e6e9244
3
+ metadata.gz: 9b8aeffe0440b8e7bc48ffa1cfb8cb4192896da0230e46fc2d900ff002a32889
4
+ data.tar.gz: 2384ea484c8f6a50460efefa32f11630a336c88b77b31c7f5591f987783049e3
5
5
  SHA512:
6
- metadata.gz: b407bd38f1d6e5dac470a165c8111b022150b501acd0f1b59b40c9a71216a7650888295aed80a8969e2206fec9e76b6f33fbf439c76e626eda430cd8caffcdba
7
- data.tar.gz: 53a49cea9ac29e8bd342867ae1714f72acdf5a3cf457b6d7d63a9962bbad9a5944bb186e9f9b627ae2c34e7c9950f3c7871aca2511d3df724f81bb34468defd4
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 of this
4
- software and associated documentation files (the "Software"), to deal in the Software
5
- without restriction, including without limitation the rights to use, copy, modify, merge,
6
- publish, distribute, sublicense, and/or sell copies of the Software, and to permit
7
- persons to whom the Software is furnished to do so, subject to the following conditions:
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 copies or
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 IMPLIED,
13
- INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14
- PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
15
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
16
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
17
- OR OTHER DEALINGS IN THE SOFTWARE.
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
- The `rackal` gem provides helpers in configuring directly configuring Rack.
3
+ [![Gem Version](https://badge.fury.io/rb/rackal.svg)](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 if used
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
- #=> Starting MyApp in production environment.
36
- puts "(root directory is #{Rackal.application.root})"
37
- #=> (root directory is /home/someuser/src/my_app)
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. Presently focus on mutation testing is
60
- ongoing.
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) was used as the original reference for boilerplate.
67
-
68
- Some application metadata concepts were inspired by Rails, with a much lighter approach taken.
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
- # TODO: -- drop this?!
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
- # stolen from Rails ActiveSupport (but simpler)
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
@@ -13,6 +13,7 @@ module Rackal
13
13
  end
14
14
  end
15
15
 
16
+ # @api private
16
17
  def initialize
17
18
  @parameters = parse
18
19
  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.2
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-10 00:00:00.000000000 Z
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.1.4
52
+ rubygems_version: 3.2.23
51
53
  signing_key:
52
54
  specification_version: 4
53
55
  summary: Rackal