necromancer 0.3.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 +5 -5
- data/CHANGELOG.md +70 -3
- data/README.md +204 -86
- data/lib/necromancer.rb +17 -18
- data/lib/necromancer/configuration.rb +1 -1
- data/lib/necromancer/context.rb +16 -3
- data/lib/necromancer/conversion_target.rb +31 -14
- data/lib/necromancer/conversions.rb +39 -16
- data/lib/necromancer/converter.rb +10 -8
- data/lib/necromancer/converters/array.rb +143 -45
- data/lib/necromancer/converters/boolean.rb +21 -19
- data/lib/necromancer/converters/date_time.rb +58 -13
- data/lib/necromancer/converters/hash.rb +119 -0
- data/lib/necromancer/converters/numeric.rb +32 -28
- data/lib/necromancer/converters/range.rb +44 -18
- data/lib/necromancer/null_converter.rb +4 -2
- data/lib/necromancer/version.rb +2 -2
- metadata +39 -72
- data/.gitignore +0 -14
- data/.rspec +0 -3
- data/.ruby-version +0 -1
- data/.travis.yml +0 -19
- data/Gemfile +0 -16
- data/Rakefile +0 -8
- data/necromancer.gemspec +0 -21
- data/spec/spec_helper.rb +0 -53
- data/spec/unit/can_spec.rb +0 -11
- data/spec/unit/config_spec.rb +0 -32
- data/spec/unit/configuration/new_spec.rb +0 -30
- data/spec/unit/conversions/register_spec.rb +0 -49
- data/spec/unit/convert_spec.rb +0 -104
- data/spec/unit/converters/array/array_to_boolean_spec.rb +0 -22
- data/spec/unit/converters/array/array_to_numeric_spec.rb +0 -22
- data/spec/unit/converters/array/array_to_set_spec.rb +0 -18
- data/spec/unit/converters/array/object_to_array_spec.rb +0 -21
- data/spec/unit/converters/array/string_to_array_spec.rb +0 -33
- data/spec/unit/converters/boolean/boolean_to_integer_spec.rb +0 -26
- data/spec/unit/converters/boolean/integer_to_boolean_spec.rb +0 -22
- data/spec/unit/converters/boolean/string_to_boolean_spec.rb +0 -36
- data/spec/unit/converters/date_time/string_to_date_spec.rb +0 -22
- data/spec/unit/converters/date_time/string_to_datetime_spec.rb +0 -32
- data/spec/unit/converters/numeric/string_to_float_spec.rb +0 -48
- data/spec/unit/converters/numeric/string_to_integer_spec.rb +0 -62
- data/spec/unit/converters/numeric/string_to_numeric_spec.rb +0 -32
- data/spec/unit/converters/range/string_to_range_spec.rb +0 -35
- data/spec/unit/new_spec.rb +0 -12
- data/spec/unit/register_spec.rb +0 -17
- data/tasks/console.rake +0 -10
- data/tasks/coverage.rake +0 -11
- data/tasks/spec.rake +0 -29
@@ -1,4 +1,7 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../converter"
|
4
|
+
require_relative "../null_converter"
|
2
5
|
|
3
6
|
module Necromancer
|
4
7
|
# Container for Boolean converter classes
|
@@ -26,12 +29,11 @@ module Necromancer
|
|
26
29
|
# 0, f, F, FALSE, false, False, n, N, NO, no, No, off, OFF
|
27
30
|
#
|
28
31
|
# @api public
|
29
|
-
def call(value,
|
30
|
-
strict = options.fetch(:strict, config.strict)
|
32
|
+
def call(value, strict: config.strict)
|
31
33
|
case value.to_s
|
32
34
|
when TRUE_MATCHER then true
|
33
35
|
when FALSE_MATCHER then false
|
34
|
-
else strict ?
|
36
|
+
else strict ? raise_conversion_type(value) : value
|
35
37
|
end
|
36
38
|
end
|
37
39
|
end
|
@@ -47,13 +49,10 @@ module Necromancer
|
|
47
49
|
# converter.call(0) # => false
|
48
50
|
#
|
49
51
|
# @api public
|
50
|
-
def call(value,
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
rescue
|
55
|
-
strict ? fail_conversion_type(value) : value
|
56
|
-
end
|
52
|
+
def call(value, strict: config.strict)
|
53
|
+
!value.zero?
|
54
|
+
rescue StandardError
|
55
|
+
strict ? raise_conversion_type(value) : value
|
57
56
|
end
|
58
57
|
end
|
59
58
|
|
@@ -68,21 +67,24 @@ module Necromancer
|
|
68
67
|
# converter.call(false) # => 0
|
69
68
|
#
|
70
69
|
# @api public
|
71
|
-
def call(value,
|
72
|
-
|
73
|
-
if ['TrueClass', 'FalseClass'].include?(value.class.name)
|
70
|
+
def call(value, strict: config.strict)
|
71
|
+
if %w[TrueClass FalseClass].include?(value.class.name)
|
74
72
|
value ? 1 : 0
|
75
73
|
else
|
76
|
-
strict ?
|
74
|
+
strict ? raise_conversion_type(value) : value
|
77
75
|
end
|
78
76
|
end
|
79
77
|
end
|
80
78
|
|
81
79
|
def self.load(conversions)
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
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
|
86
88
|
end
|
87
89
|
end # BooleanConverters
|
88
90
|
end # Necromancer
|
@@ -1,33 +1,78 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "date"
|
4
|
+
require "time"
|
5
|
+
|
6
|
+
require_relative "../converter"
|
7
|
+
require_relative "../null_converter"
|
2
8
|
|
3
9
|
module Necromancer
|
4
10
|
# Container for Date converter classes
|
5
11
|
module DateTimeConverters
|
6
12
|
# An object that converts a String to a Date
|
7
13
|
class StringToDateConverter < Converter
|
8
|
-
|
9
|
-
|
14
|
+
# Convert a string value to a Date
|
15
|
+
#
|
16
|
+
# @example
|
17
|
+
# converter.call("1-1-2015") # => "2015-01-01"
|
18
|
+
# converter.call("01/01/2015") # => "2015-01-01"
|
19
|
+
# converter.call("2015-11-12") # => "2015-11-12"
|
20
|
+
# converter.call("12/11/2015") # => "2015-11-12"
|
21
|
+
#
|
22
|
+
# @api public
|
23
|
+
def call(value, strict: config.strict)
|
10
24
|
Date.parse(value)
|
11
|
-
rescue
|
12
|
-
strict ?
|
25
|
+
rescue StandardError
|
26
|
+
strict ? raise_conversion_type(value) : value
|
13
27
|
end
|
14
28
|
end
|
15
29
|
|
16
30
|
# An object that converts a String to a DateTime
|
17
31
|
class StringToDateTimeConverter < Converter
|
18
|
-
|
19
|
-
|
32
|
+
# Convert a string value to a DateTime
|
33
|
+
#
|
34
|
+
# @example
|
35
|
+
# converer.call("1-1-2015") # => "2015-01-01T00:00:00+00:00"
|
36
|
+
# converer.call("1-1-2015 15:12:44") # => "2015-01-01T15:12:44+00:00"
|
37
|
+
#
|
38
|
+
# @api public
|
39
|
+
def call(value, strict: config.strict)
|
20
40
|
DateTime.parse(value)
|
21
|
-
rescue
|
22
|
-
strict ?
|
41
|
+
rescue StandardError
|
42
|
+
strict ? raise_conversion_type(value) : value
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class StringToTimeConverter < Converter
|
47
|
+
# Convert a String value to a Time value
|
48
|
+
#
|
49
|
+
# @param [String] value
|
50
|
+
# the value to convert
|
51
|
+
#
|
52
|
+
# @example
|
53
|
+
# converter.call("01-01-2015") # => 2015-01-01 00:00:00 +0100
|
54
|
+
# converter.call("01-01-2015 08:35") # => 2015-01-01 08:35:00 +0100
|
55
|
+
# converter.call("12:35") # => 2015-01-04 12:35:00 +0100
|
56
|
+
#
|
57
|
+
# @api public
|
58
|
+
def call(value, strict: config.strict)
|
59
|
+
Time.parse(value)
|
60
|
+
rescue StandardError
|
61
|
+
strict ? raise_conversion_type(value) : value
|
23
62
|
end
|
24
63
|
end
|
25
64
|
|
26
65
|
def self.load(conversions)
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
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
|
31
76
|
end
|
32
77
|
end # DateTimeConverters
|
33
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
|
@@ -1,25 +1,27 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../converter"
|
4
|
+
require_relative "../null_converter"
|
2
5
|
|
3
6
|
module Necromancer
|
4
7
|
# Container for Numeric converter classes
|
5
8
|
module NumericConverters
|
6
|
-
INTEGER_MATCHER =
|
9
|
+
INTEGER_MATCHER = /^\s*[-+]?\s*(\d[\d\s]*)?$/.freeze
|
7
10
|
|
8
|
-
FLOAT_MATCHER =
|
11
|
+
FLOAT_MATCHER = /^\s*[-+]?([\d\s]*)(\.[\d\s]+)?([eE]?[-+]?[\d\s]+)?$/.freeze
|
9
12
|
|
10
13
|
# An object that converts a String to an Integer
|
11
14
|
class StringToIntegerConverter < Converter
|
12
15
|
# Convert string value to integer
|
13
16
|
#
|
14
17
|
# @example
|
15
|
-
# converter.call(
|
18
|
+
# converter.call("1abc") # => 1
|
16
19
|
#
|
17
20
|
# @api public
|
18
|
-
def call(value,
|
19
|
-
strict = options.fetch(:strict, config.strict)
|
21
|
+
def call(value, strict: config.strict)
|
20
22
|
Integer(value)
|
21
|
-
rescue
|
22
|
-
strict ?
|
23
|
+
rescue StandardError
|
24
|
+
strict ? raise_conversion_type(value) : value.to_i
|
23
25
|
end
|
24
26
|
end
|
25
27
|
|
@@ -28,10 +30,10 @@ module Necromancer
|
|
28
30
|
# Convert integer value to string
|
29
31
|
#
|
30
32
|
# @example
|
31
|
-
# converter.call(1) # =>
|
33
|
+
# converter.call(1) # => "1"
|
32
34
|
#
|
33
35
|
# @api public
|
34
|
-
def call(value, _)
|
36
|
+
def call(value, **_)
|
35
37
|
value.to_s
|
36
38
|
end
|
37
39
|
end
|
@@ -41,14 +43,13 @@ module Necromancer
|
|
41
43
|
# Convert string to float value
|
42
44
|
#
|
43
45
|
# @example
|
44
|
-
# converter.call(
|
46
|
+
# converter.call("1.2") # => 1.2
|
45
47
|
#
|
46
48
|
# @api public
|
47
|
-
def call(value,
|
48
|
-
strict = options.fetch(:strict, config.strict)
|
49
|
+
def call(value, strict: config.strict)
|
49
50
|
Float(value)
|
50
|
-
rescue
|
51
|
-
strict ?
|
51
|
+
rescue StandardError
|
52
|
+
strict ? raise_conversion_type(value) : value.to_f
|
52
53
|
end
|
53
54
|
end
|
54
55
|
|
@@ -57,32 +58,35 @@ module Necromancer
|
|
57
58
|
# Convert string to numeric value
|
58
59
|
#
|
59
60
|
# @example
|
60
|
-
# converter.call(
|
61
|
+
# converter.call("1.0") # => 1.0
|
61
62
|
#
|
62
63
|
# @example
|
63
|
-
# converter.call(
|
64
|
+
# converter.call("1") # => 1
|
64
65
|
#
|
65
66
|
# @api public
|
66
|
-
def call(value,
|
67
|
-
strict = options.fetch(:strict, config.strict)
|
67
|
+
def call(value, strict: config.strict)
|
68
68
|
case value
|
69
69
|
when INTEGER_MATCHER
|
70
|
-
StringToIntegerConverter.new(:string, :integer).
|
70
|
+
StringToIntegerConverter.new(:string, :integer).(value, strict: strict)
|
71
71
|
when FLOAT_MATCHER
|
72
|
-
StringToFloatConverter.new(:string, :float).
|
72
|
+
StringToFloatConverter.new(:string, :float).(value, strict: strict)
|
73
73
|
else
|
74
|
-
strict ?
|
74
|
+
strict ? raise_conversion_type(value) : value
|
75
75
|
end
|
76
76
|
end
|
77
77
|
end
|
78
78
|
|
79
79
|
def self.load(conversions)
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
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
|
86
90
|
end
|
87
91
|
end # Conversion
|
88
92
|
end # Necromancer
|
@@ -1,13 +1,22 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../converter"
|
4
|
+
require_relative "../null_converter"
|
2
5
|
|
3
6
|
module Necromancer
|
4
7
|
# Container for Range converter classes
|
5
8
|
module RangeConverters
|
6
|
-
SINGLE_DIGIT_MATCHER = /^(
|
9
|
+
SINGLE_DIGIT_MATCHER = /^(?<digit>-?\d+(\.\d+)?)$/.freeze
|
7
10
|
|
8
|
-
DIGIT_MATCHER = /^(
|
11
|
+
DIGIT_MATCHER = /^(?<open>-?\d+(\.\d+)?)
|
12
|
+
\s*(?<sep>(\.\s*){2,3}|-|,)\s*
|
13
|
+
(?<close>-?\d+(\.\d+)?)$
|
14
|
+
/x.freeze
|
9
15
|
|
10
|
-
LETTER_MATCHER = /^(
|
16
|
+
LETTER_MATCHER = /^(?<open>\w)
|
17
|
+
\s*(?<sep>(\.\s*){2,3}|-|,)\s*
|
18
|
+
(?<close>\w)$
|
19
|
+
/x.freeze
|
11
20
|
|
12
21
|
# An object that converts a String to a Range
|
13
22
|
class StringToRangeConverter < Converter
|
@@ -16,30 +25,47 @@ module Necromancer
|
|
16
25
|
# @param [Object] value
|
17
26
|
#
|
18
27
|
# @example
|
19
|
-
# converter.call(
|
28
|
+
# converter.call("0,9") # => (0..9)
|
20
29
|
#
|
21
30
|
# @example
|
22
|
-
# converter.call(
|
31
|
+
# converter.call("0-9") # => (0..9)
|
23
32
|
#
|
24
33
|
# @api public
|
25
|
-
def call(value,
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
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*/, "") == "...")
|
34
45
|
else
|
35
|
-
strict ?
|
46
|
+
strict ? raise_conversion_type(value) : value
|
36
47
|
end
|
37
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
|
38
60
|
end
|
39
61
|
|
40
62
|
def self.load(conversions)
|
41
|
-
|
42
|
-
|
63
|
+
[
|
64
|
+
StringToRangeConverter.new(:string, :range),
|
65
|
+
NullConverter.new(:range, :range)
|
66
|
+
].each do |converter|
|
67
|
+
conversions.register converter
|
68
|
+
end
|
43
69
|
end
|
44
70
|
end # RangeConverters
|
45
71
|
end # Necromancer
|