qonfig 0.24.0 → 0.27.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (154) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +62 -0
  3. data/.gitignore +0 -2
  4. data/.rubocop.yml +19 -1
  5. data/CHANGELOG.md +53 -0
  6. data/Gemfile +2 -0
  7. data/Gemfile.lock +129 -0
  8. data/LICENSE.txt +1 -1
  9. data/README.md +115 -5
  10. data/Rakefile +0 -1
  11. data/gemfiles/with_external_deps.gemfile +2 -0
  12. data/gemfiles/with_external_deps.gemfile.lock +123 -0
  13. data/gemfiles/without_external_deps.gemfile.lock +113 -0
  14. data/lib/qonfig/commands/definition/load_from_env/value_converter.rb +2 -0
  15. data/lib/qonfig/commands/definition/load_from_env.rb +2 -0
  16. data/lib/qonfig/data_set.rb +3 -0
  17. data/lib/qonfig/imports/direct_key.rb +8 -2
  18. data/lib/qonfig/imports/mappings.rb +8 -2
  19. data/lib/qonfig/loaders/basic.rb +2 -0
  20. data/lib/qonfig/loaders/json.rb +2 -1
  21. data/lib/qonfig/loaders/yaml.rb +3 -1
  22. data/lib/qonfig/plugins/pretty_print/requirements.rb +3 -0
  23. data/lib/qonfig/plugins/pretty_print.rb +1 -0
  24. data/lib/qonfig/plugins/toml/commands/definition/expose_toml.rb +3 -3
  25. data/lib/qonfig/plugins/vault/commands/definition/expose_vault.rb +142 -0
  26. data/lib/qonfig/plugins/vault/commands/definition/load_from_vault.rb +53 -0
  27. data/lib/qonfig/plugins/vault/dsl.rb +35 -0
  28. data/lib/qonfig/plugins/vault/errors.rb +9 -0
  29. data/lib/qonfig/plugins/vault/loaders/vault.rb +74 -0
  30. data/lib/qonfig/plugins/vault.rb +24 -0
  31. data/lib/qonfig/plugins.rb +1 -0
  32. data/lib/qonfig/settings/key_matcher.rb +3 -1
  33. data/lib/qonfig/settings.rb +83 -22
  34. data/lib/qonfig/uploaders/base.rb +2 -0
  35. data/lib/qonfig/uploaders/yaml.rb +2 -0
  36. data/lib/qonfig/version.rb +1 -1
  37. data/lib/qonfig.rb +4 -1
  38. data/qonfig.gemspec +9 -8
  39. data/sig/.keep +0 -0
  40. data/spec/artifacts/.keep +0 -0
  41. data/spec/features/clear_options_spec.rb +92 -0
  42. data/spec/features/compacted_config_spec.rb +308 -0
  43. data/spec/features/composition_spec.rb +207 -0
  44. data/spec/features/config_definition_and_representation_spec.rb +535 -0
  45. data/spec/features/definition_order_spec.rb +69 -0
  46. data/spec/features/dig_functionality_spec.rb +47 -0
  47. data/spec/features/dot_notation_spec.rb +159 -0
  48. data/spec/features/export_settings_spec.rb +138 -0
  49. data/spec/features/expose_json_spec.rb +281 -0
  50. data/spec/features/expose_self/format_option_dynamic_spec.rb +69 -0
  51. data/spec/features/expose_self/format_option_json_spec.rb +74 -0
  52. data/spec/features/expose_self/format_option_unsupported_spec.rb +27 -0
  53. data/spec/features/expose_self/format_option_yaml_spec.rb +77 -0
  54. data/spec/features/expose_self_spec.rb +97 -0
  55. data/spec/features/expose_yaml_spec.rb +263 -0
  56. data/spec/features/freeze_state_spec.rb +122 -0
  57. data/spec/features/get_config_keys_spec.rb +62 -0
  58. data/spec/features/get_config_values_spec.rb +41 -0
  59. data/spec/features/has_a_key_spec.rb +48 -0
  60. data/spec/features/import_settings_spec.rb +323 -0
  61. data/spec/features/indifferent_access_spec.rb +57 -0
  62. data/spec/features/inheritance_spec.rb +110 -0
  63. data/spec/features/instantiation_without_class_definition_spec.rb +59 -0
  64. data/spec/features/iteration_over_setting_keys_spec.rb +48 -0
  65. data/spec/features/load_from_env_spec.rb +240 -0
  66. data/spec/features/load_from_json_spec.rb +97 -0
  67. data/spec/features/load_from_self/format_option_json_spec.rb +31 -0
  68. data/spec/features/load_from_self/format_option_unsupported_spec.rb +27 -0
  69. data/spec/features/load_from_self/format_option_yaml_spec.rb +49 -0
  70. data/spec/features/load_from_self/with_erb_instructions_spec.rb +33 -0
  71. data/spec/features/load_from_self/with_hash_like_data_representation_spec.rb +66 -0
  72. data/spec/features/load_from_self/with_non_hash_like_data_representation_spec.rb +19 -0
  73. data/spec/features/load_from_self/without_end_data_spec.rb +11 -0
  74. data/spec/features/load_from_yaml_spec.rb +110 -0
  75. data/spec/features/load_setting_values_from_file/by_instance_method_examples.rb +171 -0
  76. data/spec/features/load_setting_values_from_file/by_macros_examples.rb +165 -0
  77. data/spec/features/load_setting_values_from_file/load_from_json_spec.rb +21 -0
  78. data/spec/features/load_setting_values_from_file/load_from_self/json_format/end_data_with_env_spec.rb +100 -0
  79. data/spec/features/load_setting_values_from_file/load_from_self/json_format/with_end_data_spec.rb +129 -0
  80. data/spec/features/load_setting_values_from_file/load_from_self/json_format/with_incorrect_end_data_spec.rb +34 -0
  81. data/spec/features/load_setting_values_from_file/load_from_self/json_format/without_end_data_spec.rb +65 -0
  82. data/spec/features/load_setting_values_from_file/load_from_self/yaml_format/end_data_with_env_spec.rb +94 -0
  83. data/spec/features/load_setting_values_from_file/load_from_self/yaml_format/with_end_data_spec.rb +126 -0
  84. data/spec/features/load_setting_values_from_file/load_from_self/yaml_format/with_incorrect_end_data_spec.rb +32 -0
  85. data/spec/features/load_setting_values_from_file/load_from_self/yaml_format/without_end_data_spec.rb +65 -0
  86. data/spec/features/load_setting_values_from_file/load_from_yaml_spec.rb +21 -0
  87. data/spec/features/load_setting_values_from_file/shared_behavior_spec.rb +33 -0
  88. data/spec/features/mixin_spec.rb +387 -0
  89. data/spec/features/non_redefineable_core_methods_spec.rb +29 -0
  90. data/spec/features/plugins/pretty_print_spec.rb +86 -0
  91. data/spec/features/plugins/toml/expose_self/format_option_toml_spec.rb +71 -0
  92. data/spec/features/plugins/toml/expose_toml_spec.rb +221 -0
  93. data/spec/features/plugins/toml/load_from_self/format_option_toml_spec.rb +27 -0
  94. data/spec/features/plugins/toml/load_from_toml_spec.rb +109 -0
  95. data/spec/features/plugins/toml/load_setting_values_from_file/load_from_toml_spec.rb +27 -0
  96. data/spec/features/plugins/toml/load_setting_values_from_file/load_toml_from_self/end_data_with_env_spec.rb +95 -0
  97. data/spec/features/plugins/toml/load_setting_values_from_file/load_toml_from_self/with_end_data_spec.rb +125 -0
  98. data/spec/features/plugins/toml/load_setting_values_from_file/load_toml_from_self/with_incorrect_end_data_spec.rb +34 -0
  99. data/spec/features/plugins/toml/load_setting_values_from_file/load_toml_from_self/without_end_data_spec.rb +65 -0
  100. data/spec/features/plugins/toml/load_setting_values_from_file/shared_behavior_spec.rb +34 -0
  101. data/spec/features/plugins/toml/save_to_toml_spec.rb +149 -0
  102. data/spec/features/plugins/vault/expose_vault_spec.rb +117 -0
  103. data/spec/features/plugins/vault/load_from_vault_spec.rb +80 -0
  104. data/spec/features/plugins_spec.rb +89 -0
  105. data/spec/features/reload_spec.rb +75 -0
  106. data/spec/features/run_code_with_temporary_settings_spec.rb +104 -0
  107. data/spec/features/save_to_file/save_to_json_spec.rb +157 -0
  108. data/spec/features/save_to_file/save_to_yaml_spec.rb +189 -0
  109. data/spec/features/settings_as_predicates_spec.rb +47 -0
  110. data/spec/features/settings_redefinition_spec.rb +30 -0
  111. data/spec/features/slice_functionality_spec.rb +69 -0
  112. data/spec/features/subset_functionality_spec.rb +49 -0
  113. data/spec/features/validation_spec.rb +919 -0
  114. data/spec/fixtures/array_settings.yml +3 -0
  115. data/spec/fixtures/expose_json/incompatible_root_structure.json +6 -0
  116. data/spec/fixtures/expose_json/incompatible_structure.json +4 -0
  117. data/spec/fixtures/expose_json/project.development.json +7 -0
  118. data/spec/fixtures/expose_json/project.json +30 -0
  119. data/spec/fixtures/expose_json/project.production.json +7 -0
  120. data/spec/fixtures/expose_json/project.staging.json +7 -0
  121. data/spec/fixtures/expose_json/project.test.json +7 -0
  122. data/spec/fixtures/expose_yaml/incompatible_structure.yml +2 -0
  123. data/spec/fixtures/expose_yaml/project.development.yml +4 -0
  124. data/spec/fixtures/expose_yaml/project.production.yml +4 -0
  125. data/spec/fixtures/expose_yaml/project.staging.yml +4 -0
  126. data/spec/fixtures/expose_yaml/project.test.yml +4 -0
  127. data/spec/fixtures/expose_yaml/project.yml +25 -0
  128. data/spec/fixtures/json_array_sample.json +14 -0
  129. data/spec/fixtures/json_object_sample.json +9 -0
  130. data/spec/fixtures/json_with_empty_object.json +6 -0
  131. data/spec/fixtures/json_with_erb.json +6 -0
  132. data/spec/fixtures/plugins/toml/expose_toml/project.development.toml +4 -0
  133. data/spec/fixtures/plugins/toml/expose_toml/project.production.toml +4 -0
  134. data/spec/fixtures/plugins/toml/expose_toml/project.staging.toml +4 -0
  135. data/spec/fixtures/plugins/toml/expose_toml/project.test.toml +4 -0
  136. data/spec/fixtures/plugins/toml/expose_toml/project.toml +27 -0
  137. data/spec/fixtures/plugins/toml/mini_file.toml +6 -0
  138. data/spec/fixtures/plugins/toml/toml_sample_with_all_types.toml +72 -0
  139. data/spec/fixtures/plugins/toml/values_file/with_env.toml +13 -0
  140. data/spec/fixtures/plugins/toml/values_file/without_env.toml +6 -0
  141. data/spec/fixtures/rubocop_settings.yml +12 -0
  142. data/spec/fixtures/shared_settings_with_aliases.yml +10 -0
  143. data/spec/fixtures/travis_settings.yml +6 -0
  144. data/spec/fixtures/values_file/with_env.json +19 -0
  145. data/spec/fixtures/values_file/with_env.yml +17 -0
  146. data/spec/fixtures/values_file/without_env.json +8 -0
  147. data/spec/fixtures/values_file/without_env.yml +5 -0
  148. data/spec/fixtures/with_empty_hash.yml +4 -0
  149. data/spec/fixtures/with_erb_instructions.yml +3 -0
  150. data/spec/spec_helper.rb +46 -0
  151. data/spec/support/meta_scopes.rb +20 -0
  152. data/spec/support/spec_support.rb +42 -0
  153. metadata +181 -15
  154. data/.travis.yml +0 -47
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe 'Get config keys' do
4
+ let(:config) do
5
+ Qonfig::DataSet.build do
6
+ setting :credentials do
7
+ setting :social do
8
+ setting :service, 'instagram'
9
+ setting :login, '0exp'
10
+ end
11
+
12
+ setting :admin do
13
+ setting :enabled, true
14
+ end
15
+ end
16
+
17
+ setting :server do
18
+ setting :type, 'cloud'
19
+ setting :options do
20
+ setting :os, 'CentOS'
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ specify '(#keys) existing keys' do
27
+ expect(config.keys).to contain_exactly(
28
+ 'credentials.social.service',
29
+ 'credentials.social.login',
30
+ 'credentials.admin.enabled',
31
+ 'server.type',
32
+ 'server.options.os'
33
+ )
34
+ end
35
+
36
+ specify '(#keys) all key variants' do
37
+ expect(config.keys(all_variants: true)).to contain_exactly(
38
+ 'credentials',
39
+ 'credentials.social',
40
+ 'credentials.social.service',
41
+ 'credentials.social.login',
42
+ 'credentials.admin',
43
+ 'credentials.admin.enabled',
44
+ 'server',
45
+ 'server.type',
46
+ 'server.options',
47
+ 'server.options.os'
48
+ )
49
+ end
50
+
51
+ specify '(#root_keys) only root keys' do
52
+ expect(config.keys(only_root: true)).to contain_exactly(
53
+ 'credentials',
54
+ 'server'
55
+ )
56
+
57
+ expect(config.root_keys).to contain_exactly(
58
+ 'credentials',
59
+ 'server'
60
+ )
61
+ end
62
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe 'Get config values' do
4
+ subject(:config) do
5
+ Qonfig::DataSet.build do
6
+ setting :some_nested_setting do
7
+ setting :username, 'your_cool_name_here'
8
+ setting :password, 'secure_password'
9
+ end
10
+
11
+ setting :role, 'cool guy'
12
+ end.settings
13
+ end
14
+
15
+ describe '#[]' do
16
+ it 'properly gets value by value' do
17
+ expect(config[:some_nested_setting][:username]).to eq('your_cool_name_here')
18
+ expect(config[:some_nested_setting][:password]).to eq('secure_password')
19
+ expect(config[:role]).to eq('cool guy')
20
+ end
21
+
22
+ context 'with key path' do
23
+ it 'properly gets value' do
24
+ expect(config[:some_nested_setting, :username]).to eq('your_cool_name_here')
25
+ expect(config[:some_nested_setting, :password]).to eq('secure_password')
26
+ end
27
+ end
28
+
29
+ context "when setting doesn't exist" do
30
+ it 'raises error' do
31
+ expect { config[:some_nested_setting, :kek] }.to raise_error(Qonfig::UnknownSettingError)
32
+ end
33
+ end
34
+
35
+ context 'when zero arguments passed' do
36
+ it 'raises error' do
37
+ expect { config[] }.to raise_error(Qonfig::ArgumentError)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe 'Has a key? (option? / setting?)' do
4
+ specify 'setting key existence checker' do
5
+ config = Qonfig::DataSet.build do
6
+ setting :credentials do
7
+ setting :user, 'D@iVeR'
8
+ setting :password, 'test123'
9
+ end
10
+ end
11
+
12
+ # root key
13
+ expect(config.key?('credentials')).to eq(true)
14
+ expect(config.key?(:credentials)).to eq(true)
15
+
16
+ expect(config.option?('credentials')).to eq(true)
17
+ expect(config.option?(:credentials)).to eq(true)
18
+
19
+ expect(config.setting?('credentials')).to eq(true)
20
+ expect(config.setting?(:credentials)).to eq(true)
21
+
22
+ # deeply nested key (with mixed types of params)
23
+ expect(config.key?('credentials', :user)).to eq(true)
24
+ expect(config.key?(:credentials, 'user')).to eq(true)
25
+ expect(config.key?(:credentials, :user)).to eq(true)
26
+
27
+ expect(config.option?('credentials', :user)).to eq(true)
28
+ expect(config.option?(:credentials, 'user')).to eq(true)
29
+ expect(config.option?(:credentials, :user)).to eq(true)
30
+
31
+ expect(config.setting?('credentials', :user)).to eq(true)
32
+ expect(config.setting?(:credentials, 'user')).to eq(true)
33
+ expect(config.setting?(:credentials, :user)).to eq(true)
34
+
35
+ # nonexited key
36
+ expect(config.key?(:user, :password)).to eq(false)
37
+ expect(config.key?('options')).to eq(false)
38
+
39
+ expect(config.option?(:user, :password)).to eq(false)
40
+ expect(config.option?('options')).to eq(false)
41
+
42
+ expect(config.setting?(:user, :password)).to eq(false)
43
+ expect(config.setting?('options')).to eq(false)
44
+
45
+ # incorrect key type
46
+ expect { config.setting?(Object.new) }.to raise_error(Qonfig::ArgumentError)
47
+ end
48
+ end
@@ -0,0 +1,323 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe 'Import settings as access methods to a class' do
4
+ let(:config) do
5
+ Qonfig::DataSet.build do
6
+ setting :credentials do
7
+ setting :admin, true
8
+ setting :login, 'D@iVeR'
9
+ setting :password, 'test123'
10
+ end
11
+
12
+ setting :job_que do
13
+ setting :adapter, :sidekiq
14
+ setting :options do
15
+ setting :server, 'cloud'
16
+ setting :auto_run, true
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ before { stub_const('AppConfig', config) }
23
+
24
+ specify 'empty import does nothing' do
25
+ expect do
26
+ Class.new do
27
+ include Qonfig::Imports
28
+ import_settings(AppConfig, '#')
29
+ end
30
+ end.not_to raise_error
31
+
32
+ expect do
33
+ Class.new do
34
+ include Qonfig::Imports
35
+ import_settings(AppConfig, '*')
36
+ end
37
+ end.not_to raise_error
38
+ end
39
+
40
+ specify 'each required setting is imported as an instance method with access to sliced value' do
41
+ class SimpleImportCheckApp
42
+ include Qonfig::Imports
43
+
44
+ import_settings(AppConfig, 'credentials.login', 'job_que.options')
45
+ end
46
+
47
+ app_with_configs = SimpleImportCheckApp.new
48
+
49
+ # NOTE: new methods
50
+ expect(app_with_configs).to respond_to(:login)
51
+ expect(app_with_configs).to respond_to(:options)
52
+
53
+ # NOTE: get config values
54
+ expect(app_with_configs.login).to eq('D@iVeR')
55
+ expect(app_with_configs.options).to match('server' => 'cloud', 'auto_run' => true)
56
+
57
+ # NOTE: change config options and try to get them from app_with_config again
58
+ AppConfig.configure do |config|
59
+ config.credentials.login = '0exp'
60
+ config.job_que.options.server = 'localhost'
61
+ config.job_que.options.auto_run = false
62
+ end
63
+
64
+ # NOTE: check cahnged configs
65
+ expect(app_with_configs.login).to eq('0exp')
66
+ expect(app_with_configs.options).to match('server' => 'localhost', 'auto_run' => false)
67
+
68
+ # NOTE: only att_readers are generated by default
69
+ expect { app_with_configs.login = 'test123' }.to raise_error(NoMethodError)
70
+ expect { app_with_configs.options = 'test123' }.to raise_error(NoMethodError)
71
+
72
+ # NOTE: check that original values isnt changed after NoMethodError exception
73
+ expect(app_with_configs.login).to eq('0exp')
74
+ expect(app_with_configs.options).to match('server' => 'localhost', 'auto_run' => false)
75
+ end
76
+
77
+ specify 'support for predicates' do
78
+ class ImportPredicatesCheck
79
+ include Qonfig::Imports
80
+
81
+ # NOTE: without prefix
82
+ import_settings(AppConfig, 'credentials.*', accessor: true)
83
+
84
+ # NOTE: with prefix
85
+ import_settings(AppConfig, 'job_que.options.*', prefix: 'config_', accessor: true)
86
+
87
+ # NOTE: and mappings
88
+ import_settings(AppConfig, mappings: { queue_engine: 'job_que.adapter' }, accessor: true)
89
+ end
90
+
91
+ app_with_predicates = ImportPredicatesCheck.new
92
+
93
+ expect(app_with_predicates.admin?).to eq(true)
94
+ expect(app_with_predicates.login?).to eq(true)
95
+ expect(app_with_predicates.password?).to eq(true)
96
+ expect(app_with_predicates.config_server?).to eq(true)
97
+ expect(app_with_predicates.config_auto_run?).to eq(true)
98
+ expect(app_with_predicates.queue_engine?).to eq(true)
99
+
100
+ app_with_predicates.config_server = nil
101
+ app_with_predicates.admin = false
102
+ app_with_predicates.queue_engine = nil
103
+
104
+ expect(app_with_predicates.config_server?).to eq(false)
105
+ expect(app_with_predicates.admin?).to eq(false)
106
+ expect(app_with_predicates.queue_engine?).to eq(false)
107
+
108
+ app_with_predicates.config_server = 'yandex'
109
+ app_with_predicates.admin = true
110
+ app_with_predicates.queue_engine = :delayed_job
111
+
112
+ expect(app_with_predicates.config_server?).to eq(true)
113
+ expect(app_with_predicates.admin?).to eq(true)
114
+ expect(app_with_predicates.queue_engine?).to eq(true)
115
+ end
116
+
117
+ specify 'attr_writers (config muatators)' do
118
+ class AttrAccessorImportCheckApp
119
+ include Qonfig::Imports
120
+
121
+ import_settings(
122
+ AppConfig,
123
+ 'credentials.login',
124
+ mappings: { job_opts: 'job_que.options' },
125
+ accessor: true
126
+ )
127
+ end
128
+
129
+ app_with_configs = AttrAccessorImportCheckApp.new
130
+
131
+ # NOTE: you can mutate config settings via imported attr_writers
132
+ app_with_configs.login = 'D@iVeR'
133
+
134
+ # NOTE: check that original config was changed
135
+ expect(AppConfig.settings.credentials.login).to eq('D@iVeR')
136
+
137
+ # NOTE: check that reader returns new value
138
+ expect(app_with_configs.login).to eq('D@iVeR')
139
+
140
+ # NOTE: some mutators can be ambiguous - be careful :thinking:
141
+ expect { app_with_configs.job_opts = 'test' }.to raise_error(Qonfig::AmbiguousSettingValueError)
142
+ end
143
+
144
+ specify 'you can prefix imported methods' do
145
+ class PrefixImportCheckApp
146
+ include Qonfig::Imports
147
+
148
+ import_settings(AppConfig, 'credentials.password', 'credentials.login', prefix: 'config_')
149
+ end
150
+
151
+ app_with_configs = PrefixImportCheckApp.new
152
+
153
+ expect(app_with_configs).to respond_to(:config_login)
154
+ expect(app_with_configs).to respond_to(:config_password)
155
+
156
+ expect(app_with_configs.config_login).to eq('D@iVeR')
157
+ expect(app_with_configs.config_password).to eq('test123')
158
+ end
159
+
160
+ specify 'you can define your own method name for each imported setting' do
161
+ class ImportWithMappingsApp
162
+ include Qonfig::Imports
163
+
164
+ # NOTE: without prefix
165
+ import_settings(AppConfig, mappings: {
166
+ user_password: 'credentials.password',
167
+ user_login: 'credentials.login',
168
+ job_adapter: 'job_que.adapter'
169
+ })
170
+
171
+ # NOTE: with prefix
172
+ import_settings(
173
+ AppConfig,
174
+ mappings: { job_server: 'job_que.options.server' },
175
+ prefix: 'config_'
176
+ )
177
+ end
178
+
179
+ app_with_configs = ImportWithMappingsApp.new
180
+
181
+ expect(app_with_configs).to respond_to(:user_password)
182
+ expect(app_with_configs).to respond_to(:user_login)
183
+ expect(app_with_configs).to respond_to(:job_adapter)
184
+ expect(app_with_configs).to respond_to(:config_job_server)
185
+
186
+ expect(app_with_configs.user_password).to eq('test123')
187
+ expect(app_with_configs.user_login).to eq('D@iVeR')
188
+ expect(app_with_configs.job_adapter).to eq(:sidekiq)
189
+ expect(app_with_configs.config_job_server).to eq('cloud')
190
+
191
+ # NOTE: change cofnigs and check that each new method returns the real config value
192
+ AppConfig.configure do |config|
193
+ config.credentials.password = 'tratata123'
194
+ config.credentials.login = '0exp'
195
+ config.job_que.adapter = :resque
196
+ config.job_que.options.server = 'aws'
197
+ end
198
+
199
+ expect(app_with_configs.user_password).to eq('tratata123')
200
+ expect(app_with_configs.user_login).to eq('0exp')
201
+ expect(app_with_configs.job_adapter).to eq(:resque)
202
+ expect(app_with_configs.config_job_server).to eq('aws')
203
+ end
204
+
205
+ specify 'you can mix explicit keys, mappings and prefix' do
206
+ class MixedImportCheckApp
207
+ include Qonfig::Imports
208
+
209
+ import_settings(
210
+ AppConfig,
211
+ 'credentials', 'job_que.options', # simple keys
212
+ mappings: { passwd: 'credentials.password', admn: 'credentials.admin' }, # mappings
213
+ prefix: 'config_' # and prefix
214
+ )
215
+ end
216
+
217
+ app_with_configs = MixedImportCheckApp.new
218
+
219
+ expect(app_with_configs).to respond_to(:config_passwd)
220
+ expect(app_with_configs).to respond_to(:config_admn)
221
+ expect(app_with_configs).to respond_to(:config_credentials)
222
+ expect(app_with_configs).to respond_to(:config_options)
223
+
224
+ expect(app_with_configs.config_passwd).to eq('test123')
225
+ expect(app_with_configs.config_admn).to eq(true)
226
+ expect(app_with_configs.config_credentials).to match(
227
+ 'admin' => true,
228
+ 'login' => 'D@iVeR',
229
+ 'password' => 'test123'
230
+ )
231
+ expect(app_with_configs.config_options).to eq(
232
+ 'server' => 'cloud',
233
+ 'auto_run' => true
234
+ )
235
+ end
236
+
237
+ specify 'raw setting import (Qonfig::Settings object - or <value>)' do
238
+ # NOTE: default non-raw import (import nested settings as hashes)
239
+ class NonRawImportCheckApp
240
+ include Qonfig::Imports
241
+ import_settings(AppConfig, 'job_que', mappings: { creds: 'credentials' }, raw: false)
242
+ end
243
+
244
+ app_with_configs = NonRawImportCheckApp.new
245
+
246
+ expect(app_with_configs).to respond_to(:job_que)
247
+ expect(app_with_configs).to respond_to(:creds)
248
+ expect(app_with_configs.creds).to be_a(Hash)
249
+ expect(app_with_configs.job_que).to be_a(Hash)
250
+ expect(app_with_configs.creds).to match(
251
+ 'admin' => true,
252
+ 'login' => 'D@iVeR',
253
+ 'password' => 'test123'
254
+ )
255
+ expect(app_with_configs.job_que).to match(
256
+ 'adapter' => :sidekiq,
257
+ 'options' => {
258
+ 'server' => 'cloud',
259
+ 'auto_run' => true
260
+ }
261
+ )
262
+
263
+ # NOTE: raw import (import nested settings as Qonfig::Settings objects)
264
+ class RawImportCheckApp
265
+ include Qonfig::Imports
266
+ import_settings(AppConfig, 'job_que', mappings: { creds: 'credentials' }, raw: true)
267
+ end
268
+
269
+ app_with_configs = RawImportCheckApp.new
270
+
271
+ expect(app_with_configs).to respond_to(:job_que)
272
+ expect(app_with_configs).to respond_to(:creds)
273
+ expect(app_with_configs.job_que).to be_a(Qonfig::Settings)
274
+ expect(app_with_configs.creds).to be_a(Qonfig::Settings)
275
+ expect(app_with_configs.job_que.adapter).to eq(:sidekiq)
276
+ expect(app_with_configs.job_que.options.server).to eq('cloud')
277
+ expect(app_with_configs.job_que.options.auto_run).to eq(true)
278
+ expect(app_with_configs.creds.admin).to eq(true)
279
+ expect(app_with_configs.creds.login).to eq('D@iVeR')
280
+ expect(app_with_configs.creds.password).to eq('test123')
281
+ end
282
+
283
+ specify 'incorrect attributes' do
284
+ expect do
285
+ Class.new do
286
+ include Qonfig::Imports
287
+ import_settings(123)
288
+ end
289
+ end.to raise_error(Qonfig::IncompatibleImportedConfigError)
290
+
291
+ expect do
292
+ Class.new do
293
+ include Qonfig::Imports
294
+ import_settings(AppConfig, 'kek.pek', prefix: Object.new)
295
+ end
296
+ end.to raise_error(Qonfig::IncorrectImportPrefixError)
297
+
298
+ expect do
299
+ Class.new do
300
+ include Qonfig::Imports
301
+ import_settings(AppConfig, 'pek.kek', 'kek.pek', Object.new)
302
+ end
303
+ end.to raise_error(Qonfig::IncorrectImportKeyError)
304
+
305
+ expect do
306
+ Class.new do
307
+ include Qonfig::Imports
308
+ import_settings(AppConfig, 'kek.pek', mappings: {
309
+ Object.new => 'kek.pek'
310
+ })
311
+ end
312
+ end.to raise_error(Qonfig::IncorrectImportMappingsError)
313
+
314
+ expect do
315
+ Class.new do
316
+ include Qonfig::Imports
317
+ import_settings(AppConfig, 'kek.pek', mappings: {
318
+ some_method: Object.new
319
+ })
320
+ end
321
+ end.to raise_error(Qonfig::IncorrectImportMappingsError)
322
+ end
323
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe 'Indifferent Access' do
4
+ specify 'indifferently accessable options (directly via index; via string / via symbol)' do
5
+ class IndifferentlyAccessableConfig < Qonfig::DataSet
6
+ setting :project_id, 10
7
+ end
8
+
9
+ class AnotherIndifferentlyAccessableConfig < Qonfig::DataSet
10
+ compose IndifferentlyAccessableConfig
11
+
12
+ setting 'database' do
13
+ setting :hostname, 'localhost'
14
+ end
15
+ end
16
+
17
+ config = AnotherIndifferentlyAccessableConfig.new
18
+
19
+ # indifferent access via string / via symbol
20
+ expect(config.settings[:project_id]).to eq(10)
21
+ expect(config.settings['project_id']).to eq(10)
22
+ expect(config.settings[:database][:hostname]).to eq('localhost')
23
+ expect(config.settings['database']['hostname']).to eq('localhost')
24
+ expect(config.settings['database'][:hostname]).to eq('localhost')
25
+ expect(config.settings[:database]['hostname']).to eq('localhost')
26
+
27
+ # direct access via [] on the config object
28
+ expect(config[:project_id]).to eq(10)
29
+ expect(config['project_id']).to eq(10)
30
+ expect(config[:database][:hostname]).to eq('localhost')
31
+ expect(config['database']['hostname']).to eq('localhost')
32
+ expect(config['database'][:hostname]).to eq('localhost')
33
+ expect(config[:database]['hostname']).to eq('localhost')
34
+
35
+ # instant configuration with indifferently accessable options
36
+ config.configure do |conf|
37
+ conf['project_id'] = 1
38
+ conf[:database]['hostname'] = 'google.com'
39
+ end
40
+
41
+ # indifferent access via string / via symbol
42
+ expect(config.settings[:project_id]).to eq(1)
43
+ expect(config.settings['project_id']).to eq(1)
44
+ expect(config.settings[:database][:hostname]).to eq('google.com')
45
+ expect(config.settings['database']['hostname']).to eq('google.com')
46
+ expect(config.settings['database'][:hostname]).to eq('google.com')
47
+ expect(config.settings[:database]['hostname']).to eq('google.com')
48
+
49
+ # direct access via [] on the config object
50
+ expect(config[:project_id]).to eq(1)
51
+ expect(config['project_id']).to eq(1)
52
+ expect(config[:database][:hostname]).to eq('google.com')
53
+ expect(config['database']['hostname']).to eq('google.com')
54
+ expect(config['database'][:hostname]).to eq('google.com')
55
+ expect(config[:database]['hostname']).to eq('google.com')
56
+ end
57
+ end
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe 'Inheritance' do
4
+ specify 'config inheritance works correclty' do
5
+ class FrameworkConfig < Qonfig::DataSet
6
+ setting :version, '0.1.0'
7
+
8
+ setting :defaults do
9
+ setting :path, '/a/b/c'
10
+ end
11
+ end
12
+
13
+ class UnknownConfig < Qonfig::DataSet
14
+ setting :unkown_data, true
15
+ end
16
+
17
+ class SharedConfig < Qonfig::DataSet
18
+ setting :google_api do
19
+ setting :token, 'test-google-api'
20
+ end
21
+
22
+ setting :admin_access_required, false
23
+
24
+ compose FrameworkConfig
25
+ end
26
+
27
+ class ClientConfig < SharedConfig
28
+ compose UnknownConfig
29
+
30
+ setting :google_api do
31
+ setting :client_token, 'client-test-google-api'
32
+ end
33
+
34
+ setting :defaults, nil
35
+ end
36
+
37
+ client_config = ClientConfig.new
38
+
39
+ client_config.settings.tap do |config|
40
+ # own settings
41
+ expect(config.google_api.client_token).to eq('client-test-google-api')
42
+ expect(config.defaults).to eq(nil)
43
+ expect(config[:google_api][:client_token]).to eq('client-test-google-api')
44
+ expect(config[:defaults]).to eq(nil)
45
+
46
+ # inherited settings
47
+ expect(config.google_api.token).to eq('test-google-api')
48
+ expect(config.admin_access_required).to eq(false)
49
+ expect(config[:google_api][:token]).to eq('test-google-api')
50
+ expect(config[:admin_access_required]).to eq(false)
51
+
52
+ # inherited composition
53
+ expect(config.version).to eq('0.1.0')
54
+ expect(config[:version]).to eq('0.1.0')
55
+
56
+ # own composition
57
+ expect(config.unkown_data).to eq(true)
58
+ expect(config[:unkown_data]).to eq(true)
59
+ end
60
+
61
+ # hash representation
62
+ expect(client_config.to_h).to match(
63
+ 'google_api' => {
64
+ 'client_token' => 'client-test-google-api',
65
+ 'token' => 'test-google-api'
66
+ },
67
+ 'defaults' => nil,
68
+ 'admin_access_required' => false,
69
+ 'version' => '0.1.0',
70
+ 'unkown_data' => true
71
+ )
72
+
73
+ # reconfigure
74
+ client_config.configure do |config|
75
+ config.google_api.client_token = 'none'
76
+ config.defaults = { a: 1 }
77
+ config.google_api.token = 'anti-hype'
78
+ config.admin_access_required = true
79
+ config.version = '0.2.0'
80
+ config.unkown_data = nil
81
+ end
82
+
83
+ client_config.settings.tap do |config|
84
+ expect(config.google_api.client_token).to eq('none')
85
+ expect(config.defaults).to match(a: 1)
86
+ expect(config.google_api.token).to eq('anti-hype')
87
+ expect(config.admin_access_required).to eq(true)
88
+ expect(config.version).to eq('0.2.0')
89
+ expect(config.unkown_data).to eq(nil)
90
+
91
+ expect(config[:google_api][:client_token]).to eq('none')
92
+ expect(config[:defaults]).to match(a: 1)
93
+ expect(config[:google_api][:token]).to eq('anti-hype')
94
+ expect(config[:admin_access_required]).to eq(true)
95
+ expect(config[:version]).to eq('0.2.0')
96
+ expect(config[:unkown_data]).to eq(nil)
97
+ end
98
+
99
+ expect(client_config.to_h).to match(
100
+ 'google_api' => {
101
+ 'client_token' => 'none',
102
+ 'token' => 'anti-hype'
103
+ },
104
+ 'defaults' => { a: 1 },
105
+ 'admin_access_required' => true,
106
+ 'version' => '0.2.0',
107
+ 'unkown_data' => nil
108
+ )
109
+ end
110
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe 'Instantiation without class definition' do
4
+ specify '#build builds a config instance without a class' do
5
+ config = Qonfig::DataSet.build do
6
+ setting :credentials do
7
+ setting :user, 'D@iVeR'
8
+ setting :password, 'test123'
9
+ end
10
+
11
+ def custom_method(custom_param)
12
+ custom_param
13
+ end
14
+ end
15
+
16
+ expect(config).to be_a(Qonfig::DataSet)
17
+ expect(config.settings.credentials.user).to eq('D@iVeR')
18
+ expect(config.settings.credentials.password).to eq('test123')
19
+
20
+ custom_param = rand(1..1000).to_s
21
+ expect(config.custom_method(custom_param)).to eq(custom_param)
22
+ end
23
+
24
+ specify 'custom Qonfig::DataSet inheritance' do
25
+ simple_config_klass = Class.new(Qonfig::DataSet) do
26
+ setting :adapter do
27
+ setting :engine, :sidekiq
28
+ setting :options, {}
29
+ end
30
+ end
31
+
32
+ config = Qonfig::DataSet.build(simple_config_klass) do
33
+ setting :credentials do
34
+ setting :user, '0exp'
35
+ setting :password, '123test123'
36
+ end
37
+
38
+ setting :adapter do
39
+ setting :enabled, false
40
+ end
41
+ end
42
+
43
+ # NOTE: inherited configs
44
+ expect(config.settings.adapter.engine).to eq(:sidekiq)
45
+ expect(config.settings.adapter.options).to eq({})
46
+
47
+ # NOTE: extended base config
48
+ expect(config.settings.adapter.enabled).to eq(false)
49
+
50
+ # NOTE: own configs
51
+ expect(config.settings.credentials.user).to eq('0exp')
52
+ expect(config.settings.credentials.password).to eq('123test123')
53
+ end
54
+
55
+ specify 'custom inheritance fails on non-Qonfig::DataSet base classes' do
56
+ expect { Qonfig::DataSet.build(Object) }.to raise_error(Qonfig::ArgumentError)
57
+ expect { Qonfig::DataSet.build(Qonfig::DataSet) }.not_to raise_error
58
+ end
59
+ end