global 2.0.0 → 3.0.0

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
  SHA256:
3
- metadata.gz: d82e24b3a7c94f65e370d1b16142e028d3acf1ce3fe8064e9e9fcb9e4683d46e
4
- data.tar.gz: 809e1b6ac4e2f0ada443202b1d80ec7d663488515f682079cd07bc02335983c4
3
+ metadata.gz: 9b5acdeb3ad880ec202bb6754c307585a47ffc951982c2d19b85707c2bea17f8
4
+ data.tar.gz: 3c88ae1a5cd961d1d938fecf9598e0da1f87f9d5dc226a110c68bc329c633988
5
5
  SHA512:
6
- metadata.gz: b290b4951da9d199d64ec8a27bdf630be5691ec1af0829d31e01872c1260893e2a3626fcc55a70f9ac816192279fbf04a4a2823dd770127808bd63b62ad8016d
7
- data.tar.gz: afa4586a51919a0d483dbcd01e5fd027cd6a79aebaea070c544c53f4838ccbbece9312536d40ed475adf1cc207ef7864937639baa60de7bab1918de3a081944a
6
+ metadata.gz: 93a5195d7db98dc4f806e38428c9553aba5c7b54561f4db729b925145fb3fefa854ee4be3bd8a4a92a02425bd1e4e0203baaa4afcbe37fb33ad6e30ca4482267
7
+ data.tar.gz: bc9d92edd7715f96149c2a5d1ae456ce0e208c636a4f2ed562391d06d7b835c81572b8f6d31591b59aa24f1bf7ed4738e0bf81532f02efa218f98eb2af0b49bf
@@ -0,0 +1,28 @@
1
+ name: Runs linter and tests
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ linters_and_tests:
7
+ runs-on: ${{ matrix.os }}-latest
8
+ continue-on-error: ${{ matrix.experimental == true }}
9
+ name: Linter and tests on ${{ matrix.os }}-ruby-${{ matrix.ruby-version }}
10
+ strategy:
11
+ matrix:
12
+ os: [ubuntu, macos]
13
+ ruby-version:
14
+ - 3.3
15
+ - 3.2
16
+ - 3.1
17
+ - 3.0
18
+ steps:
19
+ - uses: actions/checkout@v2
20
+
21
+ - name: Set up Ruby
22
+ uses: ruby/setup-ruby@v1
23
+ with:
24
+ ruby-version: ${{ matrix.ruby-version }}
25
+ bundler-cache: true
26
+
27
+ - name: Runs linter and tests
28
+ run: bundle exec rake
data/.gitignore CHANGED
@@ -4,4 +4,11 @@ Gemfile.lock
4
4
  pkg/*
5
5
  .rspec
6
6
  coverage/**
7
- .DS_Store
7
+ .DS_Store
8
+
9
+ .ruby-gemset
10
+ .ruby-version
11
+ .tool-versions
12
+
13
+ .vscode
14
+ .idea
data/.rspec CHANGED
@@ -1 +1,2 @@
1
1
  --color
2
+ --require spec_helper
data/.rubocop.yml CHANGED
@@ -1,3 +1,11 @@
1
+ require:
2
+ - rubocop-rake
3
+ - rubocop-rspec
4
+
5
+ AllCops:
6
+ TargetRubyVersion: 3.0
7
+ NewCops: enable
8
+
1
9
  Metrics/MethodLength:
2
10
  Enabled: true
3
11
  Max: 11
data/CHANGELOG.md ADDED
@@ -0,0 +1,8 @@
1
+ ## [3.0.0] - 2024-12-04
2
+
3
+ - Predicate methods now cast the value to a boolean
4
+ ```ruby
5
+ Global.foo.enabled # => "0"
6
+ Global.foo.enabled? # => false
7
+ ```
8
+ - Dropped Ruby 2.7 support
data/Gemfile CHANGED
@@ -2,5 +2,15 @@
2
2
 
3
3
  source 'https://rubygems.org'
4
4
 
5
- # Specify your gem's dependencies in global.gemspec
6
5
  gemspec
6
+
7
+ gem 'aws-sdk-ssm', '~> 1'
8
+ gem 'google-cloud-secret_manager', '~> 0'
9
+
10
+ gem 'rake', '>= 13'
11
+ gem 'rspec', '>= 3.0'
12
+ gem 'simplecov'
13
+
14
+ gem 'rubocop', '~> 1.68'
15
+ gem 'rubocop-rake'
16
+ gem 'rubocop-rspec'
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Global [![Build Status](https://travis-ci.org/railsware/global.png)](https://travis-ci.org/railsware/global) [![Code Climate](https://codeclimate.com/github/railsware/global.png)](https://codeclimate.com/github/railsware/global)
1
+ # Global [![Runs linter and tests](https://github.com/railsware/global/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/railsware/global/actions/workflows/tests.yml) [![Code Climate](https://codeclimate.com/github/railsware/global.png)](https://codeclimate.com/github/railsware/global)
2
2
 
3
3
  The 'global' gem provides accessor methods for your configuration data and share configuration across backend and frontend.
4
4
 
@@ -19,14 +19,14 @@ Refer to the documentation on your chosen backend class for other dependencies.
19
19
  Refer to the documentation on your chosen backend class for configuration options.
20
20
 
21
21
  ```ruby
22
- > Global.backend(:filesystem, environment: "YOUR_ENV_HERE", directory: "PATH_TO_DIRECTORY_WITH_FILES")
22
+ > Global.backend(:filesystem, environment: "YOUR_ENV_HERE", path: "PATH_TO_DIRECTORY_WITH_FILES")
23
23
  ```
24
24
 
25
25
  Or you can use `configure` block:
26
26
 
27
27
  ```ruby
28
28
  Global.configure do |config|
29
- config.backend :filesystem, environment: "YOUR_ENV_HERE", directory: "PATH_TO_DIRECTORY_WITH_FILES"
29
+ config.backend :filesystem, environment: "YOUR_ENV_HERE", path: "PATH_TO_DIRECTORY_WITH_FILES"
30
30
  # set up multiple backends and have them merged together:
31
31
  config.backend :aws_parameter_store, prefix: '/prod/MyApp/'
32
32
  config.backend :gcp_secret_manager, prefix: 'prod-myapp-', project_id: 'example'
@@ -252,6 +252,12 @@ Some steps you will need to follow:
252
252
  - If you will use encrypted parameters: create a KMS key and allow the role to decrypt using the key.
253
253
  - Create parameters in Parameter Store. Use encryption for sensitive data like private keys and API credentials.
254
254
 
255
+ #### Usage with Go
256
+
257
+ You can reuse the same configuration in your Go services. For this, we developed a Go module that loads the same configuration tree into Go structs.
258
+
259
+ See [github.com/railsware/go-global](https://github.com/railsware/go-global) for further instructions.
260
+
255
261
  #### Configuration examples
256
262
 
257
263
  Backend setup:
data/Rakefile CHANGED
@@ -1,12 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rubygems'
4
- require 'bundler'
5
-
6
- Bundler.require
7
-
8
- require 'rspec/core/rake_task'
9
3
  require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
10
5
  require 'rubocop/rake_task'
11
6
 
12
7
  RSpec::Core::RakeTask.new(:spec)
data/global.gemspec CHANGED
@@ -1,31 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- $LOAD_PATH.push File.expand_path('lib', __dir__)
4
- require 'global/version'
3
+ require_relative 'lib/global/version'
5
4
 
6
5
  Gem::Specification.new do |s|
7
6
  s.name = 'global'
8
7
  s.version = Global::VERSION
8
+ s.required_ruby_version = '>= 3.0.0'
9
9
  s.authors = ['Railsware LLC']
10
10
  s.email = 'contact@railsware.com'
11
-
12
11
  s.description = 'Simple way to load your configs from yaml/aws/gcp'
12
+
13
+ s.homepage = 'https://github.com/railsware/global'
14
+ s.licenses = ['MIT']
13
15
  s.summary = 'Simple way to load your configs from yaml/aws/gcp'
14
16
 
17
+ s.metadata['rubygems_mfa_required'] = 'true'
18
+
15
19
  s.files = `git ls-files`.split("\n")
16
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
20
  s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
18
21
  s.require_paths = ['lib']
19
22
 
20
- s.homepage = 'https://github.com/railsware/global'
21
- s.licenses = ['MIT']
22
-
23
- s.add_development_dependency 'aws-sdk-ssm', '~> 1'
24
- s.add_development_dependency 'google-cloud-secret_manager', '~> 0'
25
- s.add_development_dependency 'rake', '~> 12.3.1'
26
- s.add_development_dependency 'rspec', '>= 3.0'
27
- s.add_development_dependency 'rubocop', '~> 0.81.0'
28
- s.add_development_dependency 'simplecov', '~> 0.16.1'
29
-
30
- s.add_runtime_dependency 'activesupport', '>= 2.0'
23
+ s.add_dependency 'activesupport', '>= 2.0'
31
24
  end
@@ -95,7 +95,7 @@ module Global
95
95
  def build_configuration_from_parameters(parameters)
96
96
  configuration = {}
97
97
  parameters.each do |parameter|
98
- parameter_parts = parameter.name[@prefix.length..-1].split(PATH_SEPARATOR).map(&:to_sym)
98
+ parameter_parts = parameter.name[@prefix.length..].split(PATH_SEPARATOR).map(&:to_sym)
99
99
  param_container = parameter_parts[0..-2].reduce(configuration) do |container, part|
100
100
  container[part] ||= {}
101
101
  end
@@ -5,12 +5,12 @@ module Global
5
5
  # Loads Global configuration from the filesystem
6
6
  #
7
7
  # Available options:
8
- # - `directory` (required): the directory with config files
8
+ # - `path` (required): the directory with config files
9
9
  # - `environment` (required): the environment to load
10
10
  # - `yaml_whitelist_classes`: the set of classes that are permitted to unmarshal from the configuration files
11
11
  #
12
12
  # For Rails:
13
- # - the `directory` is optional and defaults to `config/global`
13
+ # - the `path` is optional and defaults to `config/global`
14
14
  # - the `environment` is optional and defaults to the current Rails environment
15
15
  class Filesystem
16
16
 
@@ -60,11 +60,14 @@ module Global
60
60
  end
61
61
 
62
62
  def load_yml_file(file)
63
- YAML.safe_load(
64
- ERB.new(IO.read(file)).result,
65
- [Date, Time, DateTime, Symbol].concat(@yaml_whitelist_classes),
66
- [], true
67
- )
63
+ file_contents = ERB.new(File.read(file)).result
64
+ permitted_classes = [Date, Time, DateTime, Symbol].concat(@yaml_whitelist_classes)
65
+
66
+ if Gem::Version.new(Psych::VERSION) >= Gem::Version.new('4')
67
+ YAML.safe_load(file_contents, permitted_classes: permitted_classes, aliases: true)
68
+ else
69
+ YAML.safe_load(file_contents, permitted_classes, [], true)
70
+ end
68
71
  end
69
72
 
70
73
  def load_from_directory(path)
@@ -108,7 +108,7 @@ module Global
108
108
  key_name = get_gcp_key_name(parameter)
109
109
  next unless key_name.start_with?(@prefix)
110
110
 
111
- parameter_parts = key_name[@prefix.length..-1].split(PATH_SEPARATOR).map(&:to_sym)
111
+ parameter_parts = key_name[@prefix.length..].split(PATH_SEPARATOR).map(&:to_sym)
112
112
  param_container = parameter_parts[0..-2].reduce(configuration) do |container, part|
113
113
  container[part] ||= {}
114
114
  end
data/lib/global/base.rb CHANGED
@@ -34,7 +34,7 @@ module Global
34
34
  # and the configuration hashes will be merged.
35
35
  #
36
36
  # Configure with either:
37
- # Global.backend :filesystem, directory: 'config', environment: Rails.env
37
+ # Global.backend :filesystem, path: 'config', environment: Rails.env
38
38
  # or:
39
39
  # Global.backend YourConfigurationBackend.new
40
40
  #
@@ -13,6 +13,21 @@ module Global
13
13
  :member?, :[], :[]=, :to_hash, :to_json,
14
14
  :inspect, :fetch
15
15
 
16
+ # rubocop:disable Lint/BooleanSymbol
17
+ # @see ActiveModel::Type::Boolean::FALSE_VALUES
18
+ FALSE_VALUES = [
19
+ false, 0,
20
+ '0', :'0',
21
+ 'f', :f,
22
+ 'F', :F,
23
+ 'false', :false,
24
+ 'FALSE', :FALSE,
25
+ 'off', :off,
26
+ 'OFF', :OFF
27
+ ].to_set.freeze
28
+ private_constant :FALSE_VALUES
29
+ # rubocop:enable Lint/BooleanSymbol
30
+
16
31
  def initialize(hash)
17
32
  @hash = hash.respond_to?(:with_indifferent_access) ? hash.with_indifferent_access : hash
18
33
  end
@@ -45,20 +60,34 @@ module Global
45
60
 
46
61
  def respond_to_missing?(method_name, include_private = false)
47
62
  method = normalize_key_by_method(method_name)
48
- key?(method) || super
63
+ key?(method) || boolean_method?(method) || super
49
64
  end
50
65
 
51
66
  def method_missing(method, *args, &block)
52
- method = normalize_key_by_method(method)
53
- if key?(method)
54
- get_configuration_value(method)
67
+ normalized_method = normalize_key_by_method(method)
68
+ if key?(normalized_method)
69
+ value = get_configuration_value(normalized_method)
70
+ boolean_method?(method) ? cast_boolean(value) : value
55
71
  else
56
72
  super
57
73
  end
58
74
  end
59
75
 
76
+ def boolean_method?(method)
77
+ '?' == method.to_s[-1]
78
+ end
79
+
80
+ # @see ActiveModel::Type::Boolean#cast_value
81
+ def cast_boolean(value)
82
+ if value == '' || value.nil?
83
+ false
84
+ else
85
+ !FALSE_VALUES.include?(value)
86
+ end
87
+ end
88
+
60
89
  def normalize_key_by_method(method)
61
- '?' == method.to_s[-1] ? method.to_s[0..-2] : method
90
+ boolean_method?(method) ? method.to_s[0..-2].to_sym : method
62
91
  end
63
92
 
64
93
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Global
4
4
 
5
- VERSION = '2.0.0'
5
+ VERSION = '3.0.0'
6
6
 
7
7
  end
@@ -1,18 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
3
  require 'aws-sdk-ssm'
5
4
  require 'global/backend/aws_parameter_store'
6
5
 
7
6
  RSpec.describe Global::Backend::AwsParameterStore do
7
+ subject(:parameter_store) do
8
+ described_class.new(prefix: '/testapp/', client: client)
9
+ end
10
+
8
11
  let(:client) do
9
12
  Aws::SSM::Client.new(stub_responses: true)
10
13
  end
11
- subject do
12
- described_class.new(prefix: '/testapp/', client: client)
13
- end
14
14
 
15
- it 'reads parameters from the parameter store' do
15
+ it 'reads parameters from the parameter store' do # rubocop:disable RSpec/ExampleLength, RSpec/MultipleExpectations
16
16
  client.stub_responses(
17
17
  :get_parameters_by_path,
18
18
  [
@@ -37,7 +37,7 @@ RSpec.describe Global::Backend::AwsParameterStore do
37
37
  }
38
38
  ]
39
39
  )
40
- expect(subject.load).to eq(
40
+ expect(parameter_store.load).to eq(
41
41
  foo: 'foo-value',
42
42
  bar: {
43
43
  baz: 'baz-value',
@@ -1,39 +1,37 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
3
  require 'google/cloud/secret_manager'
4
+ require 'google/cloud/secret_manager/v1'
5
5
  require 'global/backend/gcp_secret_manager'
6
6
 
7
7
  RSpec.describe Global::Backend::GcpSecretManager do
8
- let(:client) { double }
9
-
10
- subject do
8
+ subject(:secret_manager) do
11
9
  described_class.new(prefix: 'prod-myapp-', client: client, project_id: 'example')
12
10
  end
13
11
 
14
- before do
15
- @match_item = double
16
- allow(@match_item).to receive(:name).and_return('prod-myapp-example-test_key')
12
+ let(:client) { instance_double(Google::Cloud::SecretManager::V1::SecretManagerService::Client) }
17
13
 
18
- @secret_data = double
19
- allow(@secret_data).to receive_message_chain(:payload, :data).and_return('secret value')
14
+ before do
15
+ # rubocop:disable RSpec/VerifiedDoubles
16
+ match_item = double(name: 'prod-myapp-example-test_key')
17
+ not_match_item = double(name: 'different_key')
20
18
 
21
- @not_match_item = double
22
- allow(@not_match_item).to receive(:name).and_return('different_key')
19
+ secret_data = double(data: 'secret value')
20
+ secret_version_response = double(payload: secret_data)
23
21
 
24
- @list = double
25
- allow(@list).to receive(:next_page_token).and_return('')
26
- allow(@list).to receive(:each).and_yield(@match_item).and_yield(@not_match_item)
22
+ page = instance_double(Gapic::PagedEnumerable)
23
+ allow(page).to receive(:next_page_token).and_return('')
24
+ allow(page).to receive(:each).and_yield(match_item).and_yield(not_match_item)
27
25
 
28
- allow(client).to receive(:project_path).and_return('projects/example')
29
26
  allow(client).to receive(:secret_version_path)
30
27
  .with(project: 'example', secret: 'prod-myapp-example-test_key', secret_version: 'latest')
31
28
  .and_return('some_key_path')
32
- allow(client).to receive(:access_secret_version).with(name: 'some_key_path').and_return(@secret_data)
33
- allow(client).to receive(:list_secrets).and_return(@list)
29
+ allow(client).to receive(:access_secret_version).with(name: 'some_key_path').and_return(secret_version_response)
30
+ allow(client).to receive_messages(project_path: 'projects/example', list_secrets: page)
31
+ # rubocop:enable RSpec/VerifiedDoubles
34
32
  end
35
33
 
36
34
  it 'reads parameters from the secret manager' do
37
- expect(subject.load).to eq({ example: { test_key: 'secret value' }})
35
+ expect(secret_manager.load).to eq({ example: { test_key: 'secret value' }})
38
36
  end
39
37
  end
@@ -1,151 +1,165 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  RSpec.describe Global::Configuration do
6
- let(:hash) { { 'key' => 'value', 'nested' => { 'key' => 'value' }} }
7
- let(:configuration) { described_class.new hash }
4
+ subject(:configuration) { described_class.new hash }
5
+
6
+ let(:hash) do
7
+ {
8
+ 'key' => 'value',
9
+ 'boolean_key' => true,
10
+ 'nested' => { 'key' => 'value' }
11
+ }
12
+ end
8
13
 
9
14
  describe '#hash' do
10
- subject { configuration.hash }
11
-
12
- it { is_expected.to eq(hash) }
15
+ it { expect(configuration.hash).to eq(hash) }
13
16
  end
14
17
 
15
18
  describe '#to_hash' do
16
- subject { configuration.to_hash }
17
-
18
- it { is_expected.to eq(hash) }
19
+ it { expect(configuration.to_hash).to eq(hash) }
19
20
  end
20
21
 
21
- describe 'key?' do
22
- subject { configuration.key?(:key) }
23
-
24
- it { is_expected.to be_truthy }
22
+ describe '#key?' do
23
+ it { expect(configuration.key?(:key)).to be(true) }
25
24
  end
26
25
 
27
- describe 'has_key?' do
28
- subject { configuration.key?(:key) }
29
-
30
- it { is_expected.to be_truthy }
26
+ describe '#has_key?' do
27
+ it { expect(configuration).to have_key(:key) }
31
28
  end
32
29
 
33
30
  describe 'include?' do
34
- subject { configuration.include?(:key) }
35
-
36
- it { is_expected.to be_truthy }
31
+ it { expect(configuration.include?(:key)).to be(true) }
37
32
  end
38
33
 
39
34
  describe 'member?' do
40
- subject { configuration.member?(:key) }
41
-
42
- it { is_expected.to be_truthy }
35
+ it { expect(configuration.member?(:key)).to be(true) }
43
36
  end
44
37
 
45
38
  describe '#[]' do
46
- subject { configuration[:key] }
47
-
48
- it { is_expected.to eq('value') }
39
+ it { expect(configuration[:key]).to eq('value') }
49
40
  end
50
41
 
51
42
  describe '#[]=' do
52
- subject { configuration[:new_key] }
53
-
54
- before { configuration[:new_key] = 'new_value' }
55
-
56
- it { is_expected.to eq('new_value') }
43
+ it 'sets new value' do
44
+ configuration[:new_key] = 'new_value'
45
+ expect(configuration[:new_key]).to eq('new_value')
46
+ end
57
47
  end
58
48
 
59
49
  describe '#inspect' do
60
- subject { configuration.inspect }
61
-
62
- it { is_expected.to eq(hash.inspect) }
50
+ it { expect(configuration.inspect).to eq(hash.inspect) }
63
51
  end
64
52
 
65
53
  describe '#filter' do
66
- subject { configuration.filter(filter_options) }
54
+ subject(:filter) { configuration.filter(filter_options) }
67
55
 
68
56
  context 'when include all' do
69
57
  let(:filter_options) { { only: :all } }
70
58
 
71
- it { should == { 'key' => 'value', 'nested' => { 'key' => 'value' }} }
59
+ it { expect(filter).to eq('key' => 'value', 'boolean_key' => true, 'nested' => { 'key' => 'value' }) }
72
60
  end
73
61
 
74
62
  context 'when except all' do
75
63
  let(:filter_options) { { except: :all } }
76
64
 
77
- it { should == {} }
65
+ it { expect(filter).to eq({}) }
78
66
  end
79
67
 
80
68
  context 'when except present' do
81
69
  let(:filter_options) { { except: %w[key] } }
82
70
 
83
- it { should == { 'nested' => { 'key' => 'value' }} }
71
+ it { expect(filter).to eq('boolean_key' => true, 'nested' => { 'key' => 'value' }) }
84
72
  end
85
73
 
86
74
  context 'when include present' do
87
75
  let(:filter_options) { { only: %w[key] } }
88
76
 
89
- it { should == { 'key' => 'value' } }
77
+ it { expect(filter).to eq('key' => 'value') }
90
78
  end
91
79
 
92
80
  context 'when empty options' do
93
81
  let(:filter_options) { {} }
94
82
 
95
- it { should == {} }
83
+ it { expect(filter).to eq({}) }
96
84
  end
97
85
  end
98
86
 
99
87
  describe '#method_missing' do
100
- context 'when key exist' do
101
- subject { configuration.key }
102
-
103
- it { is_expected.to eq('value') }
88
+ it 'returns key value' do
89
+ expect(configuration.key).to eq('value')
104
90
  end
105
91
 
106
- context 'when key does not exist' do
107
- subject { configuration.some_key }
92
+ it 'returns boolean key value' do
93
+ expect(configuration.boolean_key?).to be(true)
94
+ end
108
95
 
109
- it { expect { subject }.to raise_error(NoMethodError) }
96
+ it 'raises on missing key' do
97
+ expect { configuration.some_key }.to raise_error(NoMethodError)
110
98
  end
111
99
 
112
- context 'with nested hash' do
113
- subject { configuration.nested.key }
100
+ it 'raises on missing boolean key' do
101
+ expect { configuration.some_boolean_key? }.to raise_error(NoMethodError)
102
+ end
114
103
 
115
- it { is_expected.to eq('value') }
104
+ it 'returns nested key value' do
105
+ expect(configuration.nested.key).to eq('value')
116
106
  end
117
107
  end
118
108
 
119
- describe '#respond_to_missing?' do
120
- context 'when key exist' do
121
- subject { configuration.respond_to?(:key) }
122
-
123
- it { is_expected.to eq(true) }
109
+ describe 'predicate methods' do
110
+ let(:hash) do
111
+ {
112
+ false_string: 'false',
113
+ false_symbol: :false, # rubocop:disable Lint/BooleanSymbol
114
+ off_string: 'off',
115
+ zero_string: '0',
116
+ zero_integer: 0,
117
+ true_string: 'true',
118
+ true_symbol: :true, # rubocop:disable Lint/BooleanSymbol
119
+ on_string: 'on',
120
+ one_string: '1',
121
+ one_integer: 1,
122
+ random_string: ' Offset ',
123
+ empty_string: '',
124
+ nil_value: nil
125
+ }
124
126
  end
125
127
 
126
- context 'when key does not exist' do
127
- subject { configuration.respond_to?(:some_key) }
128
+ it { expect(configuration.false_string?).to be(false) }
129
+ it { expect(configuration.false_symbol?).to be(false) }
130
+ it { expect(configuration.off_string?).to be(false) }
131
+ it { expect(configuration.zero_string?).to be(false) }
132
+ it { expect(configuration.zero_integer?).to be(false) }
133
+ it { expect(configuration.empty_string?).to be(false) }
134
+ it { expect(configuration.nil_value?).to be(false) }
135
+
136
+ it { expect(configuration.true_string?).to be(true) }
137
+ it { expect(configuration.true_symbol?).to be(true) }
138
+ it { expect(configuration.on_string?).to be(true) }
139
+ it { expect(configuration.one_string?).to be(true) }
140
+ it { expect(configuration.one_integer?).to be(true) }
141
+ it { expect(configuration.random_string?).to be(true) }
142
+ end
128
143
 
129
- it { is_expected.to eq(false) }
144
+ describe '#respond_to_missing?' do
145
+ it 'responds to key' do
146
+ expect(configuration.respond_to?(:key)).to be(true)
130
147
  end
131
148
 
132
- context 'with nested hash' do
133
- subject { configuration.nested.respond_to?(:key) }
134
-
135
- it { is_expected.to eq(true) }
149
+ it 'does not respond to unknown key' do
150
+ expect(configuration.respond_to?(:some_key)).to be(false)
136
151
  end
137
152
 
138
- context 'when call it by method' do
139
- subject { configuration.method(:key).call }
153
+ it 'responds to nested key' do
154
+ expect(configuration.nested.respond_to?(:key)).to be(true)
155
+ end
140
156
 
141
- it { is_expected.to eq('value') }
157
+ it 'calls a method' do
158
+ expect(configuration.method(:key).call).to eq('value')
142
159
  end
143
160
 
144
- context 'when call it by method, which not exist' do
145
- it 'raise error' do
146
- expect { configuration.method(:some_key) }.to raise_error(NameError)
147
- end
161
+ it 'raised on a missing method call' do
162
+ expect { configuration.method(:some_key) }.to raise_error(NameError)
148
163
  end
149
164
  end
150
-
151
165
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Global do
4
+ subject(:global) { described_class }
5
+
6
+ describe 'merging backends' do
7
+ # rubocop:disable RSpec/VerifiedDoubles
8
+ let(:backend_alpha) { double('backend_alpha', load: { foo: 'foo', bar: 'bar-alpha' }) }
9
+ let(:backend_beta) { double('backend_beta', load: { 'bar' => 'bar-beta', 'baz' => 'baz' }) }
10
+ # rubocop:enable RSpec/VerifiedDoubles
11
+
12
+ before do
13
+ global.backend backend_alpha
14
+ global.backend backend_beta
15
+ end
16
+
17
+ it 'merges data from two backends together' do
18
+ expect(global.configuration.to_hash).to eq(
19
+ 'foo' => 'foo',
20
+ 'bar' => 'bar-beta',
21
+ 'baz' => 'baz'
22
+ )
23
+ end
24
+ end
25
+ end
data/spec/global_spec.rb CHANGED
@@ -1,65 +1,62 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  RSpec.describe Global do
6
-
7
4
  let(:config_path) { File.join(Dir.pwd, 'spec/files') }
8
- before(:each) do
5
+
6
+ before do
9
7
  described_class.configure do |config|
10
8
  config.backend :filesystem, path: config_path, environment: 'test'
11
9
  end
12
10
  end
13
11
 
14
12
  describe '.configuration' do
15
- subject { described_class.configuration }
13
+ subject(:configuration) { described_class.configuration }
16
14
 
17
15
  it { is_expected.to be_instance_of(Global::Configuration) }
18
16
 
19
17
  context 'when load from directory' do
20
- describe '#rspec_config' do
21
- subject { super().rspec_config }
22
- describe '#to_hash' do
23
- subject { super().to_hash }
24
- it { is_expected.to eq('default_value' => 'default value', 'test_value' => 'test value') }
25
- end
18
+ it 'loads configuration' do
19
+ expect(configuration.rspec_config.to_hash).to eq(
20
+ 'default_value' => 'default value',
21
+ 'test_value' => 'test value'
22
+ )
26
23
  end
27
24
  end
28
25
 
29
26
  context 'when load from file' do
30
27
  let(:config_path) { File.join(Dir.pwd, 'spec/files/rspec_config') }
31
28
 
32
- describe '#rspec_config' do
33
- describe '#to_hash' do
34
- subject { super().to_hash }
35
- it { is_expected.to eq('default_value' => 'default value', 'test_value' => 'test value') }
36
- end
29
+ it 'loads configuration' do
30
+ expect(configuration.to_hash).to eq(
31
+ 'default_value' => 'default value',
32
+ 'test_value' => 'test value'
33
+ )
37
34
  end
38
35
  end
39
36
 
40
37
  context 'when nested directories' do
41
- it { expect(subject.rspec['config'].to_hash).to eq('default_value' => 'default nested value', 'test_value' => 'test nested value') }
38
+ it { expect(configuration.rspec['config'].to_hash).to eq('default_value' => 'default nested value', 'test_value' => 'test nested value') }
42
39
  end
43
40
 
44
41
  context 'when boolean' do
45
- it { expect(subject.bool_config.works).to eq(true) }
46
- it { expect(subject.bool_config.works?).to eq(true) }
42
+ it { expect(configuration.bool_config.works).to be(true) }
43
+ it { expect(configuration.bool_config.works?).to be(true) }
47
44
  end
48
45
 
49
- context 'environment file' do
50
- it { expect(subject.aws.activated).to eq(true) }
51
- it { expect(subject.aws.api_key).to eq('some api key') }
52
- it { expect(subject.aws.api_secret).to eq('some secret') }
46
+ describe 'environment file' do
47
+ it { expect(configuration.aws.activated).to be(true) }
48
+ it { expect(configuration.aws.api_key).to eq('some api key') }
49
+ it { expect(configuration.aws.api_secret).to eq('some secret') }
53
50
  end
54
51
 
55
- context 'skip files with dots in name' do
56
- it { expect(subject['aws.test']).to eq(nil) }
57
- it { expect { subject.fetch('aws.test') }.to raise_error(KeyError, /key not found/) }
52
+ describe 'skip files with dots in name' do
53
+ it { expect(configuration['aws.test']).to be_nil }
54
+ it { expect { configuration.fetch('aws.test') }.to raise_error(KeyError, /key not found/) }
58
55
  end
59
56
  end
60
57
 
61
- context '.reload!' do
62
- subject { described_class.reload! }
58
+ describe '.reload!' do
59
+ subject(:reloaded_configuration) { described_class.reload! }
63
60
 
64
61
  before do
65
62
  described_class.configuration
@@ -67,49 +64,39 @@ RSpec.describe Global do
67
64
  described_class.backend :filesystem, path: config_path, environment: 'development'
68
65
  end
69
66
 
70
- it { is_expected.to be_instance_of(Global::Configuration) }
67
+ it 'returns configuration' do
68
+ expect(reloaded_configuration).to be_instance_of(Global::Configuration)
69
+ end
71
70
 
72
- describe '#rspec_config' do
73
- subject { super().rspec_config }
74
- describe '#to_hash' do
75
- subject { super().to_hash }
76
- it { is_expected.to eq('default_value' => 'default value', 'test_value' => 'development value') }
77
- end
71
+ it 'reloads configuration' do
72
+ expect(reloaded_configuration.rspec_config.to_hash).to eq(
73
+ 'default_value' => 'default value',
74
+ 'test_value' => 'development value'
75
+ )
78
76
  end
79
77
  end
80
78
 
81
79
  describe '.respond_to_missing?' do
82
- context 'when file exists' do
83
- subject { described_class.respond_to?(:rspec_config) }
84
-
85
- it { is_expected.to be_truthy }
80
+ it 'responds to present config' do
81
+ expect(described_class.respond_to?(:rspec_config)).to be(true)
86
82
  end
87
83
 
88
- context 'when file does not exist' do
89
- subject { described_class.respond_to?(:some_file) }
90
-
91
- it { is_expected.to be_falsey }
84
+ it 'does not respond to missing config' do
85
+ expect(described_class.respond_to?(:some_file)).to be(false)
92
86
  end
93
87
  end
94
88
 
95
89
  describe '.method_missing' do
96
- context 'when file exists' do
97
- subject { described_class.rspec_config }
98
-
99
- it { is_expected.to be_kind_of(Global::Configuration) }
90
+ it 'returns configuration' do
91
+ expect(described_class.rspec_config).to be_a(Global::Configuration)
100
92
  end
101
93
 
102
- context 'when file does not exist' do
103
- subject { described_class.some_file }
104
-
105
- it { expect { subject }.to raise_error(NoMethodError) }
94
+ it 'raises on missing configuration' do
95
+ expect { described_class.some_file }.to raise_error(NoMethodError)
106
96
  end
107
97
 
108
- context 'when file with nested hash' do
109
- subject { described_class.nested_config }
110
-
111
- it { is_expected.to be_kind_of(Global::Configuration) }
98
+ it 'returns config with nested hash' do
99
+ expect(described_class.nested_config).to be_a(Global::Configuration)
112
100
  end
113
-
114
101
  end
115
102
  end
data/spec/spec_helper.rb CHANGED
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
4
- $LOAD_PATH.unshift(File.dirname(__FILE__))
5
- require 'rspec'
6
- require 'global'
7
3
  require 'simplecov'
8
4
 
9
5
  SimpleCov.start do
@@ -12,6 +8,8 @@ SimpleCov.start do
12
8
  add_group 'Libraries', '/lib/'
13
9
  end
14
10
 
11
+ require 'global'
12
+
15
13
  RSpec.configure do |config|
16
14
  config.disable_monkey_patching!
17
15
 
metadata CHANGED
@@ -1,99 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: global
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Railsware LLC
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-04-16 00:00:00.000000000 Z
11
+ date: 2024-12-04 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: aws-sdk-ssm
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '1'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '1'
27
- - !ruby/object:Gem::Dependency
28
- name: google-cloud-secret_manager
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
- - !ruby/object:Gem::Dependency
42
- name: rake
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: 12.3.1
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: 12.3.1
55
- - !ruby/object:Gem::Dependency
56
- name: rspec
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '3.0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '3.0'
69
- - !ruby/object:Gem::Dependency
70
- name: rubocop
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: 0.81.0
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: 0.81.0
83
- - !ruby/object:Gem::Dependency
84
- name: simplecov
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - "~>"
88
- - !ruby/object:Gem::Version
89
- version: 0.16.1
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - "~>"
95
- - !ruby/object:Gem::Version
96
- version: 0.16.1
97
13
  - !ruby/object:Gem::Dependency
98
14
  name: activesupport
99
15
  requirement: !ruby/object:Gem::Requirement
@@ -115,11 +31,12 @@ executables:
115
31
  extensions: []
116
32
  extra_rdoc_files: []
117
33
  files:
34
+ - ".github/workflows/tests.yml"
118
35
  - ".gitignore"
119
36
  - ".rspec"
120
37
  - ".rubocop.yml"
121
38
  - ".ruby-version"
122
- - ".travis.yml"
39
+ - CHANGELOG.md
123
40
  - CODE_OF_CONDUCT.md
124
41
  - Gemfile
125
42
  - LICENSE.txt
@@ -143,14 +60,15 @@ files:
143
60
  - spec/global/backend/aws_parameter_store_spec.rb
144
61
  - spec/global/backend/gcp_secret_manager_spec.rb
145
62
  - spec/global/configuration_spec.rb
63
+ - spec/global_merge_backends_spec.rb
146
64
  - spec/global_spec.rb
147
- - spec/merge_backends_spec.rb
148
65
  - spec/spec_helper.rb
149
66
  homepage: https://github.com/railsware/global
150
67
  licenses:
151
68
  - MIT
152
- metadata: {}
153
- post_install_message:
69
+ metadata:
70
+ rubygems_mfa_required: 'true'
71
+ post_install_message:
154
72
  rdoc_options: []
155
73
  require_paths:
156
74
  - lib
@@ -158,27 +76,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
158
76
  requirements:
159
77
  - - ">="
160
78
  - !ruby/object:Gem::Version
161
- version: '0'
79
+ version: 3.0.0
162
80
  required_rubygems_version: !ruby/object:Gem::Requirement
163
81
  requirements:
164
82
  - - ">="
165
83
  - !ruby/object:Gem::Version
166
84
  version: '0'
167
85
  requirements: []
168
- rubygems_version: 3.0.3
169
- signing_key:
86
+ rubygems_version: 3.5.22
87
+ signing_key:
170
88
  specification_version: 4
171
89
  summary: Simple way to load your configs from yaml/aws/gcp
172
- test_files:
173
- - spec/files/aws.test.yml
174
- - spec/files/aws.yml
175
- - spec/files/bool_config.yml
176
- - spec/files/nested_config.yml
177
- - spec/files/rspec/config.yml
178
- - spec/files/rspec_config.yml
179
- - spec/global/backend/aws_parameter_store_spec.rb
180
- - spec/global/backend/gcp_secret_manager_spec.rb
181
- - spec/global/configuration_spec.rb
182
- - spec/global_spec.rb
183
- - spec/merge_backends_spec.rb
184
- - spec/spec_helper.rb
90
+ test_files: []
data/.travis.yml DELETED
@@ -1,22 +0,0 @@
1
- language: ruby
2
- os: linux
3
- dist: bionic
4
-
5
- cache:
6
- bundler: true
7
-
8
- rvm:
9
- - 2.4
10
- - 2.5
11
- - 2.6
12
- - 2.7
13
- - ruby-head
14
- - jruby-head
15
-
16
- notifications:
17
- email: false
18
-
19
- matrix:
20
- allow_failures:
21
- - rvm: ruby-head
22
- - rvm: jruby-head
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- RSpec.describe Global do
6
- describe 'merging backends' do
7
- it 'merges data from two backends together' do
8
- backend_alpha = double('backend_alpha')
9
- allow(backend_alpha).to receive(:load).and_return(foo: 'foo', bar: 'bar-alpha')
10
- described_class.backend backend_alpha
11
-
12
- backend_beta = double('backend_beta')
13
- allow(backend_beta).to receive(:load).and_return('bar' => 'bar-beta', 'baz' => 'baz')
14
- described_class.backend backend_beta
15
-
16
- expect(described_class.configuration.to_hash).to eq(
17
- 'foo' => 'foo',
18
- 'bar' => 'bar-beta',
19
- 'baz' => 'baz'
20
- )
21
- end
22
- end
23
- end