sinclair 2.1.1 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +3 -3
  3. data/.rubocop.yml +33 -1
  4. data/.rubocop_todo.yml +13 -1
  5. data/Dockerfile +2 -3
  6. data/Gemfile +17 -0
  7. data/Makefile +6 -0
  8. data/README.md +3 -3
  9. data/lib/sinclair/caster/class_methods.rb +6 -6
  10. data/lib/sinclair/chain_settable.rb +1 -1
  11. data/lib/sinclair/class_methods.rb +7 -6
  12. data/lib/sinclair/config_builder.rb +7 -7
  13. data/lib/sinclair/config_class.rb +3 -3
  14. data/lib/sinclair/config_factory.rb +7 -6
  15. data/lib/sinclair/configurable.rb +5 -5
  16. data/lib/sinclair/env_settable.rb +1 -1
  17. data/lib/sinclair/equals_checker.rb +1 -3
  18. data/lib/sinclair/exception.rb +1 -0
  19. data/lib/sinclair/input_hash.rb +3 -2
  20. data/lib/sinclair/matchers/add_class_method_to.rb +1 -1
  21. data/lib/sinclair/matchers/add_instance_method_to.rb +1 -1
  22. data/lib/sinclair/matchers/base.rb +2 -1
  23. data/lib/sinclair/matchers/change_class_method_on.rb +1 -1
  24. data/lib/sinclair/matchers/change_instance_method_on.rb +1 -1
  25. data/lib/sinclair/method_builder/base.rb +2 -1
  26. data/lib/sinclair/method_definition/block_helper.rb +4 -4
  27. data/lib/sinclair/method_definition/parameter_builder.rb +2 -2
  28. data/lib/sinclair/method_definition/parameter_helper.rb +2 -2
  29. data/lib/sinclair/method_definition.rb +21 -16
  30. data/lib/sinclair/method_definitions.rb +2 -2
  31. data/lib/sinclair/model/builder.rb +2 -2
  32. data/lib/sinclair/model.rb +4 -4
  33. data/lib/sinclair/options/class_methods.rb +0 -2
  34. data/lib/sinclair/options.rb +0 -2
  35. data/lib/sinclair/settable/builder.rb +12 -6
  36. data/lib/sinclair/settable/caster.rb +2 -0
  37. data/lib/sinclair/settable.rb +10 -1
  38. data/lib/sinclair/version.rb +1 -1
  39. data/lib/sinclair.rb +30 -18
  40. data/sinclair.gemspec +3 -20
  41. data/spec/integration/readme/my_class_spec.rb +2 -2
  42. data/spec/integration/readme/sinclair/model_spec.rb +2 -2
  43. data/spec/integration/readme/sinclair/options_spec.rb +1 -1
  44. data/spec/integration/yard/sinclair/add_class_method_spec.rb +2 -2
  45. data/spec/integration/yard/sinclair/caster/cast_spec.rb +2 -2
  46. data/spec/integration/yard/sinclair/caster/cast_with_spec.rb +1 -1
  47. data/spec/integration/yard/sinclair/config_factory_spec.rb +4 -4
  48. data/spec/integration/yard/sinclair/core_ext/object_spec.rb +2 -2
  49. data/spec/lib/sinclair/chain_settable_spec.rb +10 -2
  50. data/spec/lib/sinclair/config_factory_spec.rb +1 -1
  51. data/spec/lib/sinclair/env_settable_spec.rb +4 -0
  52. data/spec/lib/sinclair/equals_checker/reader_spec.rb +1 -1
  53. data/spec/lib/sinclair/matchers/add_class_method_spec.rb +1 -1
  54. data/spec/lib/sinclair/matchers/add_class_method_to_spec.rb +1 -1
  55. data/spec/lib/sinclair/matchers/add_instance_method_spec.rb +1 -1
  56. data/spec/lib/sinclair/matchers/add_instance_method_to_spec.rb +1 -1
  57. data/spec/lib/sinclair/matchers/change_class_method_on_spec.rb +1 -1
  58. data/spec/lib/sinclair/matchers/change_class_method_spec.rb +1 -1
  59. data/spec/lib/sinclair/matchers/change_instance_method_on_spec.rb +1 -1
  60. data/spec/lib/sinclair/matchers/change_instance_method_spec.rb +1 -1
  61. data/spec/lib/sinclair/method_builder/base_spec.rb +1 -1
  62. data/spec/lib/sinclair/method_builder/block_method_builder_spec.rb +1 -1
  63. data/spec/lib/sinclair/method_builder/call_method_builder_spec.rb +1 -1
  64. data/spec/lib/sinclair/method_builder/string_method_builder_spec.rb +1 -1
  65. data/spec/lib/sinclair/method_definition_spec.rb +1 -0
  66. data/spec/lib/sinclair/method_definitions_spec.rb +9 -9
  67. data/spec/lib/sinclair/model_spec.rb +3 -3
  68. data/spec/lib/sinclair/options/class_methods_spec.rb +1 -1
  69. data/spec/lib/sinclair/options_spec.rb +3 -3
  70. data/spec/lib/sinclair/settable/builder_spec.rb +5 -1
  71. data/spec/lib/sinclair/settable/caster_spec.rb +79 -0
  72. data/spec/lib/sinclair/settable_spec.rb +6 -0
  73. data/spec/spec_helper.rb +1 -1
  74. data/spec/support/models/app_client.rb +2 -0
  75. data/spec/support/models/default_valueable.rb +1 -1
  76. data/spec/support/models/env_settings.rb +1 -1
  77. data/spec/support/models/hash_app_client.rb +2 -0
  78. data/spec/support/models/my_app_client.rb +2 -0
  79. data/spec/support/models/non_default_app_client.rb +2 -0
  80. data/spec/support/models/random_generator.rb +1 -1
  81. data/spec/support/shared_examples/model.rb +2 -2
  82. data/spec/support/shared_examples/settable.rb +139 -12
  83. metadata +12 -233
  84. /data/spec/integration/readme/{sinclair/types_of_definition_spec.rb → sinclair_types_of_definition_spec.rb} +0 -0
  85. /data/spec/integration/yard/sinclair/{class_methods/build_spec.rb → class_methods_build_spec.rb} +0 -0
@@ -48,22 +48,22 @@ describe Sinclair::MethodDefinitions do
48
48
  let(:arguments) { %i[attr_reader some_attribute other_attribute] }
49
49
 
50
50
  it do
51
- expect(definitions.add(*arguments, type: type))
51
+ expect(definitions.add(*arguments, type:))
52
52
  .to be_a(Array)
53
53
  end
54
54
 
55
55
  it 'creates a new definition' do
56
- expect(definitions.add(*arguments, type: type).last)
56
+ expect(definitions.add(*arguments, type:).last)
57
57
  .to be_a(Sinclair::MethodDefinition)
58
58
  end
59
59
 
60
60
  it 'creates a new definition of the chosen type' do
61
- expect(definitions.add(*arguments, type: type).last)
61
+ expect(definitions.add(*arguments, type:).last)
62
62
  .to be_a(Sinclair::MethodDefinition::CallDefinition)
63
63
  end
64
64
 
65
65
  it 'initializes it correctly' do
66
- expect { klass.module_eval(&definitions.add(*arguments, type: type).last.code_block) }
66
+ expect { klass.module_eval(&definitions.add(*arguments, type:).last.code_block) }
67
67
  .to add_method(:some_attribute).to(klass)
68
68
  end
69
69
  end
@@ -89,7 +89,7 @@ describe Sinclair::MethodDefinitions do
89
89
  end
90
90
 
91
91
  it 'initializes it correctly' do
92
- expect(definitions.add(method_name, type: type, &block).last.name)
92
+ expect(definitions.add(method_name, type:, &block).last.name)
93
93
  .to eq(method_name)
94
94
  end
95
95
  end
@@ -100,22 +100,22 @@ describe Sinclair::MethodDefinitions do
100
100
  let(:code) { '10' }
101
101
 
102
102
  it do
103
- expect(definitions.add(method_name, code, type: type))
103
+ expect(definitions.add(method_name, code, type:))
104
104
  .to be_a(Array)
105
105
  end
106
106
 
107
107
  it 'creates a new definition' do
108
- expect(definitions.add(method_name, code, type: type).last)
108
+ expect(definitions.add(method_name, code, type:).last)
109
109
  .to be_a(Sinclair::MethodDefinition)
110
110
  end
111
111
 
112
112
  it 'creates a new definition of the chosen type' do
113
- expect(definitions.add(method_name, code, type: type).last)
113
+ expect(definitions.add(method_name, code, type:).last)
114
114
  .to be_a(Sinclair::MethodDefinition::StringDefinition)
115
115
  end
116
116
 
117
117
  it 'initializes it correctly' do
118
- expect(definitions.add(method_name, code, type: type).last.name)
118
+ expect(definitions.add(method_name, code, type:).last.name)
119
119
  .to eq(method_name)
120
120
  end
121
121
  end
@@ -3,7 +3,7 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Sinclair::Model do
6
- subject(:model) { klass.new(name: name) }
6
+ subject(:model) { klass.new(name:) }
7
7
 
8
8
  let(:name) { SecureRandom.hex(10) }
9
9
  let(:attributes) { %i[name] }
@@ -55,7 +55,7 @@ describe Sinclair::Model do
55
55
  end
56
56
 
57
57
  context 'when class is subclass of another model' do
58
- subject(:model) { klass.new(name: name, age: age) }
58
+ subject(:model) { klass.new(name:, age:) }
59
59
 
60
60
  let(:age) { Random.rand(10..20) }
61
61
 
@@ -72,7 +72,7 @@ describe Sinclair::Model do
72
72
  end
73
73
 
74
74
  it 'is initialized with both attributes' do
75
- expect { klass.new(name: name, age: age) }
75
+ expect { klass.new(name:, age:) }
76
76
  .not_to raise_error
77
77
  end
78
78
 
@@ -107,7 +107,7 @@ describe Sinclair::Options::ClassMethods do
107
107
  .to change {
108
108
  klass.invalid_options_in(test_keys)
109
109
  }.from(%i[protocol port invalid])
110
- .to([:invalid])
110
+ .to([:invalid])
111
111
  end
112
112
 
113
113
  it do
@@ -20,7 +20,7 @@ describe Sinclair::Options do
20
20
 
21
21
  context 'when initializing with valid args' do
22
22
  subject(:options) do
23
- klass.new(timeout: timeout, protocol: 'http')
23
+ klass.new(timeout:, protocol: 'http')
24
24
  end
25
25
 
26
26
  let(:timeout) { Random.rand(10..19) }
@@ -44,7 +44,7 @@ describe Sinclair::Options do
44
44
 
45
45
  context 'when initializing subclass with valid args' do
46
46
  subject(:options) do
47
- klass.new(timeout: timeout, protocol: 'http')
47
+ klass.new(timeout:, protocol: 'http')
48
48
  end
49
49
 
50
50
  let(:klass) { Class.new(ConnectionOptions) }
@@ -142,7 +142,7 @@ describe Sinclair::Options do
142
142
  context 'when overriding values with false' do
143
143
  let(:options) { klass.new(protocol: false) }
144
144
 
145
- it { expect(options.protocol).to eq(false) }
145
+ it { expect(options.protocol).to be(false) }
146
146
  end
147
147
  end
148
148
 
@@ -16,7 +16,7 @@ describe Sinclair::Settable::Builder do
16
16
  let(:username) { 'my_login' }
17
17
  let(:password) { Random.rand(10_000).to_s }
18
18
  let(:settings) { %i[username password] }
19
- let(:options) { { prefix: prefix } }
19
+ let(:options) { { prefix: } }
20
20
 
21
21
  let(:builder) do
22
22
  described_class.new(settable, *settings, **options)
@@ -31,6 +31,8 @@ describe Sinclair::Settable::Builder do
31
31
  let(:password_key) { 'PASSWORD' }
32
32
  let(:host_key) { 'HOST' }
33
33
  let(:port_key) { 'PORT' }
34
+ let(:domain_key) { 'DOMAIN' }
35
+ let(:secret_key) { 'SECRET' }
34
36
 
35
37
  it_behaves_like 'settings reading'
36
38
  end
@@ -41,6 +43,8 @@ describe Sinclair::Settable::Builder do
41
43
  let(:password_key) { 'MY_APP_PASSWORD' }
42
44
  let(:host_key) { 'MY_APP_HOST' }
43
45
  let(:port_key) { 'MY_APP_PORT' }
46
+ let(:domain_key) { 'MY_APP_DOMAIN' }
47
+ let(:secret_key) { 'MY_APP_SECRET' }
44
48
 
45
49
  it_behaves_like 'settings reading'
46
50
  end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Sinclair::Settable::Caster do
6
+ describe '.cast' do
7
+ context 'when casting to integer' do
8
+ it 'converts string to integer' do
9
+ expect(described_class.cast('10', :integer)).to eq(10)
10
+ end
11
+
12
+ it 'converts float to integer' do
13
+ expect(described_class.cast(10.5, :integer)).to eq(10)
14
+ end
15
+ end
16
+
17
+ context 'when casting to string' do
18
+ it 'converts integer to string' do
19
+ expect(described_class.cast(10, :string)).to eq('10')
20
+ end
21
+
22
+ it 'converts symbol to string' do
23
+ expect(described_class.cast(:symbol, :string)).to eq('symbol')
24
+ end
25
+ end
26
+
27
+ context 'when casting to float' do
28
+ it 'converts string to float' do
29
+ expect(described_class.cast('10.5', :float)).to eq(10.5)
30
+ end
31
+
32
+ it 'converts integer to float' do
33
+ expect(described_class.cast(10, :float)).to eq(10.0)
34
+ end
35
+ end
36
+
37
+ context 'when casting to seconds' do
38
+ it 'converts string to seconds duration' do
39
+ expect(described_class.cast('300', :seconds)).to eq(300.seconds)
40
+ end
41
+
42
+ it 'converts integer to seconds duration' do
43
+ expect(described_class.cast(60, :seconds)).to eq(60.seconds)
44
+ end
45
+ end
46
+
47
+ context 'when casting to boolean' do
48
+ it 'converts string "true" to boolean true' do
49
+ expect(described_class.cast('true', :boolean)).to be true
50
+ end
51
+
52
+ it 'converts string "TRUE" to boolean true' do
53
+ expect(described_class.cast('TRUE', :boolean)).to be true
54
+ end
55
+
56
+ it 'converts string "false" to boolean false' do
57
+ expect(described_class.cast('false', :boolean)).to be false
58
+ end
59
+
60
+ it 'converts string "FALSE" to boolean false' do
61
+ expect(described_class.cast('FALSE', :boolean)).to be false
62
+ end
63
+
64
+ it 'converts any other string to boolean false' do
65
+ expect(described_class.cast('anything', :boolean)).to be false
66
+ end
67
+
68
+ it 'converts nil to boolean false' do
69
+ expect(described_class.cast(nil, :boolean)).to be false
70
+ end
71
+ end
72
+
73
+ context 'when casting with unknown type' do
74
+ it 'returns the original value' do
75
+ expect(described_class.cast('value', :unknown)).to eq('value')
76
+ end
77
+ end
78
+ end
79
+ end
@@ -13,6 +13,8 @@ describe Sinclair::Settable do
13
13
  let(:password_key) { 'PASSWORD' }
14
14
  let(:host_key) { 'HOST' }
15
15
  let(:port_key) { 'PORT' }
16
+ let(:domain_key) { 'DOMAIN' }
17
+ let(:secret_key) { 'SECRET' }
16
18
 
17
19
  it_behaves_like 'settings reading'
18
20
 
@@ -23,6 +25,8 @@ describe Sinclair::Settable do
23
25
  let(:password_key) { 'MY_APP_PASSWORD' }
24
26
  let(:host_key) { 'MY_APP_HOST' }
25
27
  let(:port_key) { 'MY_APP_PORT' }
28
+ let(:domain_key) { 'MY_APP_DOMAIN' }
29
+ let(:secret_key) { 'MY_APP_SECRET' }
26
30
 
27
31
  it_behaves_like 'settings reading'
28
32
  end
@@ -38,6 +42,8 @@ describe Sinclair::Settable do
38
42
  let(:password_key) { :password }
39
43
  let(:host_key) { :host }
40
44
  let(:port_key) { :port }
45
+ let(:domain_key) { :domain }
46
+ let(:secret_key) { :secret }
41
47
 
42
48
  it_behaves_like 'settings reading' do
43
49
  let(:env_hash) { HashAppClient::HASH }
data/spec/spec_helper.rb CHANGED
@@ -14,7 +14,7 @@ require 'pry-nav'
14
14
 
15
15
  support_files = File.expand_path('spec/support/**/*.rb')
16
16
 
17
- Dir[support_files].sort.each { |file| require file }
17
+ Dir[support_files].each { |file| require file }
18
18
 
19
19
  RSpec.configure do |config|
20
20
  config.run_all_when_everything_filtered = true
@@ -5,4 +5,6 @@ class AppClient
5
5
 
6
6
  with_settings :username, :password, host: 'my-host.com'
7
7
  setting_with_options :port, type: :integer
8
+ setting_with_options :domain, cached: true
9
+ setting_with_options :secret, cached: false
8
10
  end
@@ -5,7 +5,7 @@ require './spec/support/models/default_value_builder'
5
5
  module DefaultValueable
6
6
  def default_reader(*methods, value:, accept_nil: false)
7
7
  DefaultValueBuilder.new(
8
- self, value: value, accept_nil: accept_nil
8
+ self, value:, accept_nil:
9
9
  ).add_default_values(*methods)
10
10
  end
11
11
  end
@@ -13,7 +13,7 @@ module EnvSettings
13
13
  env_key = [env_prefix, method_name].compact.join('_').upcase
14
14
 
15
15
  builder.add_class_method(method_name, cached: true) do
16
- ENV[env_key]
16
+ ENV.fetch(env_key, nil)
17
17
  end
18
18
 
19
19
  builder.build
@@ -11,4 +11,6 @@ class HashAppClient
11
11
 
12
12
  with_settings :username, :password, host: 'my-host.com'
13
13
  setting_with_options :port, type: :integer
14
+ setting_with_options :domain, cached: true
15
+ setting_with_options :secret, cached: false
14
16
  end
@@ -7,4 +7,6 @@ class MyAppClient
7
7
 
8
8
  with_settings :username, :password, host: 'my-host.com'
9
9
  setting_with_options :port, type: :integer
10
+ setting_with_options :domain, cached: true
11
+ setting_with_options :secret, cached: false
10
12
  end
@@ -5,4 +5,6 @@ class NonDefaultAppClient
5
5
 
6
6
  with_settings :username, :password, :host
7
7
  setting_with_options :port, type: :integer
8
+ setting_with_options :domain, cached: true
9
+ setting_with_options :secret, cached: false
8
10
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class RandomGenerator
4
- KAPA = 3.9 + Random.rand / 10.0
4
+ KAPA = 3.9 + (Random.rand / 10.0)
5
5
 
6
6
  class << self
7
7
  def rand
@@ -18,7 +18,7 @@ shared_examples 'sinclair model building' do
18
18
  end
19
19
 
20
20
  it 'returns a new class with a comparable that finds matches' do
21
- expect(model).to eq(klass.new(name: name))
21
+ expect(model).to eq(klass.new(name:))
22
22
  end
23
23
 
24
24
  it 'returns a new class with a comparable that find misses' do
@@ -48,7 +48,7 @@ shared_examples 'sinclair model building' do
48
48
  let(:options) { { comparable: false } }
49
49
 
50
50
  it 'returns a new class without comparable' do
51
- expect(model).not_to eq(klass.new(name: name))
51
+ expect(model).not_to eq(klass.new(name:))
52
52
  end
53
53
  end
54
54
 
@@ -4,6 +4,11 @@ shared_examples 'settings reading' do
4
4
  let(:env_hash) { ENV }
5
5
 
6
6
  context 'when the key is not set' do
7
+ after do
8
+ env_hash.delete(username_key)
9
+ env_hash.delete(password_key)
10
+ end
11
+
7
12
  it 'retrieves username from env' do
8
13
  expect(settable.username).to be_nil
9
14
  end
@@ -11,6 +16,16 @@ shared_examples 'settings reading' do
11
16
  it 'retrieves password from env' do
12
17
  expect(settable.password).to be_nil
13
18
  end
19
+
20
+ it 'cache username from env' do
21
+ expect { env_hash[username_key] = SecureRandom.hex }
22
+ .not_to(change(settable, :username))
23
+ end
24
+
25
+ it 'cache password from env' do
26
+ expect { env_hash[password_key] = SecureRandom.hex }
27
+ .not_to(change(settable, :password))
28
+ end
14
29
  end
15
30
 
16
31
  context 'when the key is set' do
@@ -31,14 +46,35 @@ shared_examples 'settings reading' do
31
46
  it 'retrieves password from env' do
32
47
  expect(settable.password).to eq(password)
33
48
  end
49
+
50
+ it 'cache username from env' do
51
+ expect { env_hash[username_key] = SecureRandom.hex }
52
+ .not_to(change(settable, :username))
53
+ end
54
+
55
+ it 'cache password from env' do
56
+ expect { env_hash[password_key] = SecureRandom.hex }
57
+ .not_to(change(settable, :password))
58
+ end
34
59
  end
35
60
 
36
61
  context 'when defining defaults' do
37
62
  let(:settings) { %i[host] }
38
- let(:options) { { prefix: prefix, default: 'my-host.com' } }
63
+ let(:options) { { prefix:, default: 'my-host.com' } }
64
+
65
+ after do
66
+ env_hash.delete(host_key)
67
+ end
68
+
69
+ context 'when not setting the env variable' do
70
+ it 'returns default value' do
71
+ expect(settable.host).to eq('my-host.com')
72
+ end
39
73
 
40
- it 'returns default value' do
41
- expect(settable.host).to eq('my-host.com')
74
+ it 'caches default value' do
75
+ expect { env_hash[host_key] = SecureRandom.hex }
76
+ .not_to(change(settable, :host))
77
+ end
42
78
  end
43
79
 
44
80
  context 'when setting the env variable' do
@@ -48,25 +84,36 @@ shared_examples 'settings reading' do
48
84
  env_hash[host_key] = other_host
49
85
  end
50
86
 
51
- after do
52
- env_hash.delete(host_key)
53
- end
54
-
55
87
  it 'retrieves host from env' do
56
88
  expect(settable.host).to eq(other_host)
57
89
  end
90
+
91
+ it 'caches env value' do
92
+ expect { env_hash[host_key] = SecureRandom.hex }
93
+ .not_to(change(settable, :host))
94
+ end
58
95
  end
59
96
  end
60
97
 
61
98
  context 'when defining a type' do
62
99
  let(:settings) { %i[port] }
63
- let(:options) { { prefix: prefix, type: :integer } }
100
+ let(:options) { { prefix:, type: :integer } }
64
101
  let(:port) { Random.rand(10..100) }
102
+ let(:new_port) { Random.rand(1000..10_000) }
103
+
104
+ after do
105
+ env_hash.delete(port_key)
106
+ end
65
107
 
66
108
  context 'when the key is not set' do
67
109
  it 'retrieves port and cast to string' do
68
110
  expect(settable.port).to be_nil
69
111
  end
112
+
113
+ it 'caches port as nil' do
114
+ expect { env_hash[port_key] = new_port.to_s }
115
+ .not_to(change(settable, :port))
116
+ end
70
117
  end
71
118
 
72
119
  context 'when the key is set' do
@@ -74,13 +121,93 @@ shared_examples 'settings reading' do
74
121
  env_hash[port_key] = port.to_s
75
122
  end
76
123
 
77
- after do
78
- env_hash.delete(port_key)
79
- end
80
-
81
124
  it 'retrieves port and cast to string' do
82
125
  expect(settable.port).to eq(port)
83
126
  end
127
+
128
+ it 'caches port as integer' do
129
+ expect { env_hash[port_key] = new_port.to_s }
130
+ .not_to(change(settable, :port))
131
+ end
132
+ end
133
+ end
134
+
135
+ context 'when defining cache type as true' do
136
+ let(:settings) { %i[domain] }
137
+ let(:options) { { prefix:, cached: true } }
138
+ let(:options_hash) { options }
139
+ let(:domain) { 'example.com' }
140
+ let(:new_domain) { 'new-example.com' }
141
+
142
+ after do
143
+ env_hash.delete(domain_key)
144
+ end
145
+
146
+ context 'when the key is not set' do
147
+ it 'retrieves domain and cast to string' do
148
+ expect(settable.domain).to be_nil
149
+ end
150
+
151
+ it 'does not caches domain as nil' do
152
+ expect { env_hash[domain_key] = new_domain.to_s }
153
+ .to change(settable, :domain)
154
+ .from(nil).to(new_domain)
155
+ end
156
+ end
157
+
158
+ context 'when the key is set' do
159
+ before do
160
+ env_hash[domain_key] = domain.to_s
161
+ end
162
+
163
+ it 'retrieves domain and cast to string' do
164
+ expect(settable.domain).to eq(domain)
165
+ end
166
+
167
+ it 'caches domain as string' do
168
+ expect { env_hash[domain_key] = new_domain }
169
+ .not_to(change(settable, :domain))
170
+ end
171
+ end
172
+ end
173
+
174
+ context 'when defining cache false' do
175
+ let(:settings) { %i[secret] }
176
+ let(:options) { { prefix:, cached: false } }
177
+ let(:options_hash) { options }
178
+ let(:secret) { 'my_secret' }
179
+ let(:new_secret) { 'new_secret' }
180
+
181
+ after do
182
+ env_hash.delete(secret_key)
183
+ end
184
+
185
+ context 'when the key is not set' do
186
+ it 'retrieves secret and cast to string' do
187
+ expect(settable.secret).to be_nil
188
+ end
189
+
190
+ it 'does not caches secret as nil' do
191
+ expect { env_hash[secret_key] = new_secret.to_s }
192
+ .to change(settable, :secret)
193
+ .from(nil).to(new_secret)
194
+ end
195
+ end
196
+
197
+ context 'when the key is set' do
198
+ before do
199
+ env_hash[secret_key] = secret.to_s
200
+ end
201
+
202
+ it 'retrieves secret and cast to string' do
203
+ expect(settable.secret).to eq(secret)
204
+ end
205
+
206
+ it 'does not caches secret' do
207
+ expect { env_hash[secret_key] = new_secret }
208
+ .to change(settable, :secret)
209
+ .from(secret).to(new_secret)
210
+ end
84
211
  end
85
212
  end
86
213
  end