remap 2.2.44 → 2.2.48
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 +4 -4
- data/lib/remap/base.rb +19 -16
- data/lib/remap/catchable.rb +31 -10
- data/lib/remap/compiler.rb +5 -7
- data/lib/remap/extensions/enumerable.rb +2 -4
- data/lib/remap/extensions/object.rb +2 -2
- data/lib/remap/failure.rb +1 -1
- data/lib/remap/mapper/support/api.rb +1 -1
- data/lib/remap/path/input.rb +1 -1
- data/lib/remap/rule/block.rb +12 -15
- data/lib/remap/rule/map/enum.rb +12 -19
- data/lib/remap/rule/map/optional.rb +6 -6
- data/lib/remap/rule/map/required.rb +13 -1
- data/lib/remap/rule/map.rb +7 -22
- data/lib/remap/selector/all.rb +1 -1
- data/lib/remap/selector/index.rb +1 -1
- data/lib/remap/selector/key.rb +1 -1
- data/lib/remap/state/extension.rb +102 -100
- data/lib/remap/state/schema.rb +6 -2
- data/lib/remap/state.rb +4 -4
- data/lib/remap/types.rb +1 -1
- data/lib/remap.rb +1 -1
- metadata +1 -19
- data/lib/remap/iteration/array.rb +0 -35
- data/lib/remap/iteration/hash.rb +0 -35
- data/lib/remap/iteration/other.rb +0 -18
- data/lib/remap/iteration.rb +0 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a564dcf130adbf8c40eb089d14f498f993362b74823728ec8ad44b98014034e6
|
4
|
+
data.tar.gz: 3dcac97cd1e4c630ec55ccdbdb6c43922f2ce5367d770e471ebaa77f5ae3fc8c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 237c0305757a4a12e5d3c24358fd9ed6295d0159baf0bb5786a9b019e3b50c98bd163334b35b04bab99ef1f19adeb232aec234a2aed76ad16ade778c3950606e
|
7
|
+
data.tar.gz: 1c6637383207baf0bd32fd6398f34dc935a5237e2fa67eafa2fccaa1db0d1f9d3f569c6f0695f9c148e737b1c4de15a974a09ba193d0af55ffaf3bef21bad07d
|
data/lib/remap/base.rb
CHANGED
@@ -34,33 +34,33 @@ module Remap
|
|
34
34
|
# Mapper.call({}) # => { api_key: "ABC-123" }
|
35
35
|
#
|
36
36
|
# @example Maps ["A", "B", "C"] to ["A", "C"]
|
37
|
-
# class
|
37
|
+
# class IfNotMapper < Remap::Base
|
38
38
|
# define do
|
39
39
|
# each do
|
40
|
-
# map?.if_not do
|
40
|
+
# map?.if_not do |value|
|
41
41
|
# value.include?("B")
|
42
42
|
# end
|
43
43
|
# end
|
44
44
|
# end
|
45
45
|
# end
|
46
46
|
#
|
47
|
-
#
|
47
|
+
# IfNotMapper.call(["A", "B", "C"]) # => ["A", "C"]
|
48
48
|
#
|
49
49
|
# @example Maps ["A", "B", "C"] to ["B"]
|
50
|
-
# class
|
50
|
+
# class IfMapper < Remap::Base
|
51
51
|
# define do
|
52
52
|
# each do
|
53
|
-
# map?.if do
|
53
|
+
# map?.if do |value|
|
54
54
|
# value.include?("B")
|
55
55
|
# end
|
56
56
|
# end
|
57
57
|
# end
|
58
58
|
# end
|
59
59
|
#
|
60
|
-
#
|
60
|
+
# IfMapper.call(["A", "B", "C"]) # => ["B"]
|
61
61
|
#
|
62
62
|
# @example Maps { a: { b: "A" } } to "A"
|
63
|
-
# class
|
63
|
+
# class EnumMapper < Remap::Base
|
64
64
|
# define do
|
65
65
|
# map(:a, :b).enum do
|
66
66
|
# value "A", "B"
|
@@ -68,11 +68,11 @@ module Remap
|
|
68
68
|
# end
|
69
69
|
# end
|
70
70
|
#
|
71
|
-
#
|
72
|
-
#
|
71
|
+
# EnumMapper.call({ a: { b: "A" } }) # => "A"
|
72
|
+
# EnumMapper.call({ a: { b: "B" } }) # => "B"
|
73
73
|
#
|
74
74
|
# @example Map { people: [{ name: "John" }] } to { names: ["John"] }
|
75
|
-
# class
|
75
|
+
# class PeopleMapper < Remap::Base
|
76
76
|
# define do
|
77
77
|
# map :people, to: :names do
|
78
78
|
# each do
|
@@ -82,12 +82,12 @@ module Remap
|
|
82
82
|
# end
|
83
83
|
# end
|
84
84
|
#
|
85
|
-
#
|
85
|
+
# PeopleMapper.call({ people: [{ name: "John" }] }) # => { names: ["John"] }
|
86
86
|
#
|
87
87
|
# @example Map "Hello" to "Hello!"
|
88
88
|
# class HelloMapper < Remap::Base
|
89
89
|
# define do
|
90
|
-
# map.adjust do
|
90
|
+
# map.adjust do |value|
|
91
91
|
# "#{value}!"
|
92
92
|
# end
|
93
93
|
# end
|
@@ -105,6 +105,7 @@ module Remap
|
|
105
105
|
# Mapper.call([1, 2, 3]) # => 2
|
106
106
|
class Base < Mapper
|
107
107
|
include ActiveSupport::Configurable
|
108
|
+
include Dry::Core::Memoizable
|
108
109
|
include Dry::Core::Constants
|
109
110
|
include Catchable
|
110
111
|
extend Mapper::API
|
@@ -239,7 +240,7 @@ module Remap
|
|
239
240
|
# @return [void]
|
240
241
|
# rubocop:disable Layout/LineLength
|
241
242
|
def self.define(target = Nothing, method: :new, strategy: :argument, backtrace: caller, &context)
|
242
|
-
unless
|
243
|
+
unless context
|
243
244
|
raise ArgumentError, "#{self}.define requires a block"
|
244
245
|
end
|
245
246
|
|
@@ -305,11 +306,11 @@ module Remap
|
|
305
306
|
end
|
306
307
|
end
|
307
308
|
|
308
|
-
s1 = catch_ignored do |
|
309
|
-
return context.call(
|
309
|
+
s1 = catch_ignored(state) do |s0|
|
310
|
+
return context.call(s0).then(&constructor).remove_id
|
310
311
|
end
|
311
312
|
|
312
|
-
|
313
|
+
error[s1.failure]
|
313
314
|
end
|
314
315
|
|
315
316
|
private
|
@@ -318,5 +319,7 @@ module Remap
|
|
318
319
|
def validation
|
319
320
|
Contract.call(attributes: attributes, contract: contract, options: options, rules: rules)
|
320
321
|
end
|
322
|
+
|
323
|
+
memoize :validation
|
321
324
|
end
|
322
325
|
end
|
data/lib/remap/catchable.rb
CHANGED
@@ -1,21 +1,42 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Remap
|
4
|
+
# @api private
|
4
5
|
module Catchable
|
5
|
-
|
6
|
-
|
6
|
+
using State::Extension
|
7
|
+
|
8
|
+
# @param state [State]
|
9
|
+
#
|
10
|
+
# @yieldparam state [State]
|
11
|
+
# @yieldparam id [Symbol, String]
|
12
|
+
# @yieldreturn [State<T>]
|
7
13
|
#
|
8
|
-
# @return [T]
|
9
|
-
def catch_ignored(&block)
|
10
|
-
|
14
|
+
# @return [State<T>]
|
15
|
+
def catch_ignored(state, &block)
|
16
|
+
id = to_id(:ignored)
|
17
|
+
|
18
|
+
catch(id) do
|
19
|
+
block[state.set(id: id), id: id].remove_id
|
20
|
+
end
|
11
21
|
end
|
12
22
|
|
13
|
-
# @
|
14
|
-
# @
|
23
|
+
# @param state [State]
|
24
|
+
# @param backtrace [Array<String>]
|
15
25
|
#
|
16
|
-
# @
|
17
|
-
|
18
|
-
|
26
|
+
# @yieldparam state [State]
|
27
|
+
# @yieldparam id [Symbol, String]
|
28
|
+
# @yieldreturn [State<T>]
|
29
|
+
#
|
30
|
+
# @return [State<T>]
|
31
|
+
# @raise [Failure::Error]
|
32
|
+
def catch_fatal(state, backtrace, &block)
|
33
|
+
id = to_id(:fatal)
|
34
|
+
|
35
|
+
failure = catch(id) do
|
36
|
+
return block[state.set(fatal_id: id), fatal_id: id].remove_fatal_id
|
37
|
+
end
|
38
|
+
|
39
|
+
raise failure.exception(backtrace)
|
19
40
|
end
|
20
41
|
|
21
42
|
private
|
data/lib/remap/compiler.rb
CHANGED
@@ -32,7 +32,7 @@ module Remap
|
|
32
32
|
#
|
33
33
|
# @return [Rule]
|
34
34
|
def self.call(backtrace: caller, &block)
|
35
|
-
unless
|
35
|
+
unless block
|
36
36
|
return Rule::VOID
|
37
37
|
end
|
38
38
|
|
@@ -317,7 +317,7 @@ module Remap
|
|
317
317
|
# @return [Rule::Each]]
|
318
318
|
# @raise [ArgumentError] if no block given
|
319
319
|
def each(backtrace: caller, &block)
|
320
|
-
unless
|
320
|
+
unless block
|
321
321
|
raise ArgumentError, "#each requires a block"
|
322
322
|
end
|
323
323
|
|
@@ -350,7 +350,7 @@ module Remap
|
|
350
350
|
# @return [Rule::Wrap]
|
351
351
|
# @raise [ArgumentError] if type is not :array
|
352
352
|
def wrap(type, backtrace: caller, &block)
|
353
|
-
unless
|
353
|
+
unless block
|
354
354
|
raise ArgumentError, "#wrap requires a block"
|
355
355
|
end
|
356
356
|
|
@@ -548,13 +548,13 @@ module Remap
|
|
548
548
|
output: [to].flatten,
|
549
549
|
input: path.flatten
|
550
550
|
},
|
551
|
+
backtrace: backtrace,
|
551
552
|
rule: call(backtrace: backtrace, &block)
|
552
553
|
})
|
553
554
|
end
|
554
555
|
|
555
556
|
def build_embed(s0, mapper, backtrace)
|
556
|
-
|
557
|
-
s1 = s0.set(fatal_id: fatal_id)
|
557
|
+
catch_fatal(s0, backtrace) do |s1|
|
558
558
|
s2 = s1.set(mapper: mapper)
|
559
559
|
old_mapper = s0.fetch(:mapper)
|
560
560
|
|
@@ -563,8 +563,6 @@ module Remap
|
|
563
563
|
s3.return!
|
564
564
|
end.except(:scope).merge(mapper: old_mapper)
|
565
565
|
end
|
566
|
-
|
567
|
-
raise f0.exception(backtrace)
|
568
566
|
end
|
569
567
|
end
|
570
568
|
end
|
@@ -33,15 +33,13 @@ module Remap
|
|
33
33
|
|
34
34
|
key = path.first
|
35
35
|
|
36
|
-
unless
|
36
|
+
unless fallback
|
37
37
|
return get(*path, trace: trace) do
|
38
|
-
|
38
|
+
throw :ignore, trace + [key]
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
42
|
fetch(key, &fallback).get(*path[1..], trace: trace + [key], &fallback)
|
43
|
-
rescue TypeError
|
44
|
-
raise PathError, trace + [key]
|
45
43
|
end
|
46
44
|
end
|
47
45
|
end
|
data/lib/remap/failure.rb
CHANGED
@@ -17,7 +17,7 @@ module Remap
|
|
17
17
|
]
|
18
18
|
end
|
19
19
|
|
20
|
-
failure = attributes.
|
20
|
+
failure = attributes.merge(other.attributes) do |key, value1, value2|
|
21
21
|
case [key, value1, value2]
|
22
22
|
in [:failures | :notices, Array, Array]
|
23
23
|
value1 + value2
|
data/lib/remap/path/input.rb
CHANGED
data/lib/remap/rule/block.rb
CHANGED
@@ -16,29 +16,26 @@ module Remap
|
|
16
16
|
#
|
17
17
|
# @return [State]
|
18
18
|
def call(state)
|
19
|
-
|
19
|
+
init = state.except(:value)
|
20
20
|
|
21
21
|
if rules.empty?
|
22
|
-
return
|
22
|
+
return init
|
23
23
|
end
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
s4 = state.set(fatal_id: fatal_id)
|
25
|
+
catch_fatal(init, backtrace) do |s1, fatal_id:|
|
26
|
+
s2 = state.set(fatal_id: fatal_id)
|
28
27
|
|
29
|
-
|
30
|
-
|
28
|
+
catch_ignored(s1) do |s3, id:|
|
29
|
+
states = rules.map do |rule|
|
30
|
+
rule.call(s2)
|
31
|
+
end
|
31
32
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
s7 = s6.set(id: id)
|
36
|
-
s5.combine(s7)
|
33
|
+
states.reduce(s3) do |s4, s5|
|
34
|
+
s6 = s5.set(id: id)
|
35
|
+
s4.combine(s6)
|
37
36
|
end
|
38
|
-
end
|
37
|
+
end
|
39
38
|
end
|
40
|
-
|
41
|
-
raise failure.exception(backtrace)
|
42
39
|
end
|
43
40
|
end
|
44
41
|
end
|
data/lib/remap/rule/map/enum.rb
CHANGED
@@ -4,13 +4,9 @@ module Remap
|
|
4
4
|
class Rule
|
5
5
|
class Map
|
6
6
|
class Enum < Proxy
|
7
|
-
include Dry::Monads[:maybe]
|
8
|
-
|
9
7
|
# @return [Hash]
|
10
|
-
option :
|
11
|
-
|
12
|
-
# @return [Maybe]
|
13
|
-
option :default, default: -> { None() }
|
8
|
+
option :table, default: -> { {} }
|
9
|
+
option :default, default: -> { Undefined }
|
14
10
|
|
15
11
|
alias execute instance_eval
|
16
12
|
|
@@ -37,7 +33,7 @@ module Remap
|
|
37
33
|
new.tap { _1.execute(&block) }
|
38
34
|
end
|
39
35
|
|
40
|
-
# Translates key into a value using predefined
|
36
|
+
# Translates key into a value using predefined table
|
41
37
|
#
|
42
38
|
# @param key [#hash]
|
43
39
|
#
|
@@ -50,24 +46,21 @@ module Remap
|
|
50
46
|
return get(key) { raise Error, _1 }
|
51
47
|
end
|
52
48
|
|
53
|
-
|
54
|
-
|
49
|
+
table.fetch(key) do
|
50
|
+
unless default == Undefined
|
51
|
+
return default
|
52
|
+
end
|
53
|
+
|
54
|
+
error["Enum key [#{key}] not found among [#{table.keys.inspect}]"]
|
55
55
|
end
|
56
56
|
end
|
57
57
|
alias call get
|
58
58
|
|
59
|
-
# @return [Maybe]
|
60
|
-
def [](key)
|
61
|
-
mappings[key]
|
62
|
-
end
|
63
|
-
|
64
59
|
# @return [void]
|
65
60
|
def from(*keys, to:)
|
66
|
-
value = Some(to)
|
67
|
-
|
68
61
|
keys.each do |key|
|
69
|
-
|
70
|
-
|
62
|
+
table[key] = to
|
63
|
+
table[to] = to
|
71
64
|
end
|
72
65
|
end
|
73
66
|
|
@@ -80,7 +73,7 @@ module Remap
|
|
80
73
|
|
81
74
|
# @return [void]
|
82
75
|
def otherwise(value)
|
83
|
-
|
76
|
+
@default = value
|
84
77
|
end
|
85
78
|
end
|
86
79
|
end
|
@@ -5,12 +5,14 @@ module Remap
|
|
5
5
|
class Map
|
6
6
|
using State::Extension
|
7
7
|
|
8
|
-
|
8
|
+
# @api private
|
9
|
+
class Optional < Required
|
9
10
|
# Represents an optional mapping rule
|
10
11
|
# When the mapping fails, the value is ignored
|
11
12
|
#
|
12
13
|
# @example Map [:name] to [:nickname]
|
13
14
|
# map = Map::Optional.call({
|
15
|
+
# backtrace: caller,
|
14
16
|
# path: {
|
15
17
|
# input: [:name],
|
16
18
|
# output: [:nickname]
|
@@ -22,16 +24,14 @@ module Remap
|
|
22
24
|
# })
|
23
25
|
#
|
24
26
|
# output = map.call(state) do |failure|
|
25
|
-
# raise failure.
|
27
|
+
# raise failure.exception(caller)
|
26
28
|
# end
|
27
29
|
#
|
28
30
|
# output.fetch(:value) # => { nickname: "John" }
|
29
31
|
#
|
30
|
-
# @
|
31
|
-
#
|
32
|
-
# @return [State]
|
32
|
+
# @see Map#call
|
33
33
|
def call(state)
|
34
|
-
|
34
|
+
catch_ignored(state) { super(_1) }
|
35
35
|
end
|
36
36
|
end
|
37
37
|
end
|
@@ -8,7 +8,19 @@ module Remap
|
|
8
8
|
class Required < Concrete
|
9
9
|
attribute :backtrace, Types::Backtrace
|
10
10
|
|
11
|
-
#
|
11
|
+
# @see Map#call
|
12
|
+
def call(state)
|
13
|
+
catch_fatal(state, backtrace) do |s0|
|
14
|
+
s2 = path.input.call(s0) do |s1|
|
15
|
+
callback(rule.call(s1))
|
16
|
+
end
|
17
|
+
|
18
|
+
s3 = s2.then(&path.output)
|
19
|
+
s4 = s3.set(path: state.path)
|
20
|
+
|
21
|
+
s4.except(:key)
|
22
|
+
end
|
23
|
+
end
|
12
24
|
end
|
13
25
|
end
|
14
26
|
end
|
data/lib/remap/rule/map.rb
CHANGED
@@ -43,29 +43,14 @@ module Remap
|
|
43
43
|
#
|
44
44
|
# @abstract
|
45
45
|
def call(state)
|
46
|
-
|
47
|
-
s0 = state.set(fatal_id: fatal_id)
|
48
|
-
|
49
|
-
s2 = path.input.call(s0) do |s1|
|
50
|
-
s2 = rule.call(s1)
|
51
|
-
callback(s2)
|
52
|
-
end
|
53
|
-
|
54
|
-
s3 = s2.then(&path.output)
|
55
|
-
s4 = s3.set(path: state.path)
|
56
|
-
s5 = s4.except(:key)
|
57
|
-
|
58
|
-
return s5.remove_fatal_id
|
59
|
-
end
|
60
|
-
|
61
|
-
raise failure.exception(backtrace)
|
46
|
+
raise NotImplementedError, "#{self.class}#call not implemented"
|
62
47
|
end
|
63
48
|
|
64
49
|
# A post-processor method
|
65
50
|
#
|
66
51
|
# @example Up-case mapped value
|
67
52
|
# state = Remap::State.call("Hello World")
|
68
|
-
# map = Remap::Rule::Map.call(
|
53
|
+
# map = Remap::Rule::Map.call(backtrace: caller)
|
69
54
|
# upcase = map.adjust(&:upcase)
|
70
55
|
# error = -> failure { raise failure.exception }
|
71
56
|
# upcase.call(state, &error).fetch(:value) # => "HELLO WORLD"
|
@@ -84,7 +69,7 @@ module Remap
|
|
84
69
|
#
|
85
70
|
# @example Pending mapping
|
86
71
|
# state = Remap::State.call(:value)
|
87
|
-
# map = Remap::Rule::Map.call(
|
72
|
+
# map = Remap::Rule::Map::Optional.call(backtrace: caller)
|
88
73
|
# pending = map.pending("this is pending")
|
89
74
|
# error = -> failure { raise failure.exception }
|
90
75
|
# pending.call(state, &error).key?(:value) # => false
|
@@ -99,7 +84,7 @@ module Remap
|
|
99
84
|
# An enumeration processor
|
100
85
|
#
|
101
86
|
# @example A mapped enum
|
102
|
-
# enum = Remap::Rule::Map.call(
|
87
|
+
# enum = Remap::Rule::Map.call(backtrace: caller).enum do
|
103
88
|
# value "A", "B"
|
104
89
|
# otherwise "C"
|
105
90
|
# end
|
@@ -132,7 +117,7 @@ module Remap
|
|
132
117
|
# Keeps map, only if block is true
|
133
118
|
#
|
134
119
|
# @example Keep if value contains "A"
|
135
|
-
# map = Remap::Rule::Map.call(
|
120
|
+
# map = Remap::Rule::Map::Optional.call(backtrace: caller).if do |value|
|
136
121
|
# value.include?("A")
|
137
122
|
# end
|
138
123
|
#
|
@@ -160,11 +145,11 @@ module Remap
|
|
160
145
|
#
|
161
146
|
|
162
147
|
# @example Keep unless value contains "A"
|
163
|
-
# map = Remap::Rule::Map.
|
148
|
+
# map = Remap::Rule::Map::Optional.new(backtrace: caller).if_not do |value|
|
164
149
|
# value.include?("A")
|
165
150
|
# end
|
166
151
|
#
|
167
|
-
# error = -> failure { raise failure.exception }
|
152
|
+
# error = -> failure { raise failure.exception(caller) }
|
168
153
|
#
|
169
154
|
# a = Remap::State.call("A")
|
170
155
|
# map.call(a, &error).key?(:value) # => false
|
data/lib/remap/selector/all.rb
CHANGED
data/lib/remap/selector/index.rb
CHANGED
data/lib/remap/selector/key.rb
CHANGED
@@ -46,14 +46,10 @@ module Remap
|
|
46
46
|
# @returns [Hash] a hash containing the given path
|
47
47
|
# @raise Europace::Error when path doesn't exist
|
48
48
|
def only(*path)
|
49
|
-
|
50
|
-
next hash unless key?(key)
|
51
|
-
|
52
|
-
hash.deep_merge(key => fetch(key))
|
53
|
-
end
|
49
|
+
dup.extract!(*path)
|
54
50
|
end
|
55
51
|
|
56
|
-
#
|
52
|
+
# @see #notice
|
57
53
|
def fatal!(...)
|
58
54
|
fatal_id = fetch(:fatal_id) do
|
59
55
|
raise ArgumentError, "Missing :fatal_id in %s" % formatted
|
@@ -62,12 +58,7 @@ module Remap
|
|
62
58
|
throw fatal_id, Failure.new(failures: [notice(...)], notices: notices)
|
63
59
|
end
|
64
60
|
|
65
|
-
#
|
66
|
-
def notice!(...)
|
67
|
-
raise NotImplementedError, "Not implemented"
|
68
|
-
end
|
69
|
-
|
70
|
-
# Throws :ignore containing a Notice
|
61
|
+
# @see #notice
|
71
62
|
def ignore!(...)
|
72
63
|
set(notice: notice(...)).except(:value).return!
|
73
64
|
end
|
@@ -117,11 +108,30 @@ module Remap
|
|
117
108
|
#
|
118
109
|
# @return [State]
|
119
110
|
def map(&block)
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
111
|
+
result = case self
|
112
|
+
in { value: Array => array }
|
113
|
+
array.each_with_index.each_with_object([]) do |(value, index), array|
|
114
|
+
s1 = block[set(value, index: index)]
|
115
|
+
|
116
|
+
if s1.key?(:value)
|
117
|
+
array << s1[:value]
|
118
|
+
end
|
119
|
+
end
|
120
|
+
in { value: Hash => hash }
|
121
|
+
hash.each_with_object({}) do |(key, value), acc|
|
122
|
+
s1 = block[set(value, key: key)]
|
123
|
+
|
124
|
+
if s1.key?(:value)
|
125
|
+
acc[key] = s1[:value]
|
126
|
+
end
|
127
|
+
end
|
128
|
+
in { value: }
|
129
|
+
fatal!("Expected an enumerable got %s", value.class)
|
130
|
+
else
|
131
|
+
return self
|
124
132
|
end
|
133
|
+
|
134
|
+
set(result)
|
125
135
|
end
|
126
136
|
|
127
137
|
# @return [String]
|
@@ -135,10 +145,14 @@ module Remap
|
|
135
145
|
#
|
136
146
|
# @return [State]
|
137
147
|
def combine(other)
|
138
|
-
|
148
|
+
merge(other) do |key, value1, value2|
|
139
149
|
case [key, value1, value2]
|
140
|
-
in [
|
141
|
-
|
150
|
+
in [_, Hash => left, Hash => right]
|
151
|
+
left.merge(right)
|
152
|
+
in [:ids | :fatal_ids, _, right]
|
153
|
+
right
|
154
|
+
in [_, Array => left, Array => right]
|
155
|
+
left + right
|
142
156
|
in [:value, left, right]
|
143
157
|
other.fatal!(
|
144
158
|
"Could not merge [%s] (%s) with [%s] (%s)",
|
@@ -147,15 +161,6 @@ module Remap
|
|
147
161
|
right.formatted,
|
148
162
|
right.class
|
149
163
|
)
|
150
|
-
in [:notices, Array => n1, Array => n2]
|
151
|
-
n1 + n2
|
152
|
-
in [:ids, i1, i2] if i1.all? { i2.include?(_1) }
|
153
|
-
i2
|
154
|
-
in [:ids, i1, i2] if i2.all? { i1.include?(_1) }
|
155
|
-
i1
|
156
|
-
in [:ids, i1, i2]
|
157
|
-
other.fatal!("Could not merge #ids [%s] (%s) with [%s] (%s)", i1, i1.class, i2,
|
158
|
-
i2.class)
|
159
164
|
in [Symbol, _, value]
|
160
165
|
value
|
161
166
|
end
|
@@ -165,31 +170,39 @@ module Remap
|
|
165
170
|
# @todo Merge with {#remove_fatal_id}
|
166
171
|
# @return [State]
|
167
172
|
def remove_id
|
168
|
-
|
173
|
+
state = dup
|
174
|
+
|
175
|
+
case state
|
169
176
|
in { ids: [], id: }
|
170
|
-
except(:id)
|
177
|
+
state.except!(:id)
|
171
178
|
in { ids:, id: }
|
172
|
-
merge(ids: ids[1...], id: ids[0])
|
179
|
+
state.merge!(ids: ids[1...], id: ids[0])
|
173
180
|
in { ids: [] }
|
174
|
-
|
181
|
+
state
|
175
182
|
in { ids: }
|
176
183
|
raise ArgumentError, "[BUG] #ids for state are set, but not #id: %s" % formatted
|
177
|
-
end
|
184
|
+
end
|
185
|
+
|
186
|
+
state
|
178
187
|
end
|
179
188
|
|
180
189
|
# @todo Merge with {#remove_id}
|
181
190
|
# @return [State]
|
182
191
|
def remove_fatal_id
|
183
|
-
|
192
|
+
state = dup
|
193
|
+
|
194
|
+
case state
|
184
195
|
in { fatal_ids: [], fatal_id: }
|
185
|
-
except(:fatal_id)
|
186
|
-
in { fatal_ids: ids, fatal_id:
|
187
|
-
merge(fatal_ids: ids[1...], fatal_id: ids[0])
|
196
|
+
state.except!(:fatal_id)
|
197
|
+
in { fatal_ids: ids, fatal_id: }
|
198
|
+
state.merge!(fatal_ids: ids[1...], fatal_id: ids[0])
|
188
199
|
in { fatal_ids: [] }
|
189
|
-
|
200
|
+
state
|
190
201
|
in { fatal_ids: }
|
191
202
|
raise ArgumentError, "[BUG] #ids for state are set, but not #id: %s" % formatted
|
192
|
-
end
|
203
|
+
end
|
204
|
+
|
205
|
+
state
|
193
206
|
end
|
194
207
|
|
195
208
|
# Creates a new state with params
|
@@ -203,24 +216,30 @@ module Remap
|
|
203
216
|
return set(**options, value: value)
|
204
217
|
end
|
205
218
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
in [{
|
210
|
-
merge(
|
211
|
-
in [{
|
212
|
-
merge(
|
213
|
-
in [{path:}, {
|
214
|
-
merge(path: path + [
|
215
|
-
in [{path:}, {
|
216
|
-
merge(path: path + [
|
217
|
-
in [{
|
218
|
-
merge(
|
219
|
-
in [{
|
220
|
-
merge(
|
219
|
+
state = dup
|
220
|
+
|
221
|
+
case [state, options]
|
222
|
+
in [{notices:}, {notice: notice}]
|
223
|
+
state.merge!(notices: notices + [notice])
|
224
|
+
in [{value:}, {mapper:}]
|
225
|
+
state.merge!(scope: value, mapper: mapper)
|
226
|
+
in [{path:}, {key:, value:}]
|
227
|
+
state.merge!(path: path + [key], key: key, value: value)
|
228
|
+
in [{path:}, {key:}]
|
229
|
+
state.merge!(path: path + [key], key: key)
|
230
|
+
in [{path:}, {index:, value:}]
|
231
|
+
state.merge!(path: path + [index], element: value, index: index, value: value)
|
232
|
+
in [{path:}, {index:}]
|
233
|
+
state.merge!(path: path + [index], index: index)
|
234
|
+
in [{ids:, id: old_id}, {id: new_id}]
|
235
|
+
state.merge!(ids: [old_id] + ids, id: new_id)
|
236
|
+
in [{fatal_ids:, fatal_id: old_id}, {fatal_id: new_id}]
|
237
|
+
state.merge!(fatal_ids: [old_id] + fatal_ids, fatal_id: new_id)
|
221
238
|
else
|
222
|
-
merge(options)
|
239
|
+
state.merge!(options)
|
223
240
|
end
|
241
|
+
|
242
|
+
state
|
224
243
|
end
|
225
244
|
|
226
245
|
# Passes {#value} to block, if defined
|
@@ -240,22 +259,6 @@ module Remap
|
|
240
259
|
end
|
241
260
|
end
|
242
261
|
|
243
|
-
# Creates a failure to be used in {Remap::Base} & {Remap::Mapper}
|
244
|
-
#
|
245
|
-
# @param reason [#to_s]
|
246
|
-
#
|
247
|
-
# @see State::Schema
|
248
|
-
#
|
249
|
-
# @return [Failure]
|
250
|
-
|
251
|
-
# class Failure < Dry::Interface
|
252
|
-
# attribute :notices, [Notice], min_size: 1
|
253
|
-
# end
|
254
|
-
|
255
|
-
def failure(reason = Undefined)
|
256
|
-
raise NotImplementedError, "Not implemented"
|
257
|
-
end
|
258
|
-
|
259
262
|
# Passes {#value} to block, if defined
|
260
263
|
# {options} are combine into the final state
|
261
264
|
#
|
@@ -267,7 +270,7 @@ module Remap
|
|
267
270
|
#
|
268
271
|
# @return [Y]
|
269
272
|
def bind(**options, &block)
|
270
|
-
unless
|
273
|
+
unless block
|
271
274
|
raise ArgumentError, "State#bind requires a block"
|
272
275
|
end
|
273
276
|
|
@@ -287,19 +290,37 @@ module Remap
|
|
287
290
|
# @return [State<U>]
|
288
291
|
def execute(&block)
|
289
292
|
bind do |value|
|
290
|
-
result =
|
293
|
+
result = catch :done do
|
294
|
+
tail_path = catch :ignore do
|
295
|
+
names = block.parameters.reduce([]) do |acc, (type, name)|
|
296
|
+
case type
|
297
|
+
in :keyreq
|
298
|
+
acc + [name]
|
299
|
+
else
|
300
|
+
acc
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
r = Proc.new(&block).call(value, **only(*names), **options.only(*names)) do |reason|
|
305
|
+
ignore!(reason)
|
306
|
+
end
|
307
|
+
throw :done, r
|
308
|
+
rescue NameError => e
|
309
|
+
fatal!(e.message)
|
310
|
+
rescue KeyError => e
|
311
|
+
[e.key]
|
312
|
+
rescue IndexError
|
313
|
+
[]
|
314
|
+
end
|
315
|
+
|
316
|
+
set(path: path + tail_path).ignore!("Undefined path")
|
317
|
+
end
|
291
318
|
|
292
319
|
if result.equal?(Dry::Core::Constants::Undefined)
|
293
320
|
ignore!("Undefined returned, skipping!")
|
294
321
|
end
|
295
322
|
|
296
323
|
set(result)
|
297
|
-
rescue KeyError => e
|
298
|
-
set(path: path + [e.key]).ignore!(e.message)
|
299
|
-
rescue IndexError => e
|
300
|
-
ignore!(e.message)
|
301
|
-
rescue PathError => e
|
302
|
-
set(path: path + e.path).ignore!("Undefined path")
|
303
324
|
end
|
304
325
|
end
|
305
326
|
|
@@ -385,6 +406,8 @@ module Remap
|
|
385
406
|
# @return [Failure]
|
386
407
|
def failure(reason = Undefined)
|
387
408
|
failures = case [path, reason]
|
409
|
+
in [_, Undefined]
|
410
|
+
return Failure.new(failures: notices)
|
388
411
|
in [_, Notice => notice]
|
389
412
|
[notice]
|
390
413
|
in [path, Array => reasons]
|
@@ -419,27 +442,6 @@ module Remap
|
|
419
442
|
|
420
443
|
throw id, remove_id
|
421
444
|
end
|
422
|
-
|
423
|
-
private
|
424
|
-
|
425
|
-
# Creates a context containing {options} and {self}
|
426
|
-
#
|
427
|
-
# @param value [Any]
|
428
|
-
#
|
429
|
-
# @yieldparam reason [T]
|
430
|
-
#
|
431
|
-
# @return [Struct]
|
432
|
-
def context(value, context: self)
|
433
|
-
::Struct.new(*except(:id).keys, *options.keys, :state, keyword_init: true) do
|
434
|
-
define_method :method_missing do |name, *|
|
435
|
-
context.fatal!("Method [%s] not defined", name)
|
436
|
-
end
|
437
|
-
|
438
|
-
define_method(:skip!) do |message = "Manual skip!"|
|
439
|
-
context.ignore!(message)
|
440
|
-
end
|
441
|
-
end.new(**to_hash, **options, value: value, state: self)
|
442
|
-
end
|
443
445
|
end
|
444
446
|
end
|
445
447
|
end
|
data/lib/remap/state/schema.rb
CHANGED
@@ -9,8 +9,12 @@ module Remap
|
|
9
9
|
required(:notices).array(Types.Instance(Notice))
|
10
10
|
required(:options).value(:hash)
|
11
11
|
required(:path).array(Types::Key)
|
12
|
-
|
13
|
-
required(:
|
12
|
+
|
13
|
+
required(:ids).array(Types::ID)
|
14
|
+
optional(:id).filled(Types::ID)
|
15
|
+
|
16
|
+
required(:fatal_ids).array(Types::ID)
|
17
|
+
optional(:fatal_id).filled(Types::ID)
|
14
18
|
|
15
19
|
optional(:index).filled(:integer)
|
16
20
|
optional(:element).filled
|
data/lib/remap/state.rb
CHANGED
@@ -31,11 +31,11 @@ module Remap
|
|
31
31
|
# @return [Hash] A valid state
|
32
32
|
def self.call(value, mapper: Dummy, options: EMPTY_HASH)
|
33
33
|
{
|
34
|
-
fatal_ids:
|
35
|
-
notices:
|
36
|
-
path:
|
34
|
+
fatal_ids: [],
|
35
|
+
notices: [],
|
36
|
+
path: [],
|
37
37
|
options: options,
|
38
|
-
ids:
|
38
|
+
ids: [],
|
39
39
|
mapper: mapper,
|
40
40
|
values: value,
|
41
41
|
value: value,
|
data/lib/remap/types.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "dry/monads/maybe"
|
4
3
|
require "dry/logic/operations/negation"
|
5
4
|
require "dry/logic"
|
6
5
|
|
@@ -18,6 +17,7 @@ module Remap
|
|
18
17
|
Rule = Interface(:call) | Instance(Proc)
|
19
18
|
Key = Interface(:hash)
|
20
19
|
Notice = Instance(Remap::Notice)
|
20
|
+
ID = String | Symbol
|
21
21
|
|
22
22
|
# Validates a state according to State::Schema
|
23
23
|
State = Hash.constructor do |input, type, &error|
|
data/lib/remap.rb
CHANGED
@@ -5,11 +5,11 @@ require "active_support/core_ext/enumerable"
|
|
5
5
|
require "active_support/core_ext/array/wrap"
|
6
6
|
require "active_support/proxy_object"
|
7
7
|
|
8
|
+
require "dry/core/memoizable"
|
8
9
|
require "dry/validation"
|
9
10
|
require "dry/interface"
|
10
11
|
require "dry/schema"
|
11
12
|
require "dry/struct"
|
12
|
-
require "dry/monads"
|
13
13
|
require "dry/types"
|
14
14
|
|
15
15
|
require "neatjson"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: remap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.2.
|
4
|
+
version: 2.2.48
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Linus Oleander
|
@@ -66,20 +66,6 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: 1.0.3
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: dry-monads
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - "~>"
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: 1.4.0
|
76
|
-
type: :runtime
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - "~>"
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: 1.4.0
|
83
69
|
- !ruby/object:Gem::Dependency
|
84
70
|
name: dry-schema
|
85
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -264,10 +250,6 @@ files:
|
|
264
250
|
- lib/remap/extensions/object.rb
|
265
251
|
- lib/remap/failure.rb
|
266
252
|
- lib/remap/failure/error.rb
|
267
|
-
- lib/remap/iteration.rb
|
268
|
-
- lib/remap/iteration/array.rb
|
269
|
-
- lib/remap/iteration/hash.rb
|
270
|
-
- lib/remap/iteration/other.rb
|
271
253
|
- lib/remap/mapper.rb
|
272
254
|
- lib/remap/mapper/and.rb
|
273
255
|
- lib/remap/mapper/binary.rb
|
@@ -1,35 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Remap
|
4
|
-
class Iteration
|
5
|
-
using State::Extension
|
6
|
-
|
7
|
-
# Implements an array iterator which defines index in state
|
8
|
-
class Array < Concrete
|
9
|
-
# @return [Array<T>]
|
10
|
-
attribute :value, Types::Array, alias: :array
|
11
|
-
|
12
|
-
# @return [State<Array<T>>]
|
13
|
-
attribute :state, Types::State
|
14
|
-
|
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
|
20
|
-
end
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
def init
|
25
|
-
state.set(EMPTY_ARRAY)
|
26
|
-
end
|
27
|
-
|
28
|
-
def reduce(state, value, index, &block)
|
29
|
-
s0 = block[value, index: index]
|
30
|
-
s1 = s0.set(**state.only(:ids, :fatal_id))
|
31
|
-
state.combine(s1.fmap { [_1] })
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
data/lib/remap/iteration/hash.rb
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Remap
|
4
|
-
class Iteration
|
5
|
-
using State::Extension
|
6
|
-
|
7
|
-
# Implements a hash iterator which defines key in state
|
8
|
-
class Hash < Concrete
|
9
|
-
# @return [Hash]
|
10
|
-
attribute :value, Types::Hash, alias: :hash
|
11
|
-
|
12
|
-
# @return [State<Hash>]
|
13
|
-
attribute :state, Types::State
|
14
|
-
|
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
|
-
end
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
def reduce(state, key, value, &block)
|
25
|
-
s0 = block[value, key: key]
|
26
|
-
s1 = s0.set(fatal_id: state.fatal_id, ids: state.ids)
|
27
|
-
state.combine(s1.fmap { { key => _1 } })
|
28
|
-
end
|
29
|
-
|
30
|
-
def init
|
31
|
-
state.set(EMPTY_HASH)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Remap
|
4
|
-
class Iteration
|
5
|
-
using State::Extension
|
6
|
-
|
7
|
-
# Default iterator which doesn't do anything
|
8
|
-
class Other < Concrete
|
9
|
-
attribute :value, Types::Any, alias: :other
|
10
|
-
attribute :state, Types::State
|
11
|
-
|
12
|
-
# @see Iteration#map
|
13
|
-
def call(&block)
|
14
|
-
state.fatal!("Expected an enumerable")
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
data/lib/remap/iteration.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Remap
|
4
|
-
class Iteration < Dry::Interface
|
5
|
-
# @return [State<T>]
|
6
|
-
attribute :state, Types::State
|
7
|
-
|
8
|
-
# @return [T]
|
9
|
-
attribute :value, Types::Any
|
10
|
-
|
11
|
-
# Maps every element in {#value}
|
12
|
-
#
|
13
|
-
# @abstract
|
14
|
-
#
|
15
|
-
# @yieldparam element [V]
|
16
|
-
# @yieldparam key [K, Integer]
|
17
|
-
# @yieldreturn [Array<V>, Hash<V, K>]
|
18
|
-
#
|
19
|
-
# @return [Array<V>, Hash<V, K>]
|
20
|
-
def call(state)
|
21
|
-
raise NotImplementedError, "#{self.class}#call not implemented"
|
22
|
-
end
|
23
|
-
|
24
|
-
order :Hash, :Array, :Other
|
25
|
-
end
|
26
|
-
end
|