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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b2c6d0f8b81e0c9f0ee662dd5a22863d3d9740b45c284d59388b2558ca2cf992
4
- data.tar.gz: 712a379832929698803fb18a01cf6f1642a50cf672b9f97834fbbf293da78b5a
3
+ metadata.gz: 40b078c1e6ca15fa3e7643e9202c3709f80b4aa41f1976483f39b904b0f039e9
4
+ data.tar.gz: 36f41a5d4fc1e256583a92db385a376518a896f9ff8dcd5102496de141c26631
5
5
  SHA512:
6
- metadata.gz: 358c8da70d166cb555baaaab22faac123624f87b00d316069839424eba2240c3fdc49fdaec4ef112c117c6a69cb7d66819ae3c260730beeaacf1dc08d4c6b8a9
7
- data.tar.gz: f6aaf8c4eb95ad0e96a1d41001845142f0acf47ea5abe6d8b62472479b6c3b82458d4379858881f17571cd2b4c0011f1aabb13add157e88d90529767f4062901
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. That said, it is not currently documented, and you should not use it just yet.
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
- Wow. Just look at all this empty space. You should check back here soon, but not right now. Later than now, definitely. As in there isn't any documentation at the present moment.
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
 
@@ -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
- def self.load_file(config_file)
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
- def self.storage
26
- @storage
27
- end
40
+ class << self
41
+ private
28
42
 
29
- def self.config
30
- @config
31
- end
43
+ def storage
44
+ @storage
45
+ end
32
46
 
33
-
34
- def self.validate_configuration
35
- return nil if required.length == 0
36
- return nil if (keys - required).length == keys.length - required.length
47
+ def config
48
+ @config
49
+ end
37
50
 
38
- missing = required.reject {|key| keys.include?(key)}
39
- raise "Required variables not set: #{missing.sort.join(', ')}"
40
- end
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
- def self.required
43
- config.required
44
- end
55
+ missing = required.reject {|key| keys.include?(key)}
56
+ raise "Required variables not set: #{missing.sort.join(', ')}"
57
+ end
45
58
 
46
- def self.keys
47
- storage.keys
48
- end
59
+ def required
60
+ config.required
61
+ end
49
62
 
50
- def self.environment
51
- config.environment
52
- end
63
+ def keys
64
+ storage.keys
65
+ end
53
66
 
54
- def self.normalize(key)
55
- key.to_s.upcase.gsub(/\s+/, '_')
56
- end
67
+ def environment
68
+ config.environment
69
+ end
57
70
 
58
- def self.setup
59
- @config = Config.new
60
- @storage = Storage.new
71
+ def setup
72
+ @config = Config.new
73
+ @storage = Storage.new
74
+ end
61
75
  end
62
76
  end
@@ -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(Figroll.normalize(key))
40
+ required.push(Util.normalize(key))
20
41
  end
21
42
 
22
43
  # load up the environment-specific data
@@ -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(Figroll.normalize(key))
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[Figroll.normalize(key)] = incoming[key]
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
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Figroll
2
- VERSION = '0.0.2'
2
+ VERSION = '1.0.0'
3
3
  end
@@ -12,26 +12,25 @@ describe Figroll do
12
12
  allow(storage).to receive(:import).and_call_original
13
13
  end
14
14
 
15
- describe '.load_file' do
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(:load_file) {described_class.load_file(config_file)}
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 'forwards the call to a config object' do
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
- load_file
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
- load_file
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
- load_file
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 {load_file}.to raise_error("Required variables not set: SAUSAGES")
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 {load_file}.to raise_error("Required variables not set: GOLDERBLATS, SAUSAGES")
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(load_file).to eql(nil)
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(load_file).to eql(nil)
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.2
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-18 00:00:00.000000000 Z
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