configerator 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/lib/configerator.rb +23 -70
- data/lib/configerator/configerator.rb +88 -0
- data/lib/generators/config_generator.rb +9 -0
- data/lib/generators/templates/config.rb +66 -0
- data/test/configerator_test.rb +172 -0
- metadata +12 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1e2d61fe028ce7011ef38f7c66473779896d8909
|
4
|
+
data.tar.gz: 4c97a839350bb20cf57663cb72eeb9bd1442a91e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7cb6c10835323f561115d47529dd1e040745f3ab802bc350f22a14eafd9f890dd4476f478f8d02c39d7ae6e6430d4f757f28929414ae6eb3d14d2759eb75b817
|
7
|
+
data.tar.gz: 526875af240df935bdcc219efb2b35e74af4889c70f646b61778f31ad17d34df2831f7ea39d10b9287fdd2985c9f9f05034d5fe73b3898cfbf92440f57a5e982
|
data/lib/configerator.rb
CHANGED
@@ -1,71 +1,24 @@
|
|
1
|
-
require '
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
def override(name, default, method=nil)
|
18
|
-
value = cast(ENV.fetch(name.to_s.upcase, default), method)
|
19
|
-
create(name, value)
|
20
|
-
end
|
21
|
-
|
22
|
-
def int
|
23
|
-
->(v) { v.to_i }
|
24
|
-
end
|
25
|
-
|
26
|
-
def float
|
27
|
-
->(v) { v.to_f }
|
28
|
-
end
|
29
|
-
|
30
|
-
def bool
|
31
|
-
->(v) { v.to_s=='true'}
|
32
|
-
end
|
33
|
-
|
34
|
-
def string
|
35
|
-
nil
|
36
|
-
end
|
37
|
-
|
38
|
-
def symbol
|
39
|
-
->(v) { v.to_sym }
|
40
|
-
end
|
41
|
-
|
42
|
-
def url
|
43
|
-
->(v) { v && URI.parse(v) }
|
44
|
-
end
|
45
|
-
|
46
|
-
# optional :accronyms, array(string)
|
47
|
-
# => ['a', 'b']
|
48
|
-
# optional :numbers, array(int)
|
49
|
-
# => [1, 2]
|
50
|
-
# optional :notype, array
|
51
|
-
# => ['a', 'b']
|
52
|
-
def array(method = nil)
|
53
|
-
-> (v) do
|
54
|
-
if v
|
55
|
-
v.split(',').map{|a| cast(a, method) }
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
private
|
61
|
-
|
62
|
-
def cast(value, method)
|
63
|
-
method ? method.call(value) : value
|
64
|
-
end
|
65
|
-
|
66
|
-
def create(name, value, error_on_load=true)
|
67
|
-
instance_variable_set(:"@#{name}", value)
|
68
|
-
instance_eval "def #{name}; @#{name} || (raise \"key not set '#{name}'\" unless #{error_on_load}) end"
|
69
|
-
instance_eval "def #{name}?; !!@#{name} end", __FILE__, __LINE__
|
70
|
-
end
|
1
|
+
require 'configerator/configerator'
|
2
|
+
|
3
|
+
# We want to detect if dotenv is in the environment and loaded it right after
|
4
|
+
# the library is loaded so that if any configurations rely on it, the
|
5
|
+
# .env environment variables will be available immediately.
|
6
|
+
#
|
7
|
+
# In order to bypass this autoloading of Dotenv, the user can load the library
|
8
|
+
# directly:
|
9
|
+
#
|
10
|
+
# require 'configerator/configerator'
|
11
|
+
|
12
|
+
begin
|
13
|
+
require 'dotenv/rails-now'
|
14
|
+
rescue LoadError
|
15
|
+
# dotenv-rails not available
|
71
16
|
end
|
17
|
+
|
18
|
+
begin
|
19
|
+
# fallback to Dotenv
|
20
|
+
require 'dotenv'
|
21
|
+
Dotenv.load
|
22
|
+
rescue LoadError
|
23
|
+
# dotenv not available
|
24
|
+
end unless defined?(Dotenv::Railtie)
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module Configerator
|
4
|
+
@processed = []
|
5
|
+
|
6
|
+
def required(name, method=nil, error_on_load: true)
|
7
|
+
# Hash#fetch raises a KeyError, Hash#[] doesn't
|
8
|
+
value = error_on_load ? ENV.fetch(name.to_s.upcase) : ENV[name.to_s.upcase]
|
9
|
+
value = cast(value, method)
|
10
|
+
|
11
|
+
create(name, value, error_on_load)
|
12
|
+
end
|
13
|
+
|
14
|
+
def optional(name, method=nil)
|
15
|
+
value = cast(ENV[name.to_s.upcase], method)
|
16
|
+
create(name, value)
|
17
|
+
end
|
18
|
+
|
19
|
+
def namespace namespace, prefix: true, &block
|
20
|
+
@processed = []
|
21
|
+
@prefix = "#{namespace}_" if prefix
|
22
|
+
yield
|
23
|
+
instance_eval "def #{namespace}?; !!(#{@processed.join(' && ')}) end"
|
24
|
+
ensure
|
25
|
+
@prefix = nil
|
26
|
+
@processed = []
|
27
|
+
end
|
28
|
+
|
29
|
+
def override(name, default, method=nil)
|
30
|
+
value = cast(ENV.fetch(name.to_s.upcase, default), method)
|
31
|
+
create(name, value)
|
32
|
+
end
|
33
|
+
|
34
|
+
def int
|
35
|
+
->(v) { v.to_i }
|
36
|
+
end
|
37
|
+
|
38
|
+
def float
|
39
|
+
->(v) { v.to_f }
|
40
|
+
end
|
41
|
+
|
42
|
+
def bool
|
43
|
+
->(v) { v.to_s=='true'}
|
44
|
+
end
|
45
|
+
|
46
|
+
def string
|
47
|
+
nil
|
48
|
+
end
|
49
|
+
|
50
|
+
def symbol
|
51
|
+
->(v) { v.to_sym }
|
52
|
+
end
|
53
|
+
|
54
|
+
def url
|
55
|
+
->(v) { v && URI.parse(v) }
|
56
|
+
end
|
57
|
+
|
58
|
+
# optional :accronyms, array(string)
|
59
|
+
# => ['a', 'b']
|
60
|
+
# optional :numbers, array(int)
|
61
|
+
# => [1, 2]
|
62
|
+
# optional :notype, array
|
63
|
+
# => ['a', 'b']
|
64
|
+
def array(method = nil)
|
65
|
+
-> (v) do
|
66
|
+
if v
|
67
|
+
v.split(',').map{|a| cast(a, method) }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def cast(value, method)
|
75
|
+
method ? method.call(value) : value
|
76
|
+
end
|
77
|
+
|
78
|
+
def create(name, value, error_on_load=true)
|
79
|
+
name = "#{@prefix}#{name}"
|
80
|
+
|
81
|
+
instance_variable_set(:"@#{name}", value)
|
82
|
+
instance_eval "def #{name}; @#{name} || (raise \"key not set '#{name}'\" unless #{error_on_load}) end"
|
83
|
+
instance_eval "def #{name}?; !!#{name} end", __FILE__, __LINE__
|
84
|
+
|
85
|
+
@processed ||= []
|
86
|
+
@processed << name
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'configerator'
|
2
|
+
|
3
|
+
module Config
|
4
|
+
extend Configerator
|
5
|
+
|
6
|
+
#
|
7
|
+
# REQUIRED - exception is raised for these variables when missing
|
8
|
+
#
|
9
|
+
|
10
|
+
# required :database_url, string
|
11
|
+
|
12
|
+
# You can also defer raising an error until the key is requested:
|
13
|
+
# required :database_url, error_on_load: false, string
|
14
|
+
|
15
|
+
|
16
|
+
#
|
17
|
+
# OPTIONAL - value is returned or nil if it wasn't present
|
18
|
+
#
|
19
|
+
|
20
|
+
optional :app_name, string
|
21
|
+
|
22
|
+
|
23
|
+
#
|
24
|
+
# OVERRIDE - value is returned or the set default
|
25
|
+
#
|
26
|
+
|
27
|
+
override :rack_env, 'development', string
|
28
|
+
override :rails_env, 'development', string
|
29
|
+
|
30
|
+
# Other examplse
|
31
|
+
# override :database_timeout, 10, int
|
32
|
+
# override :db_pool, 5, int
|
33
|
+
# override :force_ssl, true, bool
|
34
|
+
# override :port, 5000, int
|
35
|
+
# override :puma_max_threads, 16, int
|
36
|
+
# override :puma_min_threads, 1, int
|
37
|
+
# override :puma_workers, 3, int
|
38
|
+
# override :raise_errors, false, bool
|
39
|
+
|
40
|
+
|
41
|
+
#
|
42
|
+
# CLASS METHODS - for calculated/specialized values (its just ruby!)
|
43
|
+
#
|
44
|
+
|
45
|
+
# class << self
|
46
|
+
# def app_name
|
47
|
+
# "blammo-#{rails_env}"
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# def root
|
51
|
+
# Rails.root
|
52
|
+
# end
|
53
|
+
# end
|
54
|
+
|
55
|
+
#
|
56
|
+
# CASTING TYPES, there are several casting types
|
57
|
+
#
|
58
|
+
|
59
|
+
# optional :name, string # "blammo"
|
60
|
+
# optional :number, int # 42
|
61
|
+
# optional :rate, float # 1.23
|
62
|
+
# optional :flag, bool # true
|
63
|
+
# optional :key, symbol # :info
|
64
|
+
# optional :github, url # #<URI::HTTP https://github.com/heroku>
|
65
|
+
# optional :list, array(string) # ["this", "is", "a", "list"]
|
66
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require './lib/configerator'
|
4
|
+
|
5
|
+
module Config
|
6
|
+
extend Configerator
|
7
|
+
end
|
8
|
+
|
9
|
+
class TestConfigerator < Minitest::Test
|
10
|
+
FIXTURES = {
|
11
|
+
test_required: 'required',
|
12
|
+
test_optional: 'optional',
|
13
|
+
test_override: 'override',
|
14
|
+
|
15
|
+
test_int: 99,
|
16
|
+
test_float: 99.9,
|
17
|
+
test_string: 'ninty nine',
|
18
|
+
test_symbol: :ninty_nine,
|
19
|
+
test_url: 'https://99.com',
|
20
|
+
test_array_int: [ 9, 9 ],
|
21
|
+
test_array: [ 'nine', 'nine' ],
|
22
|
+
|
23
|
+
test_ns1: 'ns1',
|
24
|
+
test_ns2: 'ns2',
|
25
|
+
|
26
|
+
ns1: 'ns1',
|
27
|
+
ns2: 'ns2'
|
28
|
+
}.freeze
|
29
|
+
|
30
|
+
def setup
|
31
|
+
FIXTURES.each { |k, v|
|
32
|
+
ENV[k.to_s.upcase] = (v.is_a?(Array) ? v.join(',') : v.to_s)
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
def with_method
|
37
|
+
-> (v) { "method:#{v}" }
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_required
|
41
|
+
Config.required :test_required
|
42
|
+
|
43
|
+
assert_equal Config.test_required, 'required'
|
44
|
+
assert Config.test_required?
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_required_on_load_false
|
48
|
+
Config.required :test_required2, error_on_load: false
|
49
|
+
|
50
|
+
assert_raises RuntimeError do
|
51
|
+
Config.test_required2?
|
52
|
+
end
|
53
|
+
|
54
|
+
assert_raises RuntimeError do
|
55
|
+
Config.test_required2
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_required_with_method
|
60
|
+
Config.required :test_required, with_method
|
61
|
+
|
62
|
+
assert_equal Config.test_required, 'method:required'
|
63
|
+
assert Config.test_required?
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_required_missing
|
67
|
+
assert_raises KeyError do
|
68
|
+
Config.required :test_missing
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_optional
|
73
|
+
Config.optional :test_optional
|
74
|
+
|
75
|
+
assert_equal Config.test_optional, 'optional'
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_optional_with_method
|
79
|
+
Config.optional :test_optional, with_method
|
80
|
+
|
81
|
+
assert_equal Config.test_optional, 'method:optional'
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_optional_missing
|
85
|
+
Config.optional :test_missing_optional
|
86
|
+
|
87
|
+
assert_nil Config.test_missing_optional
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_namespace
|
91
|
+
Config.namespace :test do
|
92
|
+
Config.required :ns1
|
93
|
+
Config.optional :ns2
|
94
|
+
Config.override :ns3, "three"
|
95
|
+
end
|
96
|
+
|
97
|
+
assert Config.test_ns1
|
98
|
+
assert Config.test_ns2
|
99
|
+
assert Config.test_ns3
|
100
|
+
assert Config.test?
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_namepsace_missing
|
104
|
+
Config.namespace :test do
|
105
|
+
Config.required :ns1
|
106
|
+
Config.optional :ns2
|
107
|
+
Config.override :ns3, "three"
|
108
|
+
Config.optional :ns4
|
109
|
+
end
|
110
|
+
|
111
|
+
assert Config.test_ns1
|
112
|
+
assert Config.test_ns2
|
113
|
+
assert Config.test_ns3
|
114
|
+
refute Config.test_ns4
|
115
|
+
refute Config.test?
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_namespace_without_prefix
|
119
|
+
Config.namespace :test, prefix: false do
|
120
|
+
Config.optional :ns1
|
121
|
+
Config.optional :ns2
|
122
|
+
end
|
123
|
+
|
124
|
+
assert Config.ns1
|
125
|
+
assert Config.ns2
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_override
|
129
|
+
Config.override :test_override, 'override_default'
|
130
|
+
|
131
|
+
assert_equal Config.test_override, 'override'
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_override_with_method
|
135
|
+
Config.override :test_override, 'override_default', with_method
|
136
|
+
|
137
|
+
assert_equal Config.test_override, 'method:override'
|
138
|
+
end
|
139
|
+
|
140
|
+
def test_override_missing
|
141
|
+
Config.override :test_override_missing, 'override_default'
|
142
|
+
|
143
|
+
assert_equal Config.test_override_missing, 'override_default'
|
144
|
+
end
|
145
|
+
|
146
|
+
# build basic casting tests
|
147
|
+
FIXTURES.each do |meth, val|
|
148
|
+
caster = meth.to_s.gsub(/^test_/, '')
|
149
|
+
|
150
|
+
unless %w[ required optional override url ns1 ns2 ].include? caster
|
151
|
+
method = \
|
152
|
+
if caster =~ /_/
|
153
|
+
parts = caster.split('_')
|
154
|
+
Config.send(parts.first.to_sym, Config.send(parts.last.to_sym))
|
155
|
+
else
|
156
|
+
Config.send(caster.to_sym)
|
157
|
+
end
|
158
|
+
|
159
|
+
define_method(meth) do
|
160
|
+
Config.required meth, method
|
161
|
+
|
162
|
+
assert_equal Config.send(meth), val
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def test_url
|
168
|
+
Config.required :test_url, Config.url
|
169
|
+
|
170
|
+
assert_equal Config.test_url, URI.parse('https://99.com')
|
171
|
+
end
|
172
|
+
end
|
metadata
CHANGED
@@ -1,23 +1,30 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: configerator
|
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
|
- Joshua Mervine
|
8
|
+
- Reid MacDonald
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2016-08-
|
12
|
+
date: 2016-08-12 00:00:00.000000000 Z
|
12
13
|
dependencies: []
|
13
14
|
description: Simple module for implementing environment based configuration adapted
|
14
15
|
from Pliny and following the 12factor pattern.
|
15
|
-
email:
|
16
|
+
email:
|
17
|
+
- joshua@mervine.net
|
18
|
+
- reidmix@gmail.com
|
16
19
|
executables: []
|
17
20
|
extensions: []
|
18
21
|
extra_rdoc_files: []
|
19
22
|
files:
|
20
23
|
- lib/configerator.rb
|
24
|
+
- lib/configerator/configerator.rb
|
25
|
+
- lib/generators/config_generator.rb
|
26
|
+
- lib/generators/templates/config.rb
|
27
|
+
- test/configerator_test.rb
|
21
28
|
homepage: https://github.com/heroku/configerator
|
22
29
|
licenses:
|
23
30
|
- MIT
|
@@ -42,4 +49,5 @@ rubygems_version: 2.5.1
|
|
42
49
|
signing_key:
|
43
50
|
specification_version: 4
|
44
51
|
summary: 'Configerator: A Config Helper'
|
45
|
-
test_files:
|
52
|
+
test_files:
|
53
|
+
- test/configerator_test.rb
|