app_config_loader 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1f6fcbc8cf8afaf0cf827cdfbd109435935adb52
4
- data.tar.gz: 1cfe704eb579fb86e97e7c99ac44555a28ddf490
3
+ metadata.gz: 1e592723d0d4dc4f9f4640900c9898bb83fd4c35
4
+ data.tar.gz: c2b0ffc59d4e620846cab0c9f38a245e34460ec7
5
5
  SHA512:
6
- metadata.gz: d840c314529c38da7df35390e6dcfd666b5c748ff9a390c289caf6702080bd8f147da30199071ff69fe621400f48a5cbbc2baa7d6d8474abaf22ae1b7a714c31
7
- data.tar.gz: 1191bd4b2b0c7e4668349260c5d571090b2d8cacdac03d38ce2257f8ceba83f7370f7863d0477ad1245bb7400420da0aefeaa36cd056d206b8dd44d3a25ec8b2
6
+ metadata.gz: 8478ba6318c4ff97a6c47f8e04358d26086f07f88db2e2a5fc00b69f96aada7fadf6d391d97a6aa84ea1dfe6eefb2eb2dcc9561bedd9caed34f3f2070fff2db9
7
+ data.tar.gz: 528e97b31426dd3aa76a782a0d19945763c826c5d861e1015bd053bc25460b019e7f26ac6c21cfede5a839fa188d865c3eba223758c7f111ac3a74f25ef548f8
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## [v1.0.3](https://github.com/lscspirit/app_config_loader/tree/v1.0.3) (2017-04-23)
4
+ [Full list of commits](https://github.com/lscspirit/app_config_loader/compare/v1.0.2...v1.0.3)
5
+
6
+ - Auto-initialization through Railtie in Rails
7
+ - Make ConfigEntry comparable
8
+ - Make ConfigMap and ConfigWithIndifferentAccess enumerable.
9
+
3
10
  ## [v1.0.2](https://github.com/lscspirit/app_config_loader/tree/v1.0.2) (2017-04-23)
4
11
  [Full list of commits](https://github.com/lscspirit/app_config_loader/compare/v1.0.1...v1.0.2)
5
12
 
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # AppConfigLoader
2
2
 
3
- A easy way to define application configurations using YAML in your Rails environment.
3
+ A customizable YAML configuration library for Rails and Ruby, featuring wildcards, nesting, namespacing and local override.
4
4
 
5
5
  ## Getting Started
6
6
 
@@ -24,15 +24,6 @@ Create a YAML file in the default directory `config/app_configs` to put your app
24
24
  'host': prod.someservice.com
25
25
  ```
26
26
 
27
- Create an initializer `config/initializers/00_app_config.rb` to configure and initialize AppConfigLoader. Typically, you would want AppConfigLoader to be the first thing to be initialized so that you can access your app config values in the remaining Rails initialization process. This is why the initializer filename has the '00_' prefix.
28
-
29
-
30
- ```ruby
31
- # config/initializers/00_app_config.rb
32
-
33
- APP_CONFIG = AppConfigLoader.load
34
- ```
35
-
36
27
  From this point onward, you can access your app config values through `APP_CONFIG`.
37
28
 
38
29
  ```ruby
@@ -43,25 +34,36 @@ APP_CONFIG['some_service.host'] # => 'dev.someservice.com'
43
34
  APP_CONFIG['some_service.host'] # => 'prod.someservice.com'
44
35
  ```
45
36
 
37
+ ### Non-Rails Environment
38
+
39
+ When using `AppConfigLoader` outside of Rails, getting started is a little different:
40
+
41
+ * the default app config file directory is `<pwd>/app_configs`
42
+ * you need to manually initialize `AppConfigLoader` by including the following early on in your code:
43
+ ```ruby
44
+ AppConfigLoader.init
45
+ ```
46
+
46
47
  ## Configuration
47
48
 
48
49
  You can configure where and how AppConfigLoader load your app config file(s).
49
50
 
50
51
  ```ruby
51
- APP_CONFIG = AppConfigLoader.load do |config|
52
+ AppConfigLoader.configure do |config|
52
53
  config.use_domain = true
53
54
  config.domain = 'us'
54
55
  config.config_paths << '/path/to/additional_config.yml'
55
56
  end
56
57
  ```
57
58
 
58
- Below is a list of all the settings available:
59
+ Below is a list of all options available:
59
60
 
60
- * `config.env` - (String) app config environment. This determines which set of app config values to load. **Default:** `Rails.env`.
61
- * `config.use_domain` - (Boolean) whether the app config key uses a domain. **Default:** `false`.
61
+ * `config.const_name` - (String) the name of the constant to which the config object is assigned. **Default:** `APP_CONFIG`
62
+ * `config.env` - (String) app config environment. This determines which set of app config values to load. **Default:** Rails - `Rails.env`, non-Rails - `ENV['RACK_ENV'] || ENV['RUBY_ENV']`
63
+ * `config.use_domain` - (Boolean) whether the app config key uses a domain. **Default:** `false`
62
64
  * `config.domain` - (String) app config domain. This determines which set of app config values to load. It is only applicable if `use_domain` is set to true. **Default:** `nil`
63
- * `config.config_paths` - (Array&lt;String&gt;) a list of paths from where app config YAML files should be loaded. Path can either be a file or a directory. With a directory path, all YAML files within that directory will be loaded. **Default:** `['<rails root>/config/app_configs']`.
64
- * `config.local_overrides` - (String) path to a local overrides app config file. Entries in this file take precedence over all values from other files. **Default:** `<rails root>/config/app_configs/local_overrides.yml`.
65
+ * `config.config_paths` - (Array&lt;String&gt;) a list of paths from where app config YAML files should be loaded. Path can either be a file or a directory. With a directory path, all YAML files within that directory will be loaded. **Default:** Rails - `['<rails root>/config/app_configs']`, non-Rails - `['<pwd>/app_configs']`
66
+ * `config.local_overrides` - (String) path to a local overrides app config file. Entries in this file take precedence over all values from other files. **Default:** Rails - `<rails root>/config/app_configs/local_overrides.yml`, non-Rails - `<pwd>/app_configs/local_overrides.yml`
65
67
 
66
68
  ## Defining your App Configs
67
69
 
@@ -72,7 +74,7 @@ All app configs are defined as key-value entries in YAML format. A app config va
72
74
 
73
75
  #### Basic Example
74
76
 
75
- ```ruby
77
+ ```YAML
76
78
  # app config in YAML file
77
79
  'test.timeout': 3000
78
80
  'test.some_service.host': 'dev.someservice.com'
@@ -80,20 +82,27 @@ All app configs are defined as key-value entries in YAML format. A app config va
80
82
  'production.timeout': 500
81
83
  'production.some_service.host': 'prod.someservice.com'
82
84
  'production.some_service.port': 8000
85
+ ```
83
86
 
84
- # In Rails
85
- APP_CONFIG = AppConfigLoader.load do |config|
87
+ ```ruby
88
+ # Rails initialization
89
+ AppConfigLoader.configure do |config|
86
90
  config.env = 'test'
87
91
  end
88
92
 
93
+ # after AppConfigLoader is initialized
89
94
  APP_CONFIG['timeout'] # => 3000
90
95
  APP_CONFIG['some_service.host'] # => dev.someservice.com
91
96
  APP_CONFIG['some_service.port'] # => nil
97
+ ```
92
98
 
93
- APP_CONFIG = AppConfigLoader.load do |config|
99
+ ```ruby
100
+ # Rails initialization
101
+ AppConfigLoader.configure do |config|
94
102
  config.env = 'production'
95
103
  end
96
104
 
105
+ # after AppConfigLoader is initialized
97
106
  APP_CONFIG['timeout'] # => 500
98
107
  APP_CONFIG['some_service.host'] # => prod.someservice.com
99
108
  APP_CONFIG['some_service.port'] # => 8000
@@ -101,38 +110,45 @@ APP_CONFIG['some_service.port'] # => 8000
101
110
 
102
111
  #### Nested Definition
103
112
 
104
- ```ruby
113
+ ```YAML
105
114
  'production.some_service':
106
115
  'host': 'prod.someservice.com'
107
116
  'port': 8000
108
-
109
- # In Rails
117
+ ```
118
+ ```ruby
110
119
  APP_CONFIG['some_service.host'] # => prod.someservice.com
111
120
  APP_CONFIG['some_service.port'] # => 8000
112
121
  ```
113
122
 
114
- #### Using Domain in Key
123
+ #### Namespacing with Domain
115
124
 
116
- ```ruby
125
+ You may use `domain` to group your configuration. For example, you can provide different configuration when running in different regions.
126
+
127
+ ```YAML
117
128
  # app config in YAML file
118
129
  'production.us.some_service.host': 'prod.someservice.com'
119
130
  'production.hk.some_service.host': 'prod.someservice.com.hk'
120
-
121
- # In Rails
122
- APP_CONFIG = AppConfigLoader.load do |config|
131
+ ```
132
+ ```ruby
133
+ # Rails initialization
134
+ AppConfigLoader.configure do |config|
123
135
  config.env = 'production'
124
136
  config.use_domain = true
125
137
  config.domain = 'us'
126
138
  end
127
139
 
140
+ # after AppConfigLoader is initialized
128
141
  APP_CONFIG['some_service.host'] # => prod.someservice.com
129
-
130
- APP_CONFIG = AppConfigLoader.load do |config|
142
+ ```
143
+ ```ruby
144
+ # Rails initialization
145
+ AppConfigLoader.configure do |config|
131
146
  config.env = 'production'
132
147
  config.use_domain = true
133
148
  config.domain = 'hk'
134
149
  end
135
150
 
151
+ # after AppConfigLoader is initialized
136
152
  APP_CONFIG['some_service.host'] # => prod.someservice.com.hk
137
153
  ```
138
154
 
@@ -140,22 +156,27 @@ APP_CONFIG['some_service.host'] # => prod.someservice.com.hk
140
156
 
141
157
  You may use the wildcard `*` in place of the env and the domain. This allows you to specify app config entry that is applicable in any env or domain. An app config entry with a specific env or domain always takes precedence over ones with wildcard of the same key.
142
158
 
143
- ```ruby
159
+ ```YAML
144
160
  # app config in YAML file
145
161
  '*.some_service.host': 'dev.someservice.com'
146
162
  'production.some_service.host': 'prod.someservice.com'
147
-
148
- # In Rails
149
- APP_CONFIG = AppConfigLoader.load do |config|
163
+ ```
164
+ ```ruby
165
+ # Rails initialization
166
+ AppConfigLoader.configure do |config|
150
167
  config.env = 'test'
151
168
  end
152
169
 
170
+ # after AppConfigLoader is initialized
153
171
  APP_CONFIG['some_service.host'] # => dev.someservice.com
154
-
155
- APP_CONFIG = AppConfigLoader.load do |config|
172
+ ```
173
+ ```ruby
174
+ # Rails initialization
175
+ AppConfigLoader.configure do |config|
156
176
  config.env = 'production'
157
177
  end
158
178
 
179
+ # after AppConfigLoader is initialized
159
180
  APP_CONFIG['some_service.host'] # => prod.someservice.com
160
181
  ```
161
182
 
@@ -170,6 +191,31 @@ When there a multiple app config entries for the same key, the final value is re
170
191
  '*.*.some_service.host': 'prod.someservice.com' # lowest specificity
171
192
  ```
172
193
 
194
+ ### Key Conflict
195
+
196
+ In most cases, entries belonging to or falling under the same key can be resolved by specificity. However, there are cases when the entries' values
197
+ conflict with each other and a `ConfigKeyConflict` error will be raises.
198
+
199
+ * Assigning value to key with children
200
+
201
+ ```YAML
202
+ *.key_with_children.child_1: 'child1'
203
+ *.key_with_children.child_2: 'child2'
204
+ production.key_with_children: 'some value'
205
+
206
+ ```
207
+ The config above will raise `ConfigKeyConflict` error, regardless of the different in specificity.
208
+
209
+ * Assigning children to key with value
210
+
211
+ ```YAML
212
+ production.key_with_value: 'some value'
213
+ *.key_with_value.child_1: 'child1'
214
+
215
+ ```
216
+ The config above will raise `ConfigKeyConflict` error, regardless of the different in specificity.
217
+
218
+
173
219
  ## Local Overrides File
174
220
 
175
221
  The local overrides file provides a quick way to override any entries defined in regular app config files. Entries within this file are resolved according to the specificity rule. Once resolved, the resolved entries will override any existing entries regardless of specificity. This is meant for development or testing purposes. Typically, you would not want to check this file into your source repository.
@@ -9,8 +9,8 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["Derrick Yeung"]
10
10
  spec.email = ["lscspirit@hotmail.com"]
11
11
 
12
- spec.summary = %q{Application configuration using YAML}
13
- spec.description = %q{A easy way to define application configurations using YAML in your Rails environment.}
12
+ spec.summary = %q{Customizable YAML app config library}
13
+ spec.description = %q{A customizable YAML configuration library for Rails and Ruby, featuring wildcards, nesting, namespacing and local override.}
14
14
  spec.homepage = 'https://github.com/lscspirit/app_config_loader'
15
15
  spec.license = "MIT"
16
16
 
@@ -6,24 +6,50 @@ require 'app_config_loader/config_entry'
6
6
  require 'app_config_loader/config_map'
7
7
  require 'app_config_loader/config_with_indifferent_access'
8
8
 
9
+ require 'app_config_loader/railtie' if defined?(Rails)
10
+
9
11
  module AppConfigLoader
10
- def self.load(config = nil)
11
- raise ArgumentError, 'config must be a AppConfigLoader::Config instance' unless config.nil? || config.is_a?(AppConfigLoader::Config)
12
+ #
13
+ # Config
14
+ #
12
15
 
13
- active_cfg = config || default_config
16
+ def self.configure
17
+ yield self.config if block_given?
18
+ end
14
19
 
15
- yield active_cfg if block_given?
20
+ def self.init
21
+ cfg = self.config
16
22
 
17
- Loader.new(active_cfg).load
23
+ raise NameError, "cannot assign app config because '#{cfg.const_name}' is already defined" if Object.const_defined?(cfg.const_name)
24
+ Object.const_set cfg.const_name, self.load(cfg)
25
+ end
26
+
27
+ def self.load(config = nil)
28
+ raise ArgumentError, 'config must be a AppConfigLoader::Config instance' unless config.nil? || config.is_a?(AppConfigLoader::Config)
29
+ Loader.new(config || self.config).load
18
30
  end
19
31
 
20
32
  private
21
33
 
34
+ def self.config
35
+ @config ||= self.default_config
36
+ end
37
+
22
38
  def self.default_config
23
39
  cfg = AppConfigLoader::Config.new
24
- cfg.env = defined?(Rails) ? Rails.env : 'development'
25
- cfg.config_paths << (defined?(Rails) ? Rails.root.join('config', 'app_configs') : File.join(__dir__, 'app_configs'))
26
- cfg.local_overrides = defined? (Rails) ? Rails.root.join('config', 'app_configs', 'local_overrides.yml') : File.join(__dir__, 'config', 'local_overrides.yml')
40
+
41
+ cfg.const_name = 'APP_CONFIG'
42
+
43
+ if defined?(Rails)
44
+ cfg.env = Rails.env || ENV['RACK_ENV'] || ENV['RUBY_ENV'] || 'development'
45
+ cfg.config_paths << Rails.root.join('config', 'app_configs')
46
+ cfg.local_overrides = Rails.root.join('config', 'app_configs', 'local_overrides.yml')
47
+ else
48
+ cfg.env = ENV['RACK_ENV'] || ENV['RUBY_ENV'] || 'development'
49
+ cfg.config_paths << File.join(Dir.pwd, 'app_configs')
50
+ cfg.local_overrides = File.join(Dir.pwd, 'config', 'local_overrides.yml')
51
+ end
52
+
27
53
  cfg
28
54
  end
29
55
  end
@@ -1,6 +1,6 @@
1
1
  module AppConfigLoader
2
2
  class Config
3
- attr_accessor :env, :domain, :local_overrides
3
+ attr_accessor :const_name, :env, :domain, :local_overrides
4
4
 
5
5
  def config_paths
6
6
  @config_paths ||= []
@@ -1,12 +1,15 @@
1
1
  module AppConfigLoader
2
2
  class ConfigEntry
3
+ include Comparable
4
+
3
5
  attr_reader :env, :domain, :key_components, :value
4
6
 
5
7
  #
6
8
  # Constructor
7
9
  #
8
10
  def initialize(full_key, value, use_domain = false)
9
- @env, @domain, @key_components = parse_full_key full_key, use_domain
11
+ @use_domain = use_domain
12
+ @env, @domain, @key_components = parse_full_key full_key
10
13
  @value = value
11
14
  end
12
15
 
@@ -14,10 +17,23 @@ module AppConfigLoader
14
17
  # Accessor
15
18
  #
16
19
 
20
+ # Config key without env and domain
21
+ #
22
+ # @return [String] config key without the env and domain
17
23
  def key
18
24
  @key_components.join('.')
19
25
  end
20
26
 
27
+ # Config key including env and domain
28
+ # The domain portion is included if +config.use_domain+ is +true+
29
+ #
30
+ # @return [String] config key including the env and domain
31
+ def full_key
32
+ prefix = @env == :any ? '*.' : "#{@env}."
33
+ prefix += @domain == :any ? '*.' : "#{@domain}." if @use_domain
34
+ "#{prefix}#{self.key}"
35
+ end
36
+
21
37
  def specificity
22
38
  score = 0
23
39
  score += 1 if @env != :any # add one point if env is specified
@@ -35,27 +51,59 @@ module AppConfigLoader
35
51
  true
36
52
  end
37
53
 
38
- def ==(o)
39
- o.class == self.class &&
40
- o.env == self.env &&
41
- o.domain == self.domain &&
42
- o.key_components == self.key_components &&
43
- o.value == self.value
54
+ def to_s
55
+ "#{self.full_key}: #{self.value}"
56
+ end
57
+
58
+ #
59
+ # Comparison
60
+ #
61
+
62
+ def ==(other)
63
+ other.class == self.class &&
64
+ other.env == self.env &&
65
+ other.domain == self.domain &&
66
+ other.key_components == self.key_components &&
67
+ other.value == self.value
44
68
  end
45
69
  alias_method :eql?, :==
46
70
 
71
+ def <=>(other)
72
+ # first compare key size
73
+ comp = self.key_components.count <=> other.key_components.count
74
+ return comp if comp != 0
75
+
76
+ # lexically compare the actual key components
77
+ other_keys = other.key_components
78
+ self.key_components.each_with_index do |key, index|
79
+ comp = key <=> other_keys[index]
80
+ return comp if comp != 0
81
+ end
82
+
83
+ # compare specificity
84
+ comp = self.specificity <=> other.specificity
85
+ return comp if comp != 0
86
+
87
+ # compare env
88
+ comp = wildcard_compare self.env, other.env
89
+ return comp if comp != 0
90
+
91
+ # compare domain
92
+ wildcard_compare self.domain, other.domain
93
+ end
94
+
47
95
  private
48
96
 
49
- def parse_full_key(full_key, use_domain)
97
+ def parse_full_key(full_key)
50
98
  key_ary = full_key.split('.')
51
99
 
52
100
  raise InvalidConfigKey, "invalid config key '#{full_key}': must have a env component" unless key_ary.length > 1
53
- raise InvalidConfigKey, "invalid config key '#{full_key}': must have a domain component when 'use_domain' is enabled" unless !use_domain || key_ary.length > 2
101
+ raise InvalidConfigKey, "invalid config key '#{full_key}': must have a domain component when 'use_domain' is enabled" unless !@use_domain || key_ary.length > 2
54
102
 
55
103
  begin
56
104
  env = normalize_key_component key_ary[0], true
57
- domain = use_domain ? normalize_key_component(key_ary[1], true) : :any
58
- components = (use_domain ? key_ary[2..-1] : key_ary[1..-1]).map{ |k| normalize_key_component k }
105
+ domain = @use_domain ? normalize_key_component(key_ary[1], true) : :any
106
+ components = (@use_domain ? key_ary[2..-1] : key_ary[1..-1]).map{ |k| normalize_key_component k }
59
107
  rescue => ex
60
108
  raise InvalidConfigKey, "invalid config key component in '#{full_key}': #{ex.message}"
61
109
  end
@@ -71,5 +119,15 @@ module AppConfigLoader
71
119
  comp.to_s
72
120
  end
73
121
  end
122
+
123
+ def wildcard_compare(target, other)
124
+ if (diff = target <=> other) # comparing a symbol with string returns nil
125
+ diff
126
+ elsif target == :any
127
+ -1
128
+ else
129
+ 1
130
+ end
131
+ end
74
132
  end
75
133
  end
@@ -1,5 +1,7 @@
1
1
  module AppConfigLoader
2
2
  class ConfigMap
3
+ include Enumerable
4
+
3
5
  def initialize
4
6
  @key_map = {}
5
7
  end
@@ -38,6 +40,10 @@ module AppConfigLoader
38
40
  config_map.to_a.each { |override| self.add override, true }
39
41
  end
40
42
 
43
+ def each(&block)
44
+ self.to_a.each(&block)
45
+ end
46
+
41
47
  private
42
48
 
43
49
  def deep_add(parent, keys, &block)
@@ -1,5 +1,7 @@
1
1
  module AppConfigLoader
2
2
  class ConfigWithIndifferentAccess
3
+ include Enumerable
4
+
3
5
  def initialize(map, prefix = nil)
4
6
  @config_map = map
5
7
  @prefix = prefix
@@ -21,5 +23,13 @@ module AppConfigLoader
21
23
  end
22
24
  end
23
25
  alias_method :[], :get
26
+
27
+ def to_a
28
+ @config_map.to_a
29
+ end
30
+
31
+ def each(&block)
32
+ @config_map.each(&block)
33
+ end
24
34
  end
25
35
  end
@@ -0,0 +1,8 @@
1
+ module AppConfigLoader
2
+ class Railtie < Rails::Railtie
3
+ config.before_initialize do
4
+ # initialize the app config before Rails initialization
5
+ AppConfigLoader.init
6
+ end
7
+ end
8
+ end
@@ -1,3 +1,3 @@
1
1
  module AppConfigLoader
2
- VERSION = '1.0.2'
2
+ VERSION = '1.0.3'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: app_config_loader
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Derrick Yeung
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-04-22 00:00:00.000000000 Z
11
+ date: 2017-04-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -66,8 +66,8 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
- description: A easy way to define application configurations using YAML in your Rails
70
- environment.
69
+ description: A customizable YAML configuration library for Rails and Ruby, featuring
70
+ wildcards, nesting, namespacing and local override.
71
71
  email:
72
72
  - lscspirit@hotmail.com
73
73
  executables: []
@@ -90,6 +90,7 @@ files:
90
90
  - lib/app_config_loader/errors.rb
91
91
  - lib/app_config_loader/loader.rb
92
92
  - lib/app_config_loader/parser.rb
93
+ - lib/app_config_loader/railtie.rb
93
94
  - lib/app_config_loader/version.rb
94
95
  homepage: https://github.com/lscspirit/app_config_loader
95
96
  licenses:
@@ -114,5 +115,5 @@ rubyforge_project:
114
115
  rubygems_version: 2.5.1
115
116
  signing_key:
116
117
  specification_version: 4
117
- summary: Application configuration using YAML
118
+ summary: Customizable YAML app config library
118
119
  test_files: []