tty-config 0.2.0 → 0.3.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.
@@ -0,0 +1,16 @@
1
+ RSpec.describe TTY::Config, '#remove' do
2
+ it "removes a value from a key" do
3
+ config = TTY::Config.new
4
+ config.set(:values) { [:foo, :bar] }
5
+ values = config.remove(:bar, from: :values)
6
+ expect(values).to eq([:foo])
7
+ expect(config.fetch(:values)).to eq([:foo])
8
+ end
9
+
10
+ it "removes multiple values from a nested key" do
11
+ config = TTY::Config.new
12
+ config.set(:foo, :bar, :baz) { [1,2,3,4] }
13
+ config.remove(2,4, from: [:foo, :bar, :baz])
14
+ expect(config.fetch(:foo, :bar, :baz)).to eq([1,3])
15
+ end
16
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe TTY::Config, '#set_from_env' do
4
+ it "fetches env variables" do
5
+ allow(ENV).to receive(:[]).with('HOST').and_return('localhost')
6
+ allow(ENV).to receive(:[]).with('PORT').and_return('7727')
7
+
8
+ config = TTY::Config.new
9
+ config.set_from_env(:host)
10
+ config.set_from_env(:port)
11
+
12
+ expect(config.fetch(:host)).to eq('localhost')
13
+ expect(config.fetch(:port)).to eq('7727')
14
+ end
15
+
16
+ it "fetches multipart env variables" do
17
+ allow(ENV).to receive(:[]).with('FOO_BAR_BAZ').and_return('1')
18
+ config = TTY::Config.new
19
+ config.set_from_env(:foo_bar_baz)
20
+
21
+ expect(config.fetch(:foo_bar_baz)).to eq('1')
22
+ end
23
+
24
+ it "prefixes env variables" do
25
+ allow(ENV).to receive(:[]).with('MYTOOL_HOST').and_return('localhost')
26
+ allow(ENV).to receive(:[]).with('MYTOOL_PORT').and_return('7727')
27
+
28
+ config = TTY::Config.new
29
+ config.env_prefix = 'mytool'
30
+ config.set_from_env(:host)
31
+ config.set_from_env(:port)
32
+
33
+ expect(config.fetch(:host)).to eq('localhost')
34
+ expect(config.fetch(:port)).to eq('7727')
35
+ end
36
+
37
+ it "allows to set env vars for deeply nested keys" do
38
+ allow(ENV).to receive(:[]).with('HOST').and_return('localhost')
39
+
40
+ config = TTY::Config.new
41
+ config.set_from_env(:foo, :bar) { "HOST" }
42
+
43
+ expect(config.fetch(:foo, :bar)).to eq('localhost')
44
+ end
45
+
46
+ it "allows to set env vars with prefix for deeply nested keys" do
47
+ allow(ENV).to receive(:[]).with('MYTOOL_HOST').and_return('localhost')
48
+
49
+ config = TTY::Config.new
50
+ config.env_prefix = 'mytool'
51
+ config.set_from_env(:foo, :bar) { "HOST" }
52
+
53
+ expect(config.fetch(:foo, :bar)).to eq('localhost')
54
+ end
55
+
56
+ it "allows to set env vars for deeply nested keys as string" do
57
+ allow(ENV).to receive(:[]).with('HOST').and_return('localhost')
58
+
59
+ config = TTY::Config.new
60
+ config.set_from_env('foo.bar') { "HOST" }
61
+
62
+ expect(config.fetch(:foo, :bar)).to eq('localhost')
63
+ end
64
+
65
+ it "fails if env var is not specified for deeply nested keys as string" do
66
+ config = TTY::Config.new
67
+ expect {
68
+ config.set_from_env('foo.bar')
69
+ }.to raise_error(ArgumentError, 'Need to set env var in block')
70
+ end
71
+
72
+ it "fails if env var is not specified for deeply nested keys" do
73
+ config = TTY::Config.new
74
+ expect {
75
+ config.set_from_env(:foo, :bar)
76
+ }.to raise_error(ArgumentError, 'Need to set env var in block')
77
+ end
78
+ end
@@ -0,0 +1,26 @@
1
+ RSpec.describe TTY::Config, '#set_if_empty' do
2
+ it "sets value for empty" do
3
+ config = TTY::Config.new
4
+ config.set_if_empty(:foo, value: :bar)
5
+ expect(config.fetch(:foo)).to eq(:bar)
6
+ end
7
+
8
+ it "sets value for empty deeply nested key" do
9
+ config = TTY::Config.new({foo: {}})
10
+ config.set_if_empty(:foo, :bar, :baz, value: 2)
11
+ expect(config.fetch(:foo, :bar, :baz)).to eq(2)
12
+ end
13
+
14
+ it "sets value for a nested key as string delimited by dot" do
15
+ config = TTY::Config.new
16
+ config.set_if_empty("foo.bar.baz", value: 1)
17
+ expect(config.fetch('foo', 'bar', 'baz')).to eq(1)
18
+ end
19
+
20
+ it "doesn't override existing value" do
21
+ config = TTY::Config.new
22
+ config.set(:foo, value: 1)
23
+ config.set_if_empty(:foo, value: 2)
24
+ expect(config.fetch(:foo)).to eq(1)
25
+ end
26
+ end
@@ -0,0 +1,62 @@
1
+ RSpec.describe TTY::Config, '#set' do
2
+ it "sets value" do
3
+ config = TTY::Config.new
4
+ config.set(:foo, value: :bar)
5
+ expect(config.fetch(:foo)).to eq(:bar)
6
+ end
7
+
8
+ it "sets value as block" do
9
+ config = TTY::Config.new
10
+ config.set(:foo) { "bar" }
11
+ expect(config.fetch(:foo)).to eq("bar")
12
+ end
13
+
14
+ it "sets value for deep ensted key" do
15
+ config = TTY::Config.new
16
+ value = config.set(:foo, :bar, :baz, value: 2)
17
+ expect(value).to eq(2)
18
+ expect(config.fetch(:foo, :bar, :baz)).to eq(2)
19
+ end
20
+
21
+ it "sets value as block for deep ensted key" do
22
+ config = TTY::Config.new
23
+ value = config.set(:foo, :bar, :baz) { 2 }
24
+ expect(value.call).to eq(2)
25
+ expect(config.fetch(:foo, :bar, :baz)).to eq(2)
26
+ end
27
+
28
+ it "sets value for deep nested string key delimited by ." do
29
+ config = TTY::Config.new
30
+ value = config.set("foo.bar.baz", value: 2)
31
+ expect(value).to eq(2)
32
+ expect(config.fetch('foo', 'bar', 'baz')).to eq(2)
33
+ end
34
+
35
+ it "sets value as block for deep nested string key delimited by ." do
36
+ config = TTY::Config.new
37
+ value = config.set("foo.bar.baz") { 2 }
38
+ expect(value.call).to eq(2)
39
+ expect(config.fetch('foo', 'bar', 'baz')).to eq(2)
40
+ end
41
+
42
+ it "overrides existing value" do
43
+ config = TTY::Config.new({foo: {bar: 1}})
44
+ expect(config.fetch(:foo, :bar)).to eq(1)
45
+ config.set(:foo, :bar) { 2 }
46
+ expect(config.fetch(:foo, :bar)).to eq(2)
47
+ end
48
+
49
+ it "raises an exception when value & block provided" do
50
+ config = TTY::Config.new
51
+ expect {
52
+ config.set(:foo, value: :bar) { :baz }
53
+ }.to raise_error(ArgumentError, "Can't set both value and block")
54
+ end
55
+
56
+ it "raises an exception when no value or block provided" do
57
+ config = TTY::Config.new
58
+ expect {
59
+ config.set(:foo, :bar, 2)
60
+ }.to raise_error(ArgumentError, "Need to set either value or block")
61
+ end
62
+ end
@@ -0,0 +1,76 @@
1
+ RSpec.describe TTY::Config, '#validate' do
2
+ let(:validation) {
3
+ -> (key, value) do
4
+ unless value.is_a?(Integer)
5
+ raise TTY::Config::ValidationError, "Failed validation for key=#{key}"
6
+ end
7
+ end
8
+ }
9
+
10
+ it "validates string value successfully" do
11
+ config = TTY::Config.new
12
+ config.validate(:foo, :bar, &validation)
13
+ config.set(:foo, :bar, value: 2)
14
+ expect(config.fetch(:foo, :bar)).to eq(2)
15
+ end
16
+
17
+ it "validates a proc value successfully" do
18
+ config = TTY::Config.new
19
+ config.validate(:foo, :bar, &validation)
20
+ config.set(:foo, :bar, value: -> { 2 })
21
+ expect(config.fetch(:foo, :bar)).to eq(2)
22
+ end
23
+
24
+ it "validates a block value successfully" do
25
+ config = TTY::Config.new
26
+ config.validate(:foo, :bar, &validation)
27
+ config.set(:foo, :bar) { 2 }
28
+ expect(config.fetch(:foo, :bar)).to eq(2)
29
+ end
30
+
31
+ it "raises an error when set value fails validation" do
32
+ config = TTY::Config.new
33
+ config.validate(:foo, :bar, &validation)
34
+ expect {
35
+ config.set(:foo, :bar, value: '2')
36
+ }.to raise_error(TTY::Config::ValidationError,
37
+ 'Failed validation for key=foo.bar')
38
+ end
39
+
40
+ it "raises an error when set value as a proc fails validation" do
41
+ config = TTY::Config.new
42
+ config.validate(:foo, :bar, &validation)
43
+ config.set(:foo, :bar, value: -> { '2' })
44
+ expect {
45
+ config.fetch(:foo, :bar)
46
+ }.to raise_error(TTY::Config::ValidationError,
47
+ 'Failed validation for key=foo.bar')
48
+ end
49
+
50
+ it "raises an eror when ste value as a block fails validation" do
51
+ config = TTY::Config.new
52
+ config.validate(:foo, :bar, &validation)
53
+ config.set(:foo, :bar) { '2' }
54
+ expect {
55
+ config.fetch(:foo, :bar)
56
+ }.to raise_error(TTY::Config::ValidationError,
57
+ 'Failed validation for key=foo.bar')
58
+ end
59
+
60
+ it "applies multiple validations" do
61
+ config = TTY::Config.new
62
+ config.validate(:foo, :bar) do |key, val|
63
+ unless val.is_a?(Integer)
64
+ raise TTY::Config::ValidationError, 'Not integer'
65
+ end
66
+ end
67
+ config.validate(:foo, :bar) do |key, val|
68
+ unless val > 100
69
+ raise TTY::Config::ValidationError , 'Value out of range'
70
+ end
71
+ end
72
+ expect {
73
+ config.set(:foo, :bar, value: 99)
74
+ }.to raise_error(TTY::Config::ValidationError, 'Value out of range')
75
+ end
76
+ end
@@ -0,0 +1,197 @@
1
+ RSpec.describe TTY::Config, '#write', type: :cli do
2
+ it "writes configuration to a specified file" do
3
+ config = TTY::Config.new
4
+ config.set(:settings, :base, value: 'USD')
5
+ config.set(:settings, :exchange, value: 'CCCAGG')
6
+ config.set(:coins, value: ['BTC', 'TRX', 'DASH'])
7
+ file = tmp_path('config.yml')
8
+
9
+ config.write(file)
10
+
11
+ expect(::File.read(file)).to eq <<-EOS
12
+ ---
13
+ settings:
14
+ base: USD
15
+ exchange: CCCAGG
16
+ coins:
17
+ - BTC
18
+ - TRX
19
+ - DASH
20
+ EOS
21
+ end
22
+
23
+ it "writes by default to the current directory" do
24
+ config = TTY::Config.new
25
+ config.set('settings', 'base', value: 'USD')
26
+ config.set('settings', 'exchange', value: 'CCCAGG')
27
+ config.set('coins', value: ['BTC', 'TRX', 'DASH'])
28
+
29
+ config.write
30
+
31
+ file = dir_path('config.yml')
32
+ expect(::File.read(file)).to eq <<-EOS
33
+ ---
34
+ settings:
35
+ base: USD
36
+ exchange: CCCAGG
37
+ coins:
38
+ - BTC
39
+ - TRX
40
+ - DASH
41
+ EOS
42
+ FileUtils.rm_rf(file)
43
+ end
44
+
45
+ it "doesn't override already existing file" do
46
+ config = TTY::Config.new
47
+ config.set('settings', 'base', value: 'USD')
48
+ file = tmp_path('config.yml')
49
+
50
+ config.write(file)
51
+
52
+ expect {
53
+ config.write(file)
54
+ }.to raise_error(TTY::Config::WriteError,
55
+ "File `#{file}` already exists. Use :force option to overwrite.")
56
+ end
57
+
58
+ it "allows to overwrite already existing file" do
59
+ config = TTY::Config.new
60
+ config.set('settings', 'base', value: 'USD')
61
+ file = tmp_path('config.yml')
62
+
63
+ config.write(file)
64
+
65
+ config.write(file, force: true)
66
+ end
67
+
68
+ it "writes json format" do
69
+ config = TTY::Config.new
70
+ config.set(:settings, :base, value: 'USD')
71
+ config.set(:settings, :exchange, value: 'CCCAGG')
72
+ config.set(:coins, value: ['BTC', 'TRX', 'DASH'])
73
+ file = tmp_path('config.json')
74
+
75
+ config.write(file)
76
+
77
+ expect(config.extname).to eq('.json')
78
+ expect(::File.read(file)).to eq <<-EOS.chomp
79
+ {
80
+ "settings": {
81
+ "base": "USD",
82
+ "exchange": "CCCAGG"
83
+ },
84
+ "coins": [
85
+ "BTC",
86
+ "TRX",
87
+ "DASH"
88
+ ]
89
+ }
90
+ EOS
91
+ end
92
+
93
+ it "writes toml format and assigns default filename and extension" do
94
+ config = TTY::Config.new
95
+ config.set(:settings, :base, value: 'USD')
96
+ config.set(:settings, :exchange, value: 'CCCAGG')
97
+ config.set(:coins, value: ['BTC', 'TRX', 'DASH'])
98
+ file = tmp_path('investments.toml')
99
+
100
+ config.write(file)
101
+
102
+ expect(config.filename).to eq('investments')
103
+ expect(config.extname).to eq('.toml')
104
+ expect(::File.read(file)).to eq <<-EOS
105
+ coins = ["BTC","TRX","DASH"]
106
+
107
+ [settings]
108
+ base = "USD"
109
+ exchange = "CCCAGG"
110
+ EOS
111
+ end
112
+
113
+ it "allows to change default file extension" do
114
+ config = TTY::Config.new
115
+ config.filename = 'investments'
116
+ config.extname = '.toml'
117
+ config.set(:settings, :base, value: 'USD')
118
+ config.set(:settings, :exchange, value: 'CCCAGG')
119
+ config.set(:coins, value: ['BTC', 'TRX', 'DASH'])
120
+
121
+ config.write
122
+
123
+ file = dir_path('investments.toml')
124
+ expect(::File.read(file)).to eq <<-EOS
125
+ coins = ["BTC","TRX","DASH"]
126
+
127
+ [settings]
128
+ base = "USD"
129
+ exchange = "CCCAGG"
130
+ EOS
131
+ FileUtils.rm_rf(file)
132
+ end
133
+
134
+ it "writes ini format and assigns default filename and extension" do
135
+ config = TTY::Config.new
136
+ config.set(:settings, :base, value: 'USD')
137
+ config.set(:settings, :exchange, value: 'CCCAGG')
138
+ config.set(:coins, value: "BTC,TRX,DASH")
139
+ file = tmp_path('investments.ini')
140
+
141
+ config.write(file)
142
+
143
+ expect(config.filename).to eq('investments')
144
+ expect(config.extname).to eq('.ini')
145
+ expect(::File.read(file)).to eq <<-EOS
146
+ coins = BTC,TRX,DASH
147
+
148
+ [settings]
149
+ base = USD
150
+ exchange = CCCAGG
151
+ EOS
152
+ end
153
+
154
+ it "writes custom format with custom file extension" do
155
+ config = TTY::Config.new
156
+ config.set(:settings, :base, value: 'USD')
157
+ config.set(:settings, :exchange, value: 'CCCAGG')
158
+ config.set(:coins, value: ['BTC', 'TRX', 'DASH'])
159
+ file = tmp_path('investments.conf')
160
+
161
+ config.write(file, format: :yaml)
162
+ expect(config.filename).to eq('investments')
163
+ expect(config.extname).to eq('.conf')
164
+ expect(::File.read(file)).to eq <<-EOS
165
+ ---
166
+ settings:
167
+ base: USD
168
+ exchange: CCCAGG
169
+ coins:
170
+ - BTC
171
+ - TRX
172
+ - DASH
173
+ EOS
174
+ end
175
+
176
+ it "cannot write unknown file format" do
177
+ config = TTY::Config.new
178
+ config.set(:settings, :base, value: 'USD')
179
+ file = tmp_path('config.txt')
180
+
181
+ expect {
182
+ config.write(file)
183
+ }.to raise_error(TTY::Config::UnsupportedExtError,
184
+ "Config file format `.txt` is not supported.")
185
+ end
186
+
187
+ it "fails to load dependency for writing file format" do
188
+ config = TTY::Config.new
189
+ file = tmp_path('investments.yml')
190
+ allow(config).to receive(:require).with('yaml').and_raise(LoadError)
191
+ stub_const("YAML", double(dump: 'ok'))
192
+
193
+ expect {
194
+ config.write(file)
195
+ }.to raise_error(TTY::Config::WriteError, "Gem `yaml` is missing. Please install it to read .yml configuration format.")
196
+ end
197
+ end