necromancer 0.3.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|