necromancer 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 Version](https://badge.fury.io/rb/necromancer.svg)][gem]
|
4
|
-
[![
|
4
|
+
[![Actions CI](https://github.com/piotrmurach/tty-runner/workflows/CI/badge.svg?branch=master)][gh_actions_ci]
|
5
5
|
[![Build status](https://ci.appveyor.com/api/projects/status/qj3xn5gbbfi4puet?svg=true)][appveyor]
|
6
6
|
[![Code Climate](https://codeclimate.com/github/piotrmurach/necromancer/badges/gpa.svg)][codeclimate]
|
7
7
|
[![Coverage Status](https://coveralls.io/repos/github/piotrmurach/necromancer/badge.svg?branch=master)][coverage]
|
8
8
|
[![Inline docs](http://inch-ci.org/github/piotrmurach/necromancer.svg?branch=master)][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.
|