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 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.