dry-config 1.0.0
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 +7 -0
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +119 -0
- data/Rakefile +7 -0
- data/dry-config.gemspec +25 -0
- data/lib/dry/config/base.rb +105 -0
- data/lib/dry/config/deep_symbolizable.rb +81 -0
- data/lib/dry/config/version.rb +5 -0
- data/lib/dry/config.rb +8 -0
- data/spec/dry/config/acme.yml +30 -0
- data/spec/dry/config/base_spec.rb +103 -0
- data/spec/dry/config/deep_symbolizable_spec.rb +58 -0
- data/spec/spec_helper.rb +8 -0
- metadata +106 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d5cebd6a6d0383fcb039c2dfc66e262992d71c72
|
4
|
+
data.tar.gz: 4aa181325a5fb085cdfc7da1c0cdfa32dc7e8747
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e9a5d9294a5b1ac10eee9b1f4733cf6ccd1340fb3ad1f58d144973d169c3d864ecb7dc9e333285c783e0110900a460648b78e320fabed735192cb9013ef5fa63
|
7
|
+
data.tar.gz: a5519d08c52c8fb5d6871023286542b26615058542c8a8ccb9202b766a97896c269ab80aa299183a5168de2ea63e27f19ee0d1e0f183d4a2c8fbf4128ef8ecea
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use ruby-2.1.2@dry_config --create
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 AlienFast, LLC
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
# Dry::Config
|
2
|
+
|
3
|
+
Simple base class for DRY environment based configurations that can be loaded from multiple overriding yml files.
|
4
|
+
|
5
|
+
A programmatic seed configuration may be specified, as well as the ability to load multiple overriding configuration files
|
6
|
+
(think multi-environment and a white label multi-domain configuration).
|
7
|
+
|
8
|
+
The [elastic-beanstalk gem](https://github.com/alienfast/elastic-beanstalk) is a real world example that utilized `Dry::Config::Base`.
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
Add this line to your application's Gemfile:
|
13
|
+
|
14
|
+
gem 'dry-config'
|
15
|
+
|
16
|
+
And then execute:
|
17
|
+
|
18
|
+
$ bundle
|
19
|
+
|
20
|
+
Or install it yourself as:
|
21
|
+
|
22
|
+
$ gem install dry-config
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
|
26
|
+
### Step 1. Write a config class
|
27
|
+
Note this sample uses the `Singleton` pattern, which is useful but not required.
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
require 'singleton'
|
31
|
+
require 'dry/config'
|
32
|
+
|
33
|
+
class AcmeConfig < Dry::Config::Base
|
34
|
+
|
35
|
+
# (optional) make this the only instance
|
36
|
+
include Singleton
|
37
|
+
|
38
|
+
# seed the sensible defaults here
|
39
|
+
def seed_default_configuration
|
40
|
+
|
41
|
+
@configuration = {
|
42
|
+
environment: nil,
|
43
|
+
strategy: :blue_green,
|
44
|
+
package: {
|
45
|
+
verbose: false
|
46
|
+
},
|
47
|
+
options: {}
|
48
|
+
}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
```
|
52
|
+
|
53
|
+
### Step 2. Write a yml config file
|
54
|
+
|
55
|
+
```yaml
|
56
|
+
# sample config demonstrating multi-environment override
|
57
|
+
---
|
58
|
+
app: acme
|
59
|
+
title: Acme Holdings, LLC
|
60
|
+
#---
|
61
|
+
options:
|
62
|
+
aws:elasticbeanstalk:application:environment:
|
63
|
+
RAILS_ENV: foobar
|
64
|
+
|
65
|
+
aws:autoscaling:launchconfiguration:
|
66
|
+
InstanceType: foo
|
67
|
+
|
68
|
+
#---
|
69
|
+
development:
|
70
|
+
strategy: inplace-update
|
71
|
+
package:
|
72
|
+
verbose: true
|
73
|
+
options:
|
74
|
+
aws:autoscaling:launchconfiguration:
|
75
|
+
InstanceType: t1.micro
|
76
|
+
aws:elasticbeanstalk:application:environment:
|
77
|
+
RAILS_ENV: development
|
78
|
+
|
79
|
+
#---
|
80
|
+
production:
|
81
|
+
options:
|
82
|
+
aws:autoscaling:launchconfiguration:
|
83
|
+
InstanceType: t1.large
|
84
|
+
aws:elasticbeanstalk:application:environment:
|
85
|
+
RAILS_ENV: production
|
86
|
+
```
|
87
|
+
|
88
|
+
### Step 3. Load your config
|
89
|
+
Note that multiple files can be loaded and overriden. A nil environment is also possible.
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
AcmeConfig.instance.load!(:production, 'path_to/acme.yml')
|
93
|
+
```
|
94
|
+
|
95
|
+
### Step 4. Use the values
|
96
|
+
Note that all keys are symbolized upon loading.
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
config = Acme.config.instance
|
100
|
+
config.load!(:production, 'path_to/acme.yml')
|
101
|
+
|
102
|
+
config.app # acme
|
103
|
+
config.title # Acme Holdings, LLC
|
104
|
+
config.strategy # :blue_green,
|
105
|
+
config.options[:'aws:autoscaling:launchconfiguration'][:InstanceType] # t1.large
|
106
|
+
```
|
107
|
+
|
108
|
+
## Other options
|
109
|
+
- Expected environments are `[:development, :test, :staging, :production]`. Expand or redefine `@potential_environments` these by overriding the `#initialize` or doing so in your optional `#seed_default_configuration`. This is used in the used in the overlay pruning process to prevent unused branches of configuration from showing up in the resolved configuration.
|
110
|
+
- An optional `#seed_default_configuration` allows you to provide a configuration base
|
111
|
+
- `#clear` will restore to the seed configuration, allowing you to `#load!` new settings.
|
112
|
+
|
113
|
+
## Contributing
|
114
|
+
|
115
|
+
1. Fork it
|
116
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
117
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
118
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
119
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/dry-config.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'dry/config/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = 'dry-config'
|
8
|
+
s.version = Dry::Config::VERSION
|
9
|
+
s.authors = ['Kevin Ross']
|
10
|
+
s.email = ['kevin.ross@alienfast.com']
|
11
|
+
s.description = %q{Simple base class for DRY environment based configurations.}
|
12
|
+
s.summary = %q{Simple base class for DRY environment based configurations.}
|
13
|
+
s.homepage = 'https://github.com/alienfast/dry-config'
|
14
|
+
s.license = 'MIT'
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split($/).reject { |f| f =~ /^samples\// }
|
17
|
+
s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
19
|
+
s.require_paths = ['lib']
|
20
|
+
|
21
|
+
s.add_development_dependency 'bundler', '~> 1.3'
|
22
|
+
s.add_development_dependency 'rake'
|
23
|
+
s.add_development_dependency 'rspec', '>= 2.14.1'
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'dry/config/deep_symbolizable'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
module Dry
|
5
|
+
module Config
|
6
|
+
#
|
7
|
+
# Dry::Config::Base allows for default settings and mounting a specific environment with
|
8
|
+
# overriding hash values and merging of array values.
|
9
|
+
#
|
10
|
+
# NOTE: Anything can be overridden and merged into top-level settings (hashes) including
|
11
|
+
# anything that is an array value. Array values are merged *not* replaced. If you think
|
12
|
+
# something is screwy, see the defaults in the #initialize as those add some default array values.
|
13
|
+
# If this behavior of merging arrays or the defaults are somehow un-sensible, file an issue and we'll revisit it.
|
14
|
+
#
|
15
|
+
class Base
|
16
|
+
attr_reader :configuration
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
seed_default_configuration
|
20
|
+
|
21
|
+
# used for pruning initial base set. See #load!
|
22
|
+
@potential_environments = [:development, :test, :staging, :production]
|
23
|
+
end
|
24
|
+
|
25
|
+
def seed_default_configuration
|
26
|
+
# override and seed the sensible defaults here
|
27
|
+
@configuration = {}
|
28
|
+
end
|
29
|
+
|
30
|
+
# This is the main point of entry - we call #load! and provide
|
31
|
+
# a name of the file to read as it's argument. We can also pass in some
|
32
|
+
# options, but at the moment it's being used to allow per-environment
|
33
|
+
# overrides in Rails
|
34
|
+
def load!(environment, filename)
|
35
|
+
|
36
|
+
# raise 'Unspecified environment' if environment.nil?
|
37
|
+
raise 'Unspecified filename' if filename.nil?
|
38
|
+
|
39
|
+
# save these in case we #reload
|
40
|
+
@environment = environment
|
41
|
+
@filename = filename
|
42
|
+
|
43
|
+
# merge all top level settings with the defaults set in the #init
|
44
|
+
|
45
|
+
deep_merge!(@configuration, YAML::load_file(filename).deep_symbolize)
|
46
|
+
|
47
|
+
# add the environment to the top level settings
|
48
|
+
@configuration[:environment] = (environment.nil? ? nil : environment.to_s)
|
49
|
+
|
50
|
+
# TODO: the target file should be overlaid in an environment specific way in isolation, prior to merging with @configuration
|
51
|
+
# TODO: otherwise this will kill prior wanted settings when merging multiple files.
|
52
|
+
|
53
|
+
# overlay the specific environment if provided
|
54
|
+
if environment && @configuration[environment.to_sym]
|
55
|
+
|
56
|
+
# this is environment specific, so prune any environment
|
57
|
+
# based settings from the initial set so that they can be overlaid.
|
58
|
+
@potential_environments.each do |env|
|
59
|
+
@configuration.delete(env)
|
60
|
+
end
|
61
|
+
|
62
|
+
# re-read the file
|
63
|
+
environment_settings = YAML::load_file(filename).deep_symbolize
|
64
|
+
|
65
|
+
# snag the requested environment
|
66
|
+
environment_settings = environment_settings[environment.to_sym]
|
67
|
+
|
68
|
+
# finally overlay what was provided
|
69
|
+
#@configuration.deep_merge!(environment_settings)
|
70
|
+
deep_merge!(@configuration, environment_settings)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def reload!
|
75
|
+
clear
|
76
|
+
load! @environment, @filename
|
77
|
+
end
|
78
|
+
|
79
|
+
def clear
|
80
|
+
seed_default_configuration
|
81
|
+
end
|
82
|
+
|
83
|
+
def method_missing(name, *args, &block)
|
84
|
+
@configuration[name.to_sym] ||
|
85
|
+
#fail(NoMethodError, "Unknown settings root \'#{name}\'", caller)
|
86
|
+
nil
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def deep_merge!(target, data)
|
92
|
+
merger = proc { |key, v1, v2|
|
93
|
+
if (Hash === v1 && Hash === v2)
|
94
|
+
v1.merge(v2, &merger)
|
95
|
+
elsif (Array === v1 && Array === v2)
|
96
|
+
v1.concat(v2)
|
97
|
+
else
|
98
|
+
v2
|
99
|
+
end
|
100
|
+
}
|
101
|
+
target.merge! data, &merger
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# Slightly modified from https://gist.github.com/morhekil/998709
|
2
|
+
|
3
|
+
# Symbolizes all of hash's keys and subkeys.
|
4
|
+
# Also allows for custom pre-processing of keys (e.g. downcasing, etc)
|
5
|
+
# if the block is given:
|
6
|
+
#
|
7
|
+
# somehash.deep_symbolize { |key| key.downcase }
|
8
|
+
#
|
9
|
+
# Usage: either include it into global Hash class to make it available to
|
10
|
+
# to all hashes, or extend only your own hash objects with this
|
11
|
+
# module.
|
12
|
+
# E.g.:
|
13
|
+
# 1) class Hash; include DeepSymbolizable; end
|
14
|
+
# 2) myhash.extend DeepSymbolizable
|
15
|
+
module Dry
|
16
|
+
module Config
|
17
|
+
|
18
|
+
module DeepSymbolizable
|
19
|
+
def deep_symbolize(invert = false, &block)
|
20
|
+
method = self.class.to_s.downcase.to_sym
|
21
|
+
symbolizers = DeepSymbolizable::Symbolizers
|
22
|
+
symbolizers.respond_to?(method) ? symbolizers.send(method, self, invert, &block) : self
|
23
|
+
end
|
24
|
+
|
25
|
+
module Symbolizers
|
26
|
+
extend self
|
27
|
+
|
28
|
+
# the primary method - symbolizes keys of the given hash,
|
29
|
+
# preprocessing them with a block if one was given, and recursively
|
30
|
+
# going into all nested enumerables
|
31
|
+
def hash(hash, invert, &block)
|
32
|
+
hash.inject({}) do |result, (key, value)|
|
33
|
+
# Recursively deep-symbolize subhashes
|
34
|
+
value = _recurse_(value, invert, &block)
|
35
|
+
|
36
|
+
# Pre-process the key with a block if it was given
|
37
|
+
key = yield key if block_given?
|
38
|
+
|
39
|
+
if invert
|
40
|
+
# UN-Symbolize the key
|
41
|
+
s_key = key.to_s rescue key
|
42
|
+
|
43
|
+
# write it back into the result and return the updated hash
|
44
|
+
result[s_key] = value
|
45
|
+
|
46
|
+
else
|
47
|
+
# Symbolize the key string if it responds to to_sym
|
48
|
+
sym_key = key.to_sym rescue key
|
49
|
+
|
50
|
+
# write it back into the result and return the updated hash
|
51
|
+
result[sym_key] = value
|
52
|
+
end
|
53
|
+
result
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# walking over arrays and symbolizing all nested elements
|
58
|
+
def array(ary, invert, &block)
|
59
|
+
ary.map { |v| _recurse_(v, invert, &block) }
|
60
|
+
end
|
61
|
+
|
62
|
+
# handling recursion - any Enumerable elements (except String)
|
63
|
+
# is being extended with the module, and then symbolized
|
64
|
+
def _recurse_(value, invert, &block)
|
65
|
+
if value.is_a?(Enumerable) && !value.is_a?(String)
|
66
|
+
# support for a use case without extended core Hash
|
67
|
+
value.extend DeepSymbolizable unless value.class.include?(DeepSymbolizable)
|
68
|
+
value = value.deep_symbolize(invert, &block)
|
69
|
+
end
|
70
|
+
value
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# include in all Hash objects
|
79
|
+
class Hash;
|
80
|
+
include Dry::Config::DeepSymbolizable;
|
81
|
+
end
|
data/lib/dry/config.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# sample config demonstrating multi-environment override
|
2
|
+
---
|
3
|
+
app: acme
|
4
|
+
title: Acme Holdings, LLC
|
5
|
+
#---
|
6
|
+
options:
|
7
|
+
aws:elasticbeanstalk:application:environment:
|
8
|
+
RAILS_ENV: foobar
|
9
|
+
|
10
|
+
aws:autoscaling:launchconfiguration:
|
11
|
+
InstanceType: foo
|
12
|
+
|
13
|
+
#---
|
14
|
+
development:
|
15
|
+
strategy: inplace-update
|
16
|
+
package:
|
17
|
+
verbose: true
|
18
|
+
options:
|
19
|
+
aws:autoscaling:launchconfiguration:
|
20
|
+
InstanceType: t1.micro
|
21
|
+
aws:elasticbeanstalk:application:environment:
|
22
|
+
RAILS_ENV: development
|
23
|
+
|
24
|
+
#---
|
25
|
+
production:
|
26
|
+
options:
|
27
|
+
aws:autoscaling:launchconfiguration:
|
28
|
+
InstanceType: t1.large
|
29
|
+
aws:elasticbeanstalk:application:environment:
|
30
|
+
RAILS_ENV: production
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'singleton'
|
3
|
+
|
4
|
+
describe Dry::Config::Base do
|
5
|
+
|
6
|
+
class AcmeConfig < Dry::Config::Base
|
7
|
+
include Singleton
|
8
|
+
|
9
|
+
def seed_default_configuration
|
10
|
+
# seed the sensible defaults here
|
11
|
+
@configuration = {
|
12
|
+
environment: nil,
|
13
|
+
strategy: :blue_green,
|
14
|
+
package: {
|
15
|
+
verbose: false
|
16
|
+
},
|
17
|
+
options: {}
|
18
|
+
}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
subject(:acmeConfig) { AcmeConfig.instance }
|
23
|
+
|
24
|
+
it 'should work as a singleton' do
|
25
|
+
expect(acmeConfig).to equal(AcmeConfig.instance)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should not raise error when key is not found' do
|
29
|
+
acmeConfig.clear
|
30
|
+
expect(acmeConfig.app).to be_nil
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should provide seed configuration' do
|
34
|
+
acmeConfig.clear
|
35
|
+
assert_common_seed_settings
|
36
|
+
expect(acmeConfig.options.length).to eql 0
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should read file with nil environment' do
|
40
|
+
acmeConfig.clear
|
41
|
+
acmeConfig.load!(nil, config_file_path)
|
42
|
+
|
43
|
+
assert_common_seed_settings
|
44
|
+
assert_common_top_level_settings
|
45
|
+
|
46
|
+
assert_option :'aws:elasticbeanstalk:application:environment', :RAILS_ENV, 'foobar'
|
47
|
+
assert_option :'aws:autoscaling:launchconfiguration', :InstanceType, 'foo'
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should read file and override with development environment' do
|
51
|
+
acmeConfig.clear
|
52
|
+
acmeConfig.load!(:development, config_file_path)
|
53
|
+
|
54
|
+
# assert_common_seed_settings
|
55
|
+
assert_common_top_level_settings
|
56
|
+
|
57
|
+
assert_option :'aws:elasticbeanstalk:application:environment', :RAILS_ENV, 'development'
|
58
|
+
assert_option :'aws:autoscaling:launchconfiguration', :InstanceType, 't1.micro'
|
59
|
+
|
60
|
+
expect(acmeConfig.package[:verbose]).to eql true
|
61
|
+
expect(acmeConfig.strategy).to eql 'inplace-update'
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'should read file and override with production environment' do
|
65
|
+
acmeConfig.clear
|
66
|
+
acmeConfig.load!(:production, config_file_path)
|
67
|
+
|
68
|
+
# assert_common_seed_settings
|
69
|
+
assert_common_top_level_settings
|
70
|
+
|
71
|
+
assert_option :'aws:elasticbeanstalk:application:environment', :RAILS_ENV, 'production'
|
72
|
+
assert_option :'aws:autoscaling:launchconfiguration', :InstanceType, 't1.large'
|
73
|
+
|
74
|
+
expect(acmeConfig.package[:verbose]).to eql false
|
75
|
+
|
76
|
+
# seed values
|
77
|
+
expect(acmeConfig.strategy).to eql :blue_green
|
78
|
+
expect(acmeConfig.package[:verbose]).to eql false
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def assert_option(section, name, value)
|
84
|
+
expect(acmeConfig.options[section][name]).to eql value
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
def assert_common_seed_settings
|
89
|
+
expect(acmeConfig.strategy).to eql :blue_green
|
90
|
+
expect(acmeConfig.environment).to be_nil
|
91
|
+
expect(acmeConfig.package[:verbose]).to eql false
|
92
|
+
expect(acmeConfig.options).not_to be_nil
|
93
|
+
end
|
94
|
+
|
95
|
+
def assert_common_top_level_settings
|
96
|
+
expect(acmeConfig.app).to eql 'acme'
|
97
|
+
expect(acmeConfig.title).to eql 'Acme Holdings, LLC'
|
98
|
+
end
|
99
|
+
|
100
|
+
def config_file_path
|
101
|
+
File.expand_path('../acme.yml', __FILE__)
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# https://gist.github.com/morhekil/998709
|
2
|
+
|
3
|
+
require 'rspec'
|
4
|
+
require 'dry/config/deep_symbolizable'
|
5
|
+
|
6
|
+
describe 'Hash#deep_symbolize' do
|
7
|
+
let(:hash) { {} }
|
8
|
+
subject do
|
9
|
+
#hash.extend DeepSymbolizable
|
10
|
+
hash.deep_symbolize
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
context 'on simple hash' do
|
15
|
+
let(:hash) { {:key1 => 'val1', 'key2' => 'val2'} }
|
16
|
+
it {
|
17
|
+
h2 = hash.deep_symbolize
|
18
|
+
expect(h2).to eql({:key1 => 'val1', :key2 => 'val2'})
|
19
|
+
}
|
20
|
+
|
21
|
+
context 'when inverting' do
|
22
|
+
let(:hash) { {'key1' => 'val1', 'key2' => 'val2'} }
|
23
|
+
it {
|
24
|
+
h2 = hash.deep_symbolize
|
25
|
+
expect(h2).to eql({:key1 => 'val1', :key2 => 'val2'})
|
26
|
+
|
27
|
+
h3 = h2.deep_symbolize(true)
|
28
|
+
expect(h3).to eql({'key1' => 'val1', 'key2' => 'val2'})
|
29
|
+
}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'on nested hash' do
|
34
|
+
let(:hash) { {'key1' => 'val1', 'subkey' => {'key2' => 'val2'}} }
|
35
|
+
it {
|
36
|
+
h2 = hash.deep_symbolize
|
37
|
+
expect(h2).to eql({:key1 => 'val1', :subkey => {:key2 => 'val2'}})
|
38
|
+
}
|
39
|
+
|
40
|
+
|
41
|
+
context 'with nested array' do
|
42
|
+
let(:hash) { {'key1' => 'val1', 'subkey' => [{'key2' => 'val2'}]} }
|
43
|
+
it {
|
44
|
+
h2 = hash.deep_symbolize
|
45
|
+
expect(h2).to eql({:key1 => 'val1', :subkey => [{:key2 => 'val2'}]})
|
46
|
+
}
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
describe 'block preprocessing keys' do
|
52
|
+
let(:hash) { {'key1' => 'val1', 'subkey' => [{'key2' => 'val2'}]} }
|
53
|
+
it {
|
54
|
+
h2 = hash.deep_symbolize{ |k| k.upcase }
|
55
|
+
expect(h2).to eql({:KEY1 => 'val1', :SUBKEY => [{:KEY2 => 'val2'}]})
|
56
|
+
}
|
57
|
+
end
|
58
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dry-config
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kevin Ross
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-09-10 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: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
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: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 2.14.1
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 2.14.1
|
55
|
+
description: Simple base class for DRY environment based configurations.
|
56
|
+
email:
|
57
|
+
- kevin.ross@alienfast.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- ".gitignore"
|
63
|
+
- ".rspec"
|
64
|
+
- ".rvmrc"
|
65
|
+
- Gemfile
|
66
|
+
- LICENSE.txt
|
67
|
+
- README.md
|
68
|
+
- Rakefile
|
69
|
+
- dry-config.gemspec
|
70
|
+
- lib/dry/config.rb
|
71
|
+
- lib/dry/config/base.rb
|
72
|
+
- lib/dry/config/deep_symbolizable.rb
|
73
|
+
- lib/dry/config/version.rb
|
74
|
+
- spec/dry/config/acme.yml
|
75
|
+
- spec/dry/config/base_spec.rb
|
76
|
+
- spec/dry/config/deep_symbolizable_spec.rb
|
77
|
+
- spec/spec_helper.rb
|
78
|
+
homepage: https://github.com/alienfast/dry-config
|
79
|
+
licenses:
|
80
|
+
- MIT
|
81
|
+
metadata: {}
|
82
|
+
post_install_message:
|
83
|
+
rdoc_options: []
|
84
|
+
require_paths:
|
85
|
+
- lib
|
86
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
requirements: []
|
97
|
+
rubyforge_project:
|
98
|
+
rubygems_version: 2.2.2
|
99
|
+
signing_key:
|
100
|
+
specification_version: 4
|
101
|
+
summary: Simple base class for DRY environment based configurations.
|
102
|
+
test_files:
|
103
|
+
- spec/dry/config/acme.yml
|
104
|
+
- spec/dry/config/base_spec.rb
|
105
|
+
- spec/dry/config/deep_symbolizable_spec.rb
|
106
|
+
- spec/spec_helper.rb
|