sinclair 1.14.2 → 1.15.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b6bd1d9896437c341e52648bac78c70d453a773c92a2fba06111d88d12be06a3
4
- data.tar.gz: 5cb2ba761532e3db60ffc8a09b821509c1355949071c5346cef962b0d43dfe9d
3
+ metadata.gz: bd10c98e0ec9983e0bd34a8b438126cc391ae667c9e7d5b7ca62f473c5296aea
4
+ data.tar.gz: f1bffcf49524f9dc05ee27e7510c4e0a76be23b674642fcfa2b10cfdb9f43a82
5
5
  SHA512:
6
- metadata.gz: bf2fd682ae8e6c57a8a173a5f78492bf6c7011dfef7734fd9c0c2d3d4d73fa599bac72a9317920dd0ebf5bb6c98f0f2f511c0fcc9fe5b683f766b5624359ccf3
7
- data.tar.gz: db83a68fd9b11d0a227afca422f5a6e8e33bc64e3624a55c0d8f3b87d49235d8e17b1393c44b6ac2a67c8b9869e58d5780a3a06aad4f76429a4c4b0c48247f43
6
+ metadata.gz: f3afe247b25b8b10f692227c3d5c031e4d6fd04f8aa00e021d0aa8d5813d9cba75c05b4a7d8aae6cc5b6be96d7de404becf35e9391db92c3ceadfc2804f72ce5
7
+ data.tar.gz: c80cee176cd24ecce3410fa6a64789ca3f52789bce24d558b421751fb6c74a4bf5c86eb1246e48d09abbad962e3bc6f965f1dcf09beae9eca68a198d4e969771
data/.rubocop.yml CHANGED
@@ -31,6 +31,7 @@ RSpec/PredicateMatcher:
31
31
  RSpec/DescribedClass:
32
32
  Exclude:
33
33
  - 'spec/integration/yard/**/*_spec.rb'
34
+ - 'spec/integration/readme/**/*_spec.rb'
34
35
 
35
36
  RSpec/ExampleLength:
36
37
  Exclude:
data/README.md CHANGED
@@ -15,13 +15,13 @@ create custom comparators, configure your application, create powerfull options,
15
15
 
16
16
  Employing Sinclair in your applications helps you streamline your development workflow and enhance your development process through more efficient, cleaner code
17
17
 
18
- Current Release: [1.14.2](https://github.com/darthjee/sinclair/tree/1.14.2)
18
+ Current Release: [1.15.0](https://github.com/darthjee/sinclair/tree/1.15.0)
19
19
 
20
- [Next release](https://github.com/darthjee/sinclair/compare/1.14.2...master)
20
+ [Next release](https://github.com/darthjee/sinclair/compare/1.15.0...master)
21
21
 
22
22
  Yard Documentation
23
23
  -------------------
24
- [https://www.rubydoc.info/gems/sinclair/1.14.2](https://www.rubydoc.info/gems/sinclair/1.14.2)
24
+ [https://www.rubydoc.info/gems/sinclair/1.15.0](https://www.rubydoc.info/gems/sinclair/1.15.0)
25
25
 
26
26
  Installation
27
27
  ---------------
@@ -290,9 +290,9 @@ Block methods accepts, as option
290
290
  klass = Class.new
291
291
  instance = klass.new
292
292
 
293
- builder = Sinclair.new(klass)
294
- builder.add_method(:random_number) { Random.rand(10..20) }
295
- builder.build
293
+ Sinclair.build(klass) do
294
+ add_method(:random_number) { Random.rand(10..20) }
295
+ end
296
296
 
297
297
  instance.random_number # returns a number between 10 and 20
298
298
  ```
@@ -326,11 +326,11 @@ instance.random_number # returns a number between 10 and 20
326
326
  class MyClass
327
327
  end
328
328
 
329
- builder = described_class.new(MyClass)
330
- builder.add_class_method(
331
- :function, 'a ** b + c', parameters: [:a], named_parameters: [:b, { c: 15 }]
332
- )
333
- builder.build
329
+ Sinclair.build(MyClass) do
330
+ add_class_method(
331
+ :function, 'a ** b + c', parameters: [:a], named_parameters: [:b, { c: 15 }]
332
+ )
333
+ end
334
334
 
335
335
  MyClass.function(10, b: 2) # returns 115
336
336
  ```
data/config/yardstick.yml CHANGED
@@ -1,4 +1,4 @@
1
- threshold: 99.8
1
+ threshold: 100
2
2
  require_exact_threshold: false
3
3
  rules:
4
4
  ApiTag::Presence:
@@ -18,6 +18,14 @@ rules:
18
18
  exclude:
19
19
  - Sinclair#add_method
20
20
  - Sinclair#add_class_method
21
+ - Sinclair.build
22
+ - Sinclair::Caster.cast
23
+ - Sinclair::Caster.cast_with
24
+ - Sinclair::Caster.caster_for
25
+ - Sinclair::Caster#initialize
26
+ - Sinclair::Caster::ClassMethods#cast
27
+ - Sinclair::Caster::ClassMethods#cast_with
28
+ - Sinclair::Caster::ClassMethods#caster_for
21
29
  - Sinclair::Configurable#config
22
30
  - Sinclair::Configurable#reset_config
23
31
  - Sinclair::Configurable#configure
@@ -34,6 +42,7 @@ rules:
34
42
  ReturnTag:
35
43
  enabled: true
36
44
  exclude:
45
+ - Sinclair.build
37
46
  - Sinclair::Matchers::AddClassMethodTo#raise_block_syntax_error
38
47
  - Sinclair::Matchers::AddInstanceMethodTo#raise_block_syntax_error
39
48
  - Sinclair::MethodBuilder#build_from_definition
@@ -42,6 +51,7 @@ rules:
42
51
  Summary::Presence:
43
52
  enabled: true
44
53
  exclude:
54
+ - Sinclair::Caster#initialize
45
55
  - Sinclair::Config::MethodsBuilder#initialize
46
56
  - Sinclair::ConfigFactory#initialize
47
57
  - Sinclair::EnvSettable::Builder#initialize
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Sinclair
4
+ class Caster
5
+ # @api public
6
+ # @author darhtjee
7
+ #
8
+ # Class methods for {Caster}
9
+ module ClassMethods
10
+ # (see Caster.master_caster!)
11
+ def master_caster!
12
+ @master_caster = true
13
+ end
14
+
15
+ # (see Caster.cast_with)
16
+ def cast_with(key, method_name = nil, &block)
17
+ caster = instance_for(method_name, &block)
18
+
19
+ return class_casters[key] = caster if key.is_a?(Class)
20
+
21
+ casters[key] = caster
22
+ end
23
+
24
+ # (see Caster.cast)
25
+ def cast(value, key, **opts)
26
+ caster_for(key).cast(value, **opts)
27
+ end
28
+
29
+ # (see Caster.caster_for)
30
+ def caster_for(key)
31
+ return casters[key] if casters.key?(key)
32
+
33
+ caster_for_class(key) || superclas_caster_for(key) || new { |value| value }
34
+ end
35
+
36
+ protected
37
+
38
+ # @api private
39
+ #
40
+ # Returns a caster from the superclass
41
+ #
42
+ # @param key [Symbol,Class] key to be checked
43
+ #
44
+ # @see caster_for
45
+ # @return [Caster]
46
+ def superclas_caster_for(key)
47
+ return if master_caster?
48
+
49
+ superclass.caster_for(key)
50
+ end
51
+
52
+ # @api private
53
+ #
54
+ # Returns a caster searching for using class as key
55
+ #
56
+ # This is called by {#caster_for} any time key is a class
57
+ #
58
+ # @param klass [Class] class to be used in the search
59
+ #
60
+ # When the given class is not registered, a caster for a parent
61
+ # class is returned
62
+ #
63
+ # @return [Caster]
64
+ def caster_for_class(klass)
65
+ class_casters.find do |klazz, _|
66
+ klass <= klazz
67
+ end&.second
68
+ end
69
+
70
+ # @api private
71
+ #
72
+ # Returns a new instance {Caster}
73
+ #
74
+ # @overload instance_for(method_name, &block)
75
+ # @param method_name [Symbol] method to be called in the model
76
+ # @param block [Proc] block to perform the casting
77
+ #
78
+ # When +method_name+ is not given, the block is used
79
+ #
80
+ # @overload instance_for(caster)
81
+ # @param caster [Caster] instance of caster to be returned
82
+ #
83
+ # @return [Caster]
84
+ def instance_for(method_name, &block)
85
+ return new(&block) unless method_name
86
+ return method_name if method_name.is_a?(Caster)
87
+
88
+ new(&method_name)
89
+ end
90
+
91
+ private
92
+
93
+ # @api private
94
+ # @private
95
+ #
96
+ # Caster map stored by +Symbols+
97
+ #
98
+ # @return [Hash<Symbol,Caster>]
99
+ def casters
100
+ @casters ||= {}
101
+ end
102
+
103
+ # @api private
104
+ # @private
105
+ #
106
+ # Caster map stored by +Classs+
107
+ #
108
+ # @return [Hash<Class,Caster>]
109
+ def class_casters
110
+ @class_casters ||= {}
111
+ end
112
+
113
+ # @api private
114
+ # @private
115
+ #
116
+ # Chack if the caster class is a master
117
+ #
118
+ # A master caster never checks if a superclass has a caster
119
+ #
120
+ # @see master_caster!
121
+ # @return [TrueClass,FalseClass]
122
+ def master_caster?
123
+ @master_caster
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,381 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Sinclair
4
+ # @api public
5
+ # @author darhtjee
6
+ #
7
+ # Class responsible for defining how to and casting values
8
+ #
9
+ # First the class needs to be configured using {.cast_with} and later
10
+ # a value can be cast by using {.cast} or {.caster_for}
11
+ #
12
+ # Inheritance grants the hability to have different casting for different
13
+ # purposes / applications / gems
14
+ class Caster
15
+ autoload :ClassMethods, 'sinclair/caster/class_methods'
16
+ extend Caster::ClassMethods
17
+ master_caster!
18
+
19
+ # @method self.master_caster!
20
+ # @api public
21
+ #
22
+ # Changes the class to be the master caster
23
+ #
24
+ # The master caster never checks with its an
25
+ #
26
+ # @example
27
+ # class MyCaster < Sinclair::Caster
28
+ # end
29
+ #
30
+ # MyCaster.cast(10, :string) # returns '10'
31
+ #
32
+ # MyCaster.master_caster!
33
+ #
34
+ # MyCaster.cast(10, :string) # returns 10
35
+ #
36
+ # @see Caster::ClassMethods#master_caster!
37
+ #
38
+ # @return [TrueClass]
39
+
40
+ # @method self.cast_with
41
+ # @api public
42
+ #
43
+ # Register a caster under a key
44
+ #
45
+ # @overload cast_with(key, method_name)
46
+ # @param key [Symbol] key where the caster will be store.
47
+ # @param method_name [Symbol] method to be called on the
48
+ # value that is being converted
49
+ #
50
+ # @example Casting from pre registered symbol caster
51
+ # class MyCaster < Sinclair::Caster
52
+ # cast_with(:json, :to_json)
53
+ # end
54
+ #
55
+ # MyCaster.cast({ key: :value }, :json) # returns '{"key":"value"}'
56
+ #
57
+ # @overload cast_with(key, &block)
58
+ # @param key [Symbol] key where the caster will be store.
59
+ # @param block [Proc] block to be used when casting the value.
60
+ #
61
+ # @example Casting from pre registered block caster
62
+ # MyCaster.cast_with(:complex) do |hash|
63
+ # real = hash[:real]
64
+ # imaginary = hash[:imaginary]
65
+ #
66
+ # "#{real.to_f} + #{imaginary.to_f} i"
67
+ # end
68
+ #
69
+ # value = { real: 10, imaginary: 5 }
70
+ #
71
+ # MyCaster.cast(value, :complex) # returns '10.0 + 5.0 i'
72
+ #
73
+ # @overload cast_with(class_key, method_name)
74
+ # @param class_key [Class] class to be used as key.
75
+ # This will be used as parent class when the calling {Caster.cast}.
76
+ # @param method_name [Symbol] method to be called on the
77
+ # value that is being converted.
78
+ #
79
+ # @example Casting from pre registered class
80
+ # class MyCaster < Sinclair::Caster
81
+ # cast_with(Numeric, :to_i)
82
+ # end
83
+ #
84
+ # MyCaster.cast('10', Integer) # returns 10
85
+ #
86
+ # @overload cast_with(class_key, &block)
87
+ # @param class_key [Class] class to be used as key.
88
+ # This will be used as parent class when the calling {Caster.cast}.
89
+ # @param block [Proc] block to be used when casting the value.
90
+ #
91
+ # @example Casting from pre registered block caster from a class
92
+ # # hash_model.rb
93
+ #
94
+ # class HashModel
95
+ # def initialize(hash)
96
+ # hash.each do |attribute, value|
97
+ # method_name = "#{attribute}="
98
+ #
99
+ # send(method_name, value) if respond_to?(method_name)
100
+ # end
101
+ # end
102
+ # end
103
+ #
104
+ # # hash_person.rb
105
+ # class HashPerson < HashModel
106
+ # attr_accessor :name, :age
107
+ # end
108
+ #
109
+ # # caster_config.rb
110
+ # Caster.cast_with(HashModel) do |value, klass:|
111
+ # klass.new(value)
112
+ # end
113
+ #
114
+ # Caster.cast_with(String, &:to_json)
115
+ #
116
+ # # main.rb
117
+ # values = [
118
+ # { klass: String, value: { name: 'john', age: 20, country: 'BR' } },
119
+ # { klass: HashPerson, value: { name: 'Mary', age: 22, country: 'IT' } }
120
+ # ]
121
+ #
122
+ # values.map! do |config|
123
+ # value = config[:value]
124
+ # klass = config[:klass]
125
+ #
126
+ # Caster.cast(value, klass, klass: klass)
127
+ # end
128
+ #
129
+ # values[0] # returns '{"name":"john","age":20,"country":"BR"}'
130
+ # values[1] # returns HashPerson.new(name: 'Mary', age: 22)
131
+ #
132
+ # @see Caster::ClassMethods#cast_with
133
+ # @see Caster.caster_for
134
+ # @see Caster.cast
135
+ #
136
+ # @return [Caster] the registered caster
137
+
138
+ # @method self.cast
139
+ # @api public
140
+ #
141
+ # Cast a value using the registered caster
142
+ #
143
+ # @overload cast(value, key, **opts)
144
+ # @param value [Object] value to be cast
145
+ # @param key [Symbol] key where the caster is registered under
146
+ # @param opts [Hash] Options to be sent to the caster
147
+ #
148
+ # @example Casts with a symbol key
149
+ # # math_caster.rb
150
+ # class MathCaster < Sinclair::Caster
151
+ # cast_with(:float, :to_f)
152
+ #
153
+ # cast_with(:log) do |value, base: 10|
154
+ # value = MathCaster.cast(value, :float)
155
+ #
156
+ # Math.log(value, base)
157
+ # end
158
+ #
159
+ # cast_with(:exp) do |value, base: 10|
160
+ # value = MathCaster.cast(value, :float)
161
+ #
162
+ # base**value
163
+ # end
164
+ # end
165
+ #
166
+ # # main.rb
167
+ # initial = Random.rand(10..20)
168
+ # log = MathCaster.cast(initial, :log)
169
+ # exp = MathCaster.cast(log, :exp)
170
+ #
171
+ # # exp will be betwween initial - 0.0001 and initial + 0.0001
172
+ #
173
+ # @example Casts passing parameter
174
+ # base = Random.rand(3..6)
175
+ # initial = Random.rand(10..20)
176
+ # log = MathCaster.cast(initial, :log, base: base)
177
+ # exp = MathCaster.cast(log, :exp, base: base)
178
+ #
179
+ # # exp will be betwween initial - 0.0001 and initial + 0.0001
180
+ #
181
+ # @overload cast(value, class_key, **opts)
182
+ # @param value [Object] value to be cast
183
+ # @param class_key [Class] Class to used as key in the casters storage
184
+ # @param opts [Hash] Options to be sent to the caster
185
+ #
186
+ # When the +class_key+ does not match the stored key, but matches a superclass,
187
+ # the registerd caster is returned.
188
+ #
189
+ # @example Casts with class key
190
+ # # ruby_string_caster.rb
191
+ # class RubyStringCaster < Sinclair::Caster
192
+ # master_caster!
193
+ #
194
+ # cast_with(NilClass) { 'nil' }
195
+ # cast_with(Symbol) { |value| ":#{value}" }
196
+ # cast_with(String, :to_json)
197
+ # cast_with(Object, :to_s)
198
+ #
199
+ # def self.to_ruby_string(value)
200
+ # cast(value, value.class)
201
+ # end
202
+ # end
203
+ #
204
+ # # main.rb
205
+ # hash = { a: 1, b: 2, 'c' => nil }
206
+ # string = 'my string'
207
+ # symbol = :the_symbol
208
+ # number = 10
209
+ # null = nil
210
+ #
211
+ # <<-RUBY
212
+ # hash_value = #{RubyStringCaster.to_ruby_string(hash)}
213
+ # string_value = #{RubyStringCaster.to_ruby_string(string)}
214
+ # symbol_value = #{RubyStringCaster.to_ruby_string(symbol)}
215
+ # number = #{RubyStringCaster.to_ruby_string(number)}
216
+ # null_value = #{RubyStringCaster.to_ruby_string(null)}
217
+ # RUBY
218
+ #
219
+ # # Generates the String
220
+ # #
221
+ # # <<-RUBY
222
+ # # hash_value = {:a=>1, :b=>2, "c"=>nil}
223
+ # # string_value = "my string"
224
+ # # symbol_value = :the_symbol
225
+ # # number = 10
226
+ # # null_value = nil
227
+ # # RUBY
228
+ #
229
+ # @see Caster::ClassMethods#cast
230
+ # @see Caster.cast_with
231
+ # @see Caster.caster_for
232
+ # @see Caster#cast
233
+ #
234
+ # @return [Object] the value cast
235
+
236
+ # @method self.caster_for
237
+ # @api public
238
+ #
239
+ # Returns an instance of caster for the provided key
240
+ #
241
+ # When no registered caster is found one is requested for the parent class.
242
+ # If no caster is found, then a default caster is returned
243
+ #
244
+ # The default caster performs no casting returning the value itself
245
+ #
246
+ # @overload caster_for(key)
247
+ # @param key [Symbol] key where the caster is registered under
248
+ #
249
+ # @example Getting the caster with symbol key
250
+ # # enum_caster.rb
251
+ # class EnumCaster < Sinclair::Caster
252
+ # cast_with(:hash, :to_h)
253
+ # cast_with(:array, :to_a)
254
+ # end
255
+ #
256
+ # # enum_converter.rb
257
+ # module EnumConverter
258
+ # class << self
259
+ # def to_hash(value)
260
+ # return value if value.is_a?(Hash)
261
+ #
262
+ # hash_caster.cast(value)
263
+ # end
264
+ #
265
+ # def to_array(value)
266
+ # return value if value.is_a?(Array)
267
+ #
268
+ # array_caster.cast(value)
269
+ # end
270
+ #
271
+ # private
272
+ #
273
+ # def hash_caster
274
+ # @hash_caster ||= EnumCaster.caster_for(:hash)
275
+ # end
276
+ #
277
+ # def array_caster
278
+ # @array_caster ||= EnumCaster.caster_for(:array)
279
+ # end
280
+ # end
281
+ # end
282
+ #
283
+ # # main.rb
284
+ # EnumConverter.to_array({ key: :value }) # returns [%i[key value]]
285
+ # EnumConverter.to_hash([%i[key value]]) # returns { key: :value }
286
+ #
287
+ # @overload caster_for(class_key)
288
+ # @param class_key [Class] Class to used as key in the casters storage
289
+ #
290
+ # When the +class_key+ does not match the stored key, but matches a superclass,
291
+ # the registerd caster is returned.
292
+ #
293
+ # @example Getting the caster with class key'
294
+ # # stringer_parser.rb
295
+ # class StringParser < Sinclair::Caster
296
+ # master_caster!
297
+ #
298
+ # cast_with(JSON) { |value| JSON.parse(value) }
299
+ # cast_with(Integer, :to_i)
300
+ # cast_with(Float, :to_f)
301
+ # end
302
+ #
303
+ # # main.rb
304
+ # StringParser.cast('{"key":"value"}', JSON) # returns { "key" => "value" }
305
+ # StringParser.cast('10.2', Integer) # returns 10
306
+ # StringParser.cast('10.2', Float) # returns 10.2
307
+ #
308
+ # @see Caster::ClassMethods#caster_for
309
+ # @see Caster.cast_with
310
+ # @see Caster.cast
311
+ #
312
+ # @return [Caster]
313
+
314
+ # @param block [Proc] Proc to be used when converting the value object
315
+ def initialize(&block)
316
+ @block = block.to_proc
317
+ end
318
+
319
+ # Cast a value using the given the set +block+
320
+ #
321
+ # @param value [Object] value to be converted
322
+ # @param opts [Hash] options to be sent to the block
323
+ #
324
+ # When the block does not accept options, those
325
+ # are not passed
326
+ #
327
+ # @example Casts from a selected caster
328
+ # # math_caster.rb
329
+ # class MathCaster < Sinclair::Caster
330
+ # cast_with(:float, :to_f)
331
+ #
332
+ # cast_with(:log) do |value, base: 10|
333
+ # value = MathCaster.cast(value, :float)
334
+ #
335
+ # Math.log(value, base)
336
+ # end
337
+ # end
338
+ #
339
+ # # main.rb
340
+ # caster = MathCaster.caster_for(:log)
341
+ #
342
+ # caster.cast(100) # returns 2
343
+ # caster.cast(8, base: 2) # returns 3
344
+ #
345
+ # @return [Object] the result of the converting block
346
+ def cast(value, **opts)
347
+ options = opts.select do |key, _|
348
+ options_keys.include?(key)
349
+ end
350
+
351
+ block.call(value, **options)
352
+ end
353
+
354
+ private
355
+
356
+ # @api private
357
+ # @private
358
+ #
359
+ # Keys of options accepted by the block
360
+ #
361
+ # @return [Array<Symbol>]
362
+ def options_keys
363
+ @options_keys ||= block.parameters.select do |(type, _)|
364
+ %i[key keyreq].include? type
365
+ end.map(&:second)
366
+ end
367
+
368
+ # @method block
369
+ # @api private
370
+ # @private
371
+ #
372
+ # Proc to be used when converting the value object
373
+ #
374
+ # @return [Proc]
375
+ attr_reader :block
376
+
377
+ cast_with(:string, :to_s)
378
+ cast_with(:integer, :to_i)
379
+ cast_with(:float, :to_f)
380
+ end
381
+ end
@@ -69,22 +69,16 @@ class Sinclair
69
69
  #
70
70
  # config = AppConfig.new
71
71
  #
72
- # config.secret
73
- # # return nil
74
- #
75
- # config.app_name
76
- # # return 'MyApp'
72
+ # config.secret # return nil
73
+ # config.app_name # return 'MyApp'
77
74
  #
78
75
  # config_builder = Sinclair::ConfigBuilder.new(config)
79
76
  #
80
77
  # config_builder.secret '123abc'
81
78
  # config_builder.app_name 'MySuperApp'
82
79
  #
83
- # config.secret
84
- # # return '123abc'
85
- #
86
- # config.app_name
87
- # # return 'MySuperApp'
80
+ # config.secret # return '123abc'
81
+ # config.app_name # return 'MySuperApp'
88
82
  def add_configs(*args)
89
83
  Config::MethodsBuilder.new(self, *args).tap do |builder|
90
84
  builder.build
@@ -8,7 +8,14 @@ class Sinclair
8
8
  # @author darthjee
9
9
  #
10
10
  # Stringgify a value for {StringDefinition}
11
- class Stringifier
11
+ class Stringifier < Caster
12
+ master_caster!
13
+
14
+ cast_with(NilClass) { 'nil' }
15
+ cast_with(Symbol) { |value| ":#{value}" }
16
+ cast_with(String, :to_json)
17
+ cast_with(Object, :to_s)
18
+
12
19
  # Convert a value to a string format
13
20
  #
14
21
  # The returned string can be evaluated as code, returning the
@@ -18,12 +25,7 @@ class Sinclair
18
25
  #
19
26
  # @return [String]
20
27
  def self.value_string(value)
21
- return 'nil' if value.nil?
22
- return ":#{value}" if value.is_a?(Symbol)
23
-
24
- return value.to_s if value.is_any?(Class, Hash, Array)
25
-
26
- value.to_json
28
+ cast(value, value.class)
27
29
  end
28
30
  end
29
31
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Sinclair
4
- VERSION = '1.14.2'
4
+ VERSION = '1.15.0'
5
5
  end