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