remap 2.0.3 → 2.1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/remap/base.rb +229 -75
- data/lib/remap/compiler.rb +403 -37
- data/lib/remap/constructor/argument.rb +20 -6
- data/lib/remap/constructor/keyword.rb +20 -4
- data/lib/remap/constructor/none.rb +3 -4
- data/lib/remap/constructor.rb +12 -5
- data/lib/remap/contract.rb +27 -0
- data/lib/remap/extensions/enumerable.rb +48 -0
- data/lib/remap/extensions/hash.rb +13 -0
- data/lib/remap/extensions/object.rb +37 -0
- data/lib/remap/failure.rb +25 -15
- data/lib/remap/iteration/array.rb +20 -11
- data/lib/remap/iteration/hash.rb +21 -13
- data/lib/remap/iteration/other.rb +7 -7
- data/lib/remap/iteration.rb +8 -2
- data/lib/remap/mapper/and.rb +29 -7
- data/lib/remap/mapper/binary.rb +3 -6
- data/lib/remap/mapper/or.rb +29 -6
- data/lib/remap/mapper/support/operations.rb +40 -0
- data/lib/remap/mapper/xor.rb +29 -7
- data/lib/remap/mapper.rb +1 -48
- data/lib/remap/notice/traced.rb +19 -0
- data/lib/remap/notice/untraced.rb +11 -0
- data/lib/remap/notice.rb +34 -0
- data/lib/remap/operation.rb +26 -13
- data/lib/remap/path/input.rb +37 -0
- data/lib/remap/path/output.rb +26 -0
- data/lib/remap/path.rb +22 -0
- data/lib/remap/path_error.rb +13 -0
- data/lib/remap/proxy.rb +18 -0
- data/lib/remap/rule/each.rb +25 -24
- data/lib/remap/rule/embed.rb +33 -28
- data/lib/remap/rule/map/optional.rb +42 -0
- data/lib/remap/rule/map/required.rb +35 -0
- data/lib/remap/rule/map.rb +176 -55
- data/lib/remap/rule/set.rb +23 -33
- data/lib/remap/rule/support/collection/empty.rb +7 -7
- data/lib/remap/rule/support/collection/filled.rb +21 -8
- data/lib/remap/rule/support/collection.rb +11 -3
- data/lib/remap/rule/support/enum.rb +44 -21
- data/lib/remap/rule/void.rb +17 -18
- data/lib/remap/rule/wrap.rb +25 -17
- data/lib/remap/rule.rb +8 -1
- data/lib/remap/selector/all.rb +29 -7
- data/lib/remap/selector/index.rb +24 -16
- data/lib/remap/selector/key.rb +31 -16
- data/lib/remap/selector.rb +17 -0
- data/lib/remap/state/extension.rb +182 -208
- data/lib/remap/state/schema.rb +1 -1
- data/lib/remap/state.rb +30 -4
- data/lib/remap/static/fixed.rb +14 -3
- data/lib/remap/static/option.rb +21 -6
- data/lib/remap/static.rb +13 -0
- data/lib/remap/struct.rb +1 -0
- data/lib/remap/types.rb +13 -28
- data/lib/remap.rb +15 -19
- metadata +91 -89
- data/lib/remap/result.rb +0 -11
- data/lib/remap/rule/support/path.rb +0 -45
- data/lib/remap/state/types.rb +0 -11
- data/lib/remap/success.rb +0 -29
- data/lib/remap/version.rb +0 -5
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Remap
|
4
|
+
class Contract < Dry::Validation::Contract
|
5
|
+
# Constructs a contract used to validate mapper input
|
6
|
+
#
|
7
|
+
# @param rules [Array<Proc>]
|
8
|
+
# @param options [Hash]
|
9
|
+
# @param contract [Proc]
|
10
|
+
# @param attributes [Hash]
|
11
|
+
#
|
12
|
+
# @return [Contract]
|
13
|
+
def self.call(rules:, options:, contract:, attributes:)
|
14
|
+
Class.new(self) do
|
15
|
+
rules.each do |rule|
|
16
|
+
class_eval(&rule)
|
17
|
+
end
|
18
|
+
|
19
|
+
options.each do |option|
|
20
|
+
class_eval(&option)
|
21
|
+
end
|
22
|
+
|
23
|
+
schema(contract)
|
24
|
+
end.new(**attributes)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Remap
|
4
|
+
module Extensions
|
5
|
+
using Object
|
6
|
+
|
7
|
+
module Enumerable
|
8
|
+
refine ::Enumerable do
|
9
|
+
# Creates a hash using {self} as the {path} and {value} as the hash value
|
10
|
+
#
|
11
|
+
# @param value [Any] Hash value
|
12
|
+
#
|
13
|
+
# @example A hash from path
|
14
|
+
# [:a, :b].hide('value') # => { a: { b: 'value' } }
|
15
|
+
#
|
16
|
+
# @return [Hash]
|
17
|
+
def hide(value)
|
18
|
+
reverse.reduce(value) do |element, key|
|
19
|
+
{ key => element }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Fetches value at {path}
|
24
|
+
#
|
25
|
+
# @example Fetch value at path
|
26
|
+
# [[:a, :b], [:c, :d]].get(0, 1) # => :b
|
27
|
+
#
|
28
|
+
# @return [Any]
|
29
|
+
#
|
30
|
+
# @raise When path cannot be found
|
31
|
+
def get(*path, &error)
|
32
|
+
_, result = path.reduce([
|
33
|
+
EMPTY_ARRAY,
|
34
|
+
self
|
35
|
+
]) do |(current_path, element), key|
|
36
|
+
value = element.fetch(key) do
|
37
|
+
raise PathError, current_path + [key]
|
38
|
+
end
|
39
|
+
|
40
|
+
[current_path + [key], value]
|
41
|
+
end
|
42
|
+
|
43
|
+
result
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Remap
|
4
|
+
module Extensions
|
5
|
+
module Object
|
6
|
+
refine ::Object do
|
7
|
+
# Fallback validation method
|
8
|
+
#
|
9
|
+
# @yield if block is provided
|
10
|
+
#
|
11
|
+
# @raise unless block is provided
|
12
|
+
def _(&block)
|
13
|
+
unless block
|
14
|
+
return _ { raise _1 }
|
15
|
+
end
|
16
|
+
|
17
|
+
block["Expected a state, got [#{self}] (#{self.class})"]
|
18
|
+
end
|
19
|
+
|
20
|
+
# Fallback method used when #get is called on an object that does not respond to #get
|
21
|
+
#
|
22
|
+
# Block is invoked, if provided
|
23
|
+
# Otherwise a symbol is thrown
|
24
|
+
#
|
25
|
+
# @param path [Array<Key>]
|
26
|
+
def get(*path, &block)
|
27
|
+
raise PathError, []
|
28
|
+
end
|
29
|
+
alias_method :fetch, :get
|
30
|
+
|
31
|
+
def formated
|
32
|
+
self
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/remap/failure.rb
CHANGED
@@ -1,27 +1,37 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Remap
|
4
|
-
|
5
|
-
attribute :reasons, Types::Hash
|
4
|
+
using Extensions::Hash
|
6
5
|
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
class Failure < Dry::Concrete
|
7
|
+
attribute :failures, [Notice], min_size: 1
|
8
|
+
attribute? :notices, [Notice], default: EMPTY_ARRAY
|
10
9
|
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
# Merges two failures
|
11
|
+
#
|
12
|
+
# @param other [Failure]
|
13
|
+
#
|
14
|
+
# @return [Failure]
|
15
|
+
def merge(other)
|
16
|
+
unless other.is_a?(self.class)
|
17
|
+
raise ArgumentError, "can't merge #{self.class} with #{other.class}"
|
18
|
+
end
|
14
19
|
|
15
|
-
|
16
|
-
|
17
|
-
|
20
|
+
failure = attributes.deep_merge(other.attributes) do |_, value1, value2|
|
21
|
+
case [value1, value2]
|
22
|
+
in [Array, Array]
|
23
|
+
value1 + value2
|
24
|
+
else
|
25
|
+
raise ArgumentError, "can't merge #{self.class} with #{other.class}"
|
26
|
+
end
|
27
|
+
end
|
18
28
|
|
19
|
-
|
20
|
-
false
|
29
|
+
new(failure)
|
21
30
|
end
|
22
31
|
|
23
|
-
|
24
|
-
|
32
|
+
# @return [String]
|
33
|
+
def exception
|
34
|
+
Error.new(attributes.formated)
|
25
35
|
end
|
26
36
|
end
|
27
37
|
end
|
@@ -2,28 +2,37 @@
|
|
2
2
|
|
3
3
|
module Remap
|
4
4
|
class Iteration
|
5
|
+
using State::Extension
|
6
|
+
|
7
|
+
# Implements an array iterator which defines index in state
|
5
8
|
class Array < Concrete
|
6
|
-
|
9
|
+
# @return [Array<T>]
|
10
|
+
attribute :value, Types::Array, alias: :array
|
7
11
|
|
8
|
-
|
12
|
+
# @return [State<Array<T>>]
|
9
13
|
attribute :state, Types::State
|
10
14
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
input_state.merged(new_array_state)
|
17
|
-
end
|
18
|
-
end._
|
15
|
+
# @see Iteration#map
|
16
|
+
def call(&block)
|
17
|
+
array.each_with_index.reduce(init) do |state, (value, index)|
|
18
|
+
reduce(state, value, index, &block)
|
19
|
+
end
|
19
20
|
end
|
20
|
-
alias call map
|
21
21
|
|
22
22
|
private
|
23
23
|
|
24
24
|
def init
|
25
25
|
state.set(EMPTY_ARRAY)
|
26
26
|
end
|
27
|
+
|
28
|
+
def reduce(state, value, index, &block)
|
29
|
+
notice = catch :ignore do
|
30
|
+
other = block[value, index: index]
|
31
|
+
return state.combine(other.fmap { [_1] })
|
32
|
+
end
|
33
|
+
|
34
|
+
state.set(notice: notice)
|
35
|
+
end
|
27
36
|
end
|
28
37
|
end
|
29
38
|
end
|
data/lib/remap/iteration/hash.rb
CHANGED
@@ -2,26 +2,34 @@
|
|
2
2
|
|
3
3
|
module Remap
|
4
4
|
class Iteration
|
5
|
+
using State::Extension
|
6
|
+
|
7
|
+
# Implements a hash iterator which defines key in state
|
5
8
|
class Hash < Concrete
|
6
|
-
|
9
|
+
# @return [Hash]
|
10
|
+
attribute :value, Types::Hash, alias: :hash
|
11
|
+
|
12
|
+
# @return [State<Hash>]
|
7
13
|
attribute :state, Types::State
|
8
14
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
block[value, key: key]._.then do |new_state|
|
15
|
-
new_state.fmap { { key => _1 } }
|
16
|
-
end.then do |new_hash_state|
|
17
|
-
input_state.merged(new_hash_state)
|
18
|
-
end
|
19
|
-
end._
|
15
|
+
# @see Iteration#map
|
16
|
+
def call(&block)
|
17
|
+
hash.reduce(init) do |state, (key, value)|
|
18
|
+
reduce(state, key, value, &block)
|
19
|
+
end
|
20
20
|
end
|
21
|
-
alias call map
|
22
21
|
|
23
22
|
private
|
24
23
|
|
24
|
+
def reduce(state, key, value, &block)
|
25
|
+
notice = catch :ignore do
|
26
|
+
other = block[value, key: key]
|
27
|
+
return state.combine(other.fmap { { key => _1 } })
|
28
|
+
end
|
29
|
+
|
30
|
+
state.set(notice: notice)
|
31
|
+
end
|
32
|
+
|
25
33
|
def init
|
26
34
|
state.set(EMPTY_HASH)
|
27
35
|
end
|
@@ -2,17 +2,17 @@
|
|
2
2
|
|
3
3
|
module Remap
|
4
4
|
class Iteration
|
5
|
+
using State::Extension
|
6
|
+
|
7
|
+
# Default iterator which doesn't do anything
|
5
8
|
class Other < Concrete
|
9
|
+
attribute :value, Types::Any, alias: :other
|
6
10
|
attribute :state, Types::State
|
7
|
-
attribute :value, Types::Any
|
8
|
-
|
9
|
-
using State::Extension
|
10
11
|
|
11
|
-
# @see
|
12
|
-
def
|
13
|
-
|
12
|
+
# @see Iteration#map
|
13
|
+
def call(&block)
|
14
|
+
state.fatal!("Expected an enumerable, got %s (%s)", value, value.class)
|
14
15
|
end
|
15
|
-
alias call map
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
data/lib/remap/iteration.rb
CHANGED
@@ -2,10 +2,13 @@
|
|
2
2
|
|
3
3
|
module Remap
|
4
4
|
class Iteration < Dry::Interface
|
5
|
-
|
5
|
+
# @return [State<T>]
|
6
6
|
attribute :state, Types::State
|
7
7
|
|
8
|
-
#
|
8
|
+
# @return [T]
|
9
|
+
attribute :value, Types::Any
|
10
|
+
|
11
|
+
# Maps every element in {#value}
|
9
12
|
#
|
10
13
|
# @abstract
|
11
14
|
#
|
@@ -14,6 +17,9 @@ module Remap
|
|
14
17
|
# @yieldreturn [Array<V>, Hash<V, K>]
|
15
18
|
#
|
16
19
|
# @return [Array<V>, Hash<V, K>]
|
20
|
+
def call(state)
|
21
|
+
raise NotImplementedError, "#{self.class}#call not implemented"
|
22
|
+
end
|
17
23
|
|
18
24
|
order :Hash, :Array, :Other
|
19
25
|
end
|
data/lib/remap/mapper/and.rb
CHANGED
@@ -2,14 +2,36 @@
|
|
2
2
|
|
3
3
|
module Remap
|
4
4
|
class Mapper
|
5
|
-
|
6
|
-
using State::Extension
|
5
|
+
using State::Extension
|
7
6
|
|
7
|
+
# Represents two mappers that are combined with the & operator
|
8
|
+
#
|
9
|
+
# @example Combine two mappers
|
10
|
+
# class Mapper1 < Remap::Base
|
11
|
+
# contract do
|
12
|
+
# required(:a1)
|
13
|
+
# end
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# class Mapper2 < Remap::Base
|
17
|
+
# contract do
|
18
|
+
# required(:a2)
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# state = Remap::State.call({ a2: 2, a1: 1 })
|
23
|
+
# output = (Mapper1 & Mapper2).call!(state)
|
24
|
+
# output.fetch(:value) # => { a2: 2, a1: 1 }
|
25
|
+
class And < Binary
|
26
|
+
# Succeeds if both left and right succeed
|
27
|
+
# Returns the combined result of left and right
|
28
|
+
#
|
29
|
+
# @param state [State]
|
30
|
+
#
|
31
|
+
# @yield [Failure] if mapper fails
|
32
|
+
#
|
33
|
+
# @return [Result]
|
8
34
|
def call!(state, &error)
|
9
|
-
unless error
|
10
|
-
return call!(state, &exception)
|
11
|
-
end
|
12
|
-
|
13
35
|
state1 = left.call!(state) do |failure1|
|
14
36
|
right.call!(state) do |failure2|
|
15
37
|
return error[failure1.merge(failure2)]
|
@@ -22,7 +44,7 @@ module Remap
|
|
22
44
|
return error[failure]
|
23
45
|
end
|
24
46
|
|
25
|
-
state1.
|
47
|
+
state1.combine(state2)
|
26
48
|
end
|
27
49
|
end
|
28
50
|
end
|
data/lib/remap/mapper/binary.rb
CHANGED
@@ -2,15 +2,12 @@
|
|
2
2
|
|
3
3
|
module Remap
|
4
4
|
class Mapper
|
5
|
+
# @abstract
|
5
6
|
class Binary < self
|
7
|
+
include Operation
|
8
|
+
|
6
9
|
attribute :left, Types::Mapper
|
7
10
|
attribute :right, Types::Mapper
|
8
|
-
|
9
|
-
def exception
|
10
|
-
->(error) { raise error }
|
11
|
-
end
|
12
|
-
|
13
|
-
include Operation
|
14
11
|
end
|
15
12
|
end
|
16
13
|
end
|
data/lib/remap/mapper/or.rb
CHANGED
@@ -2,14 +2,37 @@
|
|
2
2
|
|
3
3
|
module Remap
|
4
4
|
class Mapper
|
5
|
-
|
6
|
-
using State::Extension
|
5
|
+
using State::Extension
|
7
6
|
|
7
|
+
# Represents two mappers that are combined with the | operator
|
8
|
+
#
|
9
|
+
# @example Combine two mappers
|
10
|
+
# class Mapper1 < Remap::Base
|
11
|
+
# contract do
|
12
|
+
# required(:a1)
|
13
|
+
# end
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# class Mapper2 < Remap::Base
|
17
|
+
# contract do
|
18
|
+
# required(:a2)
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# state = Remap::State.call({ a2: 2 })
|
23
|
+
# result = (Mapper1 | Mapper2).call!(state)
|
24
|
+
# result.fetch(:value) # => { a2: 2 }
|
25
|
+
class Or < Binary
|
26
|
+
# Succeeds if left or right succeeds
|
27
|
+
# Returns which ever succeeds first
|
28
|
+
#
|
29
|
+
# @param state [State]
|
30
|
+
#
|
31
|
+
# @yieldparam [Failure] if mapper fails
|
32
|
+
# @yieldreturn [Failure]
|
33
|
+
#
|
34
|
+
# @return [Result]
|
8
35
|
def call!(state, &error)
|
9
|
-
unless error
|
10
|
-
return call!(state, &exception)
|
11
|
-
end
|
12
|
-
|
13
36
|
left.call!(state) do |failure1|
|
14
37
|
return right.call!(state) do |failure2|
|
15
38
|
return error[failure1.merge(failure2)]
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Remap
|
4
|
+
class Mapper
|
5
|
+
module Operations
|
6
|
+
# Tries self and other and returns the first successful result
|
7
|
+
#
|
8
|
+
# @param other [Mapper]
|
9
|
+
#
|
10
|
+
# @return [Mapper::Or]
|
11
|
+
def |(other)
|
12
|
+
Or.new(left: self, right: other)
|
13
|
+
rescue Dry::Struct::Error => e
|
14
|
+
raise ArgumentError, e.message
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns a successful result when self & other are successful
|
18
|
+
#
|
19
|
+
# @param other [Mapper]
|
20
|
+
#
|
21
|
+
# @return [Mapper::And]
|
22
|
+
def &(other)
|
23
|
+
And.new(left: self, right: other)
|
24
|
+
rescue Dry::Struct::Error => e
|
25
|
+
raise ArgumentError, e.message
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns a successful result when only one of self & other are successful
|
29
|
+
#
|
30
|
+
# @param other [Mapper]
|
31
|
+
#
|
32
|
+
# @return [Mapper:Xor]
|
33
|
+
def ^(other)
|
34
|
+
Xor.new(left: self, right: other)
|
35
|
+
rescue Dry::Struct::Error => e
|
36
|
+
raise ArgumentError, e.message
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/remap/mapper/xor.rb
CHANGED
@@ -2,14 +2,36 @@
|
|
2
2
|
|
3
3
|
module Remap
|
4
4
|
class Mapper
|
5
|
-
|
6
|
-
using State::Extension
|
5
|
+
using State::Extension
|
7
6
|
|
7
|
+
# Represents two mappers that are combined with the ^ operator
|
8
|
+
#
|
9
|
+
# @example Combine two mappers
|
10
|
+
# class Mapper1 < Remap::Base
|
11
|
+
# contract do
|
12
|
+
# required(:a1)
|
13
|
+
# end
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# class Mapper2 < Remap::Base
|
17
|
+
# contract do
|
18
|
+
# required(:a2)
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# state = Remap::State.call({ a2: 2 })
|
23
|
+
# output = (Mapper1 ^ Mapper2).call!(state)
|
24
|
+
# output.fetch(:value) # => { a2: 2 }
|
25
|
+
class Xor < Binary
|
26
|
+
# Succeeds if left or right succeeds, but not both
|
27
|
+
#
|
28
|
+
# @param state [State]
|
29
|
+
#
|
30
|
+
# @yieldparam [Failure] if mapper fails
|
31
|
+
# @yieldreturn [Failure]
|
32
|
+
#
|
33
|
+
# @return [Result]
|
8
34
|
def call!(state, &error)
|
9
|
-
unless error
|
10
|
-
return call!(state, &exception)
|
11
|
-
end
|
12
|
-
|
13
35
|
state1 = left.call!(state) do |failure1|
|
14
36
|
return right.call!(state) do |failure2|
|
15
37
|
return error[failure1.merge(failure2)]
|
@@ -20,7 +42,7 @@ module Remap
|
|
20
42
|
return state1
|
21
43
|
end
|
22
44
|
|
23
|
-
|
45
|
+
state1.combine(state2).failure("Both left and right passed xor operation").then(&error)
|
24
46
|
end
|
25
47
|
end
|
26
48
|
end
|
data/lib/remap/mapper.rb
CHANGED
@@ -3,54 +3,7 @@
|
|
3
3
|
module Remap
|
4
4
|
# @abstract
|
5
5
|
class Mapper < Struct
|
6
|
-
# Tries {self} and {other} and returns the first successful result
|
7
|
-
#
|
8
|
-
# @param other [Mapper]
|
9
|
-
#
|
10
|
-
# @return [Mapper::Or]
|
11
|
-
module Operations
|
12
|
-
def |(other)
|
13
|
-
Or.new(left: self, right: other)
|
14
|
-
rescue Dry::Struct::Error => e
|
15
|
-
raise ArgumentError, e.message
|
16
|
-
end
|
17
|
-
|
18
|
-
# Returns a successful result when {self} & {other} are successful
|
19
|
-
#
|
20
|
-
# @param other [Mapper]
|
21
|
-
#
|
22
|
-
# @return [Mapper::And]
|
23
|
-
def &(other)
|
24
|
-
And.new(left: self, right: other)
|
25
|
-
rescue Dry::Struct::Error => e
|
26
|
-
raise ArgumentError, e.message
|
27
|
-
end
|
28
|
-
|
29
|
-
# Returns a successful result when only one of {self} & {other} are successful
|
30
|
-
#
|
31
|
-
# @param other [Mapper]
|
32
|
-
#
|
33
|
-
# @return [Mapper:Xor]
|
34
|
-
def ^(other)
|
35
|
-
Xor.new(left: self, right: other)
|
36
|
-
rescue Dry::Struct::Error => e
|
37
|
-
raise ArgumentError, e.message
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
include Operations
|
42
6
|
extend Operations
|
43
|
-
|
44
|
-
# Creates a new mapper using {state}
|
45
|
-
#
|
46
|
-
# @param state [State]
|
47
|
-
#
|
48
|
-
# @yield [State]
|
49
|
-
# If the call fails, the block is invoked with the state
|
50
|
-
# @yieldreturn [State]
|
51
|
-
#
|
52
|
-
# @return [State]
|
53
|
-
#
|
54
|
-
# @private
|
7
|
+
include Operations
|
55
8
|
end
|
56
9
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Remap
|
4
|
+
class Notice
|
5
|
+
class Traced < Concrete
|
6
|
+
attribute? :backtrace, Types::Backtrace, default: EMPTY_ARRAY
|
7
|
+
|
8
|
+
def traced(backtrace)
|
9
|
+
Notice.call(**attributes, backtrace: backtrace)
|
10
|
+
end
|
11
|
+
|
12
|
+
def exception
|
13
|
+
return super if backtrace.blank?
|
14
|
+
|
15
|
+
super.tap { _1.set_backtrace(backtrace.map(&:to_s)) }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/remap/notice.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Remap
|
4
|
+
using Extensions::Hash
|
5
|
+
|
6
|
+
class Notice < Dry::Interface
|
7
|
+
attribute? :value, Types::Any
|
8
|
+
attribute :reason, String
|
9
|
+
attribute :path, Array
|
10
|
+
|
11
|
+
class Error < Remap::Error
|
12
|
+
extend Dry::Initializer
|
13
|
+
|
14
|
+
param :notice, type: Notice
|
15
|
+
end
|
16
|
+
|
17
|
+
def inspect
|
18
|
+
"#<%s %s>" % [self.class, to_hash.formated]
|
19
|
+
end
|
20
|
+
alias to_s inspect
|
21
|
+
|
22
|
+
# Hash representation of the notice
|
23
|
+
#
|
24
|
+
# @return [Hash]
|
25
|
+
def to_hash
|
26
|
+
super.except(:backtrace).compact_blank
|
27
|
+
end
|
28
|
+
|
29
|
+
# @return [Error]
|
30
|
+
def exception
|
31
|
+
Error.new(self)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|