qonfig 0.25.0 → 0.26.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (136) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -2
  3. data/.rubocop.yml +19 -1
  4. data/.travis.yml +7 -2
  5. data/CHANGELOG.md +4 -0
  6. data/Gemfile.lock +102 -0
  7. data/README.md +2 -0
  8. data/gemfiles/with_external_deps.gemfile.lock +112 -0
  9. data/gemfiles/without_external_deps.gemfile.lock +102 -0
  10. data/lib/qonfig.rb +1 -1
  11. data/lib/qonfig/commands/definition/load_from_env.rb +2 -0
  12. data/lib/qonfig/commands/definition/load_from_env/value_converter.rb +2 -0
  13. data/lib/qonfig/imports/direct_key.rb +8 -2
  14. data/lib/qonfig/imports/mappings.rb +8 -2
  15. data/lib/qonfig/loaders/basic.rb +2 -0
  16. data/lib/qonfig/loaders/json.rb +2 -1
  17. data/lib/qonfig/settings.rb +5 -1
  18. data/lib/qonfig/settings/key_matcher.rb +1 -1
  19. data/lib/qonfig/uploaders/base.rb +2 -0
  20. data/lib/qonfig/uploaders/yaml.rb +2 -0
  21. data/lib/qonfig/version.rb +1 -1
  22. data/qonfig.gemspec +4 -6
  23. data/sig/.keep +0 -0
  24. data/spec/features/clear_options_spec.rb +92 -0
  25. data/spec/features/compacted_config_spec.rb +308 -0
  26. data/spec/features/composition_spec.rb +207 -0
  27. data/spec/features/config_definition_and_representation_spec.rb +535 -0
  28. data/spec/features/definition_order_spec.rb +69 -0
  29. data/spec/features/dig_functionality_spec.rb +47 -0
  30. data/spec/features/dot_notation_spec.rb +159 -0
  31. data/spec/features/export_settings_spec.rb +138 -0
  32. data/spec/features/expose_json_spec.rb +281 -0
  33. data/spec/features/expose_self/format_option_dynamic_spec.rb +69 -0
  34. data/spec/features/expose_self/format_option_json_spec.rb +74 -0
  35. data/spec/features/expose_self/format_option_unsupported_spec.rb +27 -0
  36. data/spec/features/expose_self/format_option_yaml_spec.rb +77 -0
  37. data/spec/features/expose_self_spec.rb +97 -0
  38. data/spec/features/expose_yaml_spec.rb +263 -0
  39. data/spec/features/freeze_state_spec.rb +122 -0
  40. data/spec/features/get_config_keys_spec.rb +62 -0
  41. data/spec/features/get_config_values_spec.rb +41 -0
  42. data/spec/features/has_a_key_spec.rb +48 -0
  43. data/spec/features/import_settings_spec.rb +323 -0
  44. data/spec/features/indifferent_access_spec.rb +57 -0
  45. data/spec/features/inheritance_spec.rb +110 -0
  46. data/spec/features/instantiation_without_class_definition_spec.rb +59 -0
  47. data/spec/features/iteration_over_setting_keys_spec.rb +48 -0
  48. data/spec/features/load_from_env_spec.rb +240 -0
  49. data/spec/features/load_from_json_spec.rb +97 -0
  50. data/spec/features/load_from_self/format_option_json_spec.rb +31 -0
  51. data/spec/features/load_from_self/format_option_unsupported_spec.rb +27 -0
  52. data/spec/features/load_from_self/format_option_yaml_spec.rb +49 -0
  53. data/spec/features/load_from_self/with_erb_instructions_spec.rb +33 -0
  54. data/spec/features/load_from_self/with_hash_like_data_representation_spec.rb +66 -0
  55. data/spec/features/load_from_self/with_non_hash_like_data_representation_spec.rb +19 -0
  56. data/spec/features/load_from_self/without_end_data_spec.rb +11 -0
  57. data/spec/features/load_from_yaml_spec.rb +110 -0
  58. data/spec/features/load_setting_values_from_file/by_instance_method_examples.rb +171 -0
  59. data/spec/features/load_setting_values_from_file/by_macros_examples.rb +165 -0
  60. data/spec/features/load_setting_values_from_file/load_from_json_spec.rb +21 -0
  61. data/spec/features/load_setting_values_from_file/load_from_self/json_format/end_data_with_env_spec.rb +100 -0
  62. data/spec/features/load_setting_values_from_file/load_from_self/json_format/with_end_data_spec.rb +129 -0
  63. data/spec/features/load_setting_values_from_file/load_from_self/json_format/with_incorrect_end_data_spec.rb +34 -0
  64. data/spec/features/load_setting_values_from_file/load_from_self/json_format/without_end_data_spec.rb +65 -0
  65. data/spec/features/load_setting_values_from_file/load_from_self/yaml_format/end_data_with_env_spec.rb +94 -0
  66. data/spec/features/load_setting_values_from_file/load_from_self/yaml_format/with_end_data_spec.rb +126 -0
  67. data/spec/features/load_setting_values_from_file/load_from_self/yaml_format/with_incorrect_end_data_spec.rb +32 -0
  68. data/spec/features/load_setting_values_from_file/load_from_self/yaml_format/without_end_data_spec.rb +65 -0
  69. data/spec/features/load_setting_values_from_file/load_from_yaml_spec.rb +21 -0
  70. data/spec/features/load_setting_values_from_file/shared_behavior_spec.rb +33 -0
  71. data/spec/features/mixin_spec.rb +387 -0
  72. data/spec/features/non_redefineable_core_methods_spec.rb +29 -0
  73. data/spec/features/plugins/pretty_print_spec.rb +86 -0
  74. data/spec/features/plugins/toml/expose_self/format_option_toml_spec.rb +71 -0
  75. data/spec/features/plugins/toml/expose_toml_spec.rb +221 -0
  76. data/spec/features/plugins/toml/load_from_self/format_option_toml_spec.rb +27 -0
  77. data/spec/features/plugins/toml/load_from_toml_spec.rb +109 -0
  78. data/spec/features/plugins/toml/load_setting_values_from_file/load_from_toml_spec.rb +27 -0
  79. data/spec/features/plugins/toml/load_setting_values_from_file/load_toml_from_self/end_data_with_env_spec.rb +95 -0
  80. data/spec/features/plugins/toml/load_setting_values_from_file/load_toml_from_self/with_end_data_spec.rb +125 -0
  81. data/spec/features/plugins/toml/load_setting_values_from_file/load_toml_from_self/with_incorrect_end_data_spec.rb +34 -0
  82. data/spec/features/plugins/toml/load_setting_values_from_file/load_toml_from_self/without_end_data_spec.rb +65 -0
  83. data/spec/features/plugins/toml/load_setting_values_from_file/shared_behavior_spec.rb +34 -0
  84. data/spec/features/plugins/toml/save_to_toml_spec.rb +149 -0
  85. data/spec/features/plugins/vault/expose_vault_spec.rb +117 -0
  86. data/spec/features/plugins/vault/load_from_vault_spec.rb +80 -0
  87. data/spec/features/plugins_spec.rb +89 -0
  88. data/spec/features/reload_spec.rb +75 -0
  89. data/spec/features/run_code_with_temporary_settings_spec.rb +104 -0
  90. data/spec/features/save_to_file/save_to_json_spec.rb +157 -0
  91. data/spec/features/save_to_file/save_to_yaml_spec.rb +189 -0
  92. data/spec/features/settings_as_predicates_spec.rb +47 -0
  93. data/spec/features/settings_redefinition_spec.rb +30 -0
  94. data/spec/features/slice_functionality_spec.rb +69 -0
  95. data/spec/features/subset_functionality_spec.rb +49 -0
  96. data/spec/features/validation_spec.rb +916 -0
  97. data/spec/fixtures/array_settings.yml +3 -0
  98. data/spec/fixtures/expose_json/incompatible_root_structure.json +6 -0
  99. data/spec/fixtures/expose_json/incompatible_structure.json +4 -0
  100. data/spec/fixtures/expose_json/project.development.json +7 -0
  101. data/spec/fixtures/expose_json/project.json +30 -0
  102. data/spec/fixtures/expose_json/project.production.json +7 -0
  103. data/spec/fixtures/expose_json/project.staging.json +7 -0
  104. data/spec/fixtures/expose_json/project.test.json +7 -0
  105. data/spec/fixtures/expose_yaml/incompatible_structure.yml +2 -0
  106. data/spec/fixtures/expose_yaml/project.development.yml +4 -0
  107. data/spec/fixtures/expose_yaml/project.production.yml +4 -0
  108. data/spec/fixtures/expose_yaml/project.staging.yml +4 -0
  109. data/spec/fixtures/expose_yaml/project.test.yml +4 -0
  110. data/spec/fixtures/expose_yaml/project.yml +25 -0
  111. data/spec/fixtures/json_array_sample.json +14 -0
  112. data/spec/fixtures/json_object_sample.json +9 -0
  113. data/spec/fixtures/json_with_empty_object.json +6 -0
  114. data/spec/fixtures/json_with_erb.json +6 -0
  115. data/spec/fixtures/plugins/toml/expose_toml/project.development.toml +4 -0
  116. data/spec/fixtures/plugins/toml/expose_toml/project.production.toml +4 -0
  117. data/spec/fixtures/plugins/toml/expose_toml/project.staging.toml +4 -0
  118. data/spec/fixtures/plugins/toml/expose_toml/project.test.toml +4 -0
  119. data/spec/fixtures/plugins/toml/expose_toml/project.toml +27 -0
  120. data/spec/fixtures/plugins/toml/mini_file.toml +6 -0
  121. data/spec/fixtures/plugins/toml/toml_sample_with_all_types.toml +72 -0
  122. data/spec/fixtures/plugins/toml/values_file/with_env.toml +13 -0
  123. data/spec/fixtures/plugins/toml/values_file/without_env.toml +6 -0
  124. data/spec/fixtures/rubocop_settings.yml +12 -0
  125. data/spec/fixtures/shared_settings_with_aliases.yml +10 -0
  126. data/spec/fixtures/travis_settings.yml +6 -0
  127. data/spec/fixtures/values_file/with_env.json +19 -0
  128. data/spec/fixtures/values_file/with_env.yml +17 -0
  129. data/spec/fixtures/values_file/without_env.json +8 -0
  130. data/spec/fixtures/values_file/without_env.yml +5 -0
  131. data/spec/fixtures/with_empty_hash.yml +4 -0
  132. data/spec/fixtures/with_erb_instructions.yml +3 -0
  133. data/spec/spec_helper.rb +27 -0
  134. data/spec/support/meta_scopes.rb +20 -0
  135. data/spec/support/spec_support.rb +42 -0
  136. metadata +128 -11
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe 'Freeze state' do
4
+ context 'instance' do
5
+ specify 'freezing' do
6
+ class FrozenableConfig < Qonfig::DataSet
7
+ setting :api_mode_enabled, true
8
+
9
+ setting :api do
10
+ setting :format, :json
11
+ end
12
+ end
13
+
14
+ frozen_config = FrozenableConfig.new
15
+
16
+ # can modify config values
17
+ frozen_config.configure do |conf|
18
+ expect { conf.api_mode_enabled = nil }.not_to raise_error
19
+ expect { conf.api.format = :plain_text }.not_to raise_error
20
+ end
21
+
22
+ # can reload config object
23
+ class FrozenableConfig
24
+ setting :additionals, false
25
+ end
26
+
27
+ expect { frozen_config.clear! }.not_to raise_error
28
+ expect { frozen_config.reload! }.not_to raise_error
29
+
30
+ frozen_config.freeze!
31
+
32
+ # cannot modify config values
33
+ frozen_config.configure do |conf|
34
+ expect { conf.api_mode_enabled = false }.to raise_error(Qonfig::FrozenSettingsError)
35
+ expect { conf.api.format = :xml }.to raise_error(Qonfig::FrozenSettingsError)
36
+ expect { conf.additionals = true }.to raise_error(Qonfig::FrozenSettingsError)
37
+
38
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.5.0')
39
+ expect { conf.api_mode_enabled = false }.to raise_error(::FrozenError)
40
+ expect { conf.api.format = :xml }.to raise_error(::FrozenError)
41
+ expect { conf.additionals = true }.to raise_error(::FrozenError)
42
+ else
43
+ expect { conf.api_mode_enabled = false }.to raise_error(::RuntimeError)
44
+ expect { conf.api.format = :xml }.to raise_error(::RuntimeError)
45
+ expect { conf.additionals = true }.to raise_error(::RuntimeError)
46
+ end
47
+ end
48
+
49
+ # cannot reload config object
50
+ class FrozenableConfig
51
+ setting :customizable, false
52
+ end
53
+
54
+ expect { frozen_config.reload! }.to raise_error(Qonfig::FrozenSettingsError)
55
+ expect { frozen_config.clear! }.to raise_error(Qonfig::FrozenSettingsError)
56
+
57
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.5.0')
58
+ expect { frozen_config.reload! }.to raise_error(::FrozenError)
59
+ expect { frozen_config.clear! }.to raise_error(::FrozenError)
60
+ else
61
+ expect { frozen_config.reload! }.to raise_error(::RuntimeError)
62
+ expect { frozen_config.clear! }.to raise_error(::RuntimeError)
63
+ end
64
+
65
+ expect(frozen_config.to_h).to match(
66
+ 'api_mode_enabled' => true,
67
+ 'api' => {
68
+ 'format' => :json
69
+ },
70
+ 'additionals' => false
71
+ )
72
+ end
73
+ end
74
+
75
+ context 'definition' do
76
+ specify 'created instance should be frozen' do
77
+ config = Qonfig::DataSet.build do
78
+ setting :test, true
79
+ freeze_state!
80
+ end
81
+
82
+ expect(config.frozen?).to eq(true)
83
+ end
84
+
85
+ specify 'inherited classes should not be frozen' do
86
+ base_config_klass = Class.new(Qonfig::DataSet) do
87
+ setting :test, true
88
+ freeze_state!
89
+ end
90
+
91
+ children_config_klass = Class.new(base_config_klass)
92
+ children_config = children_config_klass.new
93
+
94
+ expect(children_config.frozen?).to eq(false)
95
+ end
96
+
97
+ specify 'composed configurations should not be frozen' do
98
+ class BaseWithFreezeConfig < Qonfig::DataSet
99
+ setting :test, true
100
+ freeze_state!
101
+ end
102
+
103
+ class CompositionOfFreezedConfigs < Qonfig::DataSet
104
+ setting :nested do
105
+ compose BaseWithFreezeConfig
106
+ end
107
+ compose BaseWithFreezeConfig
108
+ end
109
+
110
+ config = CompositionOfFreezedConfigs.new
111
+ expect(config.frozen?).to eq(false)
112
+
113
+ expect do
114
+ config.settings.test = false
115
+ config.settings.nested.test = false
116
+ end.not_to raise_error
117
+
118
+ expect(config.settings.test).to eq(false)
119
+ expect(config.settings.nested.test).to eq(false)
120
+ end
121
+ end
122
+ end
@@ -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