necromancer 0.6.0 → 0.7.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/CHANGELOG.md +12 -0
- data/README.md +130 -70
- data/lib/necromancer/context.rb +1 -1
- data/lib/necromancer/conversions.rb +3 -0
- data/lib/necromancer/converter.rb +4 -4
- data/lib/necromancer/converters/array.rb +134 -40
- data/lib/necromancer/converters/boolean.rb +14 -15
- data/lib/necromancer/converters/date_time.rb +16 -15
- data/lib/necromancer/converters/hash.rb +119 -0
- data/lib/necromancer/converters/numeric.rb +19 -18
- data/lib/necromancer/converters/range.rb +37 -14
- data/lib/necromancer/null_converter.rb +1 -1
- data/lib/necromancer/version.rb +1 -1
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ab3ba9bfe1c011b3ecf087642ff05a74b51939fa7fb881bbcdb7acec618e9d76
|
4
|
+
data.tar.gz: 4323c173f67da37e1eab170642aff2b8f179b8dc55f777b5424f487271bef105
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bbf17295bcc8268d93805f7b3e1fb6233358db0bdfb91bd5f7de644a5a7546e735e5f046430b1dbed3a85cffcba0dba3d38b107e12e5f4c366b89b71c8882d1e
|
7
|
+
data.tar.gz: 644eb159ae79c9a7f394b858ea2b367692959562979ad7e2c4befc45006f90ab014c3aa2e222469754f71687fee7ebd549dc6e2fe6ea5bc3439b11bf8bec9332
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
# Change log
|
2
2
|
|
3
|
+
## [v0.7.0] - 2020-12-29
|
4
|
+
|
5
|
+
### Added
|
6
|
+
* Add HashConverters for transforming string into hash of string, integer, float or boolean values
|
7
|
+
* Add converters for transforming string to array of booleans, integers, floats and numeric
|
8
|
+
|
9
|
+
### Changed
|
10
|
+
* Change StringToRange converter to work with decimal numbers and spaces
|
11
|
+
* Change :strict to be a keyword argument
|
12
|
+
* Change StringToNumeric converter to allow numbers with space characters
|
13
|
+
|
3
14
|
## [v0.6.0] - 2020-03-08
|
4
15
|
|
5
16
|
### Changed
|
@@ -57,6 +68,7 @@
|
|
57
68
|
|
58
69
|
* Initial implementation and release
|
59
70
|
|
71
|
+
[v0.7.0]: https://github.com/piotrmurach/necromancer/compare/v0.6.0...v0.7.0
|
60
72
|
[v0.6.0]: https://github.com/piotrmurach/necromancer/compare/v0.5.1...v0.6.0
|
61
73
|
[v0.5.1]: https://github.com/piotrmurach/necromancer/compare/v0.5.0...v0.5.1
|
62
74
|
[v0.5.0]: https://github.com/piotrmurach/necromancer/compare/v0.4.0...v0.5.0
|
data/README.md
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
# Necromancer
|
2
2
|
|
3
3
|
[][gem]
|
4
|
-
[][gh_actions_ci]
|
5
5
|
[][appveyor]
|
6
6
|
[][codeclimate]
|
7
7
|
[][coverage]
|
8
8
|
[][inchpages]
|
9
9
|
|
10
10
|
[gem]: http://badge.fury.io/rb/necromancer
|
11
|
-
[
|
11
|
+
[gh_actions_ci]: https://github.com/piotrmurach/tty-runner/actions?query=workflow%3ACI
|
12
12
|
[appveyor]: https://ci.appveyor.com/project/piotrmurach/necromancer
|
13
13
|
[codeclimate]: https://codeclimate.com/github/piotrmurach/necromancer
|
14
14
|
[coverage]: https://coveralls.io/github/piotrmurach/necromancer
|
@@ -35,7 +35,7 @@ Conversion between Ruby core types frequently comes up in projects but is solved
|
|
35
35
|
Add this line to your application's Gemfile:
|
36
36
|
|
37
37
|
```ruby
|
38
|
-
gem
|
38
|
+
gem "necromancer"
|
39
39
|
```
|
40
40
|
|
41
41
|
And then execute:
|
@@ -73,39 +73,48 @@ Or install it yourself as:
|
|
73
73
|
For example, to convert a string to a [range](#36-range) type:
|
74
74
|
|
75
75
|
```ruby
|
76
|
-
Necromancer.convert(
|
77
|
-
Necromancer.convert(
|
78
|
-
Necromancer.convert(
|
76
|
+
Necromancer.convert("1-10").to(:range) # => 1..10
|
77
|
+
Necromancer.convert("1-10") >> :range # => 1..10
|
78
|
+
Necromancer.convert("1-10") >> Range # => 1..10
|
79
79
|
```
|
80
80
|
|
81
81
|
In order to handle [boolean](#32-boolean) conversions:
|
82
82
|
|
83
83
|
```ruby
|
84
|
-
Necromancer.convert(
|
85
|
-
Necromancer.convert(
|
84
|
+
Necromancer.convert("t").to(:boolean) # => true
|
85
|
+
Necromancer.convert("t") >> true # => true
|
86
86
|
```
|
87
87
|
|
88
88
|
To convert string to [numeric](#35-numeric) value:
|
89
89
|
|
90
90
|
```ruby
|
91
|
-
Necromancer.convert(
|
91
|
+
Necromancer.convert("10e1").to(:numeric) # => 100
|
92
92
|
```
|
93
93
|
|
94
|
-
|
94
|
+
You can convert string to [array](#31-array) of values like `boolean`, `integer` or `float`:
|
95
95
|
|
96
96
|
```ruby
|
97
|
-
Necromancer.convert(
|
97
|
+
Necromancer.convert("t,f,t"]).to(:booleans) # => [true, false, true]
|
98
|
+
Necromancer.convert("1,2.3,3.0"]).to(:integers) # => [1, 2, 3]
|
99
|
+
Necromancer.convert("1,2.3,3.0"]).to(:floats) # => [1.0, 2.3, 3.0]
|
98
100
|
```
|
99
101
|
|
100
|
-
To
|
102
|
+
To convert string to [hash](#34-hash) value:
|
101
103
|
|
102
104
|
```ruby
|
103
|
-
Necromancer.convert(
|
105
|
+
Necromancer.convert("a:1 b:2 c:3").to(:hash) # => {a: "1", b: "2", c: "3"}
|
106
|
+
Necromancer.convert("a=1 b=2 c=3").to(:hash) # => {a: "1", b: "2", c: "3"}
|
107
|
+
````
|
108
|
+
|
109
|
+
To provide extra information about the conversion value type use the `from`:
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
Necromancer.convert(["1", "2.3", "3.0"]).from(:array).to(:numeric) # => [1, 2.3, 3.0]
|
104
113
|
```
|
105
114
|
|
106
115
|
**Necromancer** also allows you to add [custom](#37-custom) conversions.
|
107
116
|
|
108
|
-
|
117
|
+
When conversion isn't possible, a `Necromancer::NoTypeConversionAvailableError` is thrown indicating that `convert` doesn't know how to perform the requested conversion:
|
109
118
|
|
110
119
|
```ruby
|
111
120
|
Necromancer.convert(:foo).to(:float)
|
@@ -121,13 +130,13 @@ Necromancer.convert(:foo).to(:float)
|
|
121
130
|
For the purpose of divination, **Necromancer** uses `convert` method to turn source type into target type. For example, in order to convert a string into a range type do:
|
122
131
|
|
123
132
|
```ruby
|
124
|
-
Necromancer.convert(
|
133
|
+
Necromancer.convert("1,10").to(:range) # => 1..10
|
125
134
|
```
|
126
135
|
|
127
136
|
Alternatively, you can use block:
|
128
137
|
|
129
138
|
```ruby
|
130
|
-
Necromancer.convert {
|
139
|
+
Necromancer.convert { "1,10" }.to(:range) # => 1..10
|
131
140
|
```
|
132
141
|
|
133
142
|
Conversion isn't always possible, in which case a `Necromancer::NoTypeConversionAvailableError` is thrown indicating that `convert` doesn't know how to perform the requested conversion:
|
@@ -142,54 +151,54 @@ Necromancer.convert(:foo).to(:float)
|
|
142
151
|
To specify conversion source type use `from` method:
|
143
152
|
|
144
153
|
```ruby
|
145
|
-
Necromancer.convert(
|
154
|
+
Necromancer.convert("1.0").from(:string).to(:numeric)
|
146
155
|
```
|
147
156
|
|
148
157
|
In majority of cases you do not need to specify `from` as the type will be inferred from the `convert` method argument and then appropriate conversion will be applied to result in `target` type such as `:numeric`. However, if you do not control the input to `convert` and want to ensure consistent behaviour please use `from`.
|
149
158
|
|
150
159
|
The source parameters are:
|
151
160
|
|
152
|
-
*
|
153
|
-
*
|
154
|
-
*
|
155
|
-
*
|
156
|
-
*
|
157
|
-
*
|
158
|
-
*
|
159
|
-
*
|
160
|
-
*
|
161
|
-
*
|
161
|
+
* `:array`
|
162
|
+
* `:boolean`
|
163
|
+
* `:date`
|
164
|
+
* `:datetime`
|
165
|
+
* `:float`
|
166
|
+
* `:integer`
|
167
|
+
* `:numeric`
|
168
|
+
* `:range`
|
169
|
+
* `:string`
|
170
|
+
* `:time`
|
162
171
|
|
163
172
|
### 2.3 to
|
164
173
|
|
165
174
|
To convert objects between types, **Necromancer** provides several target types. The `to` or functional style `>>` method allows you to pass target as an argument to perform actual conversion. The target can be one of `:symbol`, `object` or `ClassName`:
|
166
175
|
|
167
176
|
```ruby
|
168
|
-
Necromancer.convert(
|
169
|
-
Necromancer.convert(
|
170
|
-
Necromancer.convert(
|
171
|
-
Necromancer.convert(
|
177
|
+
Necromancer.convert("yes").to(:boolean) # => true
|
178
|
+
Necromancer.convert("yes") >> :boolean # => true
|
179
|
+
Necromancer.convert("yes") >> true # => true
|
180
|
+
Necromancer.convert("yes") >> TrueClass # => true
|
172
181
|
```
|
173
182
|
|
174
|
-
By default, when target conversion fails the
|
183
|
+
By default, when target conversion fails the original value is returned. However, you can pass `strict` as an additional argument to ensure failure when conversion cannot be performed:
|
175
184
|
|
176
185
|
```ruby
|
177
|
-
Necromancer.convert(
|
186
|
+
Necromancer.convert("1a").to(:integer, strict: true)
|
178
187
|
# => raises Necromancer::ConversionTypeError
|
179
188
|
```
|
180
189
|
|
181
190
|
The target parameters are:
|
182
191
|
|
183
|
-
*
|
184
|
-
*
|
185
|
-
*
|
186
|
-
*
|
187
|
-
*
|
188
|
-
*
|
189
|
-
*
|
190
|
-
*
|
191
|
-
*
|
192
|
-
*
|
192
|
+
* `:array`
|
193
|
+
* `:boolean`, `:booleans`, `:bools`, `:boolean_hash`, `:bool_hash`
|
194
|
+
* `:date`
|
195
|
+
* `:datetime`,
|
196
|
+
* `:float`, `:floats`, `:float_hash`
|
197
|
+
* `:integer`, `:integers`, `:ints`, `:integer_hash`, `:int_hash`
|
198
|
+
* `:numeric`, `:numerics`, `:nums`, `:numeric_hash`, `:num_hash`
|
199
|
+
* `:range`
|
200
|
+
* `:string`
|
201
|
+
* `:time`
|
193
202
|
|
194
203
|
### 2.4 can?
|
195
204
|
|
@@ -211,7 +220,7 @@ Necromancer.new do |config|
|
|
211
220
|
end
|
212
221
|
```
|
213
222
|
|
214
|
-
|
223
|
+
Or calling `configure` method:
|
215
224
|
|
216
225
|
```ruby
|
217
226
|
converter = Necromancer.new
|
@@ -222,12 +231,12 @@ end
|
|
222
231
|
|
223
232
|
Available configuration options are:
|
224
233
|
|
225
|
-
* strict - ensures correct types for conversion, by default `false`
|
226
|
-
* copy - ensures only copy is modified, by default `true`
|
234
|
+
* `strict` - ensures correct types for conversion, by default `false`
|
235
|
+
* `copy` - ensures only copy is modified, by default `true`
|
227
236
|
|
228
237
|
## 3. Converters
|
229
238
|
|
230
|
-
**Necromancer** flexibility means you can register your own converters or use the already defined converters for such types as `Array`, `Boolean`, `Hash`, `Numeric`, `Range`.
|
239
|
+
**Necromancer** flexibility means you can register your own converters or use the already defined converters for such types as `Array`, `Boolean`, `Date`, `DateTime`, `Hash`, `Numeric`, `Range` and `Time`.
|
231
240
|
|
232
241
|
### 3.1 Array
|
233
242
|
|
@@ -241,47 +250,61 @@ Necromancer.convert({x: 1}).to(:array) # => [[:x, 1]]
|
|
241
250
|
In addition, **Necromancer** excels at converting `,` or `-` delimited string into an array object:
|
242
251
|
|
243
252
|
```ruby
|
244
|
-
Necromancer.convert(
|
253
|
+
Necromancer.convert("a, b, c").to(:array) # => ["a", "b", "c"]
|
245
254
|
```
|
246
255
|
|
247
256
|
If the string is a list of `-` or `,` separated numbers, they will be converted to their respective numeric types:
|
248
257
|
|
249
258
|
```ruby
|
250
|
-
Necromancer.convert(
|
259
|
+
Necromancer.convert("1 - 2 - 3").to(:array) # => [1, 2, 3]
|
260
|
+
```
|
261
|
+
|
262
|
+
It handles conversion of string into an array of boolean values as well:
|
263
|
+
|
264
|
+
```ruby
|
265
|
+
Necromancer.convert("yes,no,t").to(:booleans) # => [true, false, true]
|
266
|
+
Necromancer.convert("1 - f - FALSE").to(:bools) # => [true, false, false]
|
251
267
|
```
|
252
268
|
|
253
269
|
You can also convert array containing string objects to array containing numeric values:
|
254
270
|
|
255
271
|
```ruby
|
256
|
-
Necromancer.convert([
|
272
|
+
Necromancer.convert(["1", "2.3", "3.0"]).to(:numerics) # => [1, 2.3, 3.0]
|
273
|
+
Necromancer.convert(["1", "2.3", "3.0"]).to(:nums) # => [1, 2.3, 3.0]
|
274
|
+
```
|
275
|
+
|
276
|
+
Or you can be more specific by using `:integers` and `:floats` as the resulting type:
|
277
|
+
|
278
|
+
```ruby
|
279
|
+
Necromancer.convert(["1", "2.3", "3.0"]).to(:integers) # => [1, 2, 3]
|
257
280
|
```
|
258
281
|
|
259
282
|
When in `strict` mode the conversion will raise a `Necromancer::ConversionTypeError` error like so:
|
260
283
|
|
261
284
|
```ruby
|
262
|
-
Necromancer.convert([
|
263
|
-
# => Necromancer::ConversionTypeError: false cannot be converted from `array` to `
|
285
|
+
Necromancer.convert(["1", "2.3", false]).to(:numerics, strict: true)
|
286
|
+
# => Necromancer::ConversionTypeError: false cannot be converted from `array` to `numerics`
|
264
287
|
```
|
265
288
|
|
266
289
|
However, in `non-strict` mode the value will be simply returned unchanged:
|
267
290
|
|
268
291
|
```ruby
|
269
|
-
Necromancer.convert([
|
292
|
+
Necromancer.convert(["1", "2.3", false]).to(:numerics, strict: false)
|
270
293
|
# => [1, 2.3, false]
|
271
294
|
```
|
272
295
|
|
273
296
|
### 3.2 Boolean
|
274
297
|
|
275
|
-
The **Necromancer** allows you to convert a string object to boolean object. The `1`, `
|
298
|
+
The **Necromancer** allows you to convert a string object to boolean object. The `1`, `"1"`, `"t"`, `"T"`, `"true"`, `"TRUE"`, `"y"`, `"Y"`, `"yes"`, `"Yes"`, `"on"`, `"ON"` values are converted to `TrueClass`.
|
276
299
|
|
277
300
|
```ruby
|
278
|
-
Necromancer.convert(
|
301
|
+
Necromancer.convert("yes").to(:boolean) # => true
|
279
302
|
```
|
280
303
|
|
281
|
-
Similarly, the `0`, `
|
304
|
+
Similarly, the `0`, `"0"`, `"f"`, `"F"`, `"false"`, `"FALSE"`, `"n"`, `"N"`, `"no"`, `"No"`, `"off"`, `"OFF"` values are converted to `FalseClass`.
|
282
305
|
|
283
306
|
```ruby
|
284
|
-
Necromancer.convert(
|
307
|
+
Necromancer.convert("no").to(:boolean) # => false
|
285
308
|
```
|
286
309
|
|
287
310
|
You can also convert an integer object to boolean:
|
@@ -296,8 +319,8 @@ Necromancer.convert(0).to(:boolean) # => false
|
|
296
319
|
**Necromancer** knows how to convert string to `date` object:
|
297
320
|
|
298
321
|
```ruby
|
299
|
-
Necromancer.convert(
|
300
|
-
Necromancer.convert(
|
322
|
+
Necromancer.convert("1-1-2015").to(:date) # => "2015-01-01"
|
323
|
+
Necromancer.convert("01/01/2015").to(:date) # => "2015-01-01"
|
301
324
|
```
|
302
325
|
|
303
326
|
You can also convert string to `datetime`:
|
@@ -317,9 +340,39 @@ Necromancer.convert("12:35").to(:time) # => 2015-01-04 12:35:00 +0100
|
|
317
340
|
|
318
341
|
### 3.4 Hash
|
319
342
|
|
343
|
+
With **Necromancer** you can convert a string with pairs delimited by `=` or `:` characters into a hash:
|
344
|
+
|
345
|
+
```ruby
|
346
|
+
Necromancer.convert("a:1 b:2 c:3").to(:hash)
|
347
|
+
Necromancer.convert("a=1 b=2 c=3").to(:hash)
|
348
|
+
# => {a: "1", b: "2", c: "3"}
|
349
|
+
```
|
350
|
+
|
351
|
+
The pairs can be separated by `&` symbols and mix `=` and `:` pair delimiters:
|
352
|
+
|
353
|
+
```ruby
|
354
|
+
Necromancer.convert("a:1 & b=2 & c:3").to(:hash)
|
355
|
+
# => {a: "1", b: "2", c: "3"}
|
356
|
+
```
|
357
|
+
|
358
|
+
You can also convert string to hash with integer values using `:int_hash` type:
|
359
|
+
|
360
|
+
```ruby
|
361
|
+
Necromancer.convert("a:1 b:2 c:3").to(:int_hash) # => {a: 1, b: 2, c: 3}
|
362
|
+
Necromancer.convert("a:1 b:2 c:3").to(:integer_hash) # => {a: 1, b: 2, c: 3}
|
363
|
+
```
|
364
|
+
|
365
|
+
Similarly you can convert string to hash with `float` or `numeric` values using `:float_hash` and `numeric_hash` types:
|
366
|
+
|
367
|
+
```ruby
|
368
|
+
Necromancer.convert("a:1 b:2 c:3").to(:float_hash) # => {a: 1.0, b: 2.0, c: 3.0}
|
369
|
+
Necromancer.convert("a:1 b:2.0 c:3").to(:num_hash) # => {a: 1, b:2.0, c: 3}
|
370
|
+
```
|
371
|
+
|
372
|
+
String can also be converted to hash with boolean values using `:boolean_hash` or `:bool_hash`:
|
373
|
+
|
320
374
|
```ruby
|
321
|
-
Necromancer.convert(
|
322
|
-
# => { x: 27.5, y: 4, z: 11}
|
375
|
+
Necromancer.convert("a:yes b:no c:t").to(:bool_hash) # => {a: true, b: false, c: true}
|
323
376
|
```
|
324
377
|
|
325
378
|
### 3.5 Numeric
|
@@ -329,25 +382,25 @@ Necromancer.convert({ x: '27.5', y: '4', z: '11'}).to(:numeric)
|
|
329
382
|
To convert a string to a float do:
|
330
383
|
|
331
384
|
```ruby
|
332
|
-
Necromancer.convert(
|
385
|
+
Necromancer.convert("1.2a").to(:float) # => 1.2
|
333
386
|
```
|
334
387
|
|
335
388
|
Conversion to numeric in strict mode raises `Necromancer::ConversionTypeError`:
|
336
389
|
|
337
390
|
```ruby
|
338
|
-
Necromancer.convert(
|
391
|
+
Necromancer.convert("1.2a").to(:float, strict: true) # => raises error
|
339
392
|
```
|
340
393
|
|
341
394
|
To convert a string to an integer do:
|
342
395
|
|
343
396
|
```ruby
|
344
|
-
Necromancer.convert(
|
397
|
+
Necromancer.convert("1a").to(:integer) # => 1
|
345
398
|
```
|
346
399
|
|
347
400
|
However, if you want to convert string to an appropriate matching numeric type do:
|
348
401
|
|
349
402
|
```ruby
|
350
|
-
Necromancer.convert(
|
403
|
+
Necromancer.convert("1e1").to(:numeric) # => 10
|
351
404
|
```
|
352
405
|
|
353
406
|
### 3.6 Range
|
@@ -355,15 +408,22 @@ Necromancer.convert('1e1').to(:numeric) # => 10
|
|
355
408
|
**Necromancer** is no stranger to figuring out ranges from strings. You can pass `,`, `-`, `..`, `...` characters to denote ranges:
|
356
409
|
|
357
410
|
```ruby
|
358
|
-
Necromancer.convert(
|
411
|
+
Necromancer.convert("1,10").to(:range) # => 1..10
|
359
412
|
```
|
360
413
|
|
361
|
-
|
414
|
+
Or to create a range of letters:
|
362
415
|
|
363
416
|
```ruby
|
364
|
-
Necromancer.convert(
|
417
|
+
Necromancer.convert("a-z").to(:range) # => "a".."z"
|
365
418
|
```
|
366
419
|
|
420
|
+
It will handle space characters:
|
421
|
+
|
422
|
+
```ruby
|
423
|
+
Necromancer.convert("1 . . 10") >> :range # => 1..10
|
424
|
+
Necromancer.convert("a . . . z") >> :range # => "a"..."z"
|
425
|
+
````
|
426
|
+
|
367
427
|
### 3.7 Custom
|
368
428
|
|
369
429
|
In case where provided conversions do not match your needs you can create your own and `register` with **Necromancer** by using an `Object` or a `Proc`.
|
@@ -398,7 +458,7 @@ converter.register(upcase_converter) # => true if successfully registered
|
|
398
458
|
Finally, by invoking `convert` method and specifying `:upcase` as the target for the conversion we achieve the result:
|
399
459
|
|
400
460
|
```ruby
|
401
|
-
converter.convert(
|
461
|
+
converter.convert("magic").to(:upcase) # => "MAGIC"
|
402
462
|
```
|
403
463
|
|
404
464
|
#### 3.7.2 Using a Proc
|
@@ -418,7 +478,7 @@ end
|
|
418
478
|
Then by invoking the `convert` method and passing the `:upcase` conversion type you can transform the string like so:
|
419
479
|
|
420
480
|
```ruby
|
421
|
-
converter.convert(
|
481
|
+
converter.convert("magic").to(:upcase) # => "MAGIC"
|
422
482
|
```
|
423
483
|
|
424
484
|
## Contributing
|
data/lib/necromancer/context.rb
CHANGED
@@ -5,6 +5,7 @@ require_relative "converter"
|
|
5
5
|
require_relative "converters/array"
|
6
6
|
require_relative "converters/boolean"
|
7
7
|
require_relative "converters/date_time"
|
8
|
+
require_relative "converters/hash"
|
8
9
|
require_relative "converters/numeric"
|
9
10
|
require_relative "converters/range"
|
10
11
|
|
@@ -34,6 +35,7 @@ module Necromancer
|
|
34
35
|
ArrayConverters.load(self)
|
35
36
|
BooleanConverters.load(self)
|
36
37
|
DateTimeConverters.load(self)
|
38
|
+
HashConverters.load(self)
|
37
39
|
NumericConverters.load(self)
|
38
40
|
RangeConverters.load(self)
|
39
41
|
end
|
@@ -76,6 +78,7 @@ module Necromancer
|
|
76
78
|
key = generate_key(converter)
|
77
79
|
converter = add_config(converter, @configuration)
|
78
80
|
return false if converter_map.key?(key)
|
81
|
+
|
79
82
|
converter_map[key] = converter
|
80
83
|
true
|
81
84
|
end
|
@@ -34,9 +34,9 @@ module Necromancer
|
|
34
34
|
# @api private
|
35
35
|
def self.create(&block)
|
36
36
|
Class.new(self) do
|
37
|
-
define_method(:initialize) { |*a| block.
|
37
|
+
define_method(:initialize) { |*a| block.(self, *a) }
|
38
38
|
|
39
|
-
define_method(:call) { |value| convert.
|
39
|
+
define_method(:call) { |value| convert.(value) }
|
40
40
|
end.new
|
41
41
|
end
|
42
42
|
|
@@ -48,7 +48,7 @@ module Necromancer
|
|
48
48
|
# @api private
|
49
49
|
def raise_conversion_type(value)
|
50
50
|
raise ConversionTypeError, "'#{value}' could not be converted " \
|
51
|
-
|
51
|
+
"from `#{source}` into `#{target}`"
|
52
52
|
end
|
53
53
|
|
54
54
|
attr_accessor :source
|
@@ -57,7 +57,7 @@ module Necromancer
|
|
57
57
|
|
58
58
|
attr_accessor :convert
|
59
59
|
|
60
|
-
|
60
|
+
# protected
|
61
61
|
|
62
62
|
attr_reader :config
|
63
63
|
end # Converter
|
@@ -3,10 +3,14 @@
|
|
3
3
|
require "set"
|
4
4
|
|
5
5
|
require_relative "../converter"
|
6
|
+
require_relative "boolean"
|
7
|
+
require_relative "numeric"
|
6
8
|
|
7
9
|
module Necromancer
|
8
10
|
# Container for Array converter classes
|
9
11
|
module ArrayConverters
|
12
|
+
ARRAY_MATCHER = /^(.+?(\s*(?<sep>(,|-))\s*))+/x.freeze
|
13
|
+
|
10
14
|
# An object that converts a String to an Array
|
11
15
|
class StringToArrayConverter < Converter
|
12
16
|
# Convert string value to array
|
@@ -15,24 +19,103 @@ module Necromancer
|
|
15
19
|
# converter.call("a, b, c") # => ["a", "b", "c"]
|
16
20
|
#
|
17
21
|
# @example
|
18
|
-
# converter.call("1 - 2 - 3") # => [1, 2, 3]
|
22
|
+
# converter.call("1 - 2 - 3") # => ["1", "2", "3"]
|
19
23
|
#
|
20
24
|
# @api public
|
21
|
-
def call(value,
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
value.to_s.split(
|
26
|
-
when /^((\w)(\s*(,|-)\s*)?)+$/
|
27
|
-
value.to_s.split($4)
|
25
|
+
def call(value, strict: config.strict)
|
26
|
+
return [] if value.to_s.empty?
|
27
|
+
|
28
|
+
if match = value.to_s.match(ARRAY_MATCHER)
|
29
|
+
value.to_s.split(match[:sep])
|
28
30
|
else
|
29
31
|
strict ? raise_conversion_type(value) : Array(value)
|
30
32
|
end
|
31
33
|
end
|
32
34
|
end
|
33
35
|
|
36
|
+
class StringToBooleanArrayConverter < Converter
|
37
|
+
# @example
|
38
|
+
# converter.call("t,f,yes,no") # => [true, false, true, false]
|
39
|
+
#
|
40
|
+
# @param [Array] value
|
41
|
+
# the array value to boolean
|
42
|
+
#
|
43
|
+
# @api public
|
44
|
+
def call(value, strict: config.strict)
|
45
|
+
array_converter = StringToArrayConverter.new(:string, :array)
|
46
|
+
array = array_converter.(value, strict: strict)
|
47
|
+
bool_converter = ArrayToBooleanArrayConverter.new(:array, :boolean)
|
48
|
+
bool_converter.(array, strict: strict)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class StringToIntegerArrayConverter < Converter
|
53
|
+
# @example
|
54
|
+
# converter.call("1,2,3") # => [1, 2, 3]
|
55
|
+
#
|
56
|
+
# @api public
|
57
|
+
def call(string, strict: config.strict)
|
58
|
+
array_converter = StringToArrayConverter.new(:string, :array)
|
59
|
+
array = array_converter.(string, strict: strict)
|
60
|
+
int_converter = ArrayToIntegerArrayConverter.new(:array, :integers)
|
61
|
+
int_converter.(array, strict: strict)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class StringToFloatArrayConverter < Converter
|
66
|
+
# @example
|
67
|
+
# converter.call("1,2,3") # => [1.0, 2.0, 3.0]
|
68
|
+
#
|
69
|
+
# @api public
|
70
|
+
def call(string, strict: config.strict)
|
71
|
+
array_converter = StringToArrayConverter.new(:string, :array)
|
72
|
+
array = array_converter.(string, strict: strict)
|
73
|
+
float_converter = ArrayToFloatArrayConverter.new(:array, :floats)
|
74
|
+
float_converter.(array, strict: strict)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class StringToNumericArrayConverter < Converter
|
79
|
+
# Convert string value to array with numeric values
|
80
|
+
#
|
81
|
+
# @example
|
82
|
+
# converter.call("1,2.0,3") # => [1, 2.0, 3]
|
83
|
+
#
|
84
|
+
# @api public
|
85
|
+
def call(string, strict: config.strict)
|
86
|
+
array_converter = StringToArrayConverter.new(:string, :array)
|
87
|
+
array = array_converter.(string, strict: strict)
|
88
|
+
num_converter = ArrayToNumericArrayConverter.new(:array, :numeric)
|
89
|
+
num_converter.(array, strict: strict)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
class ArrayToIntegerArrayConverter < Converter
|
94
|
+
# @example
|
95
|
+
# converter.call(["1", "2", "3"]) # => [1, 2, 3]
|
96
|
+
#
|
97
|
+
# @api public
|
98
|
+
def call(array, strict: config.strict)
|
99
|
+
int_converter = NumericConverters::StringToIntegerConverter.new(:string,
|
100
|
+
:integer)
|
101
|
+
array.map { |val| int_converter.(val, strict: strict) }
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
class ArrayToFloatArrayConverter < Converter
|
106
|
+
# @example
|
107
|
+
# converter.call(["1", "2", "3"]) # => [1.0, 2.0, 3.0]
|
108
|
+
#
|
109
|
+
# @api public
|
110
|
+
def call(array, strict: config.strict)
|
111
|
+
float_converter = NumericConverters::StringToFloatConverter.new(:string,
|
112
|
+
:float)
|
113
|
+
array.map { |val| float_converter.(val, strict: strict) }
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
34
117
|
# An object that converts an array to an array with numeric values
|
35
|
-
class
|
118
|
+
class ArrayToNumericArrayConverter < Converter
|
36
119
|
# Convert an array to an array of numeric values
|
37
120
|
#
|
38
121
|
# @example
|
@@ -42,16 +125,15 @@ module Necromancer
|
|
42
125
|
# the value to convert
|
43
126
|
#
|
44
127
|
# @api public
|
45
|
-
def call(value,
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
end
|
128
|
+
def call(value, strict: config.strict)
|
129
|
+
num_converter = NumericConverters::StringToNumericConverter.new(:string,
|
130
|
+
:numeric)
|
131
|
+
value.map { |val| num_converter.(val, strict: strict) }
|
50
132
|
end
|
51
133
|
end
|
52
134
|
|
53
135
|
# An object that converts an array to an array with boolean values
|
54
|
-
class
|
136
|
+
class ArrayToBooleanArrayConverter < Converter
|
55
137
|
# @example
|
56
138
|
# converter.call(["t", "f", "yes", "no"]) # => [true, false, true, false]
|
57
139
|
#
|
@@ -59,11 +141,10 @@ module Necromancer
|
|
59
141
|
# the array value to boolean
|
60
142
|
#
|
61
143
|
# @api public
|
62
|
-
def call(value,
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
end
|
144
|
+
def call(value, strict: config.strict)
|
145
|
+
bool_converter = BooleanConverters::StringToBooleanConverter.new(:string,
|
146
|
+
:boolean)
|
147
|
+
value.map { |val| bool_converter.(val, strict: strict) }
|
67
148
|
end
|
68
149
|
end
|
69
150
|
|
@@ -75,13 +156,10 @@ module Necromancer
|
|
75
156
|
# converter.call({x: 1}) # => [[:x, 1]]
|
76
157
|
#
|
77
158
|
# @api public
|
78
|
-
def call(value,
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
rescue
|
83
|
-
strict ? raise_conversion_type(value) : value
|
84
|
-
end
|
159
|
+
def call(value, strict: config.strict)
|
160
|
+
Array(value)
|
161
|
+
rescue StandardError
|
162
|
+
strict ? raise_conversion_type(value) : value
|
85
163
|
end
|
86
164
|
end
|
87
165
|
|
@@ -96,23 +174,39 @@ module Necromancer
|
|
96
174
|
# the array to convert
|
97
175
|
#
|
98
176
|
# @api public
|
99
|
-
def call(value,
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
rescue
|
104
|
-
strict ? raise_conversion_type(value) : value
|
105
|
-
end
|
177
|
+
def call(value, strict: config.strict)
|
178
|
+
value.to_set
|
179
|
+
rescue StandardError
|
180
|
+
strict ? raise_conversion_type(value) : value
|
106
181
|
end
|
107
182
|
end
|
108
183
|
|
109
184
|
def self.load(conversions)
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
185
|
+
[
|
186
|
+
NullConverter.new(:array, :array),
|
187
|
+
|
188
|
+
StringToArrayConverter.new(:string, :array),
|
189
|
+
StringToBooleanArrayConverter.new(:string, :bools),
|
190
|
+
StringToBooleanArrayConverter.new(:string, :booleans),
|
191
|
+
StringToIntegerArrayConverter.new(:string, :integers),
|
192
|
+
StringToIntegerArrayConverter.new(:string, :ints),
|
193
|
+
StringToFloatArrayConverter.new(:string, :floats),
|
194
|
+
StringToNumericArrayConverter.new(:string, :numerics),
|
195
|
+
StringToNumericArrayConverter.new(:string, :nums),
|
196
|
+
|
197
|
+
ArrayToNumericArrayConverter.new(:array, :numerics),
|
198
|
+
ArrayToNumericArrayConverter.new(:array, :nums),
|
199
|
+
ArrayToIntegerArrayConverter.new(:array, :integers),
|
200
|
+
ArrayToIntegerArrayConverter.new(:array, :ints),
|
201
|
+
ArrayToFloatArrayConverter.new(:array, :floats),
|
202
|
+
ArrayToBooleanArrayConverter.new(:array, :booleans),
|
203
|
+
ArrayToBooleanArrayConverter.new(:array, :bools),
|
204
|
+
|
205
|
+
ObjectToArrayConverter.new(:object, :array),
|
206
|
+
ObjectToArrayConverter.new(:hash, :array)
|
207
|
+
].each do |converter|
|
208
|
+
conversions.register converter
|
209
|
+
end
|
116
210
|
end
|
117
211
|
end # ArrayConverters
|
118
212
|
end # Necromancer
|
@@ -29,8 +29,7 @@ module Necromancer
|
|
29
29
|
# 0, f, F, FALSE, false, False, n, N, NO, no, No, off, OFF
|
30
30
|
#
|
31
31
|
# @api public
|
32
|
-
def call(value,
|
33
|
-
strict = options.fetch(:strict, config.strict)
|
32
|
+
def call(value, strict: config.strict)
|
34
33
|
case value.to_s
|
35
34
|
when TRUE_MATCHER then true
|
36
35
|
when FALSE_MATCHER then false
|
@@ -50,13 +49,10 @@ module Necromancer
|
|
50
49
|
# converter.call(0) # => false
|
51
50
|
#
|
52
51
|
# @api public
|
53
|
-
def call(value,
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
rescue
|
58
|
-
strict ? raise_conversion_type(value) : value
|
59
|
-
end
|
52
|
+
def call(value, strict: config.strict)
|
53
|
+
!value.zero?
|
54
|
+
rescue StandardError
|
55
|
+
strict ? raise_conversion_type(value) : value
|
60
56
|
end
|
61
57
|
end
|
62
58
|
|
@@ -71,8 +67,7 @@ module Necromancer
|
|
71
67
|
# converter.call(false) # => 0
|
72
68
|
#
|
73
69
|
# @api public
|
74
|
-
def call(value,
|
75
|
-
strict = options.fetch(:strict, config.strict)
|
70
|
+
def call(value, strict: config.strict)
|
76
71
|
if %w[TrueClass FalseClass].include?(value.class.name)
|
77
72
|
value ? 1 : 0
|
78
73
|
else
|
@@ -82,10 +77,14 @@ module Necromancer
|
|
82
77
|
end
|
83
78
|
|
84
79
|
def self.load(conversions)
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
80
|
+
[
|
81
|
+
StringToBooleanConverter.new(:string, :boolean),
|
82
|
+
IntegerToBooleanConverter.new(:integer, :boolean),
|
83
|
+
BooleanToIntegerConverter.new(:boolean, :integer),
|
84
|
+
NullConverter.new(:boolean, :boolean)
|
85
|
+
].each do |converter|
|
86
|
+
conversions.register converter
|
87
|
+
end
|
89
88
|
end
|
90
89
|
end # BooleanConverters
|
91
90
|
end # Necromancer
|
@@ -20,10 +20,9 @@ module Necromancer
|
|
20
20
|
# converter.call("12/11/2015") # => "2015-11-12"
|
21
21
|
#
|
22
22
|
# @api public
|
23
|
-
def call(value,
|
24
|
-
strict = options.fetch(:strict, config.strict)
|
23
|
+
def call(value, strict: config.strict)
|
25
24
|
Date.parse(value)
|
26
|
-
rescue
|
25
|
+
rescue StandardError
|
27
26
|
strict ? raise_conversion_type(value) : value
|
28
27
|
end
|
29
28
|
end
|
@@ -37,10 +36,9 @@ module Necromancer
|
|
37
36
|
# converer.call("1-1-2015 15:12:44") # => "2015-01-01T15:12:44+00:00"
|
38
37
|
#
|
39
38
|
# @api public
|
40
|
-
def call(value,
|
41
|
-
strict = options.fetch(:strict, config.strict)
|
39
|
+
def call(value, strict: config.strict)
|
42
40
|
DateTime.parse(value)
|
43
|
-
rescue
|
41
|
+
rescue StandardError
|
44
42
|
strict ? raise_conversion_type(value) : value
|
45
43
|
end
|
46
44
|
end
|
@@ -57,21 +55,24 @@ module Necromancer
|
|
57
55
|
# converter.call("12:35") # => 2015-01-04 12:35:00 +0100
|
58
56
|
#
|
59
57
|
# @api public
|
60
|
-
def call(value,
|
61
|
-
strict = options.fetch(:strict, config.strict)
|
58
|
+
def call(value, strict: config.strict)
|
62
59
|
Time.parse(value)
|
63
|
-
rescue
|
60
|
+
rescue StandardError
|
64
61
|
strict ? raise_conversion_type(value) : value
|
65
62
|
end
|
66
63
|
end
|
67
64
|
|
68
65
|
def self.load(conversions)
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
66
|
+
[
|
67
|
+
StringToDateConverter.new(:string, :date),
|
68
|
+
NullConverter.new(:date, :date),
|
69
|
+
StringToDateTimeConverter.new(:string, :datetime),
|
70
|
+
NullConverter.new(:datetime, :datetime),
|
71
|
+
StringToTimeConverter.new(:string, :time),
|
72
|
+
NullConverter.new(:time, :time)
|
73
|
+
].each do |converter|
|
74
|
+
conversions.register converter
|
75
|
+
end
|
75
76
|
end
|
76
77
|
end # DateTimeConverters
|
77
78
|
end # Necromancer
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../converter"
|
4
|
+
require_relative "boolean"
|
5
|
+
require_relative "numeric"
|
6
|
+
|
7
|
+
module Necromancer
|
8
|
+
module HashConverters
|
9
|
+
# An object that converts a String to a Hash
|
10
|
+
class StringToHashConverter < Converter
|
11
|
+
DEFAULT_CONVERSION = ->(val, *_rest) { val }
|
12
|
+
|
13
|
+
# Convert string value to hash
|
14
|
+
#
|
15
|
+
# @example
|
16
|
+
# converter.call("a:1 b:2 c:3")
|
17
|
+
# # => {a: "1", b: "2", c: "3"}
|
18
|
+
#
|
19
|
+
# @example
|
20
|
+
# converter.call("a=1 & b=3 & c=3")
|
21
|
+
# # => {a: "1", b: "2", c: "3"}
|
22
|
+
#
|
23
|
+
# @api public
|
24
|
+
def call(value, strict: config.strict, value_converter: DEFAULT_CONVERSION)
|
25
|
+
values = value.split(/\s*[& ]\s*/)
|
26
|
+
values.each_with_object({}) do |pair, pairs|
|
27
|
+
key, value = pair.split(/[=:]/, 2)
|
28
|
+
value_converted = value_converter.(value, strict: strict)
|
29
|
+
if current = pairs[key.to_sym]
|
30
|
+
pairs[key.to_sym] = Array(current) << value_converted
|
31
|
+
else
|
32
|
+
pairs[key.to_sym] = value_converted
|
33
|
+
end
|
34
|
+
pairs
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class StringToIntegerHashConverter < Converter
|
40
|
+
# Convert string value to hash with integer values
|
41
|
+
#
|
42
|
+
# @example
|
43
|
+
# converter.call("a:1 b:2 c:3")
|
44
|
+
# # => {a: 1, b: 2, c: 3}
|
45
|
+
#
|
46
|
+
# @api public
|
47
|
+
def call(value, strict: config.strict)
|
48
|
+
int_converter = NumericConverters::StringToIntegerConverter.new(:string,
|
49
|
+
:integer)
|
50
|
+
hash_converter = StringToHashConverter.new(:string, :hash)
|
51
|
+
hash_converter.(value, strict: strict, value_converter: int_converter)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class StringToFloatHashConverter < Converter
|
56
|
+
# Convert string value to hash with float values
|
57
|
+
#
|
58
|
+
# @example
|
59
|
+
# converter.call("a:1 b:2 c:3")
|
60
|
+
# # => {a: 1.0, b: 2.0, c: 3.0}
|
61
|
+
#
|
62
|
+
# @api public
|
63
|
+
def call(value, strict: config.strict)
|
64
|
+
float_converter = NumericConverters::StringToFloatConverter.new(:string,
|
65
|
+
:float)
|
66
|
+
hash_converter = StringToHashConverter.new(:string, :hash)
|
67
|
+
hash_converter.(value, strict: strict, value_converter: float_converter)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
class StringToNumericHashConverter < Converter
|
72
|
+
# Convert string value to hash with numeric values
|
73
|
+
#
|
74
|
+
# @example
|
75
|
+
# converter.call("a:1 b:2.0 c:3")
|
76
|
+
# # => {a: 1, b: 2.0, c: 3}
|
77
|
+
#
|
78
|
+
# @api public
|
79
|
+
def call(value, strict: config.strict)
|
80
|
+
num_converter = NumericConverters::StringToNumericConverter.new(:string,
|
81
|
+
:numeric)
|
82
|
+
hash_converter = StringToHashConverter.new(:string, :hash)
|
83
|
+
hash_converter.(value, strict: strict, value_converter: num_converter)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
class StringToBooleanHashConverter < Converter
|
88
|
+
# Convert string value to hash with boolean values
|
89
|
+
#
|
90
|
+
# @example
|
91
|
+
# converter.call("a:yes b:no c:t")
|
92
|
+
# # => {a: true, b: false, c: true}
|
93
|
+
#
|
94
|
+
# @api public
|
95
|
+
def call(value, strict: config.strict)
|
96
|
+
bool_converter = BooleanConverters::StringToBooleanConverter.new(:string,
|
97
|
+
:boolean)
|
98
|
+
hash_converter = StringToHashConverter.new(:string, :hash)
|
99
|
+
hash_converter.(value, strict: strict, value_converter: bool_converter)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def self.load(conversions)
|
104
|
+
[
|
105
|
+
NullConverter.new(:hash, :hash),
|
106
|
+
StringToHashConverter.new(:string, :hash),
|
107
|
+
StringToIntegerHashConverter.new(:string, :int_hash),
|
108
|
+
StringToIntegerHashConverter.new(:string, :integer_hash),
|
109
|
+
StringToFloatHashConverter.new(:string, :float_hash),
|
110
|
+
StringToNumericHashConverter.new(:string, :num_hash),
|
111
|
+
StringToNumericHashConverter.new(:string, :numeric_hash),
|
112
|
+
StringToBooleanHashConverter.new(:string, :boolean_hash),
|
113
|
+
StringToBooleanHashConverter.new(:string, :bool_hash)
|
114
|
+
].each do |converter|
|
115
|
+
conversions.register(converter)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end # HashConverters
|
119
|
+
end # Necromancer
|
@@ -6,9 +6,9 @@ require_relative "../null_converter"
|
|
6
6
|
module Necromancer
|
7
7
|
# Container for Numeric converter classes
|
8
8
|
module NumericConverters
|
9
|
-
INTEGER_MATCHER =
|
9
|
+
INTEGER_MATCHER = /^\s*[-+]?\s*(\d[\d\s]*)?$/.freeze
|
10
10
|
|
11
|
-
FLOAT_MATCHER =
|
11
|
+
FLOAT_MATCHER = /^\s*[-+]?([\d\s]*)(\.[\d\s]+)?([eE]?[-+]?[\d\s]+)?$/.freeze
|
12
12
|
|
13
13
|
# An object that converts a String to an Integer
|
14
14
|
class StringToIntegerConverter < Converter
|
@@ -18,10 +18,9 @@ module Necromancer
|
|
18
18
|
# converter.call("1abc") # => 1
|
19
19
|
#
|
20
20
|
# @api public
|
21
|
-
def call(value,
|
22
|
-
strict = options.fetch(:strict, config.strict)
|
21
|
+
def call(value, strict: config.strict)
|
23
22
|
Integer(value)
|
24
|
-
rescue
|
23
|
+
rescue StandardError
|
25
24
|
strict ? raise_conversion_type(value) : value.to_i
|
26
25
|
end
|
27
26
|
end
|
@@ -47,10 +46,9 @@ module Necromancer
|
|
47
46
|
# converter.call("1.2") # => 1.2
|
48
47
|
#
|
49
48
|
# @api public
|
50
|
-
def call(value,
|
51
|
-
strict = options.fetch(:strict, config.strict)
|
49
|
+
def call(value, strict: config.strict)
|
52
50
|
Float(value)
|
53
|
-
rescue
|
51
|
+
rescue StandardError
|
54
52
|
strict ? raise_conversion_type(value) : value.to_f
|
55
53
|
end
|
56
54
|
end
|
@@ -66,13 +64,12 @@ module Necromancer
|
|
66
64
|
# converter.call("1") # => 1
|
67
65
|
#
|
68
66
|
# @api public
|
69
|
-
def call(value,
|
70
|
-
strict = options.fetch(:strict, config.strict)
|
67
|
+
def call(value, strict: config.strict)
|
71
68
|
case value
|
72
69
|
when INTEGER_MATCHER
|
73
|
-
StringToIntegerConverter.new(:string, :integer).
|
70
|
+
StringToIntegerConverter.new(:string, :integer).(value, strict: strict)
|
74
71
|
when FLOAT_MATCHER
|
75
|
-
StringToFloatConverter.new(:string, :float).
|
72
|
+
StringToFloatConverter.new(:string, :float).(value, strict: strict)
|
76
73
|
else
|
77
74
|
strict ? raise_conversion_type(value) : value
|
78
75
|
end
|
@@ -80,12 +77,16 @@ module Necromancer
|
|
80
77
|
end
|
81
78
|
|
82
79
|
def self.load(conversions)
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
80
|
+
[
|
81
|
+
StringToIntegerConverter.new(:string, :integer),
|
82
|
+
IntegerToStringConverter.new(:integer, :string),
|
83
|
+
NullConverter.new(:integer, :integer),
|
84
|
+
StringToFloatConverter.new(:string, :float),
|
85
|
+
NullConverter.new(:float, :float),
|
86
|
+
StringToNumericConverter.new(:string, :numeric)
|
87
|
+
].each do |converter|
|
88
|
+
conversions.register converter
|
89
|
+
end
|
89
90
|
end
|
90
91
|
end # Conversion
|
91
92
|
end # Necromancer
|
@@ -6,11 +6,17 @@ require_relative "../null_converter"
|
|
6
6
|
module Necromancer
|
7
7
|
# Container for Range converter classes
|
8
8
|
module RangeConverters
|
9
|
-
SINGLE_DIGIT_MATCHER = /^(
|
9
|
+
SINGLE_DIGIT_MATCHER = /^(?<digit>-?\d+(\.\d+)?)$/.freeze
|
10
10
|
|
11
|
-
DIGIT_MATCHER = /^(
|
11
|
+
DIGIT_MATCHER = /^(?<open>-?\d+(\.\d+)?)
|
12
|
+
\s*(?<sep>(\.\s*){2,3}|-|,)\s*
|
13
|
+
(?<close>-?\d+(\.\d+)?)$
|
14
|
+
/x.freeze
|
12
15
|
|
13
|
-
LETTER_MATCHER = /^(
|
16
|
+
LETTER_MATCHER = /^(?<open>\w)
|
17
|
+
\s*(?<sep>(\.\s*){2,3}|-|,)\s*
|
18
|
+
(?<close>\w)$
|
19
|
+
/x.freeze
|
14
20
|
|
15
21
|
# An object that converts a String to a Range
|
16
22
|
class StringToRangeConverter < Converter
|
@@ -25,24 +31,41 @@ module Necromancer
|
|
25
31
|
# converter.call("0-9") # => (0..9)
|
26
32
|
#
|
27
33
|
# @api public
|
28
|
-
def call(value,
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
34
|
+
def call(value, strict: config.strict)
|
35
|
+
if match = value.match(SINGLE_DIGIT_MATCHER)
|
36
|
+
digit = cast_to_num(match[:digit])
|
37
|
+
::Range.new(digit, digit)
|
38
|
+
elsif match = value.match(DIGIT_MATCHER)
|
39
|
+
open = cast_to_num(match[:open])
|
40
|
+
close = cast_to_num(match[:close])
|
41
|
+
::Range.new(open, close, match[:sep].gsub(/\s*/, "") == "...")
|
42
|
+
elsif match = value.match(LETTER_MATCHER)
|
43
|
+
::Range.new(match[:open], match[:close],
|
44
|
+
match[:sep].gsub(/\s*/, "") == "...")
|
37
45
|
else
|
38
46
|
strict ? raise_conversion_type(value) : value
|
39
47
|
end
|
40
48
|
end
|
49
|
+
|
50
|
+
# Convert range end to numeric value
|
51
|
+
#
|
52
|
+
# @api private
|
53
|
+
def cast_to_num(str)
|
54
|
+
Integer(str)
|
55
|
+
rescue ArgumentError
|
56
|
+
Float(str)
|
57
|
+
rescue ArgumentError
|
58
|
+
nil
|
59
|
+
end
|
41
60
|
end
|
42
61
|
|
43
62
|
def self.load(conversions)
|
44
|
-
|
45
|
-
|
63
|
+
[
|
64
|
+
StringToRangeConverter.new(:string, :range),
|
65
|
+
NullConverter.new(:range, :range)
|
66
|
+
].each do |converter|
|
67
|
+
conversions.register converter
|
68
|
+
end
|
46
69
|
end
|
47
70
|
end # RangeConverters
|
48
71
|
end # Necromancer
|
data/lib/necromancer/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: necromancer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotr Murach
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-12-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -28,14 +28,14 @@ dependencies:
|
|
28
28
|
name: rspec
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '3.0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '3.0'
|
41
41
|
description: Conversion from one object type to another with a bit of black magic.
|
@@ -60,6 +60,7 @@ files:
|
|
60
60
|
- lib/necromancer/converters/array.rb
|
61
61
|
- lib/necromancer/converters/boolean.rb
|
62
62
|
- lib/necromancer/converters/date_time.rb
|
63
|
+
- lib/necromancer/converters/hash.rb
|
63
64
|
- lib/necromancer/converters/numeric.rb
|
64
65
|
- lib/necromancer/converters/range.rb
|
65
66
|
- lib/necromancer/null_converter.rb
|
@@ -88,7 +89,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
88
89
|
- !ruby/object:Gem::Version
|
89
90
|
version: '0'
|
90
91
|
requirements: []
|
91
|
-
rubygems_version: 3.
|
92
|
+
rubygems_version: 3.2.3
|
92
93
|
signing_key:
|
93
94
|
specification_version: 4
|
94
95
|
summary: Conversion from one object type to another with a bit of black magic.
|