sinclair 1.6.5 → 1.7.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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +2 -2
  3. data/Dockerfile +2 -2
  4. data/README.md +3 -1
  5. data/config/check_specs.yml +3 -0
  6. data/config/yardstick.yml +7 -1
  7. data/lib/sinclair/config.rb +46 -0
  8. data/lib/sinclair/config_class.rb +15 -0
  9. data/lib/sinclair/configurable.rb +8 -0
  10. data/lib/sinclair/matchers/add_class_method.rb +16 -13
  11. data/lib/sinclair/matchers/add_class_method_to.rb +9 -23
  12. data/lib/sinclair/matchers/add_instance_method.rb +16 -18
  13. data/lib/sinclair/matchers/add_instance_method_to.rb +12 -16
  14. data/lib/sinclair/matchers/add_method.rb +39 -30
  15. data/lib/sinclair/matchers/add_method_to.rb +4 -56
  16. data/lib/sinclair/matchers/base.rb +45 -0
  17. data/lib/sinclair/matchers/change_class_method.rb +42 -0
  18. data/lib/sinclair/matchers/change_class_method_on.rb +64 -0
  19. data/lib/sinclair/matchers/change_instance_method.rb +42 -0
  20. data/lib/sinclair/matchers/change_instance_method_on.rb +98 -0
  21. data/lib/sinclair/matchers/change_method_on.rb +25 -0
  22. data/lib/sinclair/matchers/method_to.rb +82 -0
  23. data/lib/sinclair/matchers.rb +38 -30
  24. data/lib/sinclair/options/class_methods.rb +95 -0
  25. data/lib/sinclair/options.rb +10 -60
  26. data/lib/sinclair/version.rb +1 -1
  27. data/sinclair.gemspec +12 -12
  28. data/spec/integration/readme/my_class_spec.rb +1 -1
  29. data/spec/integration/yard/sinclair/config_spec.rb +27 -0
  30. data/spec/integration/yard/sinclair/options_parser_spec.rb +9 -0
  31. data/spec/lib/sinclair/config_class_spec.rb +1 -33
  32. data/spec/lib/sinclair/config_spec.rb +71 -0
  33. data/spec/lib/sinclair/matchers/add_class_method_to_spec.rb +40 -16
  34. data/spec/lib/sinclair/matchers/add_instance_method_to_spec.rb +36 -12
  35. data/spec/lib/sinclair/matchers/change_class_method_on_spec.rb +138 -0
  36. data/spec/lib/sinclair/matchers/change_class_method_spec.rb +38 -0
  37. data/spec/lib/sinclair/matchers/change_instance_method_on_spec.rb +149 -0
  38. data/spec/lib/sinclair/matchers/change_instance_method_spec.rb +38 -0
  39. data/spec/lib/sinclair/matchers_spec.rb +30 -0
  40. data/spec/lib/sinclair/options/class_methods_spec.rb +255 -0
  41. data/spec/lib/sinclair/options_spec.rb +28 -237
  42. data/spec/support/models/builder_options.rb +7 -0
  43. data/spec/support/models/login_configurable.rb +7 -0
  44. data/spec/support/models/open_options.rb +7 -0
  45. data/spec/support/shared_examples/config.rb +48 -0
  46. metadata +43 -28
@@ -31,4 +31,34 @@ describe Sinclair::Matchers do
31
31
  .to eq(described_class::AddClassMethod.new(:method_name))
32
32
  end
33
33
  end
34
+
35
+ describe '#change_method' do
36
+ it 'has been added to DSL' do
37
+ expect(respond_to?(:change_method)).to be_truthy
38
+ end
39
+
40
+ it do
41
+ expect(change_method(:method_name)).to be_a(described_class::ChangeInstanceMethod)
42
+ end
43
+
44
+ it 'returns the matcher with correct argument' do
45
+ expect(change_method(:method_name))
46
+ .to eq(described_class::ChangeInstanceMethod.new(:method_name))
47
+ end
48
+ end
49
+
50
+ describe '#change_class_method' do
51
+ it 'has been added to DSL' do
52
+ expect(respond_to?(:change_class_method)).to be_truthy
53
+ end
54
+
55
+ it do
56
+ expect(change_class_method(:method_name)).to be_a(described_class::ChangeClassMethod)
57
+ end
58
+
59
+ it 'returns the matcher with correct argument' do
60
+ expect(change_class_method(:method_name))
61
+ .to eq(described_class::ChangeClassMethod.new(:method_name))
62
+ end
63
+ end
34
64
  end
@@ -0,0 +1,255 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Sinclair::Options::ClassMethods do
6
+ subject(:options) { klass.new }
7
+
8
+ describe '.with_options' do
9
+ let(:klass) { Class.new(Sinclair::Options) }
10
+ let(:test_keys) { %i[timeout retries invalid] }
11
+
12
+ context 'when calling with keys' do
13
+ it 'add first method' do
14
+ expect { klass.send(:with_options, :timeout, 'retries') }
15
+ .to add_method(:timeout).to(klass)
16
+ end
17
+
18
+ it 'add second method' do
19
+ expect { klass.send(:with_options, :timeout, 'retries') }
20
+ .to add_method(:retries).to(klass)
21
+ end
22
+
23
+ it 'adds options to allowed' do
24
+ expect { klass.send(:with_options, :timeout, 'retries') }
25
+ .to change { klass.invalid_options_in(test_keys) }
26
+ .from(%i[timeout retries invalid])
27
+ .to([:invalid])
28
+ end
29
+
30
+ it do
31
+ expect { klass.send(:with_options, :timeout, 'retries') }
32
+ .not_to change {
33
+ Sinclair::Options.invalid_options_in(%i[timeout retries invalid])
34
+ }
35
+ end
36
+
37
+ context 'when when calling method after building' do
38
+ before { klass.send(:with_options, :timeout, 'retries') }
39
+
40
+ it { expect(options.timeout).to be_nil }
41
+ end
42
+
43
+ context 'when calling method twice' do
44
+ before { klass.send(:with_options, :timeout, retries: 10) }
45
+
46
+ it do
47
+ expect { klass.send(:with_options, :timeout, :retries) }
48
+ .not_to change {
49
+ klass.invalid_options_in(%i[timeout retries invalid])
50
+ }
51
+ end
52
+ end
53
+ end
54
+
55
+ context 'when calling with a hash' do
56
+ it 'adds method' do
57
+ expect { klass.send(:with_options, timeout_sec: 10, 'retries' => 20) }
58
+ .to add_method(:timeout_sec).to(klass)
59
+ end
60
+
61
+ context 'when when calling method after building' do
62
+ before { klass.send(:with_options, timeout_sec: 10, 'retries' => 20) }
63
+
64
+ it 'returns default value' do
65
+ expect(options.retries).to eq(20)
66
+ end
67
+ end
68
+ end
69
+
70
+ context 'when calling on subclass' do
71
+ let(:super_class) { Class.new(Sinclair::Options) }
72
+ let(:klass) { Class.new(super_class) }
73
+
74
+ let(:test_keys) do
75
+ %i[timeout retries name protocol port invalid]
76
+ end
77
+
78
+ before { super_class.send(:with_options, :timeout, 'retries', name: 'My Connector') }
79
+
80
+ it 'add first method' do
81
+ expect { klass.send(:with_options, :protocol, 'port' => 443) }
82
+ .to add_method(:protocol).to(klass)
83
+ end
84
+
85
+ it 'add second method' do
86
+ expect { klass.send(:with_options, :protocol, 'port' => 443) }
87
+ .to add_method(:port).to(klass)
88
+ end
89
+
90
+ it do
91
+ expect { klass.send(:with_options, 'protocol', port: 443) }
92
+ .to change {
93
+ klass.invalid_options_in(test_keys)
94
+ }.from(%i[protocol port invalid])
95
+ .to([:invalid])
96
+ end
97
+
98
+ it do
99
+ expect { klass.send(:with_options, 'protocol', port: 443) }
100
+ .not_to change {
101
+ super_class.invalid_options_in(%i[protocol port])
102
+ }
103
+ end
104
+
105
+ context 'when overriding a method' do
106
+ it do
107
+ expect { klass.send(:with_options, :name, timeout: 10) }
108
+ .not_to change { klass.invalid_options_in(%i[name timeout]) }
109
+ end
110
+
111
+ it 'change methods to return new default' do
112
+ expect { klass.send(:with_options, :name, timeout: 10) }
113
+ .to change { klass.new.timeout }
114
+ .from(nil).to(10)
115
+ end
116
+
117
+ it 'change methods to return without default' do
118
+ expect { klass.send(:with_options, :name, timeout: 10) }
119
+ .to change { klass.new.name }
120
+ .from('My Connector').to(nil)
121
+ end
122
+ end
123
+ end
124
+ end
125
+
126
+ describe '.invalid_options_in' do
127
+ let(:klass) { Class.new(Sinclair::Options) }
128
+ let(:test_keys) { %i[timeout invalid] }
129
+
130
+ it 'returns alls keys as invalid' do
131
+ expect(klass.invalid_options_in(test_keys))
132
+ .to eq(test_keys)
133
+ end
134
+
135
+ context 'when allowed options was never set' do
136
+ before { klass.allow(:timeout) }
137
+
138
+ it 'returns keys that are not allowed by the input' do
139
+ expect(klass.invalid_options_in(test_keys))
140
+ .to eq([:invalid])
141
+ end
142
+ end
143
+
144
+ context 'when calling on subclass' do
145
+ let(:super_class) { Class.new(Sinclair::Options) }
146
+ let(:klass) { Class.new(super_class) }
147
+ let(:test_keys) { %i[timeout invalid] }
148
+
149
+ before { super_class.allow(:timeout) }
150
+
151
+ context 'when not adding allowed options' do
152
+ it 'returns keys that are not allowed by the input' do
153
+ expect(klass.invalid_options_in(test_keys))
154
+ .to eq([:invalid])
155
+ end
156
+ end
157
+
158
+ context 'when adding keys' do
159
+ before { super_class.allow(:retries) }
160
+
161
+ it 'returns keys that are not allowed by the input' do
162
+ expect(klass.invalid_options_in(test_keys))
163
+ .to eq([:invalid])
164
+ end
165
+
166
+ it 'adds new key to accepted' do
167
+ expect(klass.invalid_options_in([:retries]))
168
+ .to be_empty
169
+ end
170
+ end
171
+ end
172
+ end
173
+
174
+ describe '.allow' do
175
+ let(:klass) { Class.new(Sinclair::Options) }
176
+ let(:test_keys) { %i[timeout retries invalid] }
177
+
178
+ it 'adds options to allowed' do
179
+ expect { klass.allow(:timeout) }
180
+ .to change { klass.invalid_options_in(test_keys) }
181
+ .from(%i[timeout retries invalid])
182
+ .to(%i[retries invalid])
183
+ end
184
+
185
+ context 'when calling on subclass' do
186
+ let(:super_class) { Class.new(Sinclair::Options) }
187
+ let(:klass) { Class.new(super_class) }
188
+
189
+ before { super_class.allow(:timeout) }
190
+
191
+ it 'adds options to allowed' do
192
+ expect { klass.allow(:retries) }
193
+ .to change { klass.invalid_options_in(test_keys) }
194
+ .from(%i[retries invalid])
195
+ .to(%i[invalid])
196
+ end
197
+ end
198
+ end
199
+
200
+ describe '.allowed_options' do
201
+ let(:klass) { Class.new(Sinclair::Options) }
202
+
203
+ context 'when class has not been changed' do
204
+ it { expect(klass.allowed_options).to be_a(Set) }
205
+ end
206
+
207
+ context 'when initializing with with options' do
208
+ let(:expected) do
209
+ Set.new %i[timeout retries port protocol]
210
+ end
211
+
212
+ before do
213
+ klass.send(
214
+ :with_options,
215
+ :timeout, :retries, port: 443, protocol: 'https'
216
+ )
217
+ end
218
+
219
+ it do
220
+ expect(klass.allowed_options)
221
+ .to eq(expected)
222
+ end
223
+
224
+ context 'when class is descendent' do
225
+ let(:descendent_class) { Class.new(klass) }
226
+ let(:expected) do
227
+ Set.new %i[timeout retries port protocol name]
228
+ end
229
+
230
+ before do
231
+ descendent_class.send(
232
+ :with_options,
233
+ :name
234
+ )
235
+ end
236
+
237
+ it do
238
+ expect(descendent_class.allowed_options)
239
+ .to eq(expected)
240
+ end
241
+ end
242
+ end
243
+ end
244
+
245
+ describe '.skip_validation' do
246
+ let(:klass) { Class.new(Sinclair::Options) }
247
+
248
+ it 'skip initialization validation' do
249
+ klass.send(:skip_validation)
250
+
251
+ expect { klass.new(invalid: 10) }
252
+ .not_to raise_error
253
+ end
254
+ end
255
+ end
@@ -5,243 +5,6 @@ require 'spec_helper'
5
5
  describe Sinclair::Options do
6
6
  subject(:options) { klass.new }
7
7
 
8
- describe '.with_options' do
9
- let(:klass) { Class.new(described_class) }
10
- let(:test_keys) { %i[timeout retries invalid] }
11
-
12
- context 'when calling with keys' do
13
- it 'add first method' do
14
- expect { klass.send(:with_options, :timeout, 'retries') }
15
- .to add_method(:timeout).to(klass)
16
- end
17
-
18
- it 'add second method' do
19
- expect { klass.send(:with_options, :timeout, 'retries') }
20
- .to add_method(:retries).to(klass)
21
- end
22
-
23
- it 'adds options to allowed' do
24
- expect { klass.send(:with_options, :timeout, 'retries') }
25
- .to change { klass.invalid_options_in(test_keys) }
26
- .from(%i[timeout retries invalid])
27
- .to([:invalid])
28
- end
29
-
30
- it do
31
- expect { klass.send(:with_options, :timeout, 'retries') }
32
- .not_to change {
33
- described_class.invalid_options_in(%i[timeout retries invalid])
34
- }
35
- end
36
-
37
- context 'when when calling method after building' do
38
- before { klass.send(:with_options, :timeout, 'retries') }
39
-
40
- it { expect(options.timeout).to be_nil }
41
- end
42
-
43
- context 'when calling method twice' do
44
- before { klass.send(:with_options, :timeout, retries: 10) }
45
-
46
- it do
47
- expect { klass.send(:with_options, :timeout, :retries) }
48
- .not_to change {
49
- klass.invalid_options_in(%i[timeout retries invalid])
50
- }
51
- end
52
- end
53
- end
54
-
55
- context 'when calling with a hash' do
56
- it 'adds method' do
57
- expect { klass.send(:with_options, timeout_sec: 10, 'retries' => 20) }
58
- .to add_method(:timeout_sec).to(klass)
59
- end
60
-
61
- context 'when when calling method after building' do
62
- before { klass.send(:with_options, timeout_sec: 10, 'retries' => 20) }
63
-
64
- it 'returns default value' do
65
- expect(options.retries).to eq(20)
66
- end
67
- end
68
- end
69
-
70
- context 'when calling on subclass' do
71
- let(:super_class) { Class.new(described_class) }
72
- let(:klass) { Class.new(super_class) }
73
-
74
- let(:test_keys) do
75
- %i[timeout retries name protocol port invalid]
76
- end
77
-
78
- before { super_class.send(:with_options, :timeout, 'retries', name: 'My Connector') }
79
-
80
- it 'add first method' do
81
- expect { klass.send(:with_options, :protocol, 'port' => 443) }
82
- .to add_method(:protocol).to(klass)
83
- end
84
-
85
- it 'add second method' do
86
- expect { klass.send(:with_options, :protocol, 'port' => 443) }
87
- .to add_method(:port).to(klass)
88
- end
89
-
90
- it do
91
- expect { klass.send(:with_options, 'protocol', port: 443) }
92
- .to change {
93
- klass.invalid_options_in(test_keys)
94
- }.from(%i[protocol port invalid])
95
- .to([:invalid])
96
- end
97
-
98
- it do
99
- expect { klass.send(:with_options, 'protocol', port: 443) }
100
- .not_to change {
101
- super_class.invalid_options_in(%i[protocol port])
102
- }
103
- end
104
-
105
- context 'when overriding a method' do
106
- it do
107
- expect { klass.send(:with_options, :name, timeout: 10) }
108
- .not_to change { klass.invalid_options_in(%i[name timeout]) }
109
- end
110
-
111
- it 'change methods to return new default' do
112
- expect { klass.send(:with_options, :name, timeout: 10) }
113
- .to change { klass.new.timeout }
114
- .from(nil).to(10)
115
- end
116
-
117
- it 'change methods to return without default' do
118
- expect { klass.send(:with_options, :name, timeout: 10) }
119
- .to change { klass.new.name }
120
- .from('My Connector').to(nil)
121
- end
122
- end
123
- end
124
- end
125
-
126
- describe '.invalid_options_in' do
127
- let(:klass) { Class.new(described_class) }
128
- let(:test_keys) { %i[timeout invalid] }
129
-
130
- it 'returns alls keys as invalid' do
131
- expect(klass.invalid_options_in(test_keys))
132
- .to eq(test_keys)
133
- end
134
-
135
- context 'when allowed options was never set' do
136
- before { klass.allow(:timeout) }
137
-
138
- it 'returns keys that are not allowed by the input' do
139
- expect(klass.invalid_options_in(test_keys))
140
- .to eq([:invalid])
141
- end
142
- end
143
-
144
- context 'when calling on subclass' do
145
- let(:super_class) { Class.new(described_class) }
146
- let(:klass) { Class.new(super_class) }
147
- let(:test_keys) { %i[timeout invalid] }
148
-
149
- before { super_class.allow(:timeout) }
150
-
151
- context 'when not adding allowed options' do
152
- it 'returns keys that are not allowed by the input' do
153
- expect(klass.invalid_options_in(test_keys))
154
- .to eq([:invalid])
155
- end
156
- end
157
-
158
- context 'when adding keys' do
159
- before { super_class.allow(:retries) }
160
-
161
- it 'returns keys that are not allowed by the input' do
162
- expect(klass.invalid_options_in(test_keys))
163
- .to eq([:invalid])
164
- end
165
-
166
- it 'adds new key to accepted' do
167
- expect(klass.invalid_options_in([:retries]))
168
- .to be_empty
169
- end
170
- end
171
- end
172
- end
173
-
174
- describe '.allow' do
175
- let(:klass) { Class.new(described_class) }
176
- let(:test_keys) { %i[timeout retries invalid] }
177
-
178
- it 'adds options to allowed' do
179
- expect { klass.allow(:timeout) }
180
- .to change { klass.invalid_options_in(test_keys) }
181
- .from(%i[timeout retries invalid])
182
- .to(%i[retries invalid])
183
- end
184
-
185
- context 'when calling on subclass' do
186
- let(:super_class) { Class.new(described_class) }
187
- let(:klass) { Class.new(super_class) }
188
-
189
- before { super_class.allow(:timeout) }
190
-
191
- it 'adds options to allowed' do
192
- expect { klass.allow(:retries) }
193
- .to change { klass.invalid_options_in(test_keys) }
194
- .from(%i[retries invalid])
195
- .to(%i[invalid])
196
- end
197
- end
198
- end
199
-
200
- describe '.allowed_options' do
201
- let(:klass) { Class.new(described_class) }
202
-
203
- context 'when class has not been changed' do
204
- it { expect(klass.allowed_options).to be_a(Set) }
205
- end
206
-
207
- context 'when initializing with with options' do
208
- let(:expected) do
209
- Set.new %i[timeout retries port protocol]
210
- end
211
-
212
- before do
213
- klass.send(
214
- :with_options,
215
- :timeout, :retries, port: 443, protocol: 'https'
216
- )
217
- end
218
-
219
- it do
220
- expect(klass.allowed_options)
221
- .to eq(expected)
222
- end
223
-
224
- context 'when class is descendent' do
225
- let(:descendent_class) { Class.new(klass) }
226
- let(:expected) do
227
- Set.new %i[timeout retries port protocol name]
228
- end
229
-
230
- before do
231
- descendent_class.send(
232
- :with_options,
233
- :name
234
- )
235
- end
236
-
237
- it do
238
- expect(descendent_class.allowed_options)
239
- .to eq(expected)
240
- end
241
- end
242
- end
243
- end
244
-
245
8
  describe '#initialize' do
246
9
  let(:klass) { ConnectionOptions }
247
10
 
@@ -323,6 +86,34 @@ describe Sinclair::Options do
323
86
  end
324
87
  end
325
88
 
89
+ context 'when initializing with invalid args a class that skips validation' do
90
+ let(:klass) { OpenOptions }
91
+
92
+ it do
93
+ expect { klass.new(valid_option: 20, invalid: 10) }
94
+ .not_to raise_error
95
+ end
96
+
97
+ it 'initialize option' do
98
+ expect(klass.new(valid_option: 20, invalid: 10).valid_option)
99
+ .to eq(20)
100
+ end
101
+
102
+ context 'when initializing a subclass' do
103
+ let(:klass) { Class.new(OpenOptions) }
104
+
105
+ it do
106
+ expect { klass.new(valid_option: 20, invalid: 10) }
107
+ .not_to raise_error
108
+ end
109
+
110
+ it 'initialize option' do
111
+ expect(klass.new(valid_option: 20, invalid: 10).valid_option)
112
+ .to eq(20)
113
+ end
114
+ end
115
+ end
116
+
326
117
  context 'when initializing with string or symbol keys' do
327
118
  it do
328
119
  expect { klass.new('timeout' => 20, retries: 30) }
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class BuilderOptions < Sinclair::Options
4
+ with_options :name
5
+
6
+ skip_validation
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class LoginConfigurable
4
+ extend Sinclair::Configurable
5
+
6
+ configurable_by LoginConfig
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class OpenOptions < Sinclair::Options
4
+ with_options :valid_option
5
+
6
+ skip_validation
7
+ end
@@ -115,3 +115,51 @@ shared_examples 'a config class with .config_attributes method' do
115
115
  end
116
116
  end
117
117
  end
118
+
119
+ shared_examples 'a config class with .add_configs method' do
120
+ let(:setter_block) do
121
+ proc { |value| config.instance_variable_set(:@name, value) }
122
+ end
123
+
124
+ it_behaves_like 'a config methods builder adding config' do
125
+ let(:code_block) { proc { klass.add_configs(:name) } }
126
+
127
+ it 'sets nil value by default' do
128
+ code_block.call
129
+ expect(config.name).to be_nil
130
+ end
131
+
132
+ it 'adds attributes to class' do
133
+ expect(&code_block).to change(klass, :config_attributes)
134
+ .from([]).to(%i[name])
135
+ end
136
+
137
+ it do
138
+ expect(&code_block)
139
+ .to add_method(:name)
140
+ .to(klass.options_class)
141
+ end
142
+ end
143
+
144
+ context 'when giving defaults' do
145
+ it_behaves_like 'a config methods builder adding config' do
146
+ let(:code_block) { proc { klass.add_configs(name: 'Bob') } }
147
+
148
+ it 'sets default value' do
149
+ code_block.call
150
+ expect(config.name).to eq('Bob')
151
+ end
152
+
153
+ it 'adds attributes to class' do
154
+ expect(&code_block).to change(klass, :config_attributes)
155
+ .from([]).to(%i[name])
156
+ end
157
+
158
+ it do
159
+ expect(&code_block)
160
+ .to add_method(:name)
161
+ .to(klass.options_class)
162
+ end
163
+ end
164
+ end
165
+ end