greenpeace 0.0.2 → 0.1.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 +111 -0
- data/lib/greenpeace/configuration/config.rb +102 -39
- data/lib/greenpeace/configuration/default.rb +48 -12
- data/lib/greenpeace/configuration/doc.rb +16 -13
- data/lib/greenpeace/configuration/key.rb +32 -27
- data/lib/greenpeace/configuration/option.rb +31 -21
- data/lib/greenpeace/configuration/requirement.rb +42 -18
- data/lib/greenpeace/configuration/type.rb +45 -40
- data/lib/greenpeace/environment.rb +4 -7
- data/lib/greenpeace/railtie.rb +9 -6
- data/lib/greenpeace/version.rb +2 -1
- data/lib/greenpeace.rb +67 -11
- data/spec/integration/simple_requirement_spec.rb +61 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/unit/configuration/config_spec.rb +45 -0
- data/spec/unit/configuration/default_spec.rb +83 -0
- data/spec/unit/configuration/doc_spec.rb +40 -0
- data/spec/unit/configuration/key_spec.rb +54 -0
- data/spec/unit/configuration/option_spec.rb +45 -0
- data/spec/unit/configuration/requirement_spec.rb +85 -0
- data/spec/unit/configuration/type_spec.rb +96 -0
- data/spec/unit/environment_spec.rb +49 -0
- metadata +88 -76
- data/lib/greenpeace/configuration/environment.rb +0 -0
- data/test/dummy/Rakefile +0 -6
- data/test/dummy/app/assets/javascripts/application.js +0 -13
- data/test/dummy/app/assets/stylesheets/application.css +0 -15
- data/test/dummy/app/controllers/application_controller.rb +0 -5
- data/test/dummy/app/helpers/application_helper.rb +0 -2
- data/test/dummy/app/views/layouts/application.html.erb +0 -13
- data/test/dummy/bin/bundle +0 -3
- data/test/dummy/bin/rails +0 -4
- data/test/dummy/bin/rake +0 -4
- data/test/dummy/config/application.rb +0 -29
- data/test/dummy/config/boot.rb +0 -5
- data/test/dummy/config/environment.rb +0 -5
- data/test/dummy/config/environments/development.rb +0 -34
- data/test/dummy/config/environments/production.rb +0 -79
- data/test/dummy/config/environments/test.rb +0 -39
- data/test/dummy/config/greenpeace.rb +0 -6
- data/test/dummy/config/initializers/assets.rb +0 -8
- data/test/dummy/config/initializers/backtrace_silencers.rb +0 -7
- data/test/dummy/config/initializers/cookies_serializer.rb +0 -3
- data/test/dummy/config/initializers/filter_parameter_logging.rb +0 -4
- data/test/dummy/config/initializers/inflections.rb +0 -16
- data/test/dummy/config/initializers/mime_types.rb +0 -4
- data/test/dummy/config/initializers/session_store.rb +0 -3
- data/test/dummy/config/initializers/wrap_parameters.rb +0 -9
- data/test/dummy/config/locales/en.yml +0 -23
- data/test/dummy/config/routes.rb +0 -56
- data/test/dummy/config/secrets.yml +0 -22
- data/test/dummy/config.ru +0 -4
- data/test/dummy/public/404.html +0 -67
- data/test/dummy/public/422.html +0 -67
- data/test/dummy/public/500.html +0 -66
- data/test/dummy/public/favicon.ico +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1de449972c8785c764cf0f29f1d3776c3ccb4200
|
4
|
+
data.tar.gz: cbbe27c9e0ee871c4b40139b4f96de246d5cd12a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7e84ee0f0c2bb15dee1b8f585e0edb74621e2c5679e8f50beff7140d1a6d6f904718a0a826a98a1b97e141695c342f9189f9163fad1c0dda45b823c40a6d2905
|
7
|
+
data.tar.gz: a7a4dab7dc2a825c1063c7a29db8f43799dadfd158cb186da939afd0a9c10844e93f9d1e8e5f63f459357e8e7f88322c86745b99b743f538915cdd6b32550b33
|
data/README.md
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
# Greenpeace
|
2
|
+
|
3
|
+
**Greenpeace** is a small environment checker for [12 factor
|
4
|
+
apps](http://12factor.net/config).
|
5
|
+
|
6
|
+
## Why?
|
7
|
+
|
8
|
+
One of the factors in a [12 factor app](http://12factor.net) is configuration
|
9
|
+
management. The recommended approach is using environment variables to provide
|
10
|
+
configuration values to the application.
|
11
|
+
|
12
|
+
While the approach works great, we found some limitations and itches with it:
|
13
|
+
|
14
|
+
* There is no way to check if the environment has been correctly configured on
|
15
|
+
application startup. This delays deployment and configuration errors until
|
16
|
+
the moment the configuration key is required.
|
17
|
+
|
18
|
+
* Accessing configuration values through the ruby `ENV` hash is a bit
|
19
|
+
cumbersome, and does not provide typecasting.
|
20
|
+
|
21
|
+
There are some gems already out there that solve these, but none of them fixed
|
22
|
+
them how we wanted them to. See the similarities section bellow.
|
23
|
+
|
24
|
+
**Greenpeace** solves this in a simple, straightforward way. It is an
|
25
|
+
environment checker that checks that the environment contains all the required
|
26
|
+
values. It also exposes ENV values through a simple configuration API so you
|
27
|
+
can do `Greenpeace.env.port` instead of `ENV['PORT'].to_i`, applying
|
28
|
+
typecasting as required.
|
29
|
+
|
30
|
+
## Usage
|
31
|
+
|
32
|
+
### Installation
|
33
|
+
|
34
|
+
Add the gem to your Gemfile:
|
35
|
+
|
36
|
+
~~~ruby
|
37
|
+
gem "greenpeace"
|
38
|
+
~~~
|
39
|
+
|
40
|
+
Run bundle to install the engine:
|
41
|
+
|
42
|
+
~~~
|
43
|
+
> bundle install
|
44
|
+
~~~
|
45
|
+
|
46
|
+
### Usage
|
47
|
+
|
48
|
+
You need to setup your environment in a ruby file of your liking. If you are
|
49
|
+
using rails, the gem automatically loads a file at `config/greenpeace.rb` where
|
50
|
+
you should configure your requirements using the provided API. Otherwise, put
|
51
|
+
those requirements somewhere and ensure they are run before starting your
|
52
|
+
application.
|
53
|
+
|
54
|
+
The API is declarative and quite simple to read and write:
|
55
|
+
|
56
|
+
~~~ruby
|
57
|
+
Greenpeace.configure do |env|
|
58
|
+
# You can mark a key to be required for boot.
|
59
|
+
env.requires :database_url
|
60
|
+
|
61
|
+
# You can mark a key as an optional value, with a default if it is not
|
62
|
+
# defined.
|
63
|
+
env.may_have :google_analytics_account, default: "UA-xxxxx"
|
64
|
+
|
65
|
+
# You can mark required or optional keys to be converted to a type when
|
66
|
+
# reading the values. Valid types are :string and :int
|
67
|
+
env.requires :port, type: :int
|
68
|
+
env.may_have :api_timeout, type: :int, default: 30
|
69
|
+
|
70
|
+
# You can add an optional message which describes what the key is about, for
|
71
|
+
# documenting configuration options. This documentation string is used when
|
72
|
+
# raising an initialization exception if the key is not found, or if the
|
73
|
+
# type is not correct.
|
74
|
+
env.requires 'API_KEY', doc: "API key for the Frumboloizer service"
|
75
|
+
end
|
76
|
+
~~~
|
77
|
+
|
78
|
+
Whenever the `configure` method is called (which is done automatically on
|
79
|
+
rails), Greenpeace will check the environment and raise exceptions if something
|
80
|
+
is not correctly configured. In addition to this, you can now access the
|
81
|
+
configured keys through a simple API:
|
82
|
+
|
83
|
+
~~~ruby
|
84
|
+
if Greenpeace.env.use_google_analytics
|
85
|
+
# ...
|
86
|
+
end
|
87
|
+
~~~
|
88
|
+
|
89
|
+
## License
|
90
|
+
|
91
|
+
Copyright (C) 2014 Recompensa.mobi
|
92
|
+
|
93
|
+
|
94
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
95
|
+
this software and associated documentation files (the "Software"), to deal in
|
96
|
+
the Software without restriction, including without limitation the rights to
|
97
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
98
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
99
|
+
so, subject to the following conditions:
|
100
|
+
|
101
|
+
The above copyright notice and this permission notice shall be included in all
|
102
|
+
copies or substantial portions of the Software.
|
103
|
+
|
104
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
105
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
106
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
107
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
108
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
109
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
110
|
+
SOFTWARE.
|
111
|
+
|
@@ -1,46 +1,109 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
|
8
|
-
class Greenpeace::Configuration::Config
|
9
|
-
attr_reader :requirements
|
10
|
-
attr_reader :options
|
11
|
-
|
12
|
-
def initialize
|
13
|
-
@requirements = []
|
14
|
-
@options = []
|
15
|
-
end
|
1
|
+
require 'greenpeace/configuration/key'
|
2
|
+
require 'greenpeace/configuration/type'
|
3
|
+
require 'greenpeace/configuration/doc'
|
4
|
+
require 'greenpeace/configuration/default'
|
5
|
+
require 'greenpeace/configuration/requirement'
|
6
|
+
require 'greenpeace/configuration/option'
|
16
7
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
8
|
+
module Greenpeace
|
9
|
+
module Configuration
|
10
|
+
#
|
11
|
+
# = Config
|
12
|
+
#
|
13
|
+
# This class exposes the API methods that the end user can call on a
|
14
|
+
# `Greenpeace.configure` block.
|
15
|
+
#
|
16
|
+
# == Requirements
|
17
|
+
#
|
18
|
+
# Requirements are definition of environment keys which MUST be present on
|
19
|
+
# application startup. When a requirement is defined, if the environment
|
20
|
+
# key is not present and the current runtime mode does not have a specific
|
21
|
+
# default for the key an error is raised.
|
22
|
+
#
|
23
|
+
# The API is like the following:
|
24
|
+
#
|
25
|
+
# env.requires :key,
|
26
|
+
# type: TYPE,
|
27
|
+
# doc: DOC,
|
28
|
+
# defaults: DEFAULTS
|
29
|
+
#
|
30
|
+
# This defines a required value on ENV['KEY']. Everything after the key is
|
31
|
+
# absolutely optional:
|
32
|
+
#
|
33
|
+
# * TYPE: Type to convert the env value to. May be either :string or :int.
|
34
|
+
# :string by default.
|
35
|
+
#
|
36
|
+
# * DOC: Doc string which will be used when raising the exception if the
|
37
|
+
# environment value is not present. Extremely useful to make your
|
38
|
+
# application self-describing.
|
39
|
+
#
|
40
|
+
# * DEFAULTS: Hash which defines special defaults to use when the
|
41
|
+
# environment value is not present on a specific runtime mode. For example,
|
42
|
+
# if you want an entry to raise an error on production, but default to a
|
43
|
+
# given value on development, you declare a requirement like this:
|
44
|
+
#
|
45
|
+
# env.requires :port, type: :int, defaults: { development: 3000 }
|
46
|
+
#
|
47
|
+
# == Options
|
48
|
+
#
|
49
|
+
# Options are definition of environment keys which may or may not be
|
50
|
+
# present on application startup. Think of them as configurable optional
|
51
|
+
# values. When an option is defined, the environment value is used first,
|
52
|
+
# if any. If not, a default value is provided instead.
|
53
|
+
#
|
54
|
+
# The API is like this:
|
55
|
+
#
|
56
|
+
# env.may_have :key,
|
57
|
+
# type: TYPE,
|
58
|
+
# doc: DOC,
|
59
|
+
# default: DEFAULT,
|
60
|
+
# defaults: DEFAULTS
|
61
|
+
#
|
62
|
+
# The TYPE, DOC and DEFAULTS options work just like in the case of
|
63
|
+
# requirements. The main difference is in the DEFAULT value, which is used
|
64
|
+
# if no value is present in the environment, and no default is defined in
|
65
|
+
# the DEFAULTS entry for the current runtime mode. By default, if no value
|
66
|
+
# is present in the environment hash, no value is provided in the DEFAULT
|
67
|
+
# option and no value is provided in the DEFAULTS option for the current
|
68
|
+
# runtime environment, nil is returned.
|
69
|
+
class Config
|
70
|
+
attr_reader :settings
|
21
71
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
72
|
+
def initialize(environment = '')
|
73
|
+
@settings = []
|
74
|
+
@environment = environment
|
75
|
+
end
|
26
76
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
@requirements << requirement
|
33
|
-
end
|
77
|
+
def requires(key, options = {})
|
78
|
+
requirement = Greenpeace::Configuration::Requirement.new(
|
79
|
+
key,
|
80
|
+
options,
|
81
|
+
@environment)
|
34
82
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
83
|
+
add_setting_uniquely(requirement)
|
84
|
+
end
|
85
|
+
|
86
|
+
def may_have(key, options = {})
|
87
|
+
option = Greenpeace::Configuration::Option.new(
|
88
|
+
key,
|
89
|
+
options,
|
90
|
+
@environment)
|
91
|
+
|
92
|
+
add_setting_uniquely(option)
|
93
|
+
end
|
41
94
|
|
42
|
-
|
43
|
-
|
44
|
-
|
95
|
+
private
|
96
|
+
|
97
|
+
def add_setting_uniquely(setting)
|
98
|
+
if key_already_defined?(setting.key)
|
99
|
+
fail "Duplicated configuration key #{setting.key}"
|
100
|
+
end
|
101
|
+
@settings << setting
|
102
|
+
end
|
103
|
+
|
104
|
+
def key_already_defined?(key)
|
105
|
+
@settings.any? { |setting| setting.key == key }
|
106
|
+
end
|
107
|
+
end
|
45
108
|
end
|
46
109
|
end
|
@@ -1,18 +1,54 @@
|
|
1
|
-
module Greenpeace
|
2
|
-
|
3
|
-
|
1
|
+
module Greenpeace
|
2
|
+
module Configuration
|
3
|
+
# Defines a default setting in a requirement or option
|
4
|
+
class Default
|
5
|
+
def initialize(type, options, key, plural_key)
|
6
|
+
@type = type
|
4
7
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
8
|
+
@has_direct_value = options.key?(key)
|
9
|
+
@direct_value = extract_direct_value(options, key)
|
10
|
+
|
11
|
+
@has_environment_value = options.key?(plural_key)
|
12
|
+
@environment_values = extract_environment_value(options, plural_key)
|
13
|
+
end
|
14
|
+
|
15
|
+
def value(environment)
|
16
|
+
if @has_direct_value
|
17
|
+
@direct_value
|
18
|
+
elsif @has_environment_value
|
19
|
+
@environment_values[environment.to_s]
|
20
|
+
else
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def environment_value?(environment)
|
26
|
+
@has_environment_value && @environment_values[environment.to_s]
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def validate_environment_hash(hash)
|
32
|
+
hash.keys.each_with_object({}) do |key, result|
|
33
|
+
result[key.to_s] = validate_default(hash[key])
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def validate_default(value)
|
38
|
+
unless @type.valid_value?(value)
|
39
|
+
fail "Default value #{value}" \
|
40
|
+
" is not of the corresponding type #{@type}"
|
41
|
+
end
|
42
|
+
value
|
43
|
+
end
|
44
|
+
|
45
|
+
def extract_direct_value(options, key)
|
46
|
+
validate_default(options[key]) if @has_direct_value
|
47
|
+
end
|
9
48
|
|
10
|
-
|
11
|
-
|
12
|
-
unless @type.valid_value?(value)
|
13
|
-
raise "Default value #{value} is not of the corresponding type #{@type}"
|
49
|
+
def extract_environment_value(options, plural_key)
|
50
|
+
validate_environment_hash(options[plural_key]) if @has_environment_value
|
14
51
|
end
|
15
|
-
value
|
16
52
|
end
|
17
53
|
end
|
18
54
|
end
|
@@ -1,19 +1,22 @@
|
|
1
|
-
module Greenpeace
|
2
|
-
|
1
|
+
module Greenpeace
|
2
|
+
module Configuration
|
3
|
+
# Represents a doc configuration in a requirement
|
4
|
+
class Doc
|
5
|
+
def initialize(options, key)
|
6
|
+
@doc = options.key?(key) ? validate_doc(options[key]) : 'Undefined'
|
7
|
+
end
|
3
8
|
|
4
|
-
|
5
|
-
|
6
|
-
|
9
|
+
def to_s
|
10
|
+
@doc
|
11
|
+
end
|
7
12
|
|
8
|
-
|
9
|
-
@doc
|
10
|
-
end
|
13
|
+
private
|
11
14
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
def validate_doc(doc)
|
16
|
+
fail 'Doc cannot be nil' if doc.nil?
|
17
|
+
fail 'Doc must be a string' unless doc.is_a?(String)
|
18
|
+
doc
|
19
|
+
end
|
17
20
|
end
|
18
21
|
end
|
19
22
|
end
|
@@ -1,36 +1,41 @@
|
|
1
|
-
module Greenpeace
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
module Greenpeace
|
2
|
+
module Configuration
|
3
|
+
# Represents an environment key in a configuration entry
|
4
|
+
class Key
|
5
|
+
def initialize(key)
|
6
|
+
@key = validate_key(key)
|
7
|
+
end
|
6
8
|
|
7
|
-
|
8
|
-
|
9
|
-
|
9
|
+
def ==(other)
|
10
|
+
other.key == @key
|
11
|
+
end
|
10
12
|
|
11
|
-
|
12
|
-
|
13
|
-
|
13
|
+
def to_s
|
14
|
+
@key.to_s
|
15
|
+
end
|
14
16
|
|
15
|
-
|
16
|
-
|
17
|
-
|
17
|
+
def identifier
|
18
|
+
@key.to_s
|
19
|
+
end
|
18
20
|
|
19
|
-
|
20
|
-
|
21
|
-
|
21
|
+
def env_identifier
|
22
|
+
@key.to_s.upcase
|
23
|
+
end
|
22
24
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
25
|
+
protected
|
26
|
+
|
27
|
+
attr_reader :key
|
28
|
+
|
29
|
+
private
|
27
30
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
31
|
+
def validate_key(key)
|
32
|
+
fail 'Key cannot be nil' if key.nil?
|
33
|
+
unless key.is_a? Symbol
|
34
|
+
fail "Key #{key} must be a symbol, but was a #{key.class}"
|
35
|
+
end
|
36
|
+
fail 'Key cannot be blank' if key.empty?
|
37
|
+
key
|
38
|
+
end
|
34
39
|
end
|
35
40
|
end
|
36
41
|
end
|
@@ -1,27 +1,37 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
attr_reader :doc
|
6
|
-
attr_reader :default
|
1
|
+
require 'greenpeace/configuration/key'
|
2
|
+
require 'greenpeace/configuration/type'
|
3
|
+
require 'greenpeace/configuration/doc'
|
4
|
+
require 'greenpeace/configuration/default'
|
7
5
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
end
|
6
|
+
module Greenpeace
|
7
|
+
module Configuration
|
8
|
+
# Represents an environment option
|
9
|
+
class Option
|
10
|
+
attr_reader :key
|
14
11
|
|
15
|
-
|
16
|
-
|
17
|
-
|
12
|
+
def initialize(key, options, environment)
|
13
|
+
@environment = environment
|
14
|
+
@key = Greenpeace::Configuration::Key.new(key)
|
15
|
+
@type = Greenpeace::Configuration::Type.new(options, :type)
|
16
|
+
@doc = Greenpeace::Configuration::Doc.new(options, :doc)
|
17
|
+
@default = Greenpeace::Configuration::Default.new(
|
18
|
+
@type,
|
19
|
+
options,
|
20
|
+
:default,
|
21
|
+
:defaults)
|
22
|
+
end
|
23
|
+
|
24
|
+
def identifier
|
25
|
+
@key.identifier
|
26
|
+
end
|
18
27
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
28
|
+
def value
|
29
|
+
value = ENV[@key.env_identifier]
|
30
|
+
if value.nil? || value.empty?
|
31
|
+
@default.value(@environment)
|
32
|
+
else
|
33
|
+
@type.convert(value)
|
34
|
+
end
|
25
35
|
end
|
26
36
|
end
|
27
37
|
end
|
@@ -1,26 +1,50 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
attr_reader :doc
|
1
|
+
require 'greenpeace/configuration/key'
|
2
|
+
require 'greenpeace/configuration/type'
|
3
|
+
require 'greenpeace/configuration/doc'
|
4
|
+
require 'greenpeace/configuration/default'
|
6
5
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
6
|
+
module Greenpeace
|
7
|
+
module Configuration
|
8
|
+
# Represents an environment requirement
|
9
|
+
class Requirement
|
10
|
+
attr_reader :key
|
12
11
|
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
def initialize(key, options, environment)
|
13
|
+
@environment = environment
|
14
|
+
@key = Greenpeace::Configuration::Key.new(key)
|
15
|
+
@type = Greenpeace::Configuration::Type.new(options, :type)
|
16
|
+
@doc = Greenpeace::Configuration::Doc.new(options, :doc)
|
17
|
+
@default = Greenpeace::Configuration::Default.new(
|
18
|
+
@type,
|
19
|
+
options,
|
20
|
+
nil,
|
21
|
+
:defaults)
|
22
|
+
end
|
23
|
+
|
24
|
+
def identifier
|
25
|
+
@key.identifier
|
26
|
+
end
|
27
|
+
|
28
|
+
def value
|
29
|
+
value = ENV[@key.env_identifier]
|
16
30
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
31
|
+
if value.nil? || value.empty?
|
32
|
+
try_with_environment_values
|
33
|
+
else
|
34
|
+
@type.convert(value)
|
35
|
+
end
|
21
36
|
end
|
22
37
|
|
23
|
-
|
38
|
+
private
|
39
|
+
|
40
|
+
def try_with_environment_values
|
41
|
+
if @default.environment_value?(@environment)
|
42
|
+
@default.value(@environment)
|
43
|
+
else
|
44
|
+
fail "Environment key [#{@key}] is missing." \
|
45
|
+
"The key documentation: #{@doc}"
|
46
|
+
end
|
47
|
+
end
|
24
48
|
end
|
25
49
|
end
|
26
50
|
end
|
@@ -1,51 +1,56 @@
|
|
1
|
-
module Greenpeace
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
1
|
+
module Greenpeace
|
2
|
+
module Configuration
|
3
|
+
# Represents a type entry in a requirement or option. In charge of
|
4
|
+
# validating values and converting them to the appropriate type.
|
5
|
+
class Type
|
6
|
+
TYPES = {
|
7
|
+
string: {
|
8
|
+
converter: :to_s,
|
9
|
+
typeclass: String,
|
10
|
+
regexp: /.*/
|
11
|
+
},
|
12
|
+
|
13
|
+
int: {
|
14
|
+
converter: :to_i,
|
15
|
+
typeclass: Integer,
|
16
|
+
regexp: /^\d+$/
|
17
|
+
}
|
18
|
+
}
|
19
|
+
|
20
|
+
def initialize(options, key)
|
21
|
+
@type = options.key?(key) ? validate_type(options[key]) : :string
|
22
|
+
end
|
20
23
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
+
def valid_value?(value)
|
25
|
+
value.nil? || value.is_a?(type_descriptor[:typeclass])
|
26
|
+
end
|
27
|
+
|
28
|
+
def convert(value)
|
29
|
+
unless value.nil? || value.match(type_descriptor[:regexp])
|
30
|
+
fail "Value #{value} is supposed to be a #{@type}"
|
31
|
+
end
|
24
32
|
|
25
|
-
|
26
|
-
unless value.match(type_descriptor[:regexp])
|
27
|
-
raise "Value #{value} is supposed to be a #{@type}"
|
33
|
+
value.send(type_descriptor[:converter])
|
28
34
|
end
|
29
35
|
|
30
|
-
|
31
|
-
|
36
|
+
def to_s
|
37
|
+
@type.to_s
|
38
|
+
end
|
32
39
|
|
33
|
-
|
34
|
-
@type.to_s
|
35
|
-
end
|
40
|
+
private
|
36
41
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
end
|
42
|
+
def type_descriptor
|
43
|
+
TYPES[@type]
|
44
|
+
end
|
41
45
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
46
|
+
def validate_type(type)
|
47
|
+
fail 'Type cannot be nil' if type.nil?
|
48
|
+
fail 'Type must be a symbol' unless type.is_a?(Symbol)
|
49
|
+
unless TYPES.key?(type)
|
50
|
+
fail "Type #{type} must be one of #{TYPES.keys.join(', ')}"
|
51
|
+
end
|
52
|
+
type
|
47
53
|
end
|
48
|
-
type
|
49
54
|
end
|
50
55
|
end
|
51
56
|
end
|