superconfig 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/CODEOWNERS +4 -0
- data/.github/FUNDING.yml +4 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +41 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +23 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +38 -0
- data/.github/dependabot.yml +15 -0
- data/.github/workflows/ruby-tests.yml +49 -0
- data/.gitignore +10 -0
- data/.rubocop.yml +12 -0
- data/CHANGELOG.md +16 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +176 -0
- data/Rakefile +15 -0
- data/lib/superconfig/dotenv.rb +7 -0
- data/lib/superconfig.rb +182 -0
- data/superconfig.gemspec +34 -0
- data/superconfig.png +0 -0
- data/superconfig.svg +20 -0
- metadata +192 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 75ba7c940329c14aed30b1442f6e78b50286adbd42ccc0f1110d8923ee2b8ef3
|
4
|
+
data.tar.gz: 39430ed39dbc947935dee8705b52e52179f480867008f25b02f664fe47019581
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cb45a0fabec9816865b7635fa3bba29bd879f3b55997fa2dedb4703c3e7440774cb3e1c5d07421389fbdc04b27147954317ceabdc70b9695154aaee336d0b1f6
|
7
|
+
data.tar.gz: d19ec7430c5780af73cf2d7d8f51608dbff7f4f3f40cb7eb7923769af2ddf6f4352428d044002a0cd4df2eb0290e42d3a86cbd6ba3b11fef596e98e6d54565a2
|
data/.github/CODEOWNERS
ADDED
data/.github/FUNDING.yml
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
---
|
2
|
+
name: "🐛 Bug Report"
|
3
|
+
about: Report a reproducible bug or regression.
|
4
|
+
title: 'Bug: '
|
5
|
+
labels: 'Status: Unconfirmed'
|
6
|
+
|
7
|
+
---
|
8
|
+
|
9
|
+
<!--
|
10
|
+
- Please provide a clear and concise description of what the bug is.
|
11
|
+
- If possible, add an example reproducing your issue.
|
12
|
+
- Please test using the latest version of super-config
|
13
|
+
to make sure your issue has not already been fixed.
|
14
|
+
-->
|
15
|
+
|
16
|
+
## Description
|
17
|
+
|
18
|
+
[Add bug description here]
|
19
|
+
|
20
|
+
## How to reproduce
|
21
|
+
|
22
|
+
[Add steps on how to reproduce this issue]
|
23
|
+
|
24
|
+
## What do you expect
|
25
|
+
|
26
|
+
[Describe what do you expect to happen]
|
27
|
+
|
28
|
+
## What happened instead
|
29
|
+
|
30
|
+
[Describe the actual results]
|
31
|
+
|
32
|
+
## Software:
|
33
|
+
|
34
|
+
- Gem version: [Add gem version here]
|
35
|
+
- Ruby version: [Add version here]
|
36
|
+
|
37
|
+
## Full backtrace
|
38
|
+
|
39
|
+
```text
|
40
|
+
[Paste full backtrace here]
|
41
|
+
```
|
@@ -0,0 +1,23 @@
|
|
1
|
+
---
|
2
|
+
name: "💡 Feature request"
|
3
|
+
about: Have an idea that may be useful? Make a suggestion!
|
4
|
+
title: 'Feature Request: '
|
5
|
+
labels: 'Feature request'
|
6
|
+
|
7
|
+
---
|
8
|
+
|
9
|
+
## Description
|
10
|
+
|
11
|
+
_A clear and concise description of what the problem is._
|
12
|
+
|
13
|
+
## Describe the solution
|
14
|
+
|
15
|
+
_A clear and concise description of what you want to happen._
|
16
|
+
|
17
|
+
## Alternatives you considered
|
18
|
+
|
19
|
+
_A clear and concise description of any alternative solutions or features you've considered._
|
20
|
+
|
21
|
+
## Additional context
|
22
|
+
|
23
|
+
_Add any other context, screenshots, links, etc about the feature request here._
|
@@ -0,0 +1,38 @@
|
|
1
|
+
<!--
|
2
|
+
If you're making a doc PR or something tiny where the below is irrelevant,
|
3
|
+
delete this template and use a short description, but in your description aim to
|
4
|
+
include both what the change is, and why it is being made, with enough context
|
5
|
+
for anyone to understand.
|
6
|
+
-->
|
7
|
+
|
8
|
+
<details>
|
9
|
+
<summary>PR Checklist</summary>
|
10
|
+
|
11
|
+
### PR Structure
|
12
|
+
|
13
|
+
- [ ] This PR has reasonably narrow scope (if not, break it down into smaller
|
14
|
+
PRs).
|
15
|
+
- [ ] This PR avoids mixing refactoring changes with feature changes (split into
|
16
|
+
two PRs otherwise).
|
17
|
+
- [ ] This PR's title starts is concise and descriptive.
|
18
|
+
|
19
|
+
### Thoroughness
|
20
|
+
|
21
|
+
- [ ] This PR adds tests for the most critical parts of the new functionality or
|
22
|
+
fixes.
|
23
|
+
- [ ] I've updated any docs, `.md` files, etc… affected by this change.
|
24
|
+
|
25
|
+
</details>
|
26
|
+
|
27
|
+
### What
|
28
|
+
|
29
|
+
[TODO: Short statement about what is changing.]
|
30
|
+
|
31
|
+
### Why
|
32
|
+
|
33
|
+
[TODO: Why this change is being made. Include any context required to understand
|
34
|
+
the why.]
|
35
|
+
|
36
|
+
### Known limitations
|
37
|
+
|
38
|
+
[TODO or N/A]
|
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
# Documentation:
|
3
|
+
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
4
|
+
|
5
|
+
version: 2
|
6
|
+
updates:
|
7
|
+
- package-ecosystem: "github-actions"
|
8
|
+
directory: "/"
|
9
|
+
schedule:
|
10
|
+
interval: "daily"
|
11
|
+
|
12
|
+
- package-ecosystem: bundler
|
13
|
+
directory: "/"
|
14
|
+
schedule:
|
15
|
+
interval: "daily"
|
@@ -0,0 +1,49 @@
|
|
1
|
+
---
|
2
|
+
name: ruby-tests
|
3
|
+
|
4
|
+
on:
|
5
|
+
pull_request:
|
6
|
+
push:
|
7
|
+
workflow_dispatch:
|
8
|
+
inputs: {}
|
9
|
+
|
10
|
+
jobs:
|
11
|
+
build:
|
12
|
+
name: Tests with Ruby ${{ matrix.ruby }} and ${{ matrix.gemfile }}
|
13
|
+
runs-on: "ubuntu-latest"
|
14
|
+
strategy:
|
15
|
+
fail-fast: false
|
16
|
+
matrix:
|
17
|
+
ruby: ["2.7", "3.0"]
|
18
|
+
gemfile:
|
19
|
+
- Gemfile
|
20
|
+
|
21
|
+
steps:
|
22
|
+
- uses: actions/checkout@v1
|
23
|
+
|
24
|
+
- uses: actions/cache@v2
|
25
|
+
with:
|
26
|
+
path: vendor/bundle
|
27
|
+
key: >
|
28
|
+
${{ runner.os }}-${{ matrix.ruby }}-gems-${{ hashFiles(matrix.gemfile) }}
|
29
|
+
restore-keys: >
|
30
|
+
${{ runner.os }}-${{ matrix.ruby }}-gems-${{ hashFiles(matrix.gemfile) }}
|
31
|
+
|
32
|
+
- name: Set up Ruby
|
33
|
+
uses: ruby/setup-ruby@v1
|
34
|
+
with:
|
35
|
+
ruby-version: ${{ matrix.ruby }}
|
36
|
+
|
37
|
+
- name: Install gem dependencies
|
38
|
+
env:
|
39
|
+
BUNDLE_GEMFILE: ${{ matrix.gemfile }}
|
40
|
+
run: |
|
41
|
+
gem install bundler
|
42
|
+
bundle config path vendor/bundle
|
43
|
+
bundle update --jobs 4 --retry 3
|
44
|
+
|
45
|
+
- name: Run Tests
|
46
|
+
env:
|
47
|
+
BUNDLE_GEMFILE: ${{ matrix.gemfile }}
|
48
|
+
run: |
|
49
|
+
bundle exec rake
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
<!--
|
4
|
+
Prefix your message with one of the following:
|
5
|
+
|
6
|
+
- [Added] for new features.
|
7
|
+
- [Changed] for changes in existing functionality.
|
8
|
+
- [Deprecated] for soon-to-be removed features.
|
9
|
+
- [Removed] for now removed features.
|
10
|
+
- [Fixed] for any bug fixes.
|
11
|
+
- [Security] in case of vulnerabilities.
|
12
|
+
-->
|
13
|
+
|
14
|
+
## v1.0.0 - 2021-12-07
|
15
|
+
|
16
|
+
- Initial release as SuperConfig (previously known as env_vars).
|
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Contributor Code of Conduct
|
2
|
+
|
3
|
+
As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
|
4
|
+
|
5
|
+
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
|
6
|
+
|
7
|
+
Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
|
8
|
+
|
9
|
+
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
|
10
|
+
|
11
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
|
12
|
+
|
13
|
+
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2021 Nando Vieira
|
4
|
+
|
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:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
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
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
![SuperConfig: Access environment variables. Also includes presence validation, type coercion and default values.](https://raw.githubusercontent.com/fnando/superconfig/main/superconfig.png)
|
2
|
+
|
3
|
+
<p align="center">
|
4
|
+
<a href="https://github.com/fnando/superconfig/actions/workflows/tests.yml"><img src="https://github.com/fnando/superconfig/workflows/Tests/badge.svg" alt="Github Actions"></a>
|
5
|
+
<a href="https://codeclimate.com/github/fnando/superconfig"><img src="https://codeclimate.com/github/fnando/superconfig/badges/gpa.svg" alt="Code Climate"></a>
|
6
|
+
<a href="https://rubygems.org/gems/superconfig"><img src="https://img.shields.io/gem/v/superconfig.svg" alt="Gem"></a>
|
7
|
+
<a href="https://rubygems.org/gems/superconfig"><img src="https://img.shields.io/gem/dt/superconfig.svg" alt="Gem"></a>
|
8
|
+
</p>
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
Add this line to your application's Gemfile:
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
gem "superconfig"
|
16
|
+
```
|
17
|
+
|
18
|
+
And then execute:
|
19
|
+
|
20
|
+
$ bundle
|
21
|
+
|
22
|
+
Or install it yourself as:
|
23
|
+
|
24
|
+
$ gem install superconfig
|
25
|
+
|
26
|
+
## Usage
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
Config = SuperConfig.new do
|
30
|
+
mandatory :database_url, string
|
31
|
+
optional :timeout, int, 10
|
32
|
+
optional :force_ssl, bool, false
|
33
|
+
optional :rails_env, "development", string, aliases: %w[env]
|
34
|
+
end
|
35
|
+
|
36
|
+
Config.database_url
|
37
|
+
Config.timeout
|
38
|
+
Config.force_ssl?
|
39
|
+
```
|
40
|
+
|
41
|
+
You can specify the description for both `mandatory` and `optional` methods;
|
42
|
+
this will be used in exceptions.
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
Config = SuperConfig.new do
|
46
|
+
mandatory :missing_var, string, description: "this is important"
|
47
|
+
end
|
48
|
+
|
49
|
+
#=> SuperConfig::MissingEnvironmentVariable: MISSING_VAR (this is important) is not defined
|
50
|
+
```
|
51
|
+
|
52
|
+
If you're going to use `SuperConfig` as your main configuration object, you can
|
53
|
+
also set arbitrary properties, like the following:
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
Config = SuperConfig.new do
|
57
|
+
optional :redis_url, string, "redis://127.0.0.1"
|
58
|
+
property :redis, -> { Redis.new } # pass an object that responds to #call
|
59
|
+
property(:now) { Time.now } # or pass a block.
|
60
|
+
end
|
61
|
+
|
62
|
+
Config.redis.set("key", "value")
|
63
|
+
Config.redis.get("key")
|
64
|
+
#=> "value"
|
65
|
+
```
|
66
|
+
|
67
|
+
Values are cached by default. If you want to dynamically generate new values,
|
68
|
+
set `cache: false`.
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
Config = SuperConfig.new do
|
72
|
+
property(:uuid, cache: false) { SecureRandom.uuid }
|
73
|
+
end
|
74
|
+
```
|
75
|
+
|
76
|
+
You may want to start a debug session without raising exceptions for missing
|
77
|
+
variables. In this case, just pass `raise_exception: false` instead to log error
|
78
|
+
messages to `$stderr`. This is especially great with Rails' credentials command
|
79
|
+
(`rails credentials:edit`) when already defined the configuration.
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
Config = SuperConfig.new(raise_exception: false) do
|
83
|
+
mandatory :database_url, string, description: "the leader database"
|
84
|
+
end
|
85
|
+
|
86
|
+
#=> [SUPERCONFIG] DATABASE_URL (the leader database) is not defined
|
87
|
+
```
|
88
|
+
|
89
|
+
I'd like to centralize access to my credentials; there's a handy mechanism for
|
90
|
+
doing that with `SuperConfig`:
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
Config = SuperConfig.new do
|
94
|
+
credential :api_secret_key
|
95
|
+
credential :slack_oauth_credentials do |creds|
|
96
|
+
SlackCredentials.new(creds)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
Config.api_secret_key
|
101
|
+
Config.slack_oauth_credentials
|
102
|
+
#=> The value stored under `Rails.application.credentials[:api_secret_key]`
|
103
|
+
```
|
104
|
+
|
105
|
+
### Types
|
106
|
+
|
107
|
+
You can coerce values to the following types:
|
108
|
+
|
109
|
+
- `string`: Is the default. E.g. `optional :name, string`.
|
110
|
+
- `int`: E.g. `optional :timeout, int`.
|
111
|
+
- `float`: E.g. `optional :wait, float`.
|
112
|
+
- `bigdecimal`: E.g. `optional :fee, bigdecimal`.
|
113
|
+
- `bool`: E.g. `optional :force_ssl, bool`. Any of `yes`, `true` or `1` is
|
114
|
+
considered as `true`. Any other value will be coerced to `false`.
|
115
|
+
- `symbol`: E.g. `optional :app_name, symbol`.
|
116
|
+
- `array`: E.g. `optional :chars, array` or `optional :numbers, array(int)`. The
|
117
|
+
environment variable must be something like `a,b,c`.
|
118
|
+
- `json`: E.g. `mandatory :keyring, json`. The environment variable must be
|
119
|
+
parseable by `JSON.parse(content)`.
|
120
|
+
|
121
|
+
### Dotenv integration
|
122
|
+
|
123
|
+
If you're using [dotenv](https://rubygems.org/gems/dotenv), you can simply
|
124
|
+
require `superconfig/dotenv`. This will load environment variables from
|
125
|
+
`.env.local.%{environment}`, `.env.local`, `.env.%{environment}` and `.env`
|
126
|
+
files, respectively. You _must_ add `dotenv` to your `Gemfile`.
|
127
|
+
|
128
|
+
```ruby
|
129
|
+
require "superconfig/dotenv"
|
130
|
+
```
|
131
|
+
|
132
|
+
### Configuring Rails
|
133
|
+
|
134
|
+
If you want to use `SuperConfig` even on your Rails configuration files like
|
135
|
+
`database.yml` and `secrets.yml`, you must load it from `config/boot.rb`, right
|
136
|
+
after setting up Bundler.
|
137
|
+
|
138
|
+
```ruby
|
139
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)
|
140
|
+
|
141
|
+
# Set up gems listed in the Gemfile.
|
142
|
+
require "bundler/setup"
|
143
|
+
|
144
|
+
# Load configuration.
|
145
|
+
require "superconfig/dotenv"
|
146
|
+
require File.expand_path("../config", __FILE__)
|
147
|
+
```
|
148
|
+
|
149
|
+
## Development
|
150
|
+
|
151
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
152
|
+
`rake test` to run the tests. You can also run `bin/console` for an interactive
|
153
|
+
prompt that will allow you to experiment.
|
154
|
+
|
155
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To
|
156
|
+
release a new version, update the version number in `version.rb`, and then run
|
157
|
+
`bundle exec rake release`, which will create a git tag for the version, push
|
158
|
+
git commits and tags, and push the `.gem` file to
|
159
|
+
[rubygems.org](https://rubygems.org).
|
160
|
+
|
161
|
+
## Contributing
|
162
|
+
|
163
|
+
Bug reports and pull requests are welcome on GitHub at
|
164
|
+
https://github.com/fnando/superconfig. This project is intended to be a safe,
|
165
|
+
welcoming space for collaboration, and contributors are expected to adhere to
|
166
|
+
the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
167
|
+
|
168
|
+
## License
|
169
|
+
|
170
|
+
The gem is available as open source under the terms of the
|
171
|
+
[MIT License](http://opensource.org/licenses/MIT).
|
172
|
+
|
173
|
+
## Icon
|
174
|
+
|
175
|
+
Icon made by [eucalyp](https://www.flaticon.com/authors/eucalyp) from
|
176
|
+
[Flaticon](https://www.flaticon.com/) is licensed by Creative Commons BY 3.0.
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
require "rake/testtask"
|
5
|
+
require "rubocop/rake_task"
|
6
|
+
|
7
|
+
Rake::TestTask.new(:test) do |t|
|
8
|
+
t.libs << "test"
|
9
|
+
t.libs << "lib"
|
10
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
11
|
+
end
|
12
|
+
|
13
|
+
RuboCop::RakeTask.new
|
14
|
+
|
15
|
+
task default: %i[test rubocop]
|
data/lib/superconfig.rb
ADDED
@@ -0,0 +1,182 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SuperConfig
|
4
|
+
VERSION = "1.0.0"
|
5
|
+
|
6
|
+
MissingEnvironmentVariable = Class.new(StandardError)
|
7
|
+
MissingCallable = Class.new(StandardError)
|
8
|
+
|
9
|
+
def self.new(**kwargs, &block)
|
10
|
+
Base.new(**kwargs, &block)
|
11
|
+
end
|
12
|
+
|
13
|
+
class Base
|
14
|
+
BOOL_TRUE = ["yes", "true", "1", true].freeze
|
15
|
+
BOOL_FALSE = %w[no false].freeze
|
16
|
+
|
17
|
+
def initialize(env: ENV, raise_exception: true, stderr: $stderr, &block)
|
18
|
+
@env = env
|
19
|
+
@raise_exception = raise_exception
|
20
|
+
@stderr = stderr
|
21
|
+
@__cache__ = {}
|
22
|
+
instance_eval(&block)
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_s
|
26
|
+
"#<SuperConfig>"
|
27
|
+
end
|
28
|
+
alias inspect to_s
|
29
|
+
|
30
|
+
def set(
|
31
|
+
name,
|
32
|
+
type,
|
33
|
+
default = nil,
|
34
|
+
required: false,
|
35
|
+
aliases: [],
|
36
|
+
description: nil
|
37
|
+
)
|
38
|
+
name = name.to_s
|
39
|
+
env_var = name.upcase
|
40
|
+
name = "#{name}?" if type == bool
|
41
|
+
|
42
|
+
validate!(env_var, required, description)
|
43
|
+
|
44
|
+
define_singleton_method(name) do
|
45
|
+
return default unless @env.key?(env_var)
|
46
|
+
|
47
|
+
coerce(type, @env[env_var])
|
48
|
+
end
|
49
|
+
|
50
|
+
aliases.each do |alias_name|
|
51
|
+
define_singleton_method(alias_name, method(name))
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def validate!(env_var, required, description)
|
56
|
+
return unless required
|
57
|
+
return if @env.key?(env_var)
|
58
|
+
|
59
|
+
message = env_var.to_s
|
60
|
+
message << " (#{description})" if description
|
61
|
+
message << " is not defined."
|
62
|
+
|
63
|
+
raise MissingEnvironmentVariable, message if @raise_exception
|
64
|
+
|
65
|
+
message = "[SUPERCONF] #{message}"
|
66
|
+
message = "\e[31m#{message}\e[0m" if @stderr.tty?
|
67
|
+
@stderr << message << "\n"
|
68
|
+
end
|
69
|
+
|
70
|
+
def mandatory(name, type, aliases: [], description: nil)
|
71
|
+
set(
|
72
|
+
name,
|
73
|
+
type,
|
74
|
+
required: true,
|
75
|
+
aliases: aliases,
|
76
|
+
description: description
|
77
|
+
)
|
78
|
+
end
|
79
|
+
|
80
|
+
def optional(name, type, default = nil, aliases: [], description: nil)
|
81
|
+
set(name, type, default, aliases: aliases, description: description)
|
82
|
+
end
|
83
|
+
|
84
|
+
def property(name, func = nil, cache: true, description: nil, &block) # rubocop:disable Lint/UnusedMethodArgument
|
85
|
+
callable = (func || block)
|
86
|
+
|
87
|
+
unless callable
|
88
|
+
raise MissingCallable, "arg[1] must respond to #call or pass a block"
|
89
|
+
end
|
90
|
+
|
91
|
+
if cache
|
92
|
+
define_singleton_method(name) do
|
93
|
+
@__cache__[name.to_sym] ||= callable.call
|
94
|
+
end
|
95
|
+
else
|
96
|
+
define_singleton_method(name) { callable.call }
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def credential(name, &block)
|
101
|
+
define_singleton_method(name) do
|
102
|
+
@__cache__["_credential_#{name}".to_sym] ||= begin
|
103
|
+
value = Rails.application.credentials.fetch(name)
|
104
|
+
block ? block.call(value) : value # rubocop:disable Performance/RedundantBlockCall
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def int
|
110
|
+
:int
|
111
|
+
end
|
112
|
+
|
113
|
+
def string
|
114
|
+
:string
|
115
|
+
end
|
116
|
+
|
117
|
+
def bool
|
118
|
+
:bool
|
119
|
+
end
|
120
|
+
|
121
|
+
def symbol
|
122
|
+
:symbol
|
123
|
+
end
|
124
|
+
|
125
|
+
def float
|
126
|
+
:float
|
127
|
+
end
|
128
|
+
|
129
|
+
def bigdecimal
|
130
|
+
require "bigdecimal"
|
131
|
+
:bigdecimal
|
132
|
+
end
|
133
|
+
|
134
|
+
def array(type = string)
|
135
|
+
[:array, type]
|
136
|
+
end
|
137
|
+
|
138
|
+
def json
|
139
|
+
:json
|
140
|
+
end
|
141
|
+
|
142
|
+
private def coerce_to_string(value)
|
143
|
+
value
|
144
|
+
end
|
145
|
+
|
146
|
+
private def coerce_to_bool(value)
|
147
|
+
BOOL_TRUE.include?(value)
|
148
|
+
end
|
149
|
+
|
150
|
+
private def coerce_to_int(value)
|
151
|
+
Integer(value) if !BOOL_FALSE.include?(value) && value
|
152
|
+
end
|
153
|
+
|
154
|
+
private def coerce_to_float(value)
|
155
|
+
Float(value) if value
|
156
|
+
end
|
157
|
+
|
158
|
+
private def coerce_to_bigdecimal(value)
|
159
|
+
BigDecimal(value) if value
|
160
|
+
end
|
161
|
+
|
162
|
+
private def coerce_to_symbol(value)
|
163
|
+
value&.to_sym
|
164
|
+
end
|
165
|
+
|
166
|
+
private def coerce_to_array(value, type)
|
167
|
+
value&.split(/, */)&.map {|v| coerce(type, v) }
|
168
|
+
end
|
169
|
+
|
170
|
+
private def coerce_to_json(value)
|
171
|
+
value && JSON.parse(value)
|
172
|
+
end
|
173
|
+
|
174
|
+
private def coerce(type, value)
|
175
|
+
main_type, sub_type = type
|
176
|
+
args = [value]
|
177
|
+
args << sub_type if sub_type
|
178
|
+
|
179
|
+
send("coerce_to_#{main_type}", *args)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
data/superconfig.gemspec
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "./lib/superconfig"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "superconfig"
|
7
|
+
spec.version = SuperConfig::VERSION
|
8
|
+
spec.authors = ["Nando Vieira"]
|
9
|
+
spec.email = ["me@fnando.com"]
|
10
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
|
11
|
+
spec.metadata = {"rubygems_mfa_required" => "true"}
|
12
|
+
|
13
|
+
spec.summary = "Access environment variables. Also includes presence " \
|
14
|
+
"validation, type coercion and default values."
|
15
|
+
spec.description = spec.summary
|
16
|
+
spec.homepage = "https://github.com/fnando/superconfig"
|
17
|
+
spec.license = "MIT"
|
18
|
+
|
19
|
+
spec.files = `git ls-files -z`
|
20
|
+
.split("\x0")
|
21
|
+
.reject {|f| f.match(%r{^(test|spec|features)/}) }
|
22
|
+
spec.executables = spec.files.grep(%r{^exe/}) {|f| File.basename(f) }
|
23
|
+
spec.require_paths = ["lib"]
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler"
|
26
|
+
spec.add_development_dependency "minitest"
|
27
|
+
spec.add_development_dependency "minitest-utils"
|
28
|
+
spec.add_development_dependency "pry-meta"
|
29
|
+
spec.add_development_dependency "rails"
|
30
|
+
spec.add_development_dependency "rake"
|
31
|
+
spec.add_development_dependency "rubocop"
|
32
|
+
spec.add_development_dependency "rubocop-fnando"
|
33
|
+
spec.add_development_dependency "simplecov"
|
34
|
+
end
|
data/superconfig.png
ADDED
Binary file
|
data/superconfig.svg
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="300" height="300" viewBox="0 0 300 300">
|
2
|
+
<g fill="none" fill-rule="evenodd">
|
3
|
+
<rect width="155" height="63" x="73" y="92" fill="#9013FE"/>
|
4
|
+
<rect width="154.839" height="9.714" x="72.581" y="126.286" fill="#000"/>
|
5
|
+
<rect width="62.903" height="9.714" x="164.516" y="145.714" fill="#000"/>
|
6
|
+
<rect width="62.903" height="9.714" x="72.581" y="145.714" fill="#000"/>
|
7
|
+
<rect width="62.903" height="9.714" x="164.516" y="106.857" fill="#000"/>
|
8
|
+
<rect width="62.903" height="9.714" x="72.581" y="106.857" fill="#000"/>
|
9
|
+
<rect width="154.839" height="9.714" x="72.581" y="87.429" fill="#000"/>
|
10
|
+
<path fill="#000" fill-rule="nonzero" d="M283.483871,0 L14.516129,0 C6.51290323,0 0,6.53771429 0,14.5714286 L0,238 L217.741935,238 L217.741935,228.285714 L9.67741935,228.285714 L9.67741935,48.5714286 L290.322581,48.5714286 L290.322581,228.285714 L217.741935,228.285714 L217.741935,238 L300,238 L300,14.5714286 C300,6.53771429 291.487097,0 283.483871,0 Z M9.67741935,38.8571429 L9.67741935,14.5714286 C9.67741935,11.8951429 11.85,9.71428571 14.516129,9.71428571 L285.483871,9.71428571 C288.15,9.71428571 290.322581,11.8951429 290.322581,14.5714286 L290.322581,38.8571429 L9.67741935,38.8571429 Z"/>
|
11
|
+
<path fill="#9013FE" d="M163.908393,300 L137.091607,300 L134.078214,287.931964 C130.211429,286.789286 126.479643,285.236786 122.92625,283.303393 L112.251607,289.70625 L93.29375,270.748393 L99.6966071,260.07375 C97.7632143,256.520357 96.2107143,252.78375 95.0680357,248.921786 L83,245.908393 L83,219.091607 L95.0680357,216.078214 C96.2107143,212.211429 97.7632143,208.479643 99.6966071,204.92625 L93.29375,194.251607 L112.251607,175.29375 L122.92625,181.696607 C126.479643,179.763214 130.21625,178.210714 134.078214,177.068036 L137.091607,165 L163.908393,165 L166.921786,177.068036 C170.788571,178.210714 174.520357,179.763214 178.07375,181.696607 L188.748393,175.29375 L207.70625,194.251607 L201.303393,204.92625 C203.236786,208.479643 204.789286,212.21625 205.931964,216.078214 L218,219.091607 L218,245.908393 L205.931964,248.921786 C204.789286,252.788571 203.236786,256.520357 201.303393,260.07375 L207.70625,270.748393 L188.748393,289.70625 L178.07375,283.303393 C174.520357,285.236786 170.78375,286.789286 166.921786,287.931964 L163.908393,300 Z"/>
|
12
|
+
<path fill="#000" fill-rule="nonzero" d="M150,213.714286 C139.325806,213.714286 130.645161,222.428 130.645161,233.142857 C130.645161,243.857714 139.325806,252.571429 150,252.571429 C160.674194,252.571429 169.354839,243.857714 169.354839,233.142857 C169.354839,222.428 160.674194,213.714286 150,213.714286 Z M150,242.857143 C144.662903,242.857143 140.322581,238.500286 140.322581,233.142857 C140.322581,227.785429 144.662903,223.428571 150,223.428571 C155.337097,223.428571 159.677419,227.785429 159.677419,233.142857 C159.677419,238.500286 155.337097,242.857143 150,242.857143 Z"/>
|
13
|
+
<path fill="#000" d="M150 194.285714C143.574194 194.285714 137.201613 195.903143 131.579032 198.958286L136.190323 207.502C140.404839 205.214286 145.175806 204 150 204 166.01129 204 179.032258 217.070571 179.032258 233.142857 179.032258 237.985429 177.822581 242.774571 175.543548 247.005143L184.054839 251.634C187.098387 245.99 188.709677 239.593143 188.709677 233.142857 188.709677 211.718 171.343548 194.285714 150 194.285714zM150 262.285714C133.98871 262.285714 120.967742 249.215143 120.967742 233.142857 120.967742 228.300286 122.177419 223.511143 124.456452 219.280571L115.945161 214.651714C112.901613 220.295714 111.290323 226.692571 111.290323 233.142857 111.290323 254.567714 128.656452 272 150 272 156.425806 272 162.798387 270.382571 168.420968 267.327429L163.809677 258.783714C159.595161 261.071429 154.824194 262.285714 150 262.285714z"/>
|
14
|
+
<rect width="9.677" height="9.714" x="19.355" y="19.429" fill="#000"/>
|
15
|
+
<rect width="9.677" height="9.714" x="38.71" y="19.429" fill="#000"/>
|
16
|
+
<rect width="9.677" height="9.714" x="58.065" y="19.429" fill="#000"/>
|
17
|
+
<polygon fill="#000" points="45 187.289 45 60 68.99 60 68.99 73.227 58.504 73.694 58.504 173.439 68.99 174.062 68.99 187.289"/>
|
18
|
+
<polygon fill="#000" points="255.99 187.412 232 187.412 232 174.277 242.486 173.658 242.486 74.599 232 74.136 232 61 255.99 61"/>
|
19
|
+
</g>
|
20
|
+
</svg>
|
metadata
ADDED
@@ -0,0 +1,192 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: superconfig
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nando Vieira
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-12-07 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: minitest
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest-utils
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry-meta
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rails
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubocop
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rubocop-fnando
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: simplecov
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
description: Access environment variables. Also includes presence validation, type
|
140
|
+
coercion and default values.
|
141
|
+
email:
|
142
|
+
- me@fnando.com
|
143
|
+
executables: []
|
144
|
+
extensions: []
|
145
|
+
extra_rdoc_files: []
|
146
|
+
files:
|
147
|
+
- ".github/CODEOWNERS"
|
148
|
+
- ".github/FUNDING.yml"
|
149
|
+
- ".github/ISSUE_TEMPLATE/bug_report.md"
|
150
|
+
- ".github/ISSUE_TEMPLATE/feature_request.md"
|
151
|
+
- ".github/PULL_REQUEST_TEMPLATE.md"
|
152
|
+
- ".github/dependabot.yml"
|
153
|
+
- ".github/workflows/ruby-tests.yml"
|
154
|
+
- ".gitignore"
|
155
|
+
- ".rubocop.yml"
|
156
|
+
- CHANGELOG.md
|
157
|
+
- CODE_OF_CONDUCT.md
|
158
|
+
- Gemfile
|
159
|
+
- LICENSE.txt
|
160
|
+
- README.md
|
161
|
+
- Rakefile
|
162
|
+
- lib/superconfig.rb
|
163
|
+
- lib/superconfig/dotenv.rb
|
164
|
+
- superconfig.gemspec
|
165
|
+
- superconfig.png
|
166
|
+
- superconfig.svg
|
167
|
+
homepage: https://github.com/fnando/superconfig
|
168
|
+
licenses:
|
169
|
+
- MIT
|
170
|
+
metadata:
|
171
|
+
rubygems_mfa_required: 'true'
|
172
|
+
post_install_message:
|
173
|
+
rdoc_options: []
|
174
|
+
require_paths:
|
175
|
+
- lib
|
176
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: 2.7.0
|
181
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
182
|
+
requirements:
|
183
|
+
- - ">="
|
184
|
+
- !ruby/object:Gem::Version
|
185
|
+
version: '0'
|
186
|
+
requirements: []
|
187
|
+
rubygems_version: 3.2.32
|
188
|
+
signing_key:
|
189
|
+
specification_version: 4
|
190
|
+
summary: Access environment variables. Also includes presence validation, type coercion
|
191
|
+
and default values.
|
192
|
+
test_files: []
|