sinclair 1.14.1 → 1.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -0
  3. data/README.md +37 -18
  4. data/config/yardstick.yml +10 -0
  5. data/lib/sinclair/caster/class_methods.rb +127 -0
  6. data/lib/sinclair/caster.rb +381 -0
  7. data/lib/sinclair/class_methods.rb +41 -0
  8. data/lib/sinclair/config_class.rb +4 -10
  9. data/lib/sinclair/method_definition/stringifier.rb +9 -7
  10. data/lib/sinclair/version.rb +1 -1
  11. data/lib/sinclair.rb +38 -21
  12. data/spec/integration/readme/sinclair/types_of_definition_spec.rb +8 -8
  13. data/spec/integration/yard/my_builder_spec.rb +8 -14
  14. data/spec/integration/yard/sinclair/add_method_spec.rb +11 -10
  15. data/spec/integration/yard/sinclair/caster/cast_spec.rb +57 -0
  16. data/spec/integration/yard/sinclair/caster/cast_with_spec.rb +54 -0
  17. data/spec/integration/yard/sinclair/caster/caster_for_spec.rb +16 -0
  18. data/spec/integration/yard/sinclair/caster/class_methods_spec.rb +17 -0
  19. data/spec/integration/yard/sinclair/class_methods/build_spec.rb +23 -0
  20. data/spec/integration/yard/sinclair/config_builder_spec.rb +6 -8
  21. data/spec/integration/yard/sinclair/config_class_spec.rb +7 -21
  22. data/spec/integration/yard/sinclair_spec.rb +14 -33
  23. data/spec/lib/sinclair/caster/class_methods_spec.rb +186 -0
  24. data/spec/lib/sinclair/caster_spec.rb +75 -0
  25. data/spec/lib/sinclair/class_methods_spec.rb +38 -0
  26. data/spec/support/models/enum_caster.rb +6 -0
  27. data/spec/support/models/enum_converter.rb +27 -0
  28. data/spec/support/models/hash_model.rb +11 -0
  29. data/spec/support/models/hash_person.rb +11 -0
  30. data/spec/support/models/http_json_model.rb +4 -6
  31. data/spec/support/models/math_caster.rb +17 -0
  32. data/spec/support/models/ruby_string_caster.rb +14 -0
  33. data/spec/support/models/string_parser.rb +9 -0
  34. metadata +20 -2
@@ -0,0 +1,186 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Sinclair::Caster::ClassMethods do
6
+ subject(:caster) { Class.new(Sinclair::Caster) }
7
+
8
+ describe '.cast_with' do
9
+ let(:value) { instance_double('value', to_p: final_value) }
10
+ let(:final_value) { Random.rand(100) }
11
+
12
+ context 'when a proc is given' do
13
+ it do
14
+ expect { caster.cast_with(:problem, &:to_p) }
15
+ .not_to raise_error
16
+ end
17
+
18
+ context 'when casting is called' do
19
+ before { caster.cast_with(:problem, &:to_p) }
20
+
21
+ it 'returns the cast value' do
22
+ expect(caster.cast(value, :problem)).to eq(final_value)
23
+ end
24
+ end
25
+ end
26
+
27
+ context 'when a proc with two arguments is given' do
28
+ it do
29
+ expect { caster.cast_with(:problem) { |v, **_opts| v.to_p } }
30
+ .not_to raise_error
31
+ end
32
+
33
+ context 'when casting is called' do
34
+ before { caster.cast_with(:problem) { |v, sum:| v.to_p + sum } }
35
+
36
+ it 'returns the cast value' do
37
+ expect(caster.cast(value, :problem, sum: 2))
38
+ .to eq(final_value + 2)
39
+ end
40
+ end
41
+ end
42
+
43
+ context 'when a symbol is given' do
44
+ let(:instance) { Sinclair::Caster.new(&:to_p) }
45
+
46
+ it do
47
+ expect { caster.cast_with(:problem, instance) }
48
+ .not_to raise_error
49
+ end
50
+
51
+ context 'when casting is called' do
52
+ before { caster.cast_with(:problem, instance) }
53
+
54
+ it 'returns the cast value' do
55
+ expect(caster.cast(value, :problem)).to eq(final_value)
56
+ end
57
+ end
58
+ end
59
+
60
+ context 'when a caster is given is given' do
61
+ it do
62
+ expect { caster.cast_with(:problem, :to_p) }
63
+ .not_to raise_error
64
+ end
65
+
66
+ context 'when casting is called' do
67
+ before { caster.cast_with(:problem, :to_p) }
68
+
69
+ it 'returns the cast value' do
70
+ expect(caster.cast(value, :problem)).to eq(final_value)
71
+ end
72
+ end
73
+ end
74
+
75
+ context 'when key is a class' do
76
+ it do
77
+ expect { caster.cast_with(Integer, :to_i) }
78
+ .not_to raise_error
79
+ end
80
+
81
+ context 'when casting is called' do
82
+ before { caster.cast_with(Integer, :to_i) }
83
+
84
+ it 'returns the cast value' do
85
+ expect(caster.cast('10', Integer)).to eq(10)
86
+ end
87
+ end
88
+ end
89
+
90
+ context 'when key is a module' do
91
+ it do
92
+ expect { caster.cast_with(JSON) { |value| JSON.parse(value) } }
93
+ .not_to raise_error
94
+ end
95
+
96
+ context 'when casting is called' do
97
+ before { caster.cast_with(JSON) { |value| JSON.parse(value) } }
98
+
99
+ it 'returns the cast value' do
100
+ expect(caster.cast('{"key":"value"}', JSON))
101
+ .to eq({ 'key' => 'value' })
102
+ end
103
+ end
104
+ end
105
+
106
+ context 'when key is a superclass' do
107
+ it do
108
+ expect { caster.cast_with(Numeric, :to_i) }
109
+ .not_to raise_error
110
+ end
111
+
112
+ context 'when casting is called with the child class' do
113
+ before { caster.cast_with(Numeric, :to_i) }
114
+
115
+ it 'returns the cast value' do
116
+ expect(caster.cast('10', Integer)).to eq(10)
117
+ end
118
+ end
119
+ end
120
+ end
121
+
122
+ describe '.caster_for' do
123
+ context 'when the key has been defined with a symbol key' do
124
+ before { caster.cast_with(:problem, :to_p) }
125
+
126
+ it do
127
+ expect(caster.caster_for(:problem))
128
+ .to be_a(Sinclair::Caster)
129
+ end
130
+ end
131
+
132
+ context 'when the key has not been defined' do
133
+ it do
134
+ expect(caster.caster_for(:problem))
135
+ .to be_a(Sinclair::Caster)
136
+ end
137
+ end
138
+ end
139
+
140
+ describe '.cast' do
141
+ let(:value) { values.sample }
142
+ let(:values) do
143
+ [Random.rand, 'some string', { key: 10 }, Object.new, Class.new, [2, 3]]
144
+ end
145
+
146
+ context 'when klass is nil' do
147
+ it 'returns the value' do
148
+ expect(caster.cast(value, nil))
149
+ .to eq(value)
150
+ end
151
+ end
152
+
153
+ context 'when class is :string' do
154
+ it 'returns the value as string' do
155
+ expect(caster.cast(value, :string))
156
+ .to eq(value.to_s)
157
+ end
158
+ end
159
+
160
+ context 'when class is :integer' do
161
+ let(:value) { '10.5' }
162
+
163
+ it 'returns the value as integer' do
164
+ expect(caster.cast(value, :integer))
165
+ .to eq(10)
166
+ end
167
+ end
168
+
169
+ context 'when class is :float' do
170
+ let(:value) { '10.5' }
171
+
172
+ it 'returns the value as float' do
173
+ expect(caster.cast(value, :float))
174
+ .to eq(10.5)
175
+ end
176
+ end
177
+ end
178
+
179
+ describe '.master_caster!' do
180
+ it 'ignores superclass registered casters' do
181
+ expect { caster.master_caster! }
182
+ .to change { caster.cast('10', :integer) }
183
+ .from(10).to('10')
184
+ end
185
+ end
186
+ 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,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Sinclair::ClassMethods do
6
+ subject(:builder) { builder_class.new(dummy_class, options) }
7
+
8
+ let(:options) { {} }
9
+ let(:instance) { dummy_class.new }
10
+ let(:dummy_class) { Class.new }
11
+ let(:builder_class) { Sinclair }
12
+
13
+ describe '#build' do
14
+ let(:block) do
15
+ method_name = :some_method
16
+ value = 1
17
+
18
+ proc do
19
+ add_method(method_name) { value }
20
+ end
21
+ end
22
+
23
+ it 'executes the block and builds' do
24
+ expect { builder_class.build(dummy_class, options, &block) }
25
+ .to add_method(:some_method).to(dummy_class)
26
+ end
27
+
28
+ context 'when the method is built and called' do
29
+ before do
30
+ builder_class.build(dummy_class, options, &block)
31
+ end
32
+
33
+ it 'returns the value' do
34
+ expect(instance.some_method).to eq(1)
35
+ end
36
+ end
37
+ end
38
+ 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
@@ -5,15 +5,13 @@ class HttpJsonModel
5
5
 
6
6
  class << self
7
7
  def parse(attribute, path: [])
8
- builder = Sinclair.new(self)
9
-
10
8
  keys = (path + [attribute]).map(&:to_s)
11
9
 
12
- builder.add_method(attribute) do
13
- keys.inject(hash) { |h, key| h[key] }
10
+ Sinclair.build(self) do
11
+ add_method(attribute) do
12
+ keys.inject(hash) { |h, key| h[key] }
13
+ end
14
14
  end
15
-
16
- builder.build
17
15
  end
18
16
  end
19
17
 
@@ -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.1
4
+ version: 1.15.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-25 00:00:00.000000000 Z
11
+ date: 2023-04-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -273,6 +273,9 @@ 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
278
+ - lib/sinclair/class_methods.rb
276
279
  - lib/sinclair/comparable.rb
277
280
  - lib/sinclair/comparable/class_methods.rb
278
281
  - lib/sinclair/config.rb
@@ -338,6 +341,11 @@ files:
338
341
  - spec/integration/yard/my_builder_spec.rb
339
342
  - spec/integration/yard/sinclair/add_class_method_spec.rb
340
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
348
+ - spec/integration/yard/sinclair/class_methods/build_spec.rb
341
349
  - spec/integration/yard/sinclair/comparable_spec.rb
342
350
  - spec/integration/yard/sinclair/config_builder_spec.rb
343
351
  - spec/integration/yard/sinclair/config_class_spec.rb
@@ -359,6 +367,9 @@ files:
359
367
  - spec/integration/yard/sinclair/options_parser_spec.rb
360
368
  - spec/integration/yard/sinclair/options_spec.rb
361
369
  - spec/integration/yard/sinclair_spec.rb
370
+ - spec/lib/sinclair/caster/class_methods_spec.rb
371
+ - spec/lib/sinclair/caster_spec.rb
372
+ - spec/lib/sinclair/class_methods_spec.rb
362
373
  - spec/lib/sinclair/comparable_spec.rb
363
374
  - spec/lib/sinclair/config/methods_builder_spec.rb
364
375
  - spec/lib/sinclair/config_builder_spec.rb
@@ -417,7 +428,11 @@ files:
417
428
  - spec/support/models/dummy_config.rb
418
429
  - spec/support/models/dummy_configurable.rb
419
430
  - spec/support/models/dummy_options_parser.rb
431
+ - spec/support/models/enum_caster.rb
432
+ - spec/support/models/enum_converter.rb
420
433
  - spec/support/models/env_settings.rb
434
+ - spec/support/models/hash_model.rb
435
+ - spec/support/models/hash_person.rb
421
436
  - spec/support/models/host_config.rb
422
437
  - spec/support/models/http_json_model.rb
423
438
  - spec/support/models/http_person.rb
@@ -426,6 +441,7 @@ files:
426
441
  - spec/support/models/job.rb
427
442
  - spec/support/models/login_config.rb
428
443
  - spec/support/models/login_configurable.rb
444
+ - spec/support/models/math_caster.rb
429
445
  - spec/support/models/my_app_client.rb
430
446
  - spec/support/models/my_builder.rb
431
447
  - spec/support/models/my_class.rb
@@ -438,9 +454,11 @@ files:
438
454
  - spec/support/models/person.rb
439
455
  - spec/support/models/purchase.rb
440
456
  - spec/support/models/random_generator.rb
457
+ - spec/support/models/ruby_string_caster.rb
441
458
  - spec/support/models/server.rb
442
459
  - spec/support/models/server_config.rb
443
460
  - spec/support/models/service_client.rb
461
+ - spec/support/models/string_parser.rb
444
462
  - spec/support/models/tv.rb
445
463
  - spec/support/models/validator_builder.rb
446
464
  - spec/support/sample_model.rb