app_config_for 0.0.4.1 → 0.0.6.1
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/CHANGELOG.md +44 -1
- data/README.md +29 -31
- data/lib/app_config_for/errors.rb +19 -4
- data/lib/app_config_for/gem_version.rb +9 -5
- data/lib/app_config_for/legacy_support.rb +16 -0
- data/lib/app_config_for/version.rb +3 -0
- data/lib/app_config_for.rb +635 -58
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7f85a6a8ca8b5be3a0fcbccc544519908b2f257760199a6f49c06a3100824692
|
4
|
+
data.tar.gz: 6de1a37f3f917450a3214fd4ba98e70d5ce2eed0485933470cc2e072b1f89e0e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4d3810ce467896ea6d8165a8a313066c2d2d8947c07e39843bdc7886ad072e6eef29ea309d2505a67b902b2d3b0a14fdde8025a0c00c6d26092583b6fe505cd5
|
7
|
+
data.tar.gz: 3b6c650d56e7624e673d4a840d24970e9428744478c7ac9399f398bdd6fc39ac92ad1470cb6209bae26e17c2eebfa0c200be30d8823990c79257348508b0c573
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,48 @@
|
|
1
1
|
## [Alpha Release]
|
2
2
|
|
3
|
-
## [0.0.1] - 2022-
|
3
|
+
## [0.0.1] - 2022-04-07
|
4
4
|
|
5
5
|
- Initial release
|
6
|
+
|
7
|
+
## [0.0.2] - 2022-04-12
|
8
|
+
|
9
|
+
- Added prefix inheritance.
|
10
|
+
- Initial inclusion vs extension support.
|
11
|
+
- Refactored some internal behaviors.
|
12
|
+
|
13
|
+
## [0.0.3] - 2022-04-12
|
14
|
+
|
15
|
+
- More internal refactoring and miscellaneous bug fixes.
|
16
|
+
|
17
|
+
## [0.0.4] - 2022-04-14
|
18
|
+
|
19
|
+
- Reduced minimal ActiveSupport version requirements to 5.0.
|
20
|
+
- Added a legacy support shim for older versions of ActiveSupport.
|
21
|
+
- Multiple configuration directory support.
|
22
|
+
- Single configuration name override support.
|
23
|
+
- Automatically prep gems consumers with the ability to ship with a default configuration.
|
24
|
+
|
25
|
+
## [0.0.4.1] - 2022-04-15
|
26
|
+
|
27
|
+
- Reduced minimal Ruby version requirements to 2.3.6
|
28
|
+
- Bug fix: active_support/configuration_file was still being requested on older ActiveSupport installations.
|
29
|
+
|
30
|
+
## [0.0.5] - 2022-04-25
|
31
|
+
|
32
|
+
- Full Yard documentation.
|
33
|
+
- Multiple config directories for file searching can be added at one time.
|
34
|
+
- Small updates to initializations.
|
35
|
+
- Started specs.
|
36
|
+
- Fixed bug in progenitor_prefixes_of that prevented rails and rack prefixes from being used.
|
37
|
+
- additional_config_directories duped by default to prevent accidental changes.
|
38
|
+
- add_config_directory now converts its argument to a string via #to_s.
|
39
|
+
|
40
|
+
## [0.0.6] - 2022-04-25
|
41
|
+
|
42
|
+
- Reading and setting configuration values can now be done directly on the extending class/module.
|
43
|
+
- Documentation updates.
|
44
|
+
- Fallback configuration support.
|
45
|
+
- Requesting configuration for another object that can supply it's own config_files will use those files instead of locally determining them.
|
46
|
+
|
47
|
+
## [0.0.6.1] - 2022-04-25
|
48
|
+
- Fixed issue when initializing env_prefixes in a namespaced module/class.
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# AppConfigFor
|
1
|
+
# AppConfigFor [](https://badge.fury.io/rb/app_config_for)
|
2
2
|
|
3
3
|
Ruby gem providing Rails::Application#config_for style capabilities for non-rails applications, gems, and rails engines.
|
4
4
|
|
@@ -20,54 +20,52 @@ Or install it yourself as:
|
|
20
20
|
|
21
21
|
## Usage
|
22
22
|
Presume a typical rails database config at ./config/database.yml
|
23
|
-
One environment variable ('MY_APP_ENV', 'RAILS_ENV', or 'RACK_ENV') is set to 'development'
|
23
|
+
One environment variable ('MY_APP_ENV', 'RAILS_ENV', or 'RACK_ENV') is set to 'development' or all are non existent.
|
24
24
|
|
25
|
-
#### ./config/
|
25
|
+
#### ./config/sample_app.yml
|
26
26
|
```yml
|
27
27
|
default: &default
|
28
|
-
site: <%= ENV.fetch("MY_APP_SITE", 'www.slackware.com') %>
|
29
|
-
password: Slackware#1!
|
28
|
+
site: <%= ENV.fetch("MY_APP_SITE", 'www.slackware.com') %>
|
29
|
+
password: Slackware#1!
|
30
30
|
|
31
31
|
development:
|
32
|
-
<<: *default
|
33
|
-
username: Linux
|
32
|
+
<<: *default
|
33
|
+
username: Linux
|
34
34
|
|
35
35
|
test:
|
36
|
-
<<: *default
|
37
|
-
username: TestingWith
|
36
|
+
<<: *default
|
37
|
+
username: TestingWith
|
38
38
|
|
39
39
|
production:
|
40
|
-
<<: *default
|
41
|
-
username: DefinitelyUsing
|
40
|
+
<<: *default
|
41
|
+
username: DefinitelyUsing
|
42
42
|
|
43
43
|
shared:
|
44
|
-
color: 'Blue'
|
44
|
+
color: 'Blue'
|
45
45
|
```
|
46
46
|
|
47
|
-
####
|
47
|
+
#### sample_application.rb
|
48
48
|
```ruby
|
49
49
|
require 'app_config_for'
|
50
50
|
|
51
|
-
module
|
52
|
-
|
51
|
+
module Sample
|
52
|
+
class App
|
53
53
|
extend AppConfigFor
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
puts "Rails database config: MyApp.config_for(:database)"
|
68
|
-
end
|
69
|
-
end
|
54
|
+
def info
|
55
|
+
puts "Current environment is #{App.env}"
|
56
|
+
|
57
|
+
puts "Remote Host: #{App.configured.site}"
|
58
|
+
|
59
|
+
# Can access same configuration in other ways
|
60
|
+
puts "Username: self.class.config_for(:app)[:username]"
|
61
|
+
puts "Password: App.config_for(App).username"
|
62
|
+
|
63
|
+
# Access a different config
|
64
|
+
if App.config_file?(:database)
|
65
|
+
puts "Rails database config: App.config_for(:database)"
|
66
|
+
end
|
70
67
|
end
|
68
|
+
end
|
71
69
|
end
|
72
70
|
```
|
73
71
|
|
@@ -1,9 +1,15 @@
|
|
1
1
|
module AppConfigFor
|
2
|
+
# Base class for all errors generated by AppConfigFor
|
2
3
|
class Error < StandardError; end
|
3
4
|
|
5
|
+
# Raised when the configuration could not be found.
|
4
6
|
class ConfigNotFound < Error
|
5
7
|
|
6
|
-
|
8
|
+
# The full path of every place the configuration file was looked for.
|
9
|
+
attr_reader :locations_searched
|
10
|
+
# The underlying SystemCallError that signaled the missing file.
|
11
|
+
# Most commonly this will be +Errno::ENOENT+.
|
12
|
+
attr_reader :original_exception
|
7
13
|
|
8
14
|
def initialize(locations, original_exception)
|
9
15
|
@locations_searched = Array(locations).map { |x| Pathname(x).expand_path }
|
@@ -12,9 +18,14 @@ module AppConfigFor
|
|
12
18
|
end
|
13
19
|
end
|
14
20
|
|
21
|
+
# Raised when there was an issue parsing the configuration file.
|
15
22
|
class LoadError < Error
|
16
23
|
|
17
|
-
|
24
|
+
# The file that was being parsed.
|
25
|
+
attr_reader :file
|
26
|
+
# The original exception that signaled the parsing problme.
|
27
|
+
# Most commonly this will be a +Psych::SyntaxError+
|
28
|
+
attr_reader :original_exception
|
18
29
|
|
19
30
|
def initialize(file, original_exception)
|
20
31
|
@file = Pathname(file).expand_path
|
@@ -23,13 +34,17 @@ module AppConfigFor
|
|
23
34
|
end
|
24
35
|
end
|
25
36
|
|
37
|
+
# Raised when an attempting to utilize an unrecognized inheritance style.
|
26
38
|
class InvalidEnvInheritanceStyle < Error
|
27
39
|
|
28
|
-
|
40
|
+
# The inheritance style that was attempted to be used.
|
41
|
+
attr_reader :attempted
|
42
|
+
# List of valid styles at the time of the attempt.
|
43
|
+
attr_reader :valid
|
29
44
|
|
30
45
|
def initialize(attempted)
|
31
46
|
@attempted = attempted
|
32
|
-
@valid =
|
47
|
+
@valid = EnvInheritanceStyles.dup
|
33
48
|
super "Invalid inheritance style #{@attempted.inspect}. Please use one of the following: #{@valid.map(&:inspect).join(', ')}"
|
34
49
|
end
|
35
50
|
|
@@ -1,16 +1,20 @@
|
|
1
1
|
module AppConfigFor
|
2
2
|
|
3
|
+
# Current version of this gem with comparable values.
|
4
|
+
# @return [Gem::Version]
|
3
5
|
def self.gem_version
|
4
6
|
Gem::Version.new(VERSION::STRING)
|
5
7
|
end
|
6
8
|
|
9
|
+
# The rendition
|
7
10
|
module VERSION
|
8
|
-
MAJOR = 0
|
9
|
-
MINOR = 0
|
10
|
-
TINY =
|
11
|
-
PRE = 1
|
11
|
+
MAJOR = 0 # A field-grade officer
|
12
|
+
MINOR = 0 # When the semitones show up as intervals between the 2nd and 3rd degrees
|
13
|
+
TINY = 6 # The number of people who use antidisestablishmentarianism in everyday conversation
|
14
|
+
PRE = 1 # Ante not auntie
|
12
15
|
|
13
|
-
|
16
|
+
# String form of the version (duh). Are you seriously reading this? I guess it is slightly more interesting that Moby-Dick.
|
17
|
+
STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
|
14
18
|
end
|
15
19
|
|
16
20
|
end
|
@@ -9,9 +9,19 @@ if ActiveSupport.gem_version < Gem::Version.new('6.1.0')
|
|
9
9
|
require "erb"
|
10
10
|
require "yaml"
|
11
11
|
|
12
|
+
# @note This legacy support is only included if the existing ActiveSupport version is below 6.1.0.
|
13
|
+
# If your application is using any version of ActiveSupport below 6.1.4 it is *strongly* suggested you upgrade your application due to security and bug fixes.
|
14
|
+
# This backwards compatability is only enough to support AppConfigFor and is not to be considered a full backport of existing features.
|
15
|
+
# This support will be removed in the future.
|
12
16
|
module ActiveSupport
|
17
|
+
|
18
|
+
# @note This legacy support is only included if the existing ActiveSupport version is below 6.1.0.
|
19
|
+
# If your application is using any version of ActiveSupport below 6.1.4 it is *strongly* suggested you upgrade your application due to security and bug fixes.
|
20
|
+
# This backwards compatability is only enough to support AppConfigFor and is not to be considered a full backport of existing features.
|
21
|
+
# This support will be removed in the future.
|
13
22
|
class EnvironmentInquirer < StringInquirer
|
14
23
|
|
24
|
+
# Default environments
|
15
25
|
Environments = %w(development test production)
|
16
26
|
|
17
27
|
def initialize(env)
|
@@ -22,6 +32,10 @@ if ActiveSupport.gem_version < Gem::Version.new('6.1.0')
|
|
22
32
|
Environments.each { |e| define_method("#{e}?") { instance_variable_get("@#{e}") }}
|
23
33
|
end
|
24
34
|
|
35
|
+
# @note This legacy support is only included if the existing ActiveSupport version is below 6.1.0.
|
36
|
+
# If your application is using any version of ActiveSupport below 6.1.4 it is *strongly* suggested you upgrade your application due to security and bug fixes.
|
37
|
+
# This backwards compatability is only enough to support AppConfigFor and is not to be considered a full backport of existing features.
|
38
|
+
# This support will be removed in the future.
|
25
39
|
class ConfigurationFile
|
26
40
|
def initialize(file_name)
|
27
41
|
@file_name = file_name
|
@@ -29,10 +43,12 @@ if ActiveSupport.gem_version < Gem::Version.new('6.1.0')
|
|
29
43
|
warn(file_name + ' contains invisible non-breaking spaces.') if @config.match?("\u00A0")
|
30
44
|
end
|
31
45
|
|
46
|
+
# Quick and dirty parse
|
32
47
|
def self.parse(file_name)
|
33
48
|
new(file_name).parse
|
34
49
|
end
|
35
50
|
|
51
|
+
# Quick and dirty parse
|
36
52
|
def parse
|
37
53
|
YAML.load(ERB.new(@config).result) || {}
|
38
54
|
rescue Psych::SyntaxError => e
|
data/lib/app_config_for.rb
CHANGED
@@ -16,55 +16,251 @@ require 'active_support/core_ext/string/inflections'
|
|
16
16
|
require 'active_support/core_ext/hash/indifferent_access'
|
17
17
|
require 'active_support/ordered_options'
|
18
18
|
require 'active_support/core_ext/object/try'
|
19
|
-
|
19
|
+
require 'active_support/backtrace_cleaner'
|
20
|
+
|
21
|
+
# {<img src="https://badge.fury.io/rb/app_config_for.svg" alt="Gem Version" />}[https://badge.fury.io/rb/app_config_for]
|
22
|
+
#
|
23
|
+
# Ruby gem providing Rails::Application#config_for style capabilities for non-rails applications, gems, and rails engines.
|
24
|
+
# It respects RAILS_ENV and RACK_ENV while providing additional capabilities beyond Rails::Application#config_for.
|
25
|
+
#
|
26
|
+
# = Usage
|
27
|
+
# Typical usage will be done by extension but inclusion is also supported.
|
28
|
+
#
|
29
|
+
# Presume a typical rails database config at ./config/database.yml
|
30
|
+
#
|
31
|
+
# One environment variable ('MY_APP_ENV', 'RAILS_ENV', or 'RACK_ENV') is set to 'development' or all are non existent.
|
32
|
+
#
|
33
|
+
# ==== ./config/sample_app.yml
|
34
|
+
# default: &default
|
35
|
+
# site: <%= ENV.fetch("MY_APP_SITE", 'www.slackware.com') %>
|
36
|
+
# password: Slackware#1!
|
37
|
+
#
|
38
|
+
# development:
|
39
|
+
# <<: *default
|
40
|
+
# username: Linux
|
41
|
+
#
|
42
|
+
# test:
|
43
|
+
# <<: *default
|
44
|
+
# username: TestingWith
|
45
|
+
#
|
46
|
+
# production:
|
47
|
+
# <<: *default
|
48
|
+
# username: DefinitelyUsing
|
49
|
+
#
|
50
|
+
# shared:
|
51
|
+
# color: 'Blue'
|
52
|
+
#
|
53
|
+
# === sample_application.rb
|
54
|
+
# require 'app_config_for'
|
55
|
+
#
|
56
|
+
# module Sample
|
57
|
+
# class App
|
58
|
+
# extend AppConfigFor
|
59
|
+
# def info
|
60
|
+
# puts "Current environment is #{App.env}"
|
61
|
+
#
|
62
|
+
# # Access the configuration in various ways depending on need/preference.
|
63
|
+
# puts "Remote Host: #{App.site}"
|
64
|
+
# puts "Username: #{App.configured.username}"
|
65
|
+
# puts "Password: #{App.config_for(App).password}"
|
66
|
+
# puts "Domain: #{self.class.config_for(:app)[:domain]}"
|
67
|
+
#
|
68
|
+
# # Access a different config
|
69
|
+
# if App.config_file?(:database)
|
70
|
+
# adapter_name = App.config_for(:database).adapter
|
71
|
+
# puts "Rails is using the #{adapter_name} adapter."
|
72
|
+
# end
|
73
|
+
# end
|
74
|
+
# end
|
75
|
+
# end
|
76
|
+
#
|
20
77
|
module AppConfigFor
|
21
|
-
|
22
|
-
|
23
|
-
|
78
|
+
# Types of hierarchical traversal used to determine the runtime environment.
|
79
|
+
# * +:none+ - No inheritance active
|
80
|
+
# * +:namespace+ - Inheritance by lexical namespace
|
81
|
+
# * +:class+ - Inheritance by class hierarchy
|
82
|
+
# * +:namespace_class+ - Namespace inheritance combined with class inheritance
|
83
|
+
# * +:class_namespace+ - Class inheritance combined with namespace inheritance
|
84
|
+
EnvInheritanceStyles = [:none, :namespace, :class, :namespace_class, :class_namespace]
|
85
|
+
|
86
|
+
# AppConfigFor can be included instead of extended. If this occurs, instances of the class will have their
|
87
|
+
# own list of prefixes. The default class prefix will be automatically added to the list.
|
24
88
|
def initialize(*args)
|
25
89
|
add_env_prefix
|
26
90
|
super
|
27
91
|
end
|
28
92
|
|
29
|
-
|
30
|
-
|
93
|
+
# Add multiple additional directories to be used when searching for the config file.
|
94
|
+
# Any duplicates will be ignored.
|
95
|
+
# @param additional_directories [Array<#to_s>] additional directories to add
|
96
|
+
# @param at_beginning [Boolean] where to insert the new directories with respect to existing prefixes
|
97
|
+
# * +true+ - Add to the beginning of the list.
|
98
|
+
# * +false+ - Add to the end of the list.
|
99
|
+
# @return [Array<Pathname>] updated array of additional config directories
|
100
|
+
# @see #additional_config_directories Additional config directories
|
101
|
+
# @see #config_directories All config directories
|
102
|
+
def add_config_directories(*additional_directories, at_beginning: true)
|
103
|
+
additional_directories = additional_directories.flatten.map { |d| Pathname.new(d.to_s) }
|
104
|
+
directories = additional_config_directories(false).send(at_beginning ? :unshift : :push, additional_directories)
|
105
|
+
directories.flatten!
|
106
|
+
directories.uniq!
|
107
|
+
directories.dup
|
108
|
+
end
|
109
|
+
|
110
|
+
# Add an single additional directory to be used when searching for the config file.
|
111
|
+
# Any duplicates will be ignored.
|
112
|
+
# @param additional_directory [#to_s] additional directory to add
|
113
|
+
# @param at_beginning [Boolean] where to insert the new directory with respect to existing prefixes
|
114
|
+
# * +true+ - Add to the beginning of the list.
|
115
|
+
# * +false+ - Add to the end of the list.
|
116
|
+
# @return [Array<Pathname>] updated array of additional config directories
|
117
|
+
# @see #additional_config_directories Additional config directories
|
118
|
+
# @see #config_directories All config directories
|
119
|
+
def add_config_directory(additional_directory, at_beginning = true)
|
120
|
+
add_config_directories additional_directory, at_beginning: at_beginning
|
121
|
+
end
|
122
|
+
|
123
|
+
# Add an additional base name to be used when locating the config file.
|
124
|
+
# @param config_name [Object] Object to extract a config name from.
|
125
|
+
# @param at_beginning [Boolean] where to insert the new config name with respect to existing names.
|
126
|
+
# * +true+ - Add to the beginning of the list.
|
127
|
+
# * +false+ - Add to the end of the list.
|
128
|
+
# @return [Array<Object>] current config names
|
129
|
+
# @see yml_name_from How the name of the yml file is determined
|
130
|
+
def add_config_name(config_name, at_beginning = true)
|
131
|
+
add_config_names config_name, at_beginning: at_beginning
|
132
|
+
end
|
133
|
+
|
134
|
+
# Add multiple additional base names to be used when locating the config file.
|
135
|
+
# @param config_names [Array<Object>] Array of objects to extract a config name from.
|
136
|
+
# @param at_beginning [Boolean] where to insert the new config names with respect to existing names.
|
137
|
+
# * +true+ - Add to the beginning of the list.
|
138
|
+
# * +false+ - Add to the end of the list.
|
139
|
+
# @return [Array<Object>] current config names
|
140
|
+
# @see yml_name_from How the name of the yml file is determined
|
141
|
+
def add_config_names(*config_names, at_beginning: true)
|
142
|
+
names = config_names(false).send(at_beginning ? :unshift : :push, config_names)
|
143
|
+
names.flatten!
|
144
|
+
names.uniq!
|
145
|
+
names.dup
|
31
146
|
end
|
32
147
|
|
33
|
-
|
34
|
-
|
148
|
+
# Add an additional environmental prefix to be used when determining current environment.
|
149
|
+
# @param prefix [Symbol, Object] Prefix to add.
|
150
|
+
# +nil+ is treated as +self+
|
151
|
+
# Non symbols are converted via {.prefix_from AppConfigFor.prefix_from}.
|
152
|
+
# @param at_beginning [Boolean] where to insert the new prefix with respect to existing prefixes
|
153
|
+
# * +true+ - Add to the beginning of the list.
|
154
|
+
# * +false+ - Add to the end of the list.
|
155
|
+
# @return [Array<Symbol>] Current prefixes (without inheritance)
|
156
|
+
# @see #env_prefixes Current prefixes
|
157
|
+
def add_env_prefix(prefix = nil, at_beginning = true)
|
158
|
+
env_prefixes(false, false).send(at_beginning ? :unshift : :push, AppConfigFor.prefix_from(prefix || self)).uniq!
|
159
|
+
env_prefixes(false)
|
35
160
|
end
|
36
161
|
|
37
|
-
|
162
|
+
# Directories to be checked in addition to the defaults when searching for the config file.
|
163
|
+
# @param dup [Boolean] Return a duplicated array to prevent accidental side effects
|
164
|
+
# @return [Array<Pathname>]
|
165
|
+
# @see #add_config_directory Adding config directories
|
166
|
+
# @see #config_directories All config directories
|
167
|
+
def additional_config_directories(dup = true)
|
38
168
|
@additional_config_directories ||= []
|
169
|
+
dup ? @additional_config_directories.dup : @additional_config_directories
|
39
170
|
end
|
40
171
|
|
172
|
+
# Clear all additional config directories and set to the directory given.
|
173
|
+
# @param directory [#to_s] additional directory to use
|
174
|
+
# @return [Array<Pathname>] updated array of additional config directories
|
175
|
+
# @see #additional_config_directories Additional config directories
|
176
|
+
# @see #config_directories All config directories
|
177
|
+
def config_directory=(directory)
|
178
|
+
additional_config_directories(false).clear
|
179
|
+
add_config_directory(directory)
|
180
|
+
end
|
181
|
+
alias_method :config_directories=, :config_directory=
|
182
|
+
|
183
|
+
# All directories that will be used when searching for the config file. Search order is as follows:
|
184
|
+
# 1. Rails configuration directories if Rails is present.
|
185
|
+
# 2. Engine configuration directories if extended by an engine.
|
186
|
+
# 3. Additional configuration directories.
|
187
|
+
# 4. ./config within the current working directory.
|
188
|
+
# All paths are expanded at time of call.
|
189
|
+
# @return [Array<Pathname>] directories in the order they will be searched.
|
190
|
+
# @see #add_config_directory Adding config directories
|
41
191
|
def config_directories
|
42
192
|
directories = ['Rails'.safe_constantize&.application&.paths, try(:paths)].compact.map { |root| root["config"].existent.first }.compact
|
43
|
-
directories.map! { |directory| Pathname.new(directory).expand_path }
|
44
193
|
directories.concat additional_config_directories
|
45
194
|
directories.push(Pathname.getwd + 'config')
|
46
|
-
directories.uniq
|
195
|
+
directories.map { |directory| Pathname.new(directory).expand_path }.uniq
|
47
196
|
end
|
48
197
|
|
49
|
-
|
198
|
+
# Configuration file that will be used.
|
199
|
+
# This is the first file from {#config_files} that exists or +nil+ if none exists.
|
200
|
+
# @param name [Symbol, Object] Name of the config to load.
|
201
|
+
# Conversion to a file name will occur using {.yml_name_from AppConfigFor.yml_name_from}.
|
202
|
+
# If name is +nil+ {#config_names} will be used.
|
203
|
+
# @param fallback [Symbol, Object] If not +nil+, attempt to load a fallback configuration if the requested one cannot be found.
|
204
|
+
# @return [Pathname, nil]
|
205
|
+
def config_file(name = nil, fallback = nil)
|
50
206
|
unless name.is_a?(Pathname)
|
51
207
|
config_files(name).find(&:exist?)
|
52
208
|
else
|
53
209
|
name.exist? ? name.expand_path : nil
|
54
|
-
end
|
210
|
+
end.yield_self { |file| file || fallback && config_file(fallback) }
|
55
211
|
end
|
56
212
|
|
213
|
+
# The list of potential config files that will be searched for and the order in which they will be searched.
|
214
|
+
# @param name [Symbol, Object] Name of the config to load.
|
215
|
+
# Conversion to a file name will occur using {.yml_name_from AppConfigFor.yml_name_from}.
|
216
|
+
# If name is +nil+, {#config_names} will be used.
|
217
|
+
# If name is object that responds to +config_files+, it will be called instead.
|
218
|
+
# @return [Array<Pathname>]
|
57
219
|
def config_files(name = nil)
|
58
|
-
name
|
59
|
-
|
220
|
+
if name.respond_to?(:config_files) && name != self
|
221
|
+
name.config_files
|
222
|
+
else
|
223
|
+
names = (name && name != self && Array(name) || config_names).map { |name| AppConfigFor.yml_name_from(name) }
|
224
|
+
config_directories.map { |directory| names.map { |name| directory + name } }.flatten
|
225
|
+
end
|
60
226
|
end
|
61
227
|
|
62
|
-
|
63
|
-
|
228
|
+
# Does a config file exit?
|
229
|
+
# @param name [Symbol, Object] Name of the config to load.
|
230
|
+
# Conversion to a file name will occur using {.yml_name_from AppConfigFor.yml_name_from}.
|
231
|
+
# If name is +nil+ {#config_names} will be used.
|
232
|
+
# @param fallback [Symbol, Object] If not +nil+, attempt to load a fallback configuration if the requested one cannot be found.
|
233
|
+
# @return [Boolean]
|
234
|
+
def config_file?(name = nil, fallback = nil)
|
235
|
+
!config_file(name, fallback).blank?
|
64
236
|
end
|
65
237
|
|
66
|
-
|
67
|
-
|
238
|
+
# Configuration settings for the current environment.
|
239
|
+
# Shared sections in the yml config file are automatically merged into the returned configuration.
|
240
|
+
# @param name [Symbol, Object] Name of the config to load.
|
241
|
+
# Conversion to a file name will occur using {.yml_name_from AppConfigFor.yml_name_from}.
|
242
|
+
# If name is +nil+ {#config_names} will be used.
|
243
|
+
# @param env [Symbol, String] name of environment to use. +nil+ will use the current environment settings from {#env}
|
244
|
+
# @param fallback [Symbol, Object] If not +nil+, attempt to load a fallback configuration if the requested one cannot be found.
|
245
|
+
# @return [ActiveSupport::OrderedOptions]
|
246
|
+
# @raise ConfigNotFound - No configuration file could be located.
|
247
|
+
# @raise LoadError - A configuration file was found but could not be properly read.
|
248
|
+
# @see yml_name_from How the name of the yml file is determined
|
249
|
+
# @see #env The current runtime environment
|
250
|
+
# @example
|
251
|
+
# config_for(:my_app) # Load my_app.yml and extract the section relative to the current environment.
|
252
|
+
# config_for(:my_app).log_level # Get the configured logging level from my_app.yml for the current environment.
|
253
|
+
# config_for("MyApp", env: 'test') # Load my_app.yml and extract the 'test' section.
|
254
|
+
#
|
255
|
+
# module Other
|
256
|
+
# class App
|
257
|
+
# end
|
258
|
+
# end
|
259
|
+
# # Load other_app.yml and extract the 'production' section.
|
260
|
+
# # Notice that Other::App does not need to extend AppConfigFor
|
261
|
+
# config_for(Other::App, env: :production)
|
262
|
+
def config_for(name, env: nil, fallback: nil)
|
263
|
+
config, shared = config_options(name, fallback).fetch_values((env || self.env).to_sym, :shared) { nil }
|
68
264
|
config ||= shared
|
69
265
|
|
70
266
|
if config.is_a?(Hash)
|
@@ -75,43 +271,201 @@ module AppConfigFor
|
|
75
271
|
config
|
76
272
|
end
|
77
273
|
|
78
|
-
|
79
|
-
|
274
|
+
# Clear all config names and set to the name given.
|
275
|
+
# Set the base name of the config file to use.
|
276
|
+
# @param new_config_name [Object] Any object. Actual name will be determined using {.yml_name_from AppConfigFor.yml_name_for}
|
277
|
+
# @return [Array<Object>] current config names
|
278
|
+
# @see yml_name_from How the name of the yml file is determined
|
279
|
+
def config_name=(new_config_name)
|
280
|
+
config_names(false).clear
|
281
|
+
add_config_names(new_config_name)
|
80
282
|
end
|
283
|
+
alias_method :config_names=, :config_name=
|
81
284
|
|
82
|
-
|
83
|
-
|
285
|
+
# Base names of the configuration file.
|
286
|
+
# Defaults to: +[self]+
|
287
|
+
def config_names(dup = true)
|
288
|
+
@config_names ||= [self]
|
289
|
+
dup ? @config_names.dup : @config_names
|
84
290
|
end
|
85
291
|
|
86
|
-
|
87
|
-
|
88
|
-
|
292
|
+
# Configuration for all environments parsed from the {#config_file}.
|
293
|
+
# @param name [Symbol, Object] Name of the config to load.
|
294
|
+
# Conversion to a file name will occur using {.yml_name_from AppConfigFor.yml_name_from}.
|
295
|
+
# If name is +nil+ {#config_names} will be used.
|
296
|
+
# @param fallback [Symbol, Object] If not +nil+, attempt to load a fallback configuration if the requested one cannot be found.
|
297
|
+
# @return [Hash]
|
298
|
+
# @raise ConfigNotFound - No configuration file could be located.
|
299
|
+
# @raise LoadError - A configuration file was found but could not be properly read.
|
300
|
+
def config_options(name = nil, fallback = nil)
|
301
|
+
file = config_file(name, fallback).to_s
|
302
|
+
ActiveSupport::ConfigurationFile.parse(file).deep_symbolize_keys
|
89
303
|
rescue SystemCallError => exception
|
90
|
-
|
304
|
+
locations = name.is_a?(Pathname) ? Array(name) : config_files(name)
|
305
|
+
locations += config_files(fallback) if fallback
|
306
|
+
raise ConfigNotFound.new(locations, exception)
|
91
307
|
rescue => exception
|
92
308
|
raise file ? LoadError.new(file, exception) : exception
|
93
309
|
end
|
94
310
|
|
95
|
-
|
96
|
-
|
311
|
+
# Convenience method for {config_for}(+self+). Caches the result for faster access.
|
312
|
+
# @param reload [Boolean] Update the cached config by rereading the configuration file.
|
313
|
+
# @return [ActiveSupport::OrderedOptions]
|
314
|
+
# @raise ConfigNotFound - No configuration file could be located.
|
315
|
+
# @raise LoadError - A configuration file was found but could not be properly read.
|
316
|
+
# @example
|
317
|
+
# module Sample
|
318
|
+
# class App
|
319
|
+
# extend AppConfigFor
|
320
|
+
# @@logger = Logger.new($stdout, level: configured.level)
|
321
|
+
# end
|
322
|
+
# end
|
323
|
+
# Sample::App.configured.url # Get the configured url from my_app.yml for the current environment
|
324
|
+
# @see #method_missing Accessing configuration values directly from the extending class/module
|
325
|
+
def configured(reload = false)
|
326
|
+
if reload || !@configured
|
327
|
+
# @disable_local_missing = true # Disable local method missing to prevent recursion
|
328
|
+
@configured = config_for(nil, env: env(reload))
|
329
|
+
# @disable_local_missing = false # Reenable local method missing since no exception occurred.
|
330
|
+
end
|
97
331
|
@configured
|
98
332
|
end
|
99
333
|
|
334
|
+
# Convenience method for {configured}(+true+).
|
335
|
+
# @return [ActiveSupport::OrderedOptions]
|
336
|
+
# @raise ConfigNotFound - No configuration file could be located.
|
337
|
+
# @raise LoadError - A configuration file was found but could not be properly read.
|
338
|
+
# @example
|
339
|
+
# module Sample
|
340
|
+
# class App
|
341
|
+
# extend AppConfigFor
|
342
|
+
# mattr_accessor :logger, default: Logger.new($stdout)
|
343
|
+
# logger.level = configured.log_level
|
344
|
+
# end
|
345
|
+
# end
|
346
|
+
# # Switch to production
|
347
|
+
# ENV['SAMPLE_APP_ENV'] = 'production'
|
348
|
+
# # Update the log level with the production values
|
349
|
+
# Sample::App.logger.level = Sample::App.configured!.log_level
|
350
|
+
def configured!
|
351
|
+
configured(true)
|
352
|
+
end
|
353
|
+
|
354
|
+
# Check for the existence of a configuration setting. Handles exceptions and recursion.
|
355
|
+
# @param key [#to_s] Key to check for
|
356
|
+
# @return [Boolean]
|
357
|
+
# * +true+ - Configuration has the key
|
358
|
+
# * +false+ - If one of the following:
|
359
|
+
# 1. Configuration does not have the key
|
360
|
+
# 2. Called recursively while retrieving the configuration
|
361
|
+
# 3. An exception is raised while retrieving the configuration
|
362
|
+
# @note This is primarily used internally during {#respond_to_missing?} and {#method_missing} calls.
|
363
|
+
def configured?(key)
|
364
|
+
if @disable_local_missing
|
365
|
+
false
|
366
|
+
else
|
367
|
+
@disable_local_missing = true
|
368
|
+
begin
|
369
|
+
configured.has_key?(key.to_s.to_sym)
|
370
|
+
rescue Exception # One of the few times you ever want to catch this exception and not reraise it.
|
371
|
+
false
|
372
|
+
ensure
|
373
|
+
@disable_local_missing = false
|
374
|
+
end
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
# Returns the current runtime environment. Caches the result.
|
379
|
+
# @param reload [Boolean] Update the cached env by requerying the environment
|
380
|
+
# @return [ActiveSupport::EnvironmentInquirer]
|
381
|
+
# @example
|
382
|
+
# module Sample
|
383
|
+
# extend AppConfigFor
|
384
|
+
# end
|
385
|
+
# Sample.env # => 'development'
|
386
|
+
# Sample.env.development? # => true
|
387
|
+
# Sample.env.production? # => false
|
100
388
|
def env(reload = false)
|
101
|
-
@env = ActiveSupport::EnvironmentInquirer.new(
|
389
|
+
@env = ActiveSupport::EnvironmentInquirer.new(env_name) if reload || @env.nil?
|
102
390
|
@env
|
103
391
|
end
|
104
392
|
|
105
|
-
|
106
|
-
|
393
|
+
# Convenience method for {env}(+true+).
|
394
|
+
# @return [ActiveSupport::EnvironmentInquirer]
|
395
|
+
# @example
|
396
|
+
# module Sample
|
397
|
+
# extend AppConfigFor
|
398
|
+
# end
|
399
|
+
# Sample.env # => 'development'
|
400
|
+
# Sample.env.development? # => true
|
401
|
+
# Sample.env.production? # => false
|
402
|
+
# # Switch to production
|
403
|
+
# ENV['SAMPLE_APP_ENV'] = 'production'
|
404
|
+
# Sample.env.production? # => false
|
405
|
+
# Sample.env!.production? # => true
|
406
|
+
def env!
|
407
|
+
env(true)
|
408
|
+
end
|
409
|
+
|
410
|
+
# Set the runtime environment (without affecting environment variables)
|
411
|
+
# @param environment [#to_s]
|
412
|
+
# @return [ActiveSupport::EnvironmentInquirer]
|
413
|
+
# @example
|
414
|
+
# ENV['SAMPLE_ENV'] = 'test'
|
415
|
+
# module Sample
|
416
|
+
# extend AppConfigFor
|
417
|
+
# end
|
418
|
+
# Sample.env # => 'test'
|
419
|
+
# Sample.env = 'development'
|
420
|
+
# Sample.env # => 'development'
|
421
|
+
# ENV['SAMPLE_ENV'] # => 'test'
|
422
|
+
def env=(environment)
|
423
|
+
@env = ActiveSupport::EnvironmentInquirer.new(environment.to_s)
|
424
|
+
end
|
425
|
+
|
426
|
+
# Current runtime environment inheritance style. Defaults to +:namespace+.
|
427
|
+
# @return [Symbol]
|
428
|
+
def env_inheritance
|
429
|
+
@env_inheritance ||= :namespace
|
430
|
+
end
|
431
|
+
|
432
|
+
# Set the runtime environment inheritance.
|
433
|
+
# @param style [#to_s] New inheritance style
|
434
|
+
# @return [Symbol]
|
435
|
+
# @raise InvalidEnvInheritanceStyle - Attempt to set a style that is not one of the {EnvInheritanceStyles}.
|
436
|
+
# @see .verified_style! Valid inheritance styles
|
437
|
+
def env_inheritance=(style)
|
438
|
+
@env_inheritance = AppConfigFor.verified_style!(style)
|
107
439
|
end
|
108
440
|
|
109
|
-
|
110
|
-
|
441
|
+
# The name of the current runtime environment for this object.
|
442
|
+
#
|
443
|
+
# Convenience method for {.env_name AppConfigFor.env_name}({#env_prefixes env_prefixes})
|
444
|
+
#
|
445
|
+
# If no value can be found, the default is 'development'.
|
446
|
+
# @return [String] current runtime environment.
|
447
|
+
# @see #env_prefixes Environment variable prefixes
|
448
|
+
def env_name
|
449
|
+
AppConfigFor.env_name(env_prefixes)
|
111
450
|
end
|
112
451
|
|
452
|
+
# Prefixes used to determine the environment name.
|
453
|
+
#
|
454
|
+
# A prefix of :some_app will will cause AppConfigFor to react to the environment variable +'SOME_APP_ENV'+
|
455
|
+
# The order of the prefixes will be the order in which AppConfigFor searches the environment variables.
|
456
|
+
# A prefix for +self+ is automatically added at the time of extension/inclusion of AppConfigFor.
|
457
|
+
#
|
458
|
+
# @param all [Boolean] Combine current prefixes with inherited prefixes.
|
459
|
+
# @param dup [Boolean] Return a duplicate of the internal array to prevent accidental modification.
|
460
|
+
# @return [Array<Symbol>] Environment prefixes for this object.
|
461
|
+
# @see add_env_prefix Adding a prefix
|
462
|
+
# @see remove_env_prefix Removing a prefix
|
463
|
+
# @see env_name Current runtime environment
|
113
464
|
def env_prefixes(all = true, dup = true)
|
114
|
-
@env_prefixes
|
465
|
+
unless @env_prefixes
|
466
|
+
@env_prefixes = []
|
467
|
+
add_env_prefix
|
468
|
+
end
|
115
469
|
if all
|
116
470
|
@env_prefixes + AppConfigFor.progenitor_prefixes_of(self)
|
117
471
|
else
|
@@ -119,6 +473,48 @@ module AppConfigFor
|
|
119
473
|
end
|
120
474
|
end
|
121
475
|
|
476
|
+
# Allow access to configuration getters and setters directly from the extending class/module.
|
477
|
+
# @example
|
478
|
+
# class Sample
|
479
|
+
# extend AppConfigFor
|
480
|
+
# end
|
481
|
+
#
|
482
|
+
# # Presuming config/sample.yml contains a configuration for 'log_level' and 'status' but no other keys.
|
483
|
+
# Sample.log_level # => :production
|
484
|
+
# Sample.log_level = :debug
|
485
|
+
# Sample.log_level # => :debug
|
486
|
+
#
|
487
|
+
# # You are allowed to set the value prior reading it should the need should arise.
|
488
|
+
# Sample.status = 'active'
|
489
|
+
# Sample.status # => 'active'
|
490
|
+
#
|
491
|
+
# # However, you cannot invent new keys with these methods.
|
492
|
+
# Sample.something_else # => NoMethodError(undefined method `something_else' for Sample)
|
493
|
+
# Sample.something_else = 1 # => NoMethodError(undefined method `something_else=' for Sample)
|
494
|
+
# @note Values can be written or read prior to the loading of the configuration presuming the configuration can load without error.
|
495
|
+
def method_missing(name, *args, &block)
|
496
|
+
if configured?(name.to_s.split('=').first.to_sym)
|
497
|
+
configured.send(name, *args, &block)
|
498
|
+
else
|
499
|
+
begin
|
500
|
+
super
|
501
|
+
rescue Exception => e
|
502
|
+
# Remove the call to super from the backtrace to make it more apparent where the failure occurred,
|
503
|
+
super_line = Regexp.new("#{__FILE__}:#{__LINE__ - 3}")
|
504
|
+
e.set_backtrace(ActiveSupport::BacktraceCleaner.new.tap { |bc| bc.add_silencer { |line| line =~ super_line } }.clean(e.backtrace))
|
505
|
+
raise e
|
506
|
+
end
|
507
|
+
end
|
508
|
+
end
|
509
|
+
|
510
|
+
# Remove an environmental prefix from the existing list.
|
511
|
+
# @param prefix [Symbol, Object] Prefix to remove.
|
512
|
+
# +nil+ is treated as +self+
|
513
|
+
# Non symbols are converted via {.prefix_from AppConfigFor.prefix_from}.
|
514
|
+
# @param all [Boolean] Remove this prefix throughout the entire inheritance chain.
|
515
|
+
# +USE WITH CAUTION:+ When +true+ this will affect other consumers of AppConfigFor by altering their env prefix values.
|
516
|
+
# @return [Array<Symbol>] Current prefixes (without inheritance)
|
517
|
+
# @see #env_prefixes Current prefixes
|
122
518
|
def remove_env_prefix(prefix, all = false)
|
123
519
|
if all
|
124
520
|
remove_env_prefix(prefix)
|
@@ -126,24 +522,70 @@ module AppConfigFor
|
|
126
522
|
else
|
127
523
|
env_prefixes(false, false).delete(AppConfigFor.prefix_from(prefix))
|
128
524
|
end
|
525
|
+
env_prefixes(all)
|
129
526
|
end
|
130
527
|
|
528
|
+
# Return true if the missing method is a configuration getter or setter.
|
529
|
+
# @see #method_missing Accessing configuration values directly from the extending class/module
|
530
|
+
def respond_to_missing?(name, *args)
|
531
|
+
configured?(name.to_s.split('=').first.to_sym) || super
|
532
|
+
end
|
533
|
+
|
131
534
|
class << self
|
132
535
|
|
536
|
+
# Add an additional environmental prefix to be used when determining current environment.
|
537
|
+
# @param prefix [Symbol, Object] Prefix to add.
|
538
|
+
# Non symbols are converted via {.prefix_from}.
|
539
|
+
# @param at_beginning [Boolean] where to insert the new prefix with respect to existing prefixes.
|
540
|
+
# * +true+ - Add to the beginning of the list.
|
541
|
+
# * +false+ - Add to the end of the list.
|
542
|
+
# @return [Array<Symbol>] Current prefixes (without inheritance)
|
543
|
+
# @see env_prefixes Current prefixes
|
544
|
+
# @note Prefixes added here will affect all consumers of AppConfigFor. For targeted changes see: {#add_env_prefix}
|
133
545
|
def add_env_prefix(prefix, at_beginning = true)
|
134
546
|
env_prefixes(false, false).send(at_beginning ? :unshift : :push, prefix_from(prefix)).uniq!
|
547
|
+
env_prefixes(false)
|
135
548
|
end
|
136
549
|
|
550
|
+
# The name of the current runtime environment. This is value of the first non blank environment variable.
|
551
|
+
# If no value can be found, the default is 'development'.
|
552
|
+
# Prefixes like +:some_app+, +:rails+, and +:rack+ convert to +'SOME_APP_ENV'+, +'RAILS_ENV'+, and +'RACK_ENV'+ respectively.
|
553
|
+
# @param prefixes [Array<#to_s>] List of prefixes of environment variables to check.
|
554
|
+
# @return [String] current runtime environment.
|
555
|
+
# @see env_prefixes Current prefixes
|
137
556
|
def env_name(prefixes = env_prefixes)
|
138
|
-
prefixes.inject(nil) { |current_env, name| current_env || ENV["#{name.to_s.upcase}_ENV"].presence } || 'development'
|
557
|
+
Array(prefixes).inject(nil) { |current_env, name| current_env || ENV["#{name.to_s.upcase}_ENV"].presence } || 'development'
|
139
558
|
end
|
140
559
|
|
141
|
-
|
142
|
-
|
560
|
+
# Prefixes used to determine the environment name.
|
561
|
+
#
|
562
|
+
# A prefix of :some_app will will cause AppConfigFor to react to the environment variable +'SOME_APP_ENV'+
|
563
|
+
# The order of the prefixes will be the order in which AppConfigFor searches the environment variables.
|
564
|
+
#
|
565
|
+
# @param _ Ignored. Unlike {#env_prefixes}, the first parameter is ignored as there is no inheritance at this point.
|
566
|
+
# @param dup[Boolean] Return a duplicate of the internal array to prevent accidental modification.
|
567
|
+
# @return [Array<Symbol>] Defaults to +[:rails, :rack]+
|
568
|
+
# @see env_name Current runtime environment
|
569
|
+
def env_prefixes(_ = true, dup = true)
|
143
570
|
@env_prefixes ||= [:rails, :rack]
|
144
571
|
dup ? @env_prefixes.dup : @env_prefixes
|
145
572
|
end
|
146
573
|
|
574
|
+
# Lexical namespace of an object.
|
575
|
+
# Strings are considered to hold the #name of a Class or Module.
|
576
|
+
# Anything not a String, Class, or Module will return the namespace of the class of the object.
|
577
|
+
# @param object [Module, Class, String, Object]
|
578
|
+
# @return [Module, Class, nil] +nil+ is returned if there is no surrounding namespace.
|
579
|
+
# @example
|
580
|
+
# module Some
|
581
|
+
# class App
|
582
|
+
# end
|
583
|
+
# end
|
584
|
+
#
|
585
|
+
# namespace_of(Some::App) # => Some
|
586
|
+
# namespace_of('Some::App') # => Some
|
587
|
+
# namespace_of(Some::App.new) # => Some
|
588
|
+
# namespace_of(Some) # => nil
|
147
589
|
def namespace_of(object)
|
148
590
|
case object
|
149
591
|
when String
|
@@ -155,11 +597,42 @@ module AppConfigFor
|
|
155
597
|
end.deconstantize.safe_constantize
|
156
598
|
end
|
157
599
|
|
158
|
-
#
|
600
|
+
# Array of all hierarchical lexical namespaces of an object. Uses {.namespace_of}
|
601
|
+
# @param object [Module, Class, String, Object]
|
602
|
+
# @return [Array<Module, Class>]
|
603
|
+
# @example
|
604
|
+
# module Some
|
605
|
+
# class App
|
606
|
+
# class Connection
|
607
|
+
# end
|
608
|
+
# end
|
609
|
+
# end
|
610
|
+
#
|
611
|
+
# namespaces_of(Some::App::Connection) # => [Some::App, Some]
|
612
|
+
# namespaces_of(Some) # => []
|
159
613
|
def namespaces_of(object)
|
160
614
|
(object = [namespace_of(object)]).each { |x| x && object << namespace_of(x) }[0..-2]
|
161
615
|
end
|
162
616
|
|
617
|
+
# Parent of an object.
|
618
|
+
# While similar to inheritance it provides a meaningful value for strings and other objects.
|
619
|
+
# Classes return super classes.
|
620
|
+
# Strings are treated as a name of a class and an attempt is made to locate that class (not the superclass of the named class).
|
621
|
+
# All other objects return the class of the object.
|
622
|
+
# @param object [Class, String, Object]
|
623
|
+
# @return [Class, nil] +nil+ is returned if a string is given that is not the name of a class.
|
624
|
+
# @example
|
625
|
+
# module Some
|
626
|
+
# class Base
|
627
|
+
# end
|
628
|
+
# class App < Base
|
629
|
+
# end
|
630
|
+
# end
|
631
|
+
#
|
632
|
+
# parent_of(Some::App) # => Some::Base
|
633
|
+
# parent_of(Some::App.new) # => Some::App
|
634
|
+
# parent_of('Some::App') # => Some::App
|
635
|
+
# parent_of('wtf') # => nil
|
163
636
|
def parent_of(object)
|
164
637
|
case object
|
165
638
|
when String
|
@@ -171,11 +644,49 @@ module AppConfigFor
|
|
171
644
|
end
|
172
645
|
end
|
173
646
|
|
174
|
-
#
|
647
|
+
# List of all hierarchical parents of an object. Uses {.parents_of}
|
648
|
+
# @param object [Class, String, Object]
|
649
|
+
# @return [Array<Class>]
|
650
|
+
#
|
651
|
+
# @example
|
652
|
+
# module Some
|
653
|
+
# class Base
|
654
|
+
# end
|
655
|
+
# class App < Base
|
656
|
+
# end
|
657
|
+
# end
|
658
|
+
#
|
659
|
+
# parents_of(Some::App) # => [Some::Base, Object, BasicObject]
|
660
|
+
# parents_of(Some::App.new) # => [Some::App, Some::Base, Object, BasicObject]
|
661
|
+
# parents_of('Some::App') # => [Some::App, Some::Base, Object, BasicObject]
|
662
|
+
# parents_of('wtf') # => []
|
175
663
|
def parents_of(object)
|
176
664
|
(object = [parent_of(object)]).each { |x| x && object << parent_of(x) }[0..-2]
|
177
665
|
end
|
178
666
|
|
667
|
+
# Converts an object to a prefix symbol.
|
668
|
+
# Non symbols are converted to underscored symbols with '/' characters changed to underscores.
|
669
|
+
# Conversion by object type is as follows:
|
670
|
+
# * Symbol -> symbol
|
671
|
+
# * Module -> module.name
|
672
|
+
# * Class -> class.name
|
673
|
+
# * String -> string
|
674
|
+
# * Pathname -> pathname.basename (Without an extension)
|
675
|
+
# * other -> other.class.name
|
676
|
+
# @param object [Symbol, Module, Class, String, Pathname, Object] object to convert to a prefix
|
677
|
+
# @return [Symbol]
|
678
|
+
# @example
|
679
|
+
# module Some
|
680
|
+
# class App
|
681
|
+
# end
|
682
|
+
# end
|
683
|
+
#
|
684
|
+
# # All of the following return :some_app
|
685
|
+
# prefix_from(Some::App)
|
686
|
+
# prefix_from('Some::App')
|
687
|
+
# prefix_from(Some::App.new)
|
688
|
+
# prefix_from(:some_app)
|
689
|
+
# prefix_from(Pathname.new('/foo/bar/some_app.yml'))
|
179
690
|
def prefix_from(object)
|
180
691
|
if object.is_a?(Symbol)
|
181
692
|
object
|
@@ -186,26 +697,51 @@ module AppConfigFor
|
|
186
697
|
when String
|
187
698
|
object
|
188
699
|
when Pathname
|
189
|
-
object.basename.to_s
|
700
|
+
object.basename('.*').to_s
|
190
701
|
else
|
191
702
|
object.class.name
|
192
703
|
end.underscore.gsub('/','_').to_sym
|
193
704
|
end
|
194
705
|
end
|
195
706
|
|
707
|
+
# The first env_prefix aware namespace/parent of an object.
|
708
|
+
# Search is dependant on the inheritance style given.
|
709
|
+
# @param object [Object] Object to retrieve the progenitor of.
|
710
|
+
# @param style [#to_s] Type of hierarchical traversal.
|
711
|
+
# @return [Object, nil] +nil+ is returned if there is no progenitor.
|
712
|
+
# @raise InvalidEnvInheritanceStyle - Attempt to use a style that is not one of the {EnvInheritanceStyles}.
|
713
|
+
# @see .verified_style! Valid inheritance styles
|
196
714
|
def progenitor_of(object, style = nil)
|
197
715
|
style = verified_style!(style, object)
|
198
|
-
command = {namespace: :namespace_of, class: :parent_of}[style]
|
716
|
+
command = {namespace: :namespace_of, class: :parent_of}[style.to_s.split('_').first.to_sym]
|
199
717
|
object && command && send(command, object).yield_self { |n| n && (n.respond_to?(:env_prefixes) ? n : progenitor_of(n)) }
|
200
718
|
end
|
201
719
|
|
720
|
+
# Extract the env_prefixes from the progenitor of the given object.
|
721
|
+
# @param object [Object] Object to retrieve the {.progenitor_of} and subsequently the {#env_prefixes}.
|
722
|
+
# @param style [#to_s] Type of hierarchical traversal.
|
723
|
+
# @param all [Boolean] Return inherited prefixes.
|
724
|
+
# If there is no progenitor of the object and all is +true+ then {.env_prefixes AppConfigFor.env_prefixes} will be returned.
|
725
|
+
# @return [Array<Symbol>] Environment prefixes for this object.
|
726
|
+
# @raise InvalidEnvInheritanceStyle - Attempt to use a style that is not one of the {EnvInheritanceStyles}.
|
727
|
+
# @see .env_prefixes Default prefixes
|
728
|
+
# @see .verified_style! Valid inheritance styles
|
202
729
|
def progenitor_prefixes_of(object, style = nil, all = true)
|
203
|
-
Array(progenitor_of(object, style)
|
730
|
+
Array((progenitor_of(object, style) || all && AppConfigFor).try(:env_prefixes, all))
|
204
731
|
end
|
205
732
|
|
206
|
-
|
733
|
+
# List of hierarchical progenitors of an object.
|
734
|
+
# Hierarchical precedence is controlled by the style.
|
735
|
+
# @param object [Object] Object to get the progenitors from
|
736
|
+
# @param style [#to_s] Type of hierarchical traversal.
|
737
|
+
# @param unique [Boolean] Remove duplicate progenitors.
|
738
|
+
# @return [Array<Object>]
|
739
|
+
# @raise InvalidEnvInheritanceStyle - Attempt to use a style that is not one of the {EnvInheritanceStyles}.
|
740
|
+
# @see progenitor_of Progenitor of an object
|
741
|
+
# @see .verified_style! Valid inheritance styles
|
742
|
+
def progenitors_of(object, style = nil, unique = true)
|
207
743
|
style = verified_style!(style, object)
|
208
|
-
|
744
|
+
unique = unique && style != :none
|
209
745
|
if object && style != :none
|
210
746
|
styles = style.to_s.split('_')
|
211
747
|
if styles.size > 1
|
@@ -215,19 +751,59 @@ module AppConfigFor
|
|
215
751
|
end
|
216
752
|
else
|
217
753
|
[]
|
218
|
-
end.yield_self { |result|
|
754
|
+
end.yield_self { |result| unique ? result.reverse.uniq.reverse + [self] : result }
|
219
755
|
end
|
220
756
|
|
221
|
-
|
222
|
-
|
757
|
+
# Remove an environmental prefix from the existing list.
|
758
|
+
# @param prefix [Symbol, Object] Prefix to remove.
|
759
|
+
# Non symbols are converted via {.prefix_from AppConfigFor.prefix_from}.
|
760
|
+
# @param _ Ignored. Unlike {#remove_env_prefix}, the first parameter is ignored as there is no inheritance at this point.
|
761
|
+
# @return [Array<Symbol>] Current prefixes (without inheritance)
|
762
|
+
# @note Prefixes removed here will affect all consumers of AppConfigFor. For targeted changes see: {#remove_env_prefix}
|
763
|
+
def remove_env_prefix(prefix, _ = false)
|
764
|
+
env_prefixes(false, false).delete(prefix_from(prefix))
|
765
|
+
env_prefixes(false)
|
223
766
|
end
|
224
767
|
|
225
|
-
|
226
|
-
|
768
|
+
# Verifies the inheritance style. If style is nil, the object, if given, will be queried for its env_inheritance.
|
769
|
+
# Otherwise the style will default to +:namespace:+
|
770
|
+
# @param style [#to_s] Inheritance style to verify.
|
771
|
+
# @param object [Object] Object to query for env_inheritance if style is nil.
|
772
|
+
# return [Symbol] A valid inheritance style.
|
773
|
+
# @raise InvalidEnvInheritanceStyle - An invalid inheritance style was received.
|
774
|
+
def verified_style!(style = nil, object = nil)
|
775
|
+
style ||= object.respond_to?(:env_inheritance) && object.env_inheritance || :namespace
|
227
776
|
style = style.try(:to_sym) || style.to_s.to_sym
|
228
|
-
|
777
|
+
EnvInheritanceStyles.include?(style) ? style : raise(InvalidEnvInheritanceStyle.new(style))
|
229
778
|
end
|
230
779
|
|
780
|
+
# Determine the name of the yml file from the object given. No pathing is assumed.
|
781
|
+
# Anything not a Pathname is converted to an underscored string with '/' characters changed to underscores and a '.yml' extension
|
782
|
+
# @param object [Object] Object to determine a yml name from.
|
783
|
+
#
|
784
|
+
# Determination by object type is as follows:
|
785
|
+
# * Pathname -> pathname
|
786
|
+
# * Module -> module.name
|
787
|
+
# * Class -> class.name
|
788
|
+
# * String -> string
|
789
|
+
# * Symbol -> symbol.to_s
|
790
|
+
# * other -> other.class.name
|
791
|
+
# @return [String, Pathname]
|
792
|
+
# @example
|
793
|
+
# module Some
|
794
|
+
# class App
|
795
|
+
# end
|
796
|
+
# end
|
797
|
+
#
|
798
|
+
# # All of the following return 'some_app.yml'
|
799
|
+
# yml_name_from(Some::App)
|
800
|
+
# yml_name_from(Some::App.new)
|
801
|
+
# yml_name_from(:some_app)
|
802
|
+
# yml_name_from('Some/App')
|
803
|
+
# yml_name_from('Some::App')
|
804
|
+
#
|
805
|
+
# # Pathnames receive no conversion
|
806
|
+
# yml_name_from(Pathname.new('not/a/yml_file.txt')) # => #<Pathname:not/a/yml_file.txt>
|
231
807
|
def yml_name_from(object)
|
232
808
|
if object.is_a?(Pathname)
|
233
809
|
object
|
@@ -235,7 +811,9 @@ module AppConfigFor
|
|
235
811
|
case object
|
236
812
|
when Module
|
237
813
|
object.name
|
238
|
-
when String
|
814
|
+
when String
|
815
|
+
object
|
816
|
+
when Symbol
|
239
817
|
object.to_s
|
240
818
|
else
|
241
819
|
object.class.name
|
@@ -245,8 +823,8 @@ module AppConfigFor
|
|
245
823
|
|
246
824
|
private
|
247
825
|
|
248
|
-
|
249
|
-
|
826
|
+
# Add the config directory from the gem installation if this is a gem.
|
827
|
+
def add_gem_directory(base)
|
250
828
|
gem = Gem.loaded_specs[base.name.underscore]
|
251
829
|
base.add_config_directory(gem.gem_dir + '/config') if gem
|
252
830
|
end
|
@@ -254,14 +832,13 @@ module AppConfigFor
|
|
254
832
|
def extended(base)
|
255
833
|
# Todo: Add the ability to check the default environments directly from base if the methods don't yet exist.
|
256
834
|
# ie: base.development? is the same as base.env.development?
|
257
|
-
|
835
|
+
add_gem_directory(base)
|
258
836
|
end
|
259
837
|
|
260
838
|
def included(base)
|
261
|
-
|
839
|
+
add_gem_directory(base)
|
262
840
|
end
|
263
841
|
|
264
842
|
end
|
265
843
|
|
266
|
-
end
|
267
|
-
|
844
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: app_config_for
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Frank Hall
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-04-
|
11
|
+
date: 2022-04-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -87,8 +87,8 @@ licenses:
|
|
87
87
|
- MIT
|
88
88
|
metadata:
|
89
89
|
homepage_uri: https://github.com/ChapterHouse/app_config_for
|
90
|
-
source_code_uri: https://github.com/ChapterHouse/app_config_for/tree/v0.0.
|
91
|
-
changelog_uri: https://github.com/ChapterHouse/app_config_for/blob/v0.0.
|
90
|
+
source_code_uri: https://github.com/ChapterHouse/app_config_for/tree/v0.0.6.1
|
91
|
+
changelog_uri: https://github.com/ChapterHouse/app_config_for/blob/v0.0.6.1/CHANGELOG.md
|
92
92
|
post_install_message:
|
93
93
|
rdoc_options: []
|
94
94
|
require_paths:
|