anyway_config 0.5.1 → 1.0.0.rc1
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/.gitignore +3 -1
- data/.rubocop.yml +10 -8
- data/.travis.yml +12 -3
- data/CHANGELOG.md +21 -0
- data/Gemfile +3 -1
- data/LICENSE.txt +1 -1
- data/README.md +79 -45
- data/Rakefile +7 -3
- data/anyway_config.gemspec +13 -5
- data/config/cool.yml +5 -0
- data/gemfiles/railsmaster.gemfile +6 -0
- data/lib/anyway/config.rb +16 -5
- data/lib/anyway/env.rb +16 -15
- data/lib/anyway/ext/class.rb +3 -1
- data/lib/anyway/ext/deep_dup.rb +14 -2
- data/lib/anyway/ext/hash.rb +3 -1
- data/lib/anyway/rails/config.rb +3 -2
- data/lib/anyway/version.rb +3 -1
- data/lib/anyway.rb +2 -0
- data/lib/anyway_config.rb +3 -0
- data/spec/config_spec.rb +24 -13
- data/spec/config_spec_norails.rb +28 -7
- data/spec/dummy/config/cool.yml +1 -1
- data/spec/dummy/config/secrets.yml +0 -1
- data/spec/env_spec.rb +17 -13
- data/spec/ext/deep_dup_spec.rb +38 -0
- data/spec/spec_helper.rb +13 -2
- data/spec/spec_norails_helper.rb +13 -2
- data/spec/support/cool_config.rb +2 -0
- data/spec/support/test_config.rb +4 -2
- metadata +28 -9
- data/.hound.yml +0 -12
- data/spec/dummy.yml +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 429f99711260e7eb7c57d207d1c9b5df66663a3f
|
4
|
+
data.tar.gz: 79e50e810078aa95ba472587b04fc2929af1c641
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5b2ac6da8c645a45a70cc3f5a0958c12a7097da8b6a79ae5732656b3ad15d4d7e6ec360be0da47b8d496c84ba187d3a6de9ea465eaa727fec68cac713cf6ece2
|
7
|
+
data.tar.gz: 1afa0ed9d11219ef5036ad399795ce5a431c9673492eea9cf4971bf717c5165c4469198d8a7f58b0e85b8b58d3f1f679a639fc45d61c48f47d6fb297420b4170
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
@@ -1,15 +1,19 @@
|
|
1
1
|
AllCops:
|
2
|
-
# Include gemspec and Rakefile
|
3
2
|
Include:
|
4
3
|
- 'lib/**/*.rb'
|
5
4
|
- 'lib/**/*.rake'
|
6
5
|
- 'spec/**/*.rb'
|
6
|
+
- 'Gemfile'
|
7
|
+
- 'Rakefile'
|
7
8
|
Exclude:
|
8
9
|
- 'bin/**/*'
|
9
10
|
- 'spec/dummy/**/*'
|
10
|
-
|
11
|
+
- 'tmp/**/*'
|
12
|
+
- 'gemfiles/vendor/**/*'
|
13
|
+
- 'vendor/**/*'
|
11
14
|
DisplayCopNames: true
|
12
15
|
StyleGuideCopsOnly: false
|
16
|
+
TargetRubyVersion: 2.3
|
13
17
|
|
14
18
|
Style/Documentation:
|
15
19
|
Exclude:
|
@@ -26,11 +30,9 @@ Metrics/MethodLength:
|
|
26
30
|
Exclude:
|
27
31
|
- 'spec/**/*.rb'
|
28
32
|
|
33
|
+
Metrics/BlockLength:
|
34
|
+
Exclude:
|
35
|
+
- 'spec/**/*.rb'
|
36
|
+
|
29
37
|
Metrics/LineLength:
|
30
38
|
Max: 100
|
31
|
-
|
32
|
-
Rails/Date:
|
33
|
-
Enabled: false
|
34
|
-
|
35
|
-
Rails/TimeZone:
|
36
|
-
Enabled: false
|
data/.travis.yml
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
language: ruby
|
2
2
|
cache: bundler
|
3
3
|
|
4
|
+
dist: trusty
|
5
|
+
sudo: false
|
6
|
+
|
4
7
|
notifications:
|
5
8
|
email: false
|
6
9
|
|
@@ -10,8 +13,14 @@ before_install:
|
|
10
13
|
|
11
14
|
matrix:
|
12
15
|
include:
|
16
|
+
- rvm: ruby-head
|
17
|
+
gemfile: gemfiles/railsmaster.gemfile
|
18
|
+
- rvm: 2.4.1
|
19
|
+
gemfile: gemfiles/rails5.gemfile
|
13
20
|
- rvm: 2.3.1
|
14
21
|
gemfile: gemfiles/rails42.gemfile
|
15
|
-
|
16
|
-
|
17
|
-
|
22
|
+
- rvm: 2.2.3
|
23
|
+
gemfile: gemfiles/rails42.gemfile
|
24
|
+
allow_failures:
|
25
|
+
- rvm: ruby-head
|
26
|
+
gemfile: gemfiles/railsmaster.gemfile
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# Change log
|
2
|
+
|
3
|
+
## 1.0.0 (2017-06-20)
|
4
|
+
|
5
|
+
- Lazy load and parse ENV configurtaion (https://github.com/palkan/anyway_config/commit/5fe407c75fefec8994ca201ea7b4691b5ddd96e5). ([@palkan][])
|
6
|
+
|
7
|
+
- Add support for ERB in YML configuration (https://github.com/palkan/anyway_config/commit/8d8a47dbda6858a43ff509aaa4cddf4f938dd660). ([@palkan][])
|
8
|
+
|
9
|
+
## 0.5.0 (2017-01-20)
|
10
|
+
|
11
|
+
- Drop `active_support` dependency. ([@palkan][])
|
12
|
+
|
13
|
+
Use custom refinements instead of requiring `active_support`.
|
14
|
+
|
15
|
+
No we're dependency-free!
|
16
|
+
|
17
|
+
## 0.1.0 (2015-01-20)
|
18
|
+
|
19
|
+
Initial version.
|
20
|
+
|
21
|
+
[@palkan]: https://github.com/palkan
|
data/Gemfile
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
source 'https://rubygems.org'
|
2
4
|
|
3
5
|
# Specify your gem's dependencies in anyway_config.gemspec
|
@@ -7,7 +9,7 @@ gemspec
|
|
7
9
|
local_gemfile = "#{File.dirname(__FILE__)}/Gemfile.local"
|
8
10
|
|
9
11
|
if File.exist?(local_gemfile)
|
10
|
-
eval(File.read(local_gemfile)) # rubocop:disable
|
12
|
+
eval(File.read(local_gemfile)) # rubocop:disable Security/Eval
|
11
13
|
else
|
12
14
|
gem 'rails', '~> 5.0'
|
13
15
|
end
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -2,34 +2,45 @@
|
|
2
2
|
|
3
3
|
# Anyway Config
|
4
4
|
|
5
|
-
Rails/Ruby plugin/application configuration
|
5
|
+
Rails/Ruby plugin/application configuration tool which allows you to load parameters from different sources: YAML, Rails secrets, environment.
|
6
6
|
|
7
|
+
Apps using AnywayConfig:
|
7
8
|
|
8
|
-
Apps using Anyway Config:
|
9
9
|
- [Influxer](https://github.com/palkan/influxer)
|
10
|
-
- [AnyCable](https://github.com/anycable/anycable).
|
11
10
|
|
12
|
-
|
11
|
+
- [AnyCable](https://github.com/anycable/anycable)
|
13
12
|
|
14
|
-
|
13
|
+
- [and others](https://github.com/palkan/anyway_config/network/dependents).
|
14
|
+
|
15
|
+
## Installation
|
16
|
+
|
17
|
+
1) Adding to a gem:
|
15
18
|
|
16
19
|
```ruby
|
17
|
-
|
20
|
+
# my-cool-gem.gemspec
|
21
|
+
Gem::Specification.new do |spec|
|
18
22
|
...
|
19
|
-
|
23
|
+
spec.add_dependancy "anyway_config", "~> 1.0"
|
20
24
|
...
|
21
25
|
end
|
22
26
|
```
|
23
27
|
|
24
|
-
|
28
|
+
2) Adding to your project:
|
25
29
|
|
26
|
-
|
30
|
+
```ruby
|
31
|
+
# Gemfile
|
32
|
+
gem "anyway_config", "~> 1.0"
|
33
|
+
```
|
27
34
|
|
28
|
-
|
35
|
+
3) Install globally:
|
29
36
|
|
30
|
-
|
37
|
+
```sh
|
38
|
+
$ gem install anyway_config
|
39
|
+
```
|
31
40
|
|
32
|
-
|
41
|
+
## Usage
|
42
|
+
|
43
|
+
### Pre-defined configuration
|
33
44
|
|
34
45
|
Create configuration class:
|
35
46
|
|
@@ -49,11 +60,21 @@ end
|
|
49
60
|
attr_config :user, :password, host: 'localhost'
|
50
61
|
```
|
51
62
|
|
52
|
-
|
63
|
+
Then create an instance of the config class and use it:
|
53
64
|
|
54
|
-
|
65
|
+
```ruby
|
66
|
+
module MyCoolGem
|
67
|
+
def self.config
|
68
|
+
@config ||= Config.new
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
MyCoolGem.config.user #=> 'root'
|
73
|
+
```
|
74
|
+
|
75
|
+
#### Customize name
|
55
76
|
|
56
|
-
|
77
|
+
By default, AnywayConfig uses the namespace (the outer module name) as the config name, but you can set it manually:
|
57
78
|
|
58
79
|
```ruby
|
59
80
|
module MyCoolGem
|
@@ -64,30 +85,41 @@ module MyCoolGem
|
|
64
85
|
end
|
65
86
|
```
|
66
87
|
|
67
|
-
###
|
88
|
+
### Dynamic configuration
|
68
89
|
|
69
|
-
You can
|
90
|
+
You can also create configuration objects without pre-defined schema (just like `Rails.application.config_for` but more [powerful](#railsapplicationconfig_for-vs-anywayconfigfor)):
|
70
91
|
|
92
|
+
```ruby
|
93
|
+
# load data from config/my_app.yml, secrets.my_app (if using Rails), ENV["MYAPP_*"]
|
94
|
+
config = Anyway::Config.for(:my_app)
|
95
|
+
```
|
71
96
|
|
72
|
-
|
97
|
+
### Using with Rails
|
73
98
|
|
74
|
-
|
99
|
+
Your config will be filled up with values from the following sources (ordered by priority from low to high):
|
75
100
|
|
76
|
-
|
77
|
-
require 'anyway_config', "~>0.5", require: 'anyway'
|
78
|
-
```
|
101
|
+
- `RAILS_ROOT/config/my_cool_gem.yml` (for the current `RAILS_ENV`, supports `ERB`)
|
79
102
|
|
80
|
-
|
103
|
+
- `Rails.application.secrets.my_cool_gem`
|
81
104
|
|
82
|
-
|
105
|
+
- `ENV['MYCOOLGEM_*']`.
|
83
106
|
|
84
|
-
|
107
|
+
### Using with Ruby
|
108
|
+
|
109
|
+
By default AnywayConfig is looking for a config YAML at `./config/<config-name>.yml`. You can override this setting
|
110
|
+
through special environment variable – 'MYGEM_CONF' – containing the path to the YAML file.
|
111
|
+
|
112
|
+
Environmental variables work the same way as with Rails.
|
113
|
+
|
114
|
+
|
115
|
+
### Config clear and reload
|
116
|
+
|
117
|
+
There are `#clear` and `#reload` functions on your config (which do exactly what they state).
|
85
118
|
|
86
|
-
```
|
87
119
|
|
88
120
|
## `Rails.application.config_for` vs `Anyway::Config.for`
|
89
121
|
|
90
|
-
Rails 4.2
|
122
|
+
Rails 4.2 introduced new feature: `Rails.application.config_for`. It looks very similar to
|
91
123
|
`Anyway::Config.for`, but there are some differences:
|
92
124
|
|
93
125
|
| Feature | Rails | Anyway |
|
@@ -96,26 +128,33 @@ Rails 4.2 introduces new feature: `Rails.application.config_for`. It looks very
|
|
96
128
|
| load data from `secrets` | no | yes |
|
97
129
|
| load data from environment | no | yes |
|
98
130
|
| return Hash with indifferent access | no | yes |
|
99
|
-
| support ERB within `config/app.yml` | yes |
|
131
|
+
| support ERB within `config/app.yml` | yes | yes* |
|
100
132
|
| raise errors if file doesn't exist | yes | no |
|
101
133
|
|
102
|
-
|
134
|
+
<sub><sup>*</sup>make sure that ERB is loaded</sub>
|
135
|
+
|
136
|
+
But the main advantage of Anyway::Config is that it can be used [without Rails](#using-with-ruby)!)
|
103
137
|
|
104
138
|
## How to set env vars
|
105
139
|
|
106
|
-
Environmental variables for your config should start with your
|
140
|
+
Environmental variables for your config should start with your config name, uppercased and underscore-free.
|
141
|
+
|
142
|
+
For example, if your module is called "MyCoolGem" then the env var "MYCOOLGEM_PASSWORD" is used as `config.password`.
|
107
143
|
|
108
|
-
|
144
|
+
Environment variables are type-casted (case-insensitive).
|
109
145
|
|
110
|
-
Environment variables are type-casted (case-insensitive).
|
111
146
|
Examples:
|
112
|
-
- "True", "T" and "yes" to `true`;
|
113
|
-
- "False", "f" and "no" to `false`;
|
114
|
-
- "nil" and "null" to `nil` (do you really need it?);
|
115
|
-
- "123" to 123 and "3.14" to 3.14.
|
116
147
|
|
117
|
-
|
118
|
-
|
148
|
+
- `"True"`, `"t"` and `"yes"` to `true`;
|
149
|
+
|
150
|
+
- `"False"`, `"f"` and `"no"` to `false`;
|
151
|
+
|
152
|
+
- `"nil"` and `"null"` to `nil` (do you really need it?);
|
153
|
+
|
154
|
+
- `"123"` to 123 and `"3.14"` to 3.14.
|
155
|
+
|
156
|
+
*Anyway Config* supports nested (_hashed_) env variables. Just separate keys with double-underscore.
|
157
|
+
For example, "MYCOOLGEM_OPTIONS__VERBOSE" is parsed as `config.options.verbose`.
|
119
158
|
|
120
159
|
Array values are also supported:
|
121
160
|
|
@@ -124,21 +163,16 @@ Array values are also supported:
|
|
124
163
|
config.ids #=> [1,2,3]
|
125
164
|
```
|
126
165
|
|
127
|
-
If you want to provide text-like env variable which
|
166
|
+
If you want to provide a text-like env variable which contains commas then wrap it into quotes:
|
128
167
|
|
129
168
|
```ruby
|
130
169
|
MYCOOLGEM="Nif-Nif, Naf-Naf and Nouf-Nouf"
|
131
170
|
```
|
132
171
|
|
133
|
-
## Using without Rails
|
134
|
-
|
135
|
-
AnywayConfig can be used without Rails too.
|
136
|
-
Environmental variables remain the same. To load config from YAML add special environment variable 'MYGEM_CONF' containing path to config. But you cannot use one file for different environments (unless you do it yourself).
|
137
|
-
|
138
172
|
## Contributing
|
139
173
|
|
140
174
|
1. Fork it
|
141
175
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
142
176
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
143
177
|
4. Push to the branch (`git push origin my-new-feature`)
|
144
|
-
5. Create a new Pull Request
|
178
|
+
5. Create a new Pull Request
|
data/Rakefile
CHANGED
@@ -1,6 +1,10 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "bundler/gem_tasks"
|
3
4
|
require 'rspec/core/rake_task'
|
5
|
+
require "rubocop/rake_task"
|
6
|
+
|
7
|
+
RuboCop::RakeTask.new
|
4
8
|
|
5
9
|
task(:spec).clear
|
6
10
|
desc "Run specs with Rails app"
|
@@ -15,5 +19,5 @@ RSpec::Core::RakeTask.new("spec:norails") do |task|
|
|
15
19
|
task.verbose = false
|
16
20
|
end
|
17
21
|
|
18
|
-
desc "Run the all specs"
|
19
|
-
task default: %w
|
22
|
+
desc "Run the all specs and linters"
|
23
|
+
task default: %w[spec:norails spec rubocop]
|
data/anyway_config.gemspec
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
# coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
2
4
|
lib = File.expand_path('../lib', __FILE__)
|
3
5
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
6
|
require 'anyway/version'
|
@@ -6,17 +8,23 @@ require 'anyway/version'
|
|
6
8
|
Gem::Specification.new do |s|
|
7
9
|
s.name = "anyway_config"
|
8
10
|
s.version = Anyway::VERSION
|
9
|
-
s.authors = ["
|
11
|
+
s.authors = ["Vladimir Dementyev"]
|
10
12
|
s.email = ["dementiev.vm@gmail.com"]
|
11
13
|
s.homepage = "http://github.com/palkan/anyway_config"
|
12
|
-
s.summary = "Configuration for Ruby
|
13
|
-
s.description =
|
14
|
-
|
14
|
+
s.summary = "Configuration DSL for Ruby libraries and applications"
|
15
|
+
s.description = %{
|
16
|
+
Configuration DSL for Ruby libraries and applications.
|
17
|
+
|
18
|
+
Allows you to easily follow the twevle factor application principles (https://12factor.net/config).
|
19
|
+
}
|
20
|
+
|
21
|
+
s.license = "MIT"
|
15
22
|
|
16
|
-
s.files = `git ls-files`.split(
|
23
|
+
s.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
17
24
|
s.require_paths = ["lib"]
|
18
25
|
s.required_ruby_version = '>= 2'
|
19
26
|
|
20
27
|
s.add_development_dependency "simplecov", ">= 0.3.8"
|
21
28
|
s.add_development_dependency "rspec", "~> 3.5.0"
|
29
|
+
s.add_development_dependency "rubocop", "~> 0.49"
|
22
30
|
end
|
data/config/cool.yml
ADDED
data/lib/anyway/config.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'anyway/ext/class'
|
2
4
|
require 'anyway/ext/deep_dup'
|
3
5
|
require 'anyway/ext/hash'
|
4
6
|
|
5
|
-
module Anyway
|
7
|
+
module Anyway # :nodoc:
|
6
8
|
using Anyway::Ext::Class
|
7
9
|
using Anyway::Ext::DeepDup
|
8
10
|
using Anyway::Ext::Hash
|
@@ -73,16 +75,16 @@ module Anyway
|
|
73
75
|
end
|
74
76
|
|
75
77
|
def load_from_file(config)
|
76
|
-
config_path =
|
78
|
+
config_path = Anyway.env.fetch(config_name).delete('conf') ||
|
79
|
+
"./config/#{config_name}.yml"
|
77
80
|
if config_path && File.file?(config_path)
|
78
|
-
|
79
|
-
config.deep_merge!(YAML.load_file(config_path) || {})
|
81
|
+
config.deep_merge!(parse_yml(config_path) || {})
|
80
82
|
end
|
81
83
|
config
|
82
84
|
end
|
83
85
|
|
84
86
|
def load_from_env(config)
|
85
|
-
config.deep_merge!(Anyway.env.
|
87
|
+
config.deep_merge!(Anyway.env.fetch(config_name))
|
86
88
|
config
|
87
89
|
end
|
88
90
|
|
@@ -91,5 +93,14 @@ module Anyway
|
|
91
93
|
def set_value(key, val)
|
92
94
|
send("#{key}=", val) if respond_to?(key)
|
93
95
|
end
|
96
|
+
|
97
|
+
def parse_yml(path)
|
98
|
+
require 'yaml'
|
99
|
+
if defined?(ERB)
|
100
|
+
YAML.safe_load(ERB.new(File.read(path)).result)
|
101
|
+
else
|
102
|
+
YAML.load_file(path)
|
103
|
+
end
|
104
|
+
end
|
94
105
|
end
|
95
106
|
end
|
data/lib/anyway/env.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Anyway
|
2
4
|
# Parses environment variables and provides
|
3
5
|
# method-like access
|
@@ -9,34 +11,29 @@ module Anyway
|
|
9
11
|
|
10
12
|
def initialize
|
11
13
|
@data = {}
|
12
|
-
load
|
13
|
-
end
|
14
|
-
|
15
|
-
def reload
|
16
|
-
clear
|
17
|
-
load
|
18
|
-
self
|
19
14
|
end
|
20
15
|
|
21
16
|
def clear
|
22
17
|
@data.clear
|
23
|
-
self
|
24
18
|
end
|
25
19
|
|
26
|
-
def
|
27
|
-
|
28
|
-
return @data[method_name] if args.empty? && @data.key?(method_name)
|
20
|
+
def fetch(config_name)
|
21
|
+
@data[config_name] ||= parse_env(config_name)
|
29
22
|
end
|
30
23
|
|
31
24
|
private
|
32
25
|
|
33
|
-
def
|
26
|
+
def parse_env(config_name)
|
27
|
+
config_env_name = config_name.to_s.delete("_")
|
28
|
+
config_env_name.upcase!
|
29
|
+
data = {}
|
34
30
|
ENV.each_pair do |key, val|
|
35
|
-
if
|
36
|
-
|
37
|
-
set_by_path(
|
31
|
+
if key.start_with?(config_env_name)
|
32
|
+
_mod, path = extract_module_path(key)
|
33
|
+
set_by_path(data, path, serialize_val(val))
|
38
34
|
end
|
39
35
|
end
|
36
|
+
data
|
40
37
|
end
|
41
38
|
|
42
39
|
def config_key?(key)
|
@@ -61,6 +58,8 @@ module Anyway
|
|
61
58
|
(from[name] ||= {})
|
62
59
|
end
|
63
60
|
|
61
|
+
# rubocop:disable Metrics/MethodLength
|
62
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
64
63
|
def serialize_val(value)
|
65
64
|
case value
|
66
65
|
when ARRAY_RXP
|
@@ -81,5 +80,7 @@ module Anyway
|
|
81
80
|
value
|
82
81
|
end
|
83
82
|
end
|
83
|
+
# rubocop:enable Metrics/MethodLength
|
84
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
84
85
|
end
|
85
86
|
end
|
data/lib/anyway/ext/class.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Anyway
|
2
4
|
module Ext
|
3
5
|
# Extend String through refinements
|
@@ -6,7 +8,7 @@ module Anyway
|
|
6
8
|
def underscore_name
|
7
9
|
return unless name
|
8
10
|
word = name[/^(\w+)/]
|
9
|
-
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
|
11
|
+
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
|
10
12
|
word.downcase!
|
11
13
|
word
|
12
14
|
end
|
data/lib/anyway/ext/deep_dup.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Anyway
|
2
4
|
module Ext
|
3
5
|
# Extend Object through refinements
|
@@ -6,7 +8,11 @@ module Anyway
|
|
6
8
|
# Based on ActiveSupport http://api.rubyonrails.org/classes/Hash.html#method-i-deep_dup
|
7
9
|
def deep_dup
|
8
10
|
each_with_object(dup) do |(key, value), hash|
|
9
|
-
hash[key] = value.
|
11
|
+
hash[key] = if value.is_a?(::Hash) || value.is_a?(::Array)
|
12
|
+
value.deep_dup
|
13
|
+
else
|
14
|
+
value
|
15
|
+
end
|
10
16
|
end
|
11
17
|
end
|
12
18
|
end
|
@@ -14,7 +20,13 @@ module Anyway
|
|
14
20
|
refine ::Array do
|
15
21
|
# From ActiveSupport http://api.rubyonrails.org/classes/Array.html#method-i-deep_dup
|
16
22
|
def deep_dup
|
17
|
-
map
|
23
|
+
map do |value|
|
24
|
+
if value.is_a?(::Hash) || value.is_a?(::Array)
|
25
|
+
value.deep_dup
|
26
|
+
else
|
27
|
+
value
|
28
|
+
end
|
29
|
+
end
|
18
30
|
end
|
19
31
|
end
|
20
32
|
end
|
data/lib/anyway/ext/hash.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Anyway
|
2
4
|
module Ext
|
3
5
|
# Extend Hash through refinements
|
@@ -20,7 +22,7 @@ module Anyway
|
|
20
22
|
end
|
21
23
|
|
22
24
|
def stringify_keys!
|
23
|
-
|
25
|
+
keys.each do |key|
|
24
26
|
value = delete(key)
|
25
27
|
value.stringify_keys! if value.is_a?(::Hash)
|
26
28
|
self[key.to_s] = value
|
data/lib/anyway/rails/config.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Anyway
|
2
4
|
class Config # :nodoc:
|
3
5
|
class << self
|
@@ -17,8 +19,7 @@ module Anyway
|
|
17
19
|
def load_from_file(config)
|
18
20
|
config_path = Rails.root.join("config", "#{@config_name}.yml")
|
19
21
|
if File.file? config_path
|
20
|
-
|
21
|
-
config.deep_merge!(YAML.load_file(config_path)[Rails.env] || {})
|
22
|
+
config.deep_merge!(parse_yml(config_path)[Rails.env] || {})
|
22
23
|
end
|
23
24
|
config
|
24
25
|
end
|
data/lib/anyway/version.rb
CHANGED
data/lib/anyway.rb
CHANGED
data/spec/config_spec.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
5
|
describe Anyway::Config do
|
@@ -5,6 +7,10 @@ describe Anyway::Config do
|
|
5
7
|
let(:test_conf) { Anyway::TestConfig.new }
|
6
8
|
|
7
9
|
describe "config with name" do
|
10
|
+
before(:each) do
|
11
|
+
ENV.delete_if { |var| var =~ /^(cool|anyway)_/i }
|
12
|
+
end
|
13
|
+
|
8
14
|
specify { expect(CoolConfig.config_name).to eq "cool" }
|
9
15
|
|
10
16
|
describe "defaults" do
|
@@ -21,21 +27,20 @@ describe Anyway::Config do
|
|
21
27
|
end
|
22
28
|
|
23
29
|
describe "load from files" do
|
24
|
-
it "
|
30
|
+
it "set defaults" do
|
25
31
|
expect(conf.port).to eq 8080
|
26
32
|
end
|
27
33
|
|
28
|
-
it "
|
34
|
+
it "load config from YAML" do
|
29
35
|
expect(conf.host).to eq "test.host"
|
30
36
|
end
|
31
37
|
|
32
38
|
if Rails.application.respond_to?(:secrets)
|
33
|
-
it "
|
39
|
+
it "load config from secrets" do
|
34
40
|
expect(conf.user[:name]).to eq "test"
|
35
|
-
expect(conf.user[:password]).to eq "test"
|
36
41
|
end
|
37
42
|
else
|
38
|
-
it "
|
43
|
+
it "load config from file if no secrets" do
|
39
44
|
expect(conf.user[:name]).to eq "root"
|
40
45
|
expect(conf.user[:password]).to eq "root"
|
41
46
|
end
|
@@ -43,14 +48,18 @@ describe Anyway::Config do
|
|
43
48
|
end
|
44
49
|
|
45
50
|
describe "load from env" do
|
46
|
-
|
47
|
-
it "should work" do
|
51
|
+
it "work" do
|
48
52
|
ENV['COOL_PORT'] = '80'
|
49
53
|
ENV['COOL_USER__NAME'] = 'john'
|
50
|
-
Anyway.env.
|
54
|
+
Anyway.env.clear
|
51
55
|
expect(conf.port).to eq 80
|
52
56
|
expect(conf.user[:name]).to eq 'john'
|
53
57
|
end
|
58
|
+
|
59
|
+
it "handle ENV in YML thru ERB" do
|
60
|
+
ENV['ANYWAY_SECRET_PASSWORD'] = 'my_pass'
|
61
|
+
expect(conf.user[:password]).to eq 'my_pass'
|
62
|
+
end
|
54
63
|
end
|
55
64
|
|
56
65
|
describe "clear" do
|
@@ -66,12 +75,11 @@ describe Anyway::Config do
|
|
66
75
|
end
|
67
76
|
|
68
77
|
describe "reload" do
|
69
|
-
after(:each) { Anyway.env.clear }
|
70
78
|
it do
|
71
79
|
expect(conf.port).to eq 8080
|
72
80
|
ENV['COOL_PORT'] = '80'
|
73
81
|
ENV['COOL_USER__NAME'] = 'john'
|
74
|
-
Anyway.env.
|
82
|
+
Anyway.env.clear
|
75
83
|
conf.reload
|
76
84
|
expect(conf.port).to eq 80
|
77
85
|
expect(conf.user[:name]).to eq 'john'
|
@@ -80,11 +88,14 @@ describe Anyway::Config do
|
|
80
88
|
end
|
81
89
|
|
82
90
|
describe "config for name" do
|
83
|
-
|
84
|
-
|
91
|
+
before(:each) do
|
92
|
+
ENV.delete_if { |var| var =~ /^myapp_/i }
|
93
|
+
end
|
94
|
+
|
95
|
+
it "load data by config name", :aggregate_failures do
|
85
96
|
ENV['MYAPP_TEST'] = '1'
|
86
97
|
ENV['MYAPP_NAME'] = 'my_app'
|
87
|
-
Anyway.env.
|
98
|
+
Anyway.env.clear
|
88
99
|
data = Anyway::Config.for(:my_app)
|
89
100
|
expect(data[:test]).to eq 1
|
90
101
|
expect(data[:name]).to eq 'my_app'
|
data/spec/config_spec_norails.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_norails_helper'
|
2
4
|
|
3
5
|
describe Anyway::Config do
|
4
6
|
let(:conf) { Anyway::TestConfig.new }
|
5
7
|
|
6
8
|
describe "config without Rails" do
|
7
|
-
|
8
|
-
Anyway.env.clear
|
9
|
+
before(:each) do
|
9
10
|
ENV.delete_if { |var| var =~ /^anyway_/i }
|
10
11
|
end
|
11
12
|
|
@@ -25,26 +26,27 @@ describe Anyway::Config do
|
|
25
26
|
ENV['ANYWAY_LOG__FORMAT__COLOR'] = 't'
|
26
27
|
ENV['ANYWAY_LOG_LEVELS'] = 'debug,warning,info'
|
27
28
|
|
28
|
-
Anyway.env.
|
29
|
+
Anyway.env.clear
|
29
30
|
expect(conf.api['key']).to eq "test1"
|
30
31
|
expect(conf.api['endpoint']).to eq "localhost"
|
31
32
|
expect(conf.test).to eq "test"
|
32
33
|
expect(conf.log['format']['color']).to eq true
|
33
|
-
expect(conf.log_levels).to eq(%w
|
34
|
+
expect(conf.log_levels).to eq(%w[debug warning info])
|
34
35
|
end
|
35
36
|
|
36
37
|
it "reloads config", :aggregate_failures do
|
38
|
+
ENV['ANYWAY_CONF'] = File.join(File.dirname(__FILE__), "anyway.yml")
|
39
|
+
|
37
40
|
expect(conf.api['key']).to eq ""
|
38
|
-
expect(conf.api['endpoint']).to
|
41
|
+
expect(conf.api['endpoint']).to eq 'localhost'
|
39
42
|
expect(conf.test).to be_nil
|
40
43
|
expect(conf.log['format']['color']).to eq false
|
41
44
|
|
42
|
-
ENV['ANYWAY_CONF'] = File.join(File.dirname(__FILE__), "anyway.yml")
|
43
45
|
ENV['ANYWAY_API__KEY'] = 'test1'
|
44
46
|
ENV['ANYWAY_API__SSL'] = 'yes'
|
45
47
|
ENV['ANYWAY_TEST'] = 'test'
|
46
48
|
ENV['ANYWAY_LOG__FORMAT__COLOR'] = 't'
|
47
|
-
Anyway.env.
|
49
|
+
Anyway.env.clear
|
48
50
|
|
49
51
|
conf.reload
|
50
52
|
expect(conf.api['key']).to eq "test1"
|
@@ -61,5 +63,24 @@ describe Anyway::Config do
|
|
61
63
|
|
62
64
|
specify { expect(conf.config_name).to be_nil }
|
63
65
|
end
|
66
|
+
|
67
|
+
context "loading from default path" do
|
68
|
+
let(:conf) { CoolConfig.new }
|
69
|
+
|
70
|
+
before(:each) do
|
71
|
+
ENV.delete_if { |var| var =~ /^cool_/i }
|
72
|
+
end
|
73
|
+
|
74
|
+
it "loads from ./config", :aggregate_failures do
|
75
|
+
expect(conf.user).to eq("name" => "root", "password" => "root")
|
76
|
+
expect(conf.host).to eq "test.host"
|
77
|
+
expect(conf.port).to eq 9292
|
78
|
+
end
|
79
|
+
|
80
|
+
it "handle ENV in YML thru ERB" do
|
81
|
+
ENV["ANYWAY_COOL_PORT"] = "1957"
|
82
|
+
expect(conf.port).to eq 1957
|
83
|
+
end
|
84
|
+
end
|
64
85
|
end
|
65
86
|
end
|
data/spec/dummy/config/cool.yml
CHANGED
data/spec/env_spec.rb
CHANGED
@@ -1,32 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
5
|
describe Anyway::Env do
|
4
|
-
let(:env) { Anyway.env
|
6
|
+
let(:env) { Anyway.env }
|
5
7
|
|
6
|
-
it "
|
8
|
+
it "loads simple key/values by module", :aggregate_failures do
|
7
9
|
ENV['TESTO_KEY'] = 'a'
|
8
10
|
ENV['MYTEST_KEY'] = 'b'
|
9
|
-
expect(env.testo['key']).to eq 'a'
|
10
|
-
expect(env.my_test['key']).to eq 'b'
|
11
|
+
expect(env.fetch('testo')['key']).to eq 'a'
|
12
|
+
expect(env.fetch('my_test')['key']).to eq 'b'
|
11
13
|
end
|
12
14
|
|
13
|
-
it "
|
15
|
+
it "loads hash values", :aggregate_failures do
|
14
16
|
ENV['TESTO_DATA__ID'] = '1'
|
15
17
|
ENV['TESTO_DATA__META__NAME'] = 'meta'
|
16
18
|
ENV['TESTO_DATA__META__VAL'] = 'true'
|
17
|
-
|
18
|
-
expect(
|
19
|
-
expect(
|
19
|
+
testo_config = env.fetch('testo')
|
20
|
+
expect(testo_config['data']['id']).to eq 1
|
21
|
+
expect(testo_config['data']['meta']['name']).to eq 'meta'
|
22
|
+
expect(testo_config['data']['meta']['val']).to be_truthy
|
20
23
|
end
|
21
24
|
|
22
|
-
it "
|
25
|
+
it "loads array values", :aggregate_failures do
|
23
26
|
ENV['TESTO_DATA__IDS'] = '1,2, 3'
|
24
27
|
ENV['TESTO_DATA__META__NAMES'] = 'meta, kotleta'
|
25
28
|
ENV['TESTO_DATA__META__SIZE'] = '2'
|
26
29
|
ENV['TESTO_DATA__TEXT'] = '"C\'mon, everybody"'
|
27
|
-
|
28
|
-
expect(
|
29
|
-
expect(
|
30
|
-
expect(
|
30
|
+
testo_config = env.fetch('testo')
|
31
|
+
expect(testo_config['data']['ids']).to include(1, 2, 3)
|
32
|
+
expect(testo_config['data']['meta']['names']).to include('meta', 'kotleta')
|
33
|
+
expect(testo_config['data']['meta']['size']).to eq 2
|
34
|
+
expect(testo_config['data']['text']).to eq "C'mon, everybody"
|
31
35
|
end
|
32
36
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Anyway::Ext::DeepDup do
|
6
|
+
using Anyway::Ext::DeepDup
|
7
|
+
|
8
|
+
it "duplicates nested arrays and hashes", :aggregate_failures do
|
9
|
+
source = {
|
10
|
+
a: 1,
|
11
|
+
b: 'hello',
|
12
|
+
c: {
|
13
|
+
id: 1,
|
14
|
+
list: [1, 2, { name: 'John' }]
|
15
|
+
},
|
16
|
+
d: [{ id: 1 }, { id: 2 }]
|
17
|
+
}
|
18
|
+
|
19
|
+
dup = source.deep_dup
|
20
|
+
|
21
|
+
expect(dup[:a]).to eq 1
|
22
|
+
expect(dup[:b]).to eq 'hello'
|
23
|
+
expect(dup[:c]).to eq(
|
24
|
+
id: 1,
|
25
|
+
list: [1, 2, { name: 'John' }]
|
26
|
+
)
|
27
|
+
expect(dup[:d]).to eq(
|
28
|
+
[{ id: 1 }, { id: 2 }]
|
29
|
+
)
|
30
|
+
|
31
|
+
expect(dup[:c]).not_to be_equal(source[:c])
|
32
|
+
expect(dup[:c][:list]).not_to be_equal(source[:c][:list])
|
33
|
+
expect(dup[:c][:list].last).not_to be_equal(source[:c][:list].last)
|
34
|
+
|
35
|
+
expect(dup[:d].first).not_to be_equal(source[:d].first)
|
36
|
+
expect(dup[:d].last).not_to be_equal(source[:d].last)
|
37
|
+
end
|
38
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
4
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
5
|
|
4
6
|
begin
|
5
7
|
require "pry-byebug"
|
6
|
-
rescue LoadError
|
8
|
+
rescue LoadError # rubocop:disable all
|
7
9
|
end
|
8
10
|
|
9
11
|
ENV["RAILS_ENV"] = 'test'
|
10
12
|
|
11
13
|
require File.expand_path("../dummy/config/environment", __FILE__)
|
12
|
-
require '
|
14
|
+
require 'anyway_config'
|
13
15
|
|
14
16
|
Rails.application.eager_load!
|
15
17
|
|
@@ -17,4 +19,13 @@ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
|
17
19
|
|
18
20
|
RSpec.configure do |config|
|
19
21
|
config.mock_with :rspec
|
22
|
+
|
23
|
+
config.example_status_persistence_file_path = "tmp/rspec_examples.txt"
|
24
|
+
config.filter_run :focus
|
25
|
+
config.run_all_when_everything_filtered = true
|
26
|
+
|
27
|
+
config.order = :random
|
28
|
+
Kernel.srand config.seed
|
29
|
+
|
30
|
+
config.before(:each) { Anyway.env.clear }
|
20
31
|
end
|
data/spec/spec_norails_helper.rb
CHANGED
@@ -1,15 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
4
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
5
|
|
4
6
|
begin
|
5
7
|
require "pry-byebug"
|
6
|
-
rescue LoadError
|
8
|
+
rescue LoadError # rubocop:disable all
|
7
9
|
end
|
8
10
|
|
9
|
-
require '
|
11
|
+
require 'anyway_config'
|
12
|
+
require 'erb'
|
10
13
|
|
11
14
|
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
12
15
|
|
13
16
|
RSpec.configure do |config|
|
14
17
|
config.mock_with :rspec
|
18
|
+
|
19
|
+
config.filter_run :focus
|
20
|
+
config.run_all_when_everything_filtered = true
|
21
|
+
|
22
|
+
config.order = :random
|
23
|
+
Kernel.srand config.seed
|
24
|
+
|
25
|
+
config.before(:each) { Anyway.env.clear }
|
15
26
|
end
|
data/spec/support/cool_config.rb
CHANGED
data/spec/support/test_config.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Anyway
|
2
4
|
class TestConfig < Anyway::Config # :nodoc:
|
3
|
-
attr_config :test,
|
5
|
+
attr_config :test,
|
4
6
|
api: { key: '' },
|
5
7
|
log: {
|
6
8
|
format: {
|
@@ -9,6 +11,6 @@ module Anyway
|
|
9
11
|
},
|
10
12
|
level: :info
|
11
13
|
},
|
12
|
-
log_levels: [
|
14
|
+
log_levels: %i[info fatal]
|
13
15
|
end
|
14
16
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: anyway_config
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
7
|
+
- Vladimir Dementyev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-06-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: simplecov
|
@@ -38,7 +38,23 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 3.5.0
|
41
|
-
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rubocop
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.49'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.49'
|
55
|
+
description: "\n Configuration DSL for Ruby libraries and applications.\n\n Allows
|
56
|
+
you to easily follow the twevle factor application principles (https://12factor.net/config).\n
|
57
|
+
\ "
|
42
58
|
email:
|
43
59
|
- dementiev.vm@gmail.com
|
44
60
|
executables: []
|
@@ -46,16 +62,18 @@ extensions: []
|
|
46
62
|
extra_rdoc_files: []
|
47
63
|
files:
|
48
64
|
- ".gitignore"
|
49
|
-
- ".hound.yml"
|
50
65
|
- ".rubocop.yml"
|
51
66
|
- ".travis.yml"
|
67
|
+
- CHANGELOG.md
|
52
68
|
- Gemfile
|
53
69
|
- LICENSE.txt
|
54
70
|
- README.md
|
55
71
|
- Rakefile
|
56
72
|
- anyway_config.gemspec
|
73
|
+
- config/cool.yml
|
57
74
|
- gemfiles/rails42.gemfile
|
58
75
|
- gemfiles/rails5.gemfile
|
76
|
+
- gemfiles/railsmaster.gemfile
|
59
77
|
- lib/anyway.rb
|
60
78
|
- lib/anyway/config.rb
|
61
79
|
- lib/anyway/env.rb
|
@@ -64,10 +82,10 @@ files:
|
|
64
82
|
- lib/anyway/ext/hash.rb
|
65
83
|
- lib/anyway/rails/config.rb
|
66
84
|
- lib/anyway/version.rb
|
85
|
+
- lib/anyway_config.rb
|
67
86
|
- spec/anyway.yml
|
68
87
|
- spec/config_spec.rb
|
69
88
|
- spec/config_spec_norails.rb
|
70
|
-
- spec/dummy.yml
|
71
89
|
- spec/dummy/config.ru
|
72
90
|
- spec/dummy/config/application.rb
|
73
91
|
- spec/dummy/config/boot.rb
|
@@ -78,6 +96,7 @@ files:
|
|
78
96
|
- spec/dummy/config/routes.rb
|
79
97
|
- spec/dummy/config/secrets.yml
|
80
98
|
- spec/env_spec.rb
|
99
|
+
- spec/ext/deep_dup_spec.rb
|
81
100
|
- spec/spec_helper.rb
|
82
101
|
- spec/spec_norails_helper.rb
|
83
102
|
- spec/support/cool_config.rb
|
@@ -97,13 +116,13 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
97
116
|
version: '2'
|
98
117
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
99
118
|
requirements:
|
100
|
-
- - "
|
119
|
+
- - ">"
|
101
120
|
- !ruby/object:Gem::Version
|
102
|
-
version:
|
121
|
+
version: 1.3.1
|
103
122
|
requirements: []
|
104
123
|
rubyforge_project:
|
105
124
|
rubygems_version: 2.6.4
|
106
125
|
signing_key:
|
107
126
|
specification_version: 4
|
108
|
-
summary: Configuration for Ruby
|
127
|
+
summary: Configuration DSL for Ruby libraries and applications
|
109
128
|
test_files: []
|
data/.hound.yml
DELETED
data/spec/dummy.yml
DELETED
File without changes
|