figroll 0.0.2 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +93 -2
- data/lib/figroll.rb +43 -29
- data/lib/figroll/config.rb +23 -2
- data/lib/figroll/storage.rb +22 -2
- data/lib/figroll/util.rb +15 -0
- data/lib/figroll/version.rb +1 -1
- data/spec/figroll_spec.rb +10 -11
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 40b078c1e6ca15fa3e7643e9202c3709f80b4aa41f1976483f39b904b0f039e9
|
4
|
+
data.tar.gz: 36f41a5d4fc1e256583a92db385a376518a896f9ff8dcd5102496de141c26631
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0bca3e98cca1149636ecb263625c7155d9d3928a1f755cf75940faa25cf1f0ce7103739f543949b2a903cdbfdd8d030b2fffb494dc6841f77dbd8dfa978a4c28
|
7
|
+
data.tar.gz: eb08fcd1bb9fc67b047f9f8bf14c6d365474b7412f2d6eef4d75dad765cad093fa1bcc8f8253c6f0c25e7edee715b8251658e3dafa3666af65ec9f0a690c02f0
|
data/README.md
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
# figroll #
|
2
2
|
|
3
|
-
Figroll is a somewhat simple gem to ease your way into the use of environment variables for configuration.
|
3
|
+
Figroll is a somewhat simple gem to ease your way into the use of environment variables for configuration. It is not tied to any specific framework, so you can use it just about anywhere.
|
4
|
+
|
5
|
+
Fetching information via Figroll works roughly like this:
|
6
|
+
|
7
|
+
* If `ENV` contains the variable that you want to use, Figroll provides the data from `ENV`
|
8
|
+
* If the varible you want to use is not in `ENV`, Figroll falls back to data provided in a YAML config file.
|
9
|
+
* If the variable you want to use is missing from both `ENV` and the config file, Figroll raises an error.
|
4
10
|
|
5
11
|
## Installation ##
|
6
12
|
|
@@ -20,10 +26,95 @@ Or install it yourself as:
|
|
20
26
|
|
21
27
|
## Usage ##
|
22
28
|
|
23
|
-
|
29
|
+
There are two aspects of usage with Figroll: Configuration and Consumption
|
30
|
+
|
31
|
+
### Configuration ###
|
32
|
+
|
33
|
+
To configure `Figroll` and initialize it for use, you pass a config file location to `Figroll.configure`, preferably rather early in your application's startup process. For example, in a Rails 2 application, I generally make the `configure` call towards the top of `config/environment.rb`:
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
# Bootstrap the Rails environment, frameworks, and default configuration
|
37
|
+
require File.join(File.dirname(__FILE__), 'boot')
|
38
|
+
require 'figroll'
|
39
|
+
|
40
|
+
Rails::Initializer.run do |config|
|
41
|
+
Figroll.configure(File.join(File.dirname(__FILE__), 'figroll.yml'))
|
42
|
+
|
43
|
+
# ...
|
44
|
+
end
|
45
|
+
```
|
46
|
+
|
47
|
+
#### Config File ####
|
48
|
+
|
49
|
+
The Figroll configuration file is just a YAML file with specific information. Here's an example config file that shows off all of the configuration features:
|
50
|
+
|
51
|
+
```yaml
|
52
|
+
# The variables listed in "required" *must* be present either as incoming
|
53
|
+
# environment variables (`ENV`) or via the "environments" section below.
|
54
|
+
required:
|
55
|
+
- REQUIRED_VARIABLE_1
|
56
|
+
- REQUIRED_VARIABLE_2
|
57
|
+
|
58
|
+
# The entries in the "environments" section are tied to the `FIGROLL_ENV`
|
59
|
+
# environment variable. Each of these is in turn a list of default values for
|
60
|
+
# that specific environment to use in case those variables are not set in the
|
61
|
+
# execution environment.
|
62
|
+
environments:
|
63
|
+
development:
|
64
|
+
REQUIRED_VARIABLE_1: dev 1
|
65
|
+
REQUIRED_VARIABLE_2: dev 2
|
66
|
+
staging:
|
67
|
+
REQUIRED_VARIABLE_1: staging 1
|
68
|
+
REQUIRED_VARIABLE_2: staging 2
|
69
|
+
```
|
70
|
+
|
71
|
+
***Best Practice: Use Figroll in production, but do not store a "production" environment in your Figroll config file. Instead, define the variables in production's execution environment.***
|
72
|
+
|
73
|
+
#### Required Variables ####
|
74
|
+
|
75
|
+
The "required" section of the config file is used to list out environment variables without which your application absolutely cannot run. A good example of such a beast is `DATABASE_URL` for the great majority of Rails apps, but we suggest making all or most of your variables required.
|
76
|
+
|
77
|
+
If a variable listed in this section lacks a value at the time that `Figroll.configure` is run, the configure call raises a runtime error to reflect that missing variable. As mentioned above, it's a good idea to configure Figroll early in your application's boot process, and the specific reasoning behind that is to ensure that if there is missing configuration data, app booting fails as early as possible so you can fix it more quickly.
|
78
|
+
|
79
|
+
The "required" section, however, is optional. To that end, if you leave it out, you may end up seeing fun surprises later in your application deployment's lifetime. My go-to example for this is that everything about your app may run seemingly well, but a missing payment gateway API key variable might cause checkouts to inexplicably fail.
|
80
|
+
|
81
|
+
#### Variable Precedence ####
|
82
|
+
|
83
|
+
The "environments" section of the Figroll config file allows one to provide default values for specific variables in case they don't appear in the execution environment.
|
84
|
+
|
85
|
+
Using the above config file as an example, let's assume that `FIGROLL_ENV` is set to `staging`.
|
86
|
+
|
87
|
+
If you pass this file to `Figroll.configure` with no other information in your environment, `Figroll.fetch(:required_variable_1)` will return `staging 1`.
|
88
|
+
|
89
|
+
On the other hand, if `FIGROLL_ENV` is set to `staging` and `REQUIRED_VARIABLE_1` is set to `algebraic`" when you `Figroll.configure`, `Figroll.fetch(:required_variable)` will return `algebraic`.
|
90
|
+
|
91
|
+
***tl;dr - Values from the execution environment have precedence over values from the Figroll config file.***
|
92
|
+
|
93
|
+
### Consumption ###
|
94
|
+
|
95
|
+
One consumes values from Figroll via `Figroll.fetch`, which takes either a symbol or a string as the variable name to fetch. One important consideration is that variable names in Figroll are not case-sensitive. That is, `var1` is the same as both `Var1` and `VAR1`.
|
96
|
+
|
97
|
+
If you should call `Figroll.fetch` for a variable that was not known when `Figroll.configure` was called, a `RuntimeError` is raised. Otherwise, if we can resolve the requested variable name to a known variable, the value of that variable is returned.
|
98
|
+
|
99
|
+
#### Consistency ####
|
100
|
+
|
101
|
+
While it's easy and reasonable to think of Figroll as a proxy to `ENV`, that's not entirely accurate. Figroll only considers variables and values that are known (either in the execution environment or in the config file) at the point in time when `Figroll.configure` is called.
|
102
|
+
|
103
|
+
**That is, changing an environment variable while an app is running does not affect what is returned when you `Figroll.fetch` that variable.**
|
104
|
+
|
105
|
+
To that end, it would be best to avoid retrieving information directly from `ENV`.
|
106
|
+
|
107
|
+
## Similar Projects ##
|
108
|
+
|
109
|
+
Figroll isn't an entirely new idea at all. In this case, we're standing on the shoulders of these giants:
|
110
|
+
|
111
|
+
* [figaro](https://github.com/laserlemon/figaro) is the most direct inspiration for this library, to the effect that we borrowed most of its features. The big difference is that Figroll does not automagically inject itself into your application, as it is meant to serve more frameworks than just Rails 3+. Additionally, `figaro` is a proper `ENV` proxy, so it's possible to use it somewhat interchangeably with `ENV`, and it also allows for env var mutability.
|
112
|
+
* [dotenv](https://github.com/bkeepers/dotenv) is somewhat the grandfather of Figroll. The primary issue with it that made us want to roll our own library is that it's specifically not advised to use dotenv for production, whereas we want to do exactly that without much hoop jumping.
|
113
|
+
* [envyable](https://github.com/philnash/envyable) is another gem that works quite a lot like Figroll. The primary difference here is that of variable precedence ... it appears that envyable favors values from its config file rather than incoming variables from the execution environment.
|
24
114
|
|
25
115
|
## History ##
|
26
116
|
|
117
|
+
* 1.0.0 - Initial public release
|
27
118
|
* 0.0.2 - Clean error message
|
28
119
|
* 0.0.1 - A prerelease for internal tire kicking
|
29
120
|
|
data/lib/figroll.rb
CHANGED
@@ -1,8 +1,12 @@
|
|
1
1
|
require 'figroll/config'
|
2
2
|
require 'figroll/storage'
|
3
3
|
|
4
|
+
# A simple universal ENV-focused configuration library
|
4
5
|
module Figroll
|
5
|
-
|
6
|
+
|
7
|
+
# Given a config file, set up Figroll for ENV consumption
|
8
|
+
# @param config_file [String] the figroll configuration for your app
|
9
|
+
def self.configure(config_file)
|
6
10
|
setup
|
7
11
|
|
8
12
|
# Load the config file
|
@@ -18,45 +22,55 @@ module Figroll
|
|
18
22
|
validate_configuration
|
19
23
|
end
|
20
24
|
|
25
|
+
# Retrieve the value of an environment configuration variable. The key may be
|
26
|
+
# either a String or a Symbol, non-case-sensitive. For example, these all
|
27
|
+
# reference the same value:
|
28
|
+
# * 'i am a variable'
|
29
|
+
# * 'i_am_a_variable'
|
30
|
+
# * 'I_AM_A_VARIABLE'
|
31
|
+
# * :i_am_a_variable
|
32
|
+
# @param key [String, Symbol] the stringified or symbolized name of the
|
33
|
+
# variable for which you want to know the value.
|
34
|
+
# @return [String] the value of the variable when Figroll was configured
|
35
|
+
# @raise [RuntimeError] if the varible was not known at configuration time
|
21
36
|
def self.fetch(key)
|
22
37
|
storage.fetch(key)
|
23
38
|
end
|
24
39
|
|
25
|
-
|
26
|
-
|
27
|
-
end
|
40
|
+
class << self
|
41
|
+
private
|
28
42
|
|
29
|
-
|
30
|
-
|
31
|
-
|
43
|
+
def storage
|
44
|
+
@storage
|
45
|
+
end
|
32
46
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
return nil if (keys - required).length == keys.length - required.length
|
47
|
+
def config
|
48
|
+
@config
|
49
|
+
end
|
37
50
|
|
38
|
-
|
39
|
-
|
40
|
-
|
51
|
+
def validate_configuration
|
52
|
+
return nil if required.length == 0
|
53
|
+
return nil if (keys - required).length == keys.length - required.length
|
41
54
|
|
42
|
-
|
43
|
-
|
44
|
-
|
55
|
+
missing = required.reject {|key| keys.include?(key)}
|
56
|
+
raise "Required variables not set: #{missing.sort.join(', ')}"
|
57
|
+
end
|
45
58
|
|
46
|
-
|
47
|
-
|
48
|
-
|
59
|
+
def required
|
60
|
+
config.required
|
61
|
+
end
|
49
62
|
|
50
|
-
|
51
|
-
|
52
|
-
|
63
|
+
def keys
|
64
|
+
storage.keys
|
65
|
+
end
|
53
66
|
|
54
|
-
|
55
|
-
|
56
|
-
|
67
|
+
def environment
|
68
|
+
config.environment
|
69
|
+
end
|
57
70
|
|
58
|
-
|
59
|
-
|
60
|
-
|
71
|
+
def setup
|
72
|
+
@config = Config.new
|
73
|
+
@storage = Storage.new
|
74
|
+
end
|
61
75
|
end
|
62
76
|
end
|
data/lib/figroll/config.rb
CHANGED
@@ -1,13 +1,34 @@
|
|
1
1
|
require 'yaml'
|
2
|
+
require 'figroll/util'
|
2
3
|
|
3
4
|
module Figroll
|
5
|
+
# A configuration object for Figroll
|
4
6
|
class Config
|
5
|
-
attr_reader :required, :environment, :data
|
6
7
|
|
8
|
+
# A list of required environment variables defined by the configuration
|
9
|
+
# @return [Array<String>, nil]
|
10
|
+
# @api private
|
11
|
+
attr_reader :required
|
12
|
+
|
13
|
+
# The `FIGROLL_ENV` under which we're running
|
14
|
+
# @return [String, nil]
|
15
|
+
# @api private
|
16
|
+
attr_reader :environment
|
17
|
+
|
18
|
+
# Values defined in the configuration to inject into Figroll
|
19
|
+
# @return [Array<String>, nil]
|
20
|
+
# @api private
|
21
|
+
attr_reader :data
|
22
|
+
|
23
|
+
# Create a new Config instance
|
24
|
+
# @api private
|
7
25
|
def initialize
|
8
26
|
reset
|
9
27
|
end
|
10
28
|
|
29
|
+
# Given a config file name, load the configuration specified in that file.
|
30
|
+
# @param config_file [String]
|
31
|
+
# @api private
|
11
32
|
def load_file(config_file)
|
12
33
|
return unless File.exists?(config_file)
|
13
34
|
|
@@ -16,7 +37,7 @@ module Figroll
|
|
16
37
|
# set up required keys
|
17
38
|
file_data['required'] ||= []
|
18
39
|
file_data['required'].each do |key|
|
19
|
-
required.push(
|
40
|
+
required.push(Util.normalize(key))
|
20
41
|
end
|
21
42
|
|
22
43
|
# load up the environment-specific data
|
data/lib/figroll/storage.rb
CHANGED
@@ -1,23 +1,43 @@
|
|
1
|
+
require 'figroll/util'
|
2
|
+
|
1
3
|
module Figroll
|
4
|
+
# A storage object for Figroll
|
2
5
|
class Storage
|
6
|
+
# The known variables tracked by this storage instance
|
7
|
+
# @return [Hash<String, String>]
|
8
|
+
# @api private
|
3
9
|
attr_reader :vars
|
4
10
|
|
11
|
+
# Create a new Storage instance
|
12
|
+
# @api private
|
5
13
|
def initialize
|
6
14
|
reset
|
7
15
|
end
|
8
16
|
|
17
|
+
# Given a key, retrieve the value stored for that key.
|
18
|
+
# @param key [String, Symbol] the variable for which we want a value
|
19
|
+
# @return [String] the value of that variable
|
20
|
+
# @raise [RuntimeError] if the varible is not known
|
21
|
+
# @api private
|
9
22
|
def fetch(key)
|
10
|
-
@vars.fetch(
|
23
|
+
@vars.fetch(Util.normalize(key))
|
11
24
|
end
|
12
25
|
|
26
|
+
# Given a hash of variables, import those variables into the instance.
|
27
|
+
# @params incoming [Hash<String, String>]
|
28
|
+
# @return nil
|
29
|
+
# @api private
|
13
30
|
def import(incoming)
|
14
31
|
incoming.keys.each do |key|
|
15
|
-
vars[
|
32
|
+
vars[Util.normalize(key)] = incoming[key]
|
16
33
|
end
|
17
34
|
|
18
35
|
nil
|
19
36
|
end
|
20
37
|
|
38
|
+
# Get the list of all stored variable names
|
39
|
+
# @return [Array<String>]
|
40
|
+
# @api private
|
21
41
|
def keys
|
22
42
|
vars.keys
|
23
43
|
end
|
data/lib/figroll/util.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
module Figroll
|
2
|
+
|
3
|
+
# A collection of utility methods used throughout Figroll
|
4
|
+
module Util
|
5
|
+
|
6
|
+
# Normalize a given key to the format generally used for environment
|
7
|
+
# variable names.
|
8
|
+
# @param key [String, Symbol] the key to normalize
|
9
|
+
# @return [String] the normalized key
|
10
|
+
def self.normalize(key)
|
11
|
+
key.to_s.upcase.gsub(/\s+/, '_')
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
data/lib/figroll/version.rb
CHANGED
data/spec/figroll_spec.rb
CHANGED
@@ -12,26 +12,25 @@ describe Figroll do
|
|
12
12
|
allow(storage).to receive(:import).and_call_original
|
13
13
|
end
|
14
14
|
|
15
|
-
describe '.
|
15
|
+
describe '.configure' do
|
16
16
|
let(:filename) {'figroll.yml'}
|
17
17
|
let(:config_file) {
|
18
18
|
File.join(MOCK_PATH, filename)
|
19
19
|
}
|
20
20
|
|
21
|
-
let(:
|
21
|
+
let(:configure) {described_class.configure(config_file)}
|
22
22
|
|
23
23
|
before(:each) do
|
24
24
|
storage.send(:reset)
|
25
25
|
config.send(:reset)
|
26
26
|
end
|
27
27
|
|
28
|
-
it '
|
29
|
-
expect(described_class.config).to eql(config)
|
28
|
+
it 'loads the config file via a config object' do
|
30
29
|
expect(config).
|
31
30
|
to receive(:load_file).
|
32
31
|
with(config_file)
|
33
32
|
|
34
|
-
|
33
|
+
configure
|
35
34
|
end
|
36
35
|
|
37
36
|
context 'when there is an applicable configuration environment' do
|
@@ -42,7 +41,7 @@ describe Figroll do
|
|
42
41
|
to receive(:import).
|
43
42
|
with({'SAUSAGES' => 'gold'})
|
44
43
|
|
45
|
-
|
44
|
+
configure
|
46
45
|
end
|
47
46
|
end
|
48
47
|
|
@@ -51,7 +50,7 @@ describe Figroll do
|
|
51
50
|
to receive(:import).
|
52
51
|
with(ENV)
|
53
52
|
|
54
|
-
|
53
|
+
configure
|
55
54
|
end
|
56
55
|
|
57
56
|
context 'when there are required variables' do
|
@@ -63,7 +62,7 @@ describe Figroll do
|
|
63
62
|
end
|
64
63
|
|
65
64
|
it 'raises an error' do
|
66
|
-
expect {
|
65
|
+
expect {configure}.to raise_error("Required variables not set: SAUSAGES")
|
67
66
|
end
|
68
67
|
end
|
69
68
|
|
@@ -76,7 +75,7 @@ describe Figroll do
|
|
76
75
|
end
|
77
76
|
|
78
77
|
it 'raises an error' do
|
79
|
-
expect {
|
78
|
+
expect {configure}.to raise_error("Required variables not set: GOLDERBLATS, SAUSAGES")
|
80
79
|
end
|
81
80
|
|
82
81
|
end
|
@@ -92,7 +91,7 @@ describe Figroll do
|
|
92
91
|
end
|
93
92
|
|
94
93
|
it 'returns nil' do
|
95
|
-
expect(
|
94
|
+
expect(configure).to eql(nil)
|
96
95
|
end
|
97
96
|
end
|
98
97
|
end
|
@@ -101,7 +100,7 @@ describe Figroll do
|
|
101
100
|
let(:filename) {'withoutreqs.yml'}
|
102
101
|
|
103
102
|
it 'returns nil' do
|
104
|
-
expect(
|
103
|
+
expect(configure).to eql(nil)
|
105
104
|
end
|
106
105
|
end
|
107
106
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: figroll
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- EY Cloud Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-07-
|
11
|
+
date: 2019-07-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -97,6 +97,7 @@ files:
|
|
97
97
|
- lib/figroll.rb
|
98
98
|
- lib/figroll/config.rb
|
99
99
|
- lib/figroll/storage.rb
|
100
|
+
- lib/figroll/util.rb
|
100
101
|
- lib/figroll/version.rb
|
101
102
|
- mock/figroll.yml
|
102
103
|
- mock/multireqs.yml
|