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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 68eb8e7721b9b177485217e74aecb8e9c9bbe2995615bdb21d2601c04afe2bb2
4
- data.tar.gz: d80270564204a03b60dacfc21c0e4da9283a0c387bef4fe1566829e9bce9bd54
3
+ metadata.gz: ab3ba9bfe1c011b3ecf087642ff05a74b51939fa7fb881bbcdb7acec618e9d76
4
+ data.tar.gz: 4323c173f67da37e1eab170642aff2b8f179b8dc55f777b5424f487271bef105
5
5
  SHA512:
6
- metadata.gz: 5638c5411b0f5a2f4b2fe59d78ef59c59a4c0de675989c8c3fe40b6694f02b11ecb87f8294e1cc9147e17efcc6c7b906f9cbb23caa75e4b21c32e48607b01a08
7
- data.tar.gz: b89a52e45e1aab9d36121a7ef17aba54436bdb3fa58182df77808d57cb146e0688cb05e335b6464b6d66bf396bf579fbe61ea0ecb9abdac59ed9d80cbf992f26
6
+ metadata.gz: bbf17295bcc8268d93805f7b3e1fb6233358db0bdfb91bd5f7de644a5a7546e735e5f046430b1dbed3a85cffcba0dba3d38b107e12e5f4c366b89b71c8882d1e
7
+ data.tar.gz: 644eb159ae79c9a7f394b858ea2b367692959562979ad7e2c4befc45006f90ab014c3aa2e222469754f71687fee7ebd549dc6e2fe6ea5bc3439b11bf8bec9332
@@ -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
- [![Build Status](https://secure.travis-ci.org/piotrmurach/necromancer.svg?branch=master)][travis]
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
- [travis]: http://travis-ci.org/piotrmurach/necromancer
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 'necromancer'
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('1-10').to(:range) # => 1..10
77
- Necromancer.convert('1-10') >> :range # => 1..10
78
- Necromancer.convert('1-10') >> Range # => 1..10
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('t').to(:boolean) # => true
85
- Necromancer.convert('t') >> true # => true
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('10e1').to(:numeric) # => 100
91
+ Necromancer.convert("10e1").to(:numeric) # => 100
92
92
  ```
93
93
 
94
- or convert [array](#31-array) of string values into numeric type:
94
+ You can convert string to [array](#31-array) of values like `boolean`, `integer` or `float`:
95
95
 
96
96
  ```ruby
97
- Necromancer.convert(['1', '2.3', '3.0']).to(:numeric) # => [1, 2.3, 3.0]
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 provide extra information about the conversion value type you can use `from`.
102
+ To convert string to [hash](#34-hash) value:
101
103
 
102
104
  ```ruby
103
- Necromancer.convert(['1', '2.3', '3.0']).from(:array).to(:numeric) # => [1, 2.3, 3.0]
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
- 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:
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('1,10').to(:range) # => 1..10
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 { '1,10' }.to(:range) # => 1..10
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('1.0').from(:string).to(:numeric)
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
- * :array
153
- * :boolean
154
- * :date
155
- * :datetime
156
- * :float
157
- * :integer
158
- * :numeric
159
- * :range
160
- * :string
161
- * :time
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('yes').to(:boolean) # => true
169
- Necromancer.convert('yes') >> :boolean # => true
170
- Necromancer.convert('yes') >> true # => true
171
- Necromancer.convert('yes') >> TrueClass # => true
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 orignal value is returned. However, you can pass `strict` as an additional argument to ensure failure when conversion cannot be performed:
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('1a').to(:integer, strict: true)
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
- * :array
184
- * :boolean
185
- * :date
186
- * :datetime
187
- * :float
188
- * :integer
189
- * :numeric
190
- * :range
191
- * :string
192
- * :time
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
- or calling `configure` method:
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('a, b, c').to(:array) # => ['a', 'b', 'c']
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('1 - 2 - 3').to(:array) # => [1, 2, 3]
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(['1', '2.3', '3.0']).to(:numeric)
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(['1', '2.3', false]).to(:numeric, strict: true)
263
- # => Necromancer::ConversionTypeError: false cannot be converted from `array` to `numeric`
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(['1', '2.3', false]).to(:numeric, strict: false)
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`, `'1'`, `'t'`, `'T'`, `'true'`, `'TRUE'`, `'y'`, `'Y'`, `'yes'`, `'Yes'`, `'on'`, `'ON'` values are converted to `TrueClass`.
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('yes').to(:boolean) # => true
301
+ Necromancer.convert("yes").to(:boolean) # => true
279
302
  ```
280
303
 
281
- Similarly, the `0`, `'0'`, `'f'`, `'F'`, `'false'`, `'FALSE'`, `'n'`, `'N'`, `'no'`, `'No'`, `'off'`, `'OFF'` values are converted to `FalseClass`.
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('no').to(:boolean) # => false
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('1-1-2015').to(:date) # => "2015-01-01"
300
- Necromancer.convert('01/01/2015').to(:date) # => "2015-01-01"
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({ x: '27.5', y: '4', z: '11'}).to(:numeric)
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('1.2a').to(:float) # => 1.2
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('1.2a').to(:float, strict: true) # => raises error
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('1a').to(:integer) # => 1
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('1e1').to(:numeric) # => 10
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('1,10').to(:range) # => 1..10
411
+ Necromancer.convert("1,10").to(:range) # => 1..10
359
412
  ```
360
413
 
361
- or to create a range of letters:
414
+ Or to create a range of letters:
362
415
 
363
416
  ```ruby
364
- Necromancer.convert('a-z').to(:range) # => 'a'..'z'
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('magic').to(:upcase) # => 'MAGIC'
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('magic').to(:upcase) # => 'MAGIC'
481
+ converter.convert("magic").to(:upcase) # => "MAGIC"
422
482
  ```
423
483
 
424
484
  ## Contributing
@@ -19,7 +19,7 @@ module Necromancer
19
19
  #
20
20
  # @api private
21
21
  def initialize(&block)
22
- block.call(configuration) if block_given?
22
+ block.(configuration) if block_given?
23
23
  @conversions = Conversions.new(configuration)
24
24
  @conversions.load
25
25
  end
@@ -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.call(self, *a) }
37
+ define_method(:initialize) { |*a| block.(self, *a) }
38
38
 
39
- define_method(:call) { |value| convert.call(value) }
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
- "from `#{source}` into `#{target}` "
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
- protected
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, options = {})
22
- strict = options.fetch(:strict, config.strict)
23
- case value.to_s
24
- when /^\s*?((\d+)(\s*(,|-)\s*)?)+\s*?$/
25
- value.to_s.split($4).map(&:to_i)
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 ArrayToNumericConverter < Converter
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, options = {})
46
- numeric_converter = NumericConverters::StringToNumericConverter.new(:string, :numeric)
47
- value.reduce([]) do |acc, el|
48
- acc << numeric_converter.call(el, **options)
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 ArrayToBooleanConverter < Converter
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, options = {})
63
- boolean_converter = BooleanConverters::StringToBooleanConverter.new(:string, :boolean)
64
- value.reduce([]) do |acc, el|
65
- acc << boolean_converter.call(el, options)
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, options = {})
79
- strict = options.fetch(:strict, config.strict)
80
- begin
81
- Array(value)
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, options = {})
100
- strict = options.fetch(:strict, config.strict)
101
- begin
102
- value.to_set
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
- conversions.register NullConverter.new(:array, :array)
111
- conversions.register StringToArrayConverter.new(:string, :array)
112
- conversions.register ArrayToNumericConverter.new(:array, :numeric)
113
- conversions.register ArrayToBooleanConverter.new(:array, :boolean)
114
- conversions.register ObjectToArrayConverter.new(:object, :array)
115
- conversions.register ObjectToArrayConverter.new(:hash, :array)
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, options = {})
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, options = {})
54
- strict = options.fetch(:strict, config.strict)
55
- begin
56
- !value.zero?
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, options = {})
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
- conversions.register StringToBooleanConverter.new(:string, :boolean)
86
- conversions.register IntegerToBooleanConverter.new(:integer, :boolean)
87
- conversions.register BooleanToIntegerConverter.new(:boolean, :integer)
88
- conversions.register NullConverter.new(:boolean, :boolean)
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, options = {})
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, options = {})
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, options = {})
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
- conversions.register StringToDateConverter.new(:string, :date)
70
- conversions.register NullConverter.new(:date, :date)
71
- conversions.register StringToDateTimeConverter.new(:string, :datetime)
72
- conversions.register NullConverter.new(:datetime, :datetime)
73
- conversions.register StringToTimeConverter.new(:string, :time)
74
- conversions.register NullConverter.new(:time, :time)
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 = /^[-+]?(\d+)$/.freeze
9
+ INTEGER_MATCHER = /^\s*[-+]?\s*(\d[\d\s]*)?$/.freeze
10
10
 
11
- FLOAT_MATCHER = /^[-+]?(\d*)(\.\d+)?([eE]?[-+]?\d+)?$/.freeze
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, **options)
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, **options)
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, **options)
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).call(value, **options)
70
+ StringToIntegerConverter.new(:string, :integer).(value, strict: strict)
74
71
  when FLOAT_MATCHER
75
- StringToFloatConverter.new(:string, :float).call(value, **options)
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
- conversions.register StringToIntegerConverter.new(:string, :integer)
84
- conversions.register IntegerToStringConverter.new(:integer, :string)
85
- conversions.register NullConverter.new(:integer, :integer)
86
- conversions.register StringToFloatConverter.new(:string, :float)
87
- conversions.register NullConverter.new(:float, :float)
88
- conversions.register StringToNumericConverter.new(:string, :numeric)
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 = /^(\-?\d+)$/.freeze
9
+ SINGLE_DIGIT_MATCHER = /^(?<digit>-?\d+(\.\d+)?)$/.freeze
10
10
 
11
- DIGIT_MATCHER = /^(-?\d+?)(\.{2}\.?|-|,)(-?\d+)$/.freeze
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 = /^(\w)(\.{2}\.?|-|,)(\w)$/.freeze
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, options = {})
29
- strict = options.fetch(:strict, config.strict)
30
- case value
31
- when SINGLE_DIGIT_MATCHER
32
- ::Range.new($1.to_i, $1.to_i)
33
- when DIGIT_MATCHER
34
- ::Range.new($1.to_i, $3.to_i, $2 == "...")
35
- when LETTER_MATCHER
36
- ::Range.new($1.to_s, $3.to_s, $2 == "...")
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
- conversions.register StringToRangeConverter.new(:string, :range)
45
- conversions.register NullConverter.new(:range, :range)
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
@@ -5,7 +5,7 @@ require_relative "converter"
5
5
  module Necromancer
6
6
  # A pass through converter
7
7
  class NullConverter < Converter
8
- def call(value, **options)
8
+ def call(value, strict: config.strict)
9
9
  value
10
10
  end
11
11
  end # NullConverter
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Necromancer
4
- VERSION = "0.6.0"
4
+ VERSION = "0.7.0"
5
5
  end # Necromancer
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.6.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-03-08 00:00:00.000000000 Z
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.1.2
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.