consul_application_settings 0.1.4 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8abc7a1661131160a981373791ccc8ac3a48323283803b32f04a866ae33d3cd2
4
- data.tar.gz: f6c70feae5652f55c564a98df789518efe4e3980ded79c09f51c7429811444b6
3
+ metadata.gz: b20ecf9e1eb2ea05e41f729b69082093305d3ce5291d8fb45a64f185ba8ae44f
4
+ data.tar.gz: ce5d16eb80ae0a9c0be78dda05d06e350546328d737ae1dd65309120f17fa814
5
5
  SHA512:
6
- metadata.gz: 20fd00d62bbb2c98fcb4566fe505d67b208190c6bf7b5240520c410d11822252caad6b5574d08a7603f0c5400d75dc80d4b566c1524bd8181ae912fb5d6d3d48
7
- data.tar.gz: a0d0d0ed7fbdb672bb4252558875d01638d78fb4a92c5179f661192fc4125db47800aff3c6b27b1a185f85cde38c356f096fc6ee1ee09b1c05f24c8718dd6abe
6
+ metadata.gz: eac2795525ed07225d749c836781c5f9bebdfcaa55a8490d4cdca4ce2463db3130cd94e081cd87bd808743d7d1acf29729ccb5002000d5efc79a76b87a57bc0a
7
+ data.tar.gz: ed28b56badd89cbf5097ac4d061eadd43e7aa1da37aefec1693d5b17b4bb78996e9cc8c9f4b38564b6c0383ea77ac65f89c8b66bb4e7ba4af8c7e8c7820dc2d7
data/Gemfile.lock CHANGED
@@ -24,7 +24,7 @@ GEM
24
24
  ast (~> 2.4.0)
25
25
  psych (3.1.0)
26
26
  rainbow (3.0.0)
27
- rake (10.5.0)
27
+ rake (13.0.1)
28
28
  rspec (3.8.0)
29
29
  rspec-core (~> 3.8.0)
30
30
  rspec-expectations (~> 3.8.0)
@@ -62,7 +62,7 @@ PLATFORMS
62
62
  DEPENDENCIES
63
63
  bundler (~> 2.0)
64
64
  consul_application_settings!
65
- rake (~> 10.0)
65
+ rake (~> 13.0)
66
66
  rspec (~> 3.0)
67
67
  rubocop (~> 0.66)
68
68
  rubocop-rspec (~> 1.32.0)
data/README.md CHANGED
@@ -23,7 +23,7 @@ Example use cases:
23
23
 
24
24
  Gem reads any particular setting from consul and if it is missing tries to find value in YAML defaults file
25
25
 
26
- **NOTE** Consul is requested every time you query the settings. Defaults YAML file loaded in memory and not changing.
26
+ **NOTE** Consul is requested every time you query the settings. Defaults YAML file is loaded in memory and is not changing.
27
27
 
28
28
  ## Installation
29
29
 
@@ -40,13 +40,17 @@ gem 'consul_application_settings'
40
40
  At the load of application:
41
41
  ```ruby
42
42
  ConsulApplicationSettings.configure do |config|
43
- # Specify path to defaults file
44
- config.defaults = Rails.root.join('config/settings.yml')
45
- # Specify namespace to consul settings
46
- config.namespace = 'staging/my_cool_app'
43
+ # Specify path to the base settings YML. Default: 'config/application_settings.yml'
44
+ config.base_file_path = Rails.root.join('config/my_settings.yml')
45
+ # Specify path to the local settings YML, which overrides the base file. Default: 'config/application_settings.local.yml'
46
+ config.local_file_path = Rails.root.join('config/my_settings.local.yml')
47
+ # Specify whether exceprion should be thrown on Consul connection errors. Default: false
48
+ config.disable_consul_connection_errors = true
47
49
  end
48
50
 
49
51
  APP_SETTINGS = ConsulApplicationSettings.load
52
+ # Specify path to settings both in YML files and Consul
53
+ AUTH_SETTIGNS = ConsulApplicationSettings.load('authentication')
50
54
  ```
51
55
 
52
56
  **NOTE** For rails you can add this code to custom initializer `console_application_settings.rb` in `app/config/initializers`
@@ -55,7 +59,7 @@ APP_SETTINGS = ConsulApplicationSettings.load
55
59
 
56
60
  ### Settings structure
57
61
 
58
- Assuming your defaults file in repository `config/settings.yml` looks like:
62
+ Assuming your defaults file in repository `config/application_settings.yml` looks like:
59
63
  ```yaml
60
64
  staging:
61
65
  my_cool_app:
@@ -98,15 +102,13 @@ Anywhere in your code base, after initialization, you can use
98
102
  previously loaded settings to query any key by full path
99
103
 
100
104
  ```ruby
101
- APP_SETTINGS.app_name # "MyCoolApp"
105
+ APP_SETTINGS['app_name'] # "MyCoolApp"
102
106
  APP_SETTINGS.get(:hostname) # "https://mycoolapp.com"
103
107
 
104
108
  APP_SETTINGS.get('integrations/database/user') # "app"
105
109
  APP_SETTINGS['integrations/slack/enabled'] # true
106
110
  ```
107
111
 
108
- **NOTE** Gem is pulling settings from consul with namespace but ignores namespace for defaults
109
-
110
112
  ### Nested settings
111
113
 
112
114
  Assuming some part of your code needs to work with smaller part of settings -
@@ -114,36 +116,30 @@ gem provides interface to avoid duplicating absolute path
114
116
 
115
117
  ```ruby
116
118
  # You can load subsettings from root object
117
- db_settings = APP_SETTINGS.load_from('integrations/database')
118
- db_settings.domain # "194.78.92.19"
119
- db_settings['user'] # "app"
120
-
121
- # You can load subsettings from subsettings
122
- integrations_settings = APP_SETTINGS.load_from('integrations')
123
- slack_settings = integrations_settings.load_from('slack')
124
- slack_settings.enabled # true
125
- slack_settings.get('webhook_url') # "https://hooks.slack.com/services/XXXXXX/XXXXX/XXXXXXX"
119
+ db_settings = APP_SETTINGS.load('integrations/database')
120
+ db_settings.get(:domain) # "194.78.92.19"
121
+ db_settings['user'] # "app"
126
122
  ```
127
123
 
128
124
  ### Gem Configuration
129
125
  You can configure gem with block:
130
126
  ```ruby
131
127
  ConsulApplicationSettings.configure do |config|
132
- config.namespace = 'staging/my_cool_app'
128
+ config.local_file_path = 'config/config.yml'
133
129
  end
134
130
  ```
135
131
  or one option at a time
136
132
  ```ruby
137
- ConsulApplicationSettings.config.namespace = 'staging/my_cool_app'
133
+ ConsulApplicationSettings.config.local_file_path = 'config/config.yml'
138
134
  ```
139
135
 
140
136
  All Gem configurations
141
137
 
142
- | Configuration | Required | Default | Type | Description |
143
- |----------------------------------|----------|---------|---------|------------------------------------------------------------------------------|
144
- | defaults | yes | | String | Path to the file with default settings |
145
- | namespace | no | | String | Base path to read settings from in consul and defaults |
146
- | disable_consul_connection_errors | no | false | Boolean | Do not raise exception when consul is not available (useful for development) |
138
+ | Configuration | Required | Default | Type | Description |
139
+ |----------------------------------|----------|-----------------------------------------|---------|------------------------------------------------------------------------------|
140
+ | base_file_path | no | 'config/application_settings.yml' | String | Path to the file with base settings |
141
+ | local_file_path | no | 'config/application_settings.local.yml' | String | Path to the file with local settings overriding the base settings |
142
+ | disable_consul_connection_errors | no | true | Boolean | Do not raise exception when consul is not available (useful for development) |
147
143
 
148
144
  ## Development
149
145
 
@@ -32,7 +32,7 @@ Gem::Specification.new do |spec|
32
32
  spec.add_dependency 'diplomat', '~> 2.1.3'
33
33
 
34
34
  spec.add_development_dependency 'bundler', '~> 2.0'
35
- spec.add_development_dependency 'rake', '~> 10.0'
35
+ spec.add_development_dependency 'rake', '~> 13.0'
36
36
  spec.add_development_dependency 'rspec', '~> 3.0'
37
37
  spec.add_development_dependency 'rubocop', '~> 0.66'
38
38
  spec.add_development_dependency 'rubocop-rspec', '~> 1.32.0'
@@ -1,11 +1,11 @@
1
1
  require 'consul_application_settings/version'
2
2
  require 'consul_application_settings/configuration'
3
- require 'consul_application_settings/defaults'
4
- require 'consul_application_settings/options'
3
+ require 'consul_application_settings/consul_provider'
4
+ require 'consul_application_settings/file_provider'
5
+ require 'consul_application_settings/settings_provider'
5
6
  require 'consul_application_settings/utils'
6
- require 'diplomat'
7
7
 
8
- # Main class used to configure defaults file path and load initial settings
8
+ # The gem provides possibility to load settings from Consul and automatically fall back to data stored in file system
9
9
  module ConsulApplicationSettings
10
10
  class Error < StandardError; end
11
11
 
@@ -16,19 +16,11 @@ module ConsulApplicationSettings
16
16
 
17
17
  self.config ||= ConsulApplicationSettings::Configuration.new
18
18
 
19
- class << self
20
- def configure
21
- yield(config)
22
- self.defaults = ConsulApplicationSettings::Defaults.read(config.defaults_path)
23
- end
24
-
25
- def load_from(path)
26
- settings_path = ConsulApplicationSettings::Utils.generate_path(config.namespace, path)
27
- ConsulApplicationSettings::Options.new(settings_path, defaults)
28
- end
19
+ def self.configure
20
+ yield(config)
21
+ end
29
22
 
30
- def load
31
- load_from('')
32
- end
23
+ def self.load(path = '')
24
+ SettingsProvider.new(path, config)
33
25
  end
34
26
  end
@@ -1,14 +1,14 @@
1
1
  module ConsulApplicationSettings
2
2
  # All gem configuration settings
3
3
  class Configuration
4
- # Required attributes
5
- attr_accessor :defaults_path
6
- # Optional attributes
7
- attr_accessor :namespace
8
- attr_accessor :disable_consul_connection_errors
4
+ DEFAULT_BASE_FILE_PATH = 'config/application_settings.yml'.freeze
5
+ DEFAULT_LOCAL_FILE_PATH = 'config/application_settings.local.yml'.freeze
6
+ attr_accessor :base_file_path, :local_file_path, :disable_consul_connection_errors
9
7
 
10
8
  def initialize
11
- self.namespace = ''
9
+ @base_file_path = DEFAULT_BASE_FILE_PATH
10
+ @local_file_path = DEFAULT_LOCAL_FILE_PATH
11
+ @disable_consul_connection_errors = true
12
12
  end
13
13
  end
14
14
  end
@@ -0,0 +1,33 @@
1
+ require 'diplomat'
2
+
3
+ module ConsulApplicationSettings
4
+ # Provides access to settings stored in Consul
5
+ class ConsulProvider
6
+ def initialize(base_path, config)
7
+ @base_path = base_path
8
+ @config = config
9
+ end
10
+
11
+ def get(path)
12
+ value = fetch_value(path)
13
+ ConsulApplicationSettings::Utils.cast_consul_value(value)
14
+ end
15
+
16
+ private
17
+
18
+ def fetch_value(path)
19
+ full_path = generate_full_path(path)
20
+ Diplomat::Kv.get(full_path, {}, :return)
21
+ rescue SystemCallError, Faraday::ConnectionFailed, Diplomat::PathNotFound => e
22
+ raise e unless disable_consul_connection_errors?
23
+ end
24
+
25
+ def generate_full_path(path)
26
+ ConsulApplicationSettings::Utils.generate_path(@base_path, path)
27
+ end
28
+
29
+ def disable_consul_connection_errors?
30
+ @config.disable_consul_connection_errors
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,54 @@
1
+ require 'yaml'
2
+
3
+ module ConsulApplicationSettings
4
+ # Provides access to settings stored in file system with support of base and local files
5
+ class FileProvider
6
+ def initialize(base_path, config)
7
+ @base_path = base_path
8
+ @config = config
9
+ load
10
+ end
11
+
12
+ def get(path)
13
+ read_path(path).clone
14
+ end
15
+
16
+ private
17
+
18
+ def load
19
+ base_yml = read_yml(base_file_path)
20
+ local_yml = read_yml(local_file_path)
21
+ @data = DeepMerge.deep_merge!(local_yml, base_yml, preserve_unmergeables: false, overwrite_arrays: true,
22
+ merge_nil_values: true)
23
+ end
24
+
25
+ def base_file_path
26
+ @config.base_file_path
27
+ end
28
+
29
+ def local_file_path
30
+ @config.local_file_path
31
+ end
32
+
33
+ def read_yml(path)
34
+ return {} unless File.exist?(path)
35
+
36
+ YAML.safe_load(IO.read(path))
37
+ rescue Psych::SyntaxError, Errno::ENOENT => e
38
+ raise ConsulApplicationSettings::Error, "Cannot read settings file at #{path}: #{e.message}"
39
+ end
40
+
41
+ def read_path(path)
42
+ full_path = ConsulApplicationSettings::Utils.generate_path(@base_path, path)
43
+ parts = ConsulApplicationSettings::Utils.decompose_path(full_path)
44
+ parts.reduce(@data, &method(:read_value))
45
+ end
46
+
47
+ def read_value(hash, key)
48
+ raise ConsulApplicationSettings::Error, 'reading arrays not implemented' if hash.is_a? Array
49
+ return {} if hash.nil?
50
+
51
+ hash.fetch(key.to_s)
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,16 @@
1
+ module ConsulApplicationSettings
2
+ # Provides access to settings stored in Consul or in file system
3
+ class SettingsProvider
4
+ def initialize(base_path, config)
5
+ @consul_provider = ConsulProvider.new(base_path, config)
6
+ @file_provider = FileProvider.new(base_path, config)
7
+ end
8
+
9
+ def get(path)
10
+ consul_value = @consul_provider.get(path)
11
+ !consul_value.nil? && consul_value != '' ? consul_value : @file_provider.get(path)
12
+ end
13
+
14
+ alias [] get
15
+ end
16
+ end
@@ -1,3 +1,3 @@
1
1
  module ConsulApplicationSettings
2
- VERSION = '0.1.4'.freeze
2
+ VERSION = '1.0.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: consul_application_settings
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Volodymyr Mykhailyk
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-04-16 00:00:00.000000000 Z
11
+ date: 2020-05-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: diplomat
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '10.0'
47
+ version: '13.0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '10.0'
54
+ version: '13.0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -136,8 +136,9 @@ files:
136
136
  - consul_application_settings.gemspec
137
137
  - lib/consul_application_settings.rb
138
138
  - lib/consul_application_settings/configuration.rb
139
- - lib/consul_application_settings/defaults.rb
140
- - lib/consul_application_settings/options.rb
139
+ - lib/consul_application_settings/consul_provider.rb
140
+ - lib/consul_application_settings/file_provider.rb
141
+ - lib/consul_application_settings/settings_provider.rb
141
142
  - lib/consul_application_settings/utils.rb
142
143
  - lib/consul_application_settings/version.rb
143
144
  homepage: https://github.com/matic-insurance/consul_application_settings
@@ -1,43 +0,0 @@
1
- require 'yaml'
2
-
3
- module ConsulApplicationSettings
4
- # Reading default file from YAML file and providing interface to query them
5
- class Defaults
6
- attr_reader :contents
7
-
8
- def initialize(hash)
9
- @contents = hash
10
- end
11
-
12
- def get(name)
13
- read_path(name, contents).clone
14
- end
15
-
16
- def load_from(path)
17
- keys = ConsulApplicationSettings::Utils.decompose_path(path)
18
- new_defaults = keys.reduce(contents) { |hash, key| read_path(key, hash, {}) }
19
- self.class.new(new_defaults)
20
- end
21
-
22
- def self.read(path)
23
- new YAML.safe_load(IO.read(path))
24
- rescue Psych::SyntaxError, Errno::ENOENT => e
25
- raise ConsulApplicationSettings::Error, "Cannot read defaults file at #{path}: #{e.message}"
26
- end
27
-
28
- private
29
-
30
- def read_path(path, hash, default = nil)
31
- parts = ConsulApplicationSettings::Utils.decompose_path(path)
32
- result = parts.reduce(hash, &method(:read_value))
33
- result || default
34
- end
35
-
36
- def read_value(hash, key)
37
- raise ConsulApplicationSettings::Error, 'reading arrays not implemented' if hash.is_a? Array
38
- return {} if hash.nil?
39
-
40
- hash.fetch(key.to_s)
41
- end
42
- end
43
- end
@@ -1,53 +0,0 @@
1
- require 'json'
2
-
3
- module ConsulApplicationSettings
4
- # Reads settings from consul or ask defaults for value
5
- class Options
6
- attr_reader :path, :defaults
7
-
8
- def initialize(path, defaults)
9
- @path = path
10
- @defaults = defaults.load_from(path)
11
- end
12
-
13
- def load_from(new_path)
14
- full_path = ConsulApplicationSettings::Utils.generate_path(path, new_path)
15
- self.class.new(full_path, defaults)
16
- end
17
-
18
- def get(name)
19
- consul_value = key_value(name)
20
- if consul_value.nil? || consul_value.empty?
21
- defaults.get(name)
22
- else
23
- ConsulApplicationSettings::Utils.cast_consul_value(consul_value)
24
- end
25
- end
26
-
27
- def [](name)
28
- get(name)
29
- end
30
-
31
- # rubocop:disable Style/MethodMissingSuper
32
- def method_missing(name, *_args)
33
- get(name)
34
- end
35
- # rubocop:enable Style/MethodMissingSuper
36
-
37
- def respond_to_missing?(_name)
38
- true
39
- end
40
-
41
- private
42
-
43
- def key_value(name)
44
- Diplomat::Kv.get(key_path(name), {}, :return)
45
- rescue SystemCallError, Faraday::ConnectionFailed, Diplomat::PathNotFound => e
46
- raise e unless ConsulApplicationSettings.config.disable_consul_connection_errors
47
- end
48
-
49
- def key_path(name)
50
- ConsulApplicationSettings::Utils.generate_path(path, name)
51
- end
52
- end
53
- end