sinclair 1.14.2 → 1.16.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,208 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Sinclair::Caster::ClassMethods do
6
+ subject(:caster) { Class.new(superclass) }
7
+
8
+ let(:superclass) do
9
+ Class.new(Sinclair::Caster) do
10
+ cast_with(:string, :to_s)
11
+ cast_with(:integer, :to_i)
12
+ cast_with(:float, :to_f)
13
+ cast_with(String, :to_s)
14
+ end
15
+ end
16
+
17
+ describe '.cast_with' do
18
+ let(:value) { instance_double('value', to_p: final_value) }
19
+ let(:final_value) { Random.rand(100) }
20
+
21
+ context 'when a proc is given' do
22
+ it do
23
+ expect { caster.cast_with(:problem, &:to_p) }
24
+ .not_to raise_error
25
+ end
26
+
27
+ context 'when casting is called' do
28
+ before { caster.cast_with(:problem, &:to_p) }
29
+
30
+ it 'returns the cast value' do
31
+ expect(caster.cast(value, :problem)).to eq(final_value)
32
+ end
33
+ end
34
+ end
35
+
36
+ context 'when a proc with two arguments is given' do
37
+ it do
38
+ expect { caster.cast_with(:problem) { |v, **_opts| v.to_p } }
39
+ .not_to raise_error
40
+ end
41
+
42
+ context 'when casting is called' do
43
+ before { caster.cast_with(:problem) { |v, sum:| v.to_p + sum } }
44
+
45
+ it 'returns the cast value' do
46
+ expect(caster.cast(value, :problem, sum: 2))
47
+ .to eq(final_value + 2)
48
+ end
49
+ end
50
+ end
51
+
52
+ context 'when a symbol is given' do
53
+ let(:instance) { Sinclair::Caster.new(&:to_p) }
54
+
55
+ it do
56
+ expect { caster.cast_with(:problem, instance) }
57
+ .not_to raise_error
58
+ end
59
+
60
+ context 'when casting is called' do
61
+ before { caster.cast_with(:problem, instance) }
62
+
63
+ it 'returns the cast value' do
64
+ expect(caster.cast(value, :problem)).to eq(final_value)
65
+ end
66
+ end
67
+ end
68
+
69
+ context 'when a caster is given is given' do
70
+ it do
71
+ expect { caster.cast_with(:problem, :to_p) }
72
+ .not_to raise_error
73
+ end
74
+
75
+ context 'when casting is called' do
76
+ before { caster.cast_with(:problem, :to_p) }
77
+
78
+ it 'returns the cast value' do
79
+ expect(caster.cast(value, :problem)).to eq(final_value)
80
+ end
81
+ end
82
+ end
83
+
84
+ context 'when key is a class' do
85
+ it do
86
+ expect { caster.cast_with(Integer, :to_i) }
87
+ .not_to raise_error
88
+ end
89
+
90
+ context 'when casting is called' do
91
+ before { caster.cast_with(Integer, :to_i) }
92
+
93
+ it 'returns the cast value' do
94
+ expect(caster.cast('10', Integer)).to eq(10)
95
+ end
96
+ end
97
+ end
98
+
99
+ context 'when key is a module' do
100
+ it do
101
+ expect { caster.cast_with(JSON) { |value| JSON.parse(value) } }
102
+ .not_to raise_error
103
+ end
104
+
105
+ context 'when casting is called' do
106
+ before { caster.cast_with(JSON) { |value| JSON.parse(value) } }
107
+
108
+ it 'returns the cast value' do
109
+ expect(caster.cast('{"key":"value"}', JSON))
110
+ .to eq({ 'key' => 'value' })
111
+ end
112
+ end
113
+ end
114
+
115
+ context 'when key is a superclass' do
116
+ it do
117
+ expect { caster.cast_with(Numeric, :to_i) }
118
+ .not_to raise_error
119
+ end
120
+
121
+ context 'when casting is called with the child class' do
122
+ before { caster.cast_with(Numeric, :to_i) }
123
+
124
+ it 'returns the cast value' do
125
+ expect(caster.cast('10', Integer)).to eq(10)
126
+ end
127
+ end
128
+ end
129
+ end
130
+
131
+ describe '.caster_for' do
132
+ context 'when nil key is given' do
133
+ let(:value) { values.sample }
134
+ let(:values) do
135
+ [Random.rand, 'some string', { key: 10 }, Object.new, Class.new, [2, 3]]
136
+ end
137
+
138
+ it { expect(caster.caster_for(nil)).to be_a(Sinclair::Caster) }
139
+
140
+ it 'returns the default caster' do
141
+ expect(caster.caster_for(nil).cast(value)).to eq(value)
142
+ end
143
+ end
144
+
145
+ context 'when the key has been defined with a symbol key' do
146
+ before { caster.cast_with(:problem, :to_p) }
147
+
148
+ it do
149
+ expect(caster.caster_for(:problem))
150
+ .to be_a(Sinclair::Caster)
151
+ end
152
+ end
153
+
154
+ context 'when the key has not been defined' do
155
+ it do
156
+ expect(caster.caster_for(:problem))
157
+ .to be_a(Sinclair::Caster)
158
+ end
159
+ end
160
+ end
161
+
162
+ describe '.cast' do
163
+ let(:value) { values.sample }
164
+ let(:values) do
165
+ [Random.rand, 'some string', { key: 10 }, Object.new, Class.new, [2, 3]]
166
+ end
167
+
168
+ context 'when klass is nil' do
169
+ it 'returns the value' do
170
+ expect(caster.cast(value, nil))
171
+ .to eq(value)
172
+ end
173
+ end
174
+
175
+ context 'when class is :string' do
176
+ it 'returns the value as string' do
177
+ expect(caster.cast(value, :string))
178
+ .to eq(value.to_s)
179
+ end
180
+ end
181
+
182
+ context 'when class is :integer' do
183
+ let(:value) { '10.5' }
184
+
185
+ it 'returns the value as integer' do
186
+ expect(caster.cast(value, :integer))
187
+ .to eq(10)
188
+ end
189
+ end
190
+
191
+ context 'when class is :float' do
192
+ let(:value) { '10.5' }
193
+
194
+ it 'returns the value as float' do
195
+ expect(caster.cast(value, :float))
196
+ .to eq(10.5)
197
+ end
198
+ end
199
+ end
200
+
201
+ describe '.master_caster!' do
202
+ it 'ignores superclass registered casters' do
203
+ expect { caster.master_caster! }
204
+ .to change { caster.cast('10', :integer) }
205
+ .from(10).to('10')
206
+ end
207
+ end
208
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Sinclair::Caster do
6
+ subject(:caster) { caster_class.new(&method_name) }
7
+
8
+ let(:caster_class) { Class.new(described_class) }
9
+
10
+ describe '.cast' do
11
+ context 'when no options are given and the block accepts none' do
12
+ let(:method_name) { :to_s }
13
+
14
+ it 'uses the block to transform the value' do
15
+ expect(caster.cast(10)).to eq('10')
16
+ end
17
+ end
18
+
19
+ context 'when options are given and the block accepts none' do
20
+ let(:method_name) { :to_i }
21
+
22
+ it 'uses the block to transform the value' do
23
+ expect(caster.cast('10', extra: true)).to eq(10)
24
+ end
25
+ end
26
+
27
+ context 'when no options are given and the block accepts options' do
28
+ subject(:caster) do
29
+ caster_class.new do |value, sum: 5|
30
+ (value.to_i + sum).to_s
31
+ end
32
+ end
33
+
34
+ it 'uses the block to transform the value' do
35
+ expect(caster.cast('10')).to eq('15')
36
+ end
37
+ end
38
+
39
+ context 'when options are given and the block accepts options' do
40
+ subject(:caster) do
41
+ caster_class.new do |value, sum:|
42
+ (value.to_i + sum).to_s
43
+ end
44
+ end
45
+
46
+ it 'uses the options in the block' do
47
+ expect(caster.cast('10', sum: 5)).to eq('15')
48
+ end
49
+ end
50
+
51
+ context 'when no options are given and the block requires options' do
52
+ subject(:caster) do
53
+ caster_class.new do |value, sum:|
54
+ (value.to_i + sum).to_s
55
+ end
56
+ end
57
+
58
+ it do
59
+ expect { caster.cast('10') }.to raise_error(ArgumentError)
60
+ end
61
+ end
62
+
63
+ context 'when extra options are given and the block accepts options' do
64
+ subject(:caster) do
65
+ caster_class.new do |value, sum:|
66
+ (value.to_i + sum).to_s
67
+ end
68
+ end
69
+
70
+ it 'ignores extra options' do
71
+ expect(caster.cast('10', sum: 5, extra: true)).to eq('15')
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: false
2
+
3
+ class EnumCaster < Sinclair::Caster
4
+ cast_with(:hash, :to_h)
5
+ cast_with(:array, :to_a)
6
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: false
2
+
3
+ module EnumConverter
4
+ class << self
5
+ def to_hash(value)
6
+ return value if value.is_a?(Hash)
7
+
8
+ hash_caster.cast(value)
9
+ end
10
+
11
+ def to_array(value)
12
+ return value if value.is_a?(Array)
13
+
14
+ array_caster.cast(value)
15
+ end
16
+
17
+ private
18
+
19
+ def hash_caster
20
+ @hash_caster ||= EnumCaster.caster_for(:hash)
21
+ end
22
+
23
+ def array_caster
24
+ @array_caster ||= EnumCaster.caster_for(:array)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class HashModel
4
+ def initialize(hash)
5
+ hash.each do |attribute, value|
6
+ method_name = "#{attribute}="
7
+
8
+ send(method_name, value) if respond_to?(method_name)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class HashPerson < HashModel
4
+ attr_accessor :name, :age
5
+
6
+ def ==(other)
7
+ return unless other.class == self.class
8
+
9
+ other.name == name && other.age == age
10
+ end
11
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MathCaster < Sinclair::Caster
4
+ cast_with(:float, :to_f)
5
+
6
+ cast_with(:log) do |value, base: 10|
7
+ value = MathCaster.cast(value, :float)
8
+
9
+ Math.log(value, base)
10
+ end
11
+
12
+ cast_with(:exp) do |value, base: 10|
13
+ value = MathCaster.cast(value, :float)
14
+
15
+ base**value
16
+ end
17
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ class RubyStringCaster < Sinclair::Caster
4
+ master_caster!
5
+
6
+ cast_with(NilClass) { 'nil' }
7
+ cast_with(Symbol) { |value| ":#{value}" }
8
+ cast_with(String, :to_json)
9
+ cast_with(Object, :to_s)
10
+
11
+ def self.to_ruby_string(value)
12
+ cast(value, value.class)
13
+ end
14
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: false
2
+
3
+ class StringParser < Sinclair::Caster
4
+ master_caster!
5
+
6
+ cast_with(JSON) { |value| JSON.parse(value) }
7
+ cast_with(Integer, :to_i)
8
+ cast_with(Float, :to_f)
9
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sinclair
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.14.2
4
+ version: 1.16.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - DarthJee
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-04-27 00:00:00.000000000 Z
11
+ date: 2023-05-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -273,6 +273,8 @@ files:
273
273
  - config/yardstick.yml
274
274
  - docker-compose.yml
275
275
  - lib/sinclair.rb
276
+ - lib/sinclair/caster.rb
277
+ - lib/sinclair/caster/class_methods.rb
276
278
  - lib/sinclair/class_methods.rb
277
279
  - lib/sinclair/comparable.rb
278
280
  - lib/sinclair/comparable/class_methods.rb
@@ -339,6 +341,10 @@ files:
339
341
  - spec/integration/yard/my_builder_spec.rb
340
342
  - spec/integration/yard/sinclair/add_class_method_spec.rb
341
343
  - spec/integration/yard/sinclair/add_method_spec.rb
344
+ - spec/integration/yard/sinclair/caster/cast_spec.rb
345
+ - spec/integration/yard/sinclair/caster/cast_with_spec.rb
346
+ - spec/integration/yard/sinclair/caster/caster_for_spec.rb
347
+ - spec/integration/yard/sinclair/caster/class_methods_spec.rb
342
348
  - spec/integration/yard/sinclair/class_methods/build_spec.rb
343
349
  - spec/integration/yard/sinclair/comparable_spec.rb
344
350
  - spec/integration/yard/sinclair/config_builder_spec.rb
@@ -361,6 +367,8 @@ files:
361
367
  - spec/integration/yard/sinclair/options_parser_spec.rb
362
368
  - spec/integration/yard/sinclair/options_spec.rb
363
369
  - spec/integration/yard/sinclair_spec.rb
370
+ - spec/lib/sinclair/caster/class_methods_spec.rb
371
+ - spec/lib/sinclair/caster_spec.rb
364
372
  - spec/lib/sinclair/class_methods_spec.rb
365
373
  - spec/lib/sinclair/comparable_spec.rb
366
374
  - spec/lib/sinclair/config/methods_builder_spec.rb
@@ -420,7 +428,11 @@ files:
420
428
  - spec/support/models/dummy_config.rb
421
429
  - spec/support/models/dummy_configurable.rb
422
430
  - spec/support/models/dummy_options_parser.rb
431
+ - spec/support/models/enum_caster.rb
432
+ - spec/support/models/enum_converter.rb
423
433
  - spec/support/models/env_settings.rb
434
+ - spec/support/models/hash_model.rb
435
+ - spec/support/models/hash_person.rb
424
436
  - spec/support/models/host_config.rb
425
437
  - spec/support/models/http_json_model.rb
426
438
  - spec/support/models/http_person.rb
@@ -429,6 +441,7 @@ files:
429
441
  - spec/support/models/job.rb
430
442
  - spec/support/models/login_config.rb
431
443
  - spec/support/models/login_configurable.rb
444
+ - spec/support/models/math_caster.rb
432
445
  - spec/support/models/my_app_client.rb
433
446
  - spec/support/models/my_builder.rb
434
447
  - spec/support/models/my_class.rb
@@ -441,9 +454,11 @@ files:
441
454
  - spec/support/models/person.rb
442
455
  - spec/support/models/purchase.rb
443
456
  - spec/support/models/random_generator.rb
457
+ - spec/support/models/ruby_string_caster.rb
444
458
  - spec/support/models/server.rb
445
459
  - spec/support/models/server_config.rb
446
460
  - spec/support/models/service_client.rb
461
+ - spec/support/models/string_parser.rb
447
462
  - spec/support/models/tv.rb
448
463
  - spec/support/models/validator_builder.rb
449
464
  - spec/support/sample_model.rb