global 2.0.0 → 3.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: 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