sinclair 1.14.2 → 1.16.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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