remap 2.0.3 → 2.1.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 +4 -4
- data/lib/remap/base.rb +229 -75
- data/lib/remap/compiler.rb +127 -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
data/lib/remap/rule/map.rb
CHANGED
@@ -2,62 +2,72 @@
|
|
2
2
|
|
3
3
|
module Remap
|
4
4
|
class Rule
|
5
|
-
|
6
|
-
|
5
|
+
using Extensions::Enumerable
|
6
|
+
using State::Extension
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
# Maps an input path to an output path
|
9
|
+
#
|
10
|
+
# @example Map { name: "Ford" } to { person: { name: "Ford" } }
|
11
|
+
# class Mapper < Remap::Base
|
12
|
+
# define do
|
13
|
+
# map :name, to: [:person, :name]
|
14
|
+
# end
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# Mapper.call({ name: "Ford" }) # => { person: { name: "Ford" } }
|
18
|
+
class Map < Abstract
|
19
|
+
class Path < Struct
|
20
|
+
Output = Remap::Path::Output
|
21
|
+
Input = Remap::Path::Input
|
10
22
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
# 2. For each yielded value
|
15
|
-
# 2.1. Map value using {#rule}
|
16
|
-
# 2.2. Map value using {#fn}
|
23
|
+
attribute :output, Output.default { Output.call(EMPTY_ARRAY) }
|
24
|
+
attribute :input, Input.default { Input.call(EMPTY_ARRAY) }
|
25
|
+
end
|
17
26
|
|
18
|
-
# @
|
19
|
-
|
20
|
-
|
21
|
-
#
|
22
|
-
|
23
|
-
|
24
|
-
#
|
25
|
-
|
26
|
-
|
27
|
+
# @return [Hash]
|
28
|
+
attribute? :path, Path.default { Path.call(EMPTY_HASH) }
|
29
|
+
|
30
|
+
# @return [Rule]
|
31
|
+
attribute :rule, Rule.default { Void.call(EMPTY_HASH) }
|
32
|
+
|
33
|
+
# @return [Array<String>]
|
34
|
+
attribute? :backtrace, Types::Backtrace, default: EMPTY_ARRAY
|
35
|
+
|
36
|
+
order :Optional, :Required
|
37
|
+
|
38
|
+
# Represents a required or optional mapping rule
|
27
39
|
#
|
28
|
-
#
|
40
|
+
# @param state [State]
|
29
41
|
#
|
30
|
-
# @
|
31
|
-
# @param state [State] Current state
|
42
|
+
# @return [State]
|
32
43
|
#
|
33
|
-
# @
|
34
|
-
def call(state)
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
44
|
+
# @abstract
|
45
|
+
def call(state, &error)
|
46
|
+
unless error
|
47
|
+
raise ArgumentError, "Map#call(state, &error) requires error handler block"
|
48
|
+
end
|
49
|
+
|
50
|
+
notice = catch :fatal do
|
51
|
+
return path.input.call(state) do |inner_state|
|
52
|
+
rule.call(inner_state) do |failure|
|
53
|
+
return error[failure]
|
54
|
+
end.then(&callback)
|
55
|
+
end.then(&path.output)
|
41
56
|
end
|
57
|
+
|
58
|
+
raise notice.traced(backtrace).exception
|
42
59
|
end
|
43
60
|
|
44
|
-
#
|
45
|
-
#
|
46
|
-
# @example Add 5 to mapped value
|
47
|
-
# class Mapper < Remap
|
48
|
-
# define do
|
49
|
-
# map.adjust do |value|
|
50
|
-
# value + 5
|
51
|
-
# end
|
52
|
-
# end
|
53
|
-
# end
|
54
|
-
#
|
55
|
-
# Mapper.call(10) # => 15
|
61
|
+
# A post-processor method
|
56
62
|
#
|
57
|
-
# @
|
58
|
-
#
|
63
|
+
# @example Upcase mapped value
|
64
|
+
# state = Remap::State.call("Hello World")
|
65
|
+
# map = Remap::Rule::Map.call({})
|
66
|
+
# upcase = map.adjust(&:upcase)
|
67
|
+
# error = -> failure { raise failure.exception }
|
68
|
+
# upcase.call(state, &error).fetch(:value) # => "HELLO WORLD"
|
59
69
|
#
|
60
|
-
# @return [
|
70
|
+
# @return [Map]
|
61
71
|
def adjust(&block)
|
62
72
|
add do |state|
|
63
73
|
state.execute(&block)
|
@@ -65,45 +75,156 @@ module Remap
|
|
65
75
|
end
|
66
76
|
alias then adjust
|
67
77
|
|
78
|
+
# A pending rule
|
79
|
+
#
|
80
|
+
# @param reason [String]
|
81
|
+
#
|
82
|
+
# @example Pending mapping
|
83
|
+
# state = Remap::State.call(:value)
|
84
|
+
# map = Remap::Rule::Map.call({})
|
85
|
+
# pending = map.pending("this is pending")
|
86
|
+
# error = -> failure { raise failure.exception }
|
87
|
+
# pending.call(state, &error).key?(:value) # => false
|
88
|
+
#
|
89
|
+
# @return [Map]
|
68
90
|
def pending(reason = "Pending mapping")
|
69
91
|
add do |state|
|
70
|
-
state.
|
92
|
+
state.notice!(reason)
|
71
93
|
end
|
72
94
|
end
|
73
95
|
|
96
|
+
# An enumeration processor
|
97
|
+
#
|
98
|
+
# @example A mapped enum
|
99
|
+
# enum = Remap::Rule::Map.call({}).enum do
|
100
|
+
# value "A", "B"
|
101
|
+
# otherwise "C"
|
102
|
+
# end
|
103
|
+
#
|
104
|
+
# error = -> failure { raise failure.exception }
|
105
|
+
#
|
106
|
+
# a = Remap::State.call("A")
|
107
|
+
# enum.call(a, &error).fetch(:value) # => "A"
|
108
|
+
#
|
109
|
+
# b = Remap::State.call("B")
|
110
|
+
# enum.call(b, &error).fetch(:value) # => "B"
|
111
|
+
#
|
112
|
+
# c = Remap::State.call("C")
|
113
|
+
# enum.call(c, &error).fetch(:value) # => "C"
|
114
|
+
#
|
115
|
+
# d = Remap::State.call("D")
|
116
|
+
# enum.call(d, &error).fetch(:value) # => "C"
|
117
|
+
#
|
118
|
+
# @return [Map]
|
74
119
|
def enum(&block)
|
75
|
-
add do |
|
76
|
-
|
77
|
-
Enum.call(&block).get(id
|
120
|
+
add do |outer_state|
|
121
|
+
outer_state.fmap do |id, state|
|
122
|
+
Enum.call(&block).get(id) do
|
123
|
+
state.ignore!("Enum value %p (%s) not defined", id, id.class)
|
124
|
+
end
|
78
125
|
end
|
79
126
|
end
|
80
127
|
end
|
81
128
|
|
129
|
+
# Keeps map, only if block is true
|
130
|
+
#
|
131
|
+
# @example Keep if value contains "A"
|
132
|
+
# map = Remap::Rule::Map.call({}).if do
|
133
|
+
# value.include?("A")
|
134
|
+
# end
|
135
|
+
#
|
136
|
+
# error = -> failure { raise failure.exception }
|
137
|
+
#
|
138
|
+
# a = Remap::State.call("A")
|
139
|
+
# map.call(a, &error).fetch(:value) # => "A"
|
140
|
+
#
|
141
|
+
# b = Remap::State.call("BA")
|
142
|
+
# map.call(b, &error).fetch(:value) # => "BA"
|
143
|
+
#
|
144
|
+
# c = Remap::State.call("C")
|
145
|
+
# map.call(c, &error).key?(:value) # => false
|
146
|
+
#
|
147
|
+
# @return [Map]
|
82
148
|
def if(&block)
|
83
|
-
add do |
|
84
|
-
|
85
|
-
bool ?
|
149
|
+
add do |outer_state|
|
150
|
+
outer_state.execute(&block).fmap do |bool, state|
|
151
|
+
bool ? outer_state.value : state.notice!("#if returned false")
|
86
152
|
end
|
87
153
|
end
|
88
154
|
end
|
89
155
|
|
156
|
+
# Keeps map, only if block is false
|
157
|
+
#
|
158
|
+
|
159
|
+
# @example Keep unless value contains "A"
|
160
|
+
# map = Remap::Rule::Map.call({}).if_not do
|
161
|
+
# value.include?("A")
|
162
|
+
# end
|
163
|
+
#
|
164
|
+
# error = -> failure { raise failure.exception }
|
165
|
+
#
|
166
|
+
# a = Remap::State.call("A")
|
167
|
+
# map.call(a, &error).key?(:value) # => false
|
168
|
+
#
|
169
|
+
# b = Remap::State.call("BA")
|
170
|
+
# map.call(b, &error).key?(:value) # => false
|
171
|
+
#
|
172
|
+
# c = Remap::State.call("C")
|
173
|
+
# map.call(c, &error).fetch(:value) # => "C"
|
174
|
+
#
|
175
|
+
# @return [Map]
|
90
176
|
def if_not(&block)
|
91
|
-
add do |
|
92
|
-
|
93
|
-
bool ?
|
177
|
+
add do |outer_state|
|
178
|
+
outer_state.execute(&block).fmap do |bool, state|
|
179
|
+
bool ? state.notice!("#if_not returned false") : outer_state.value
|
94
180
|
end
|
95
181
|
end
|
96
182
|
end
|
97
183
|
|
98
184
|
private
|
99
185
|
|
186
|
+
# @return [self]
|
100
187
|
def add(&block)
|
101
188
|
tap { fn << block }
|
102
189
|
end
|
103
190
|
|
191
|
+
# @return [Array<Proc>]
|
104
192
|
def fn
|
105
193
|
@fn ||= []
|
106
194
|
end
|
195
|
+
|
196
|
+
# @return [Proc]
|
197
|
+
def callback
|
198
|
+
-> state do
|
199
|
+
fn.reduce(state) do |inner, fn|
|
200
|
+
fn[inner]
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
# Catches :fatal and raises {Notice::Error}
|
206
|
+
#
|
207
|
+
# @param state [State]
|
208
|
+
# @param id (:fatal) [:fatal, :notice, :ignore]
|
209
|
+
#
|
210
|
+
# raise [Notice::Error]
|
211
|
+
def fatal(state, id: :fatal, &block)
|
212
|
+
raise catch(id, &block).traced(backtrace).exception
|
213
|
+
end
|
214
|
+
|
215
|
+
# Catches :notice exceptions and repackages them as a state
|
216
|
+
#
|
217
|
+
# @param state [State]
|
218
|
+
#
|
219
|
+
# @return [State]
|
220
|
+
def notice(state, &block)
|
221
|
+
state.set(notice: catch(:notice, &block).traced(backtrace)).except(:value)
|
222
|
+
end
|
223
|
+
|
224
|
+
# @abstract
|
225
|
+
def ignore(...)
|
226
|
+
raise NotImplementedError, "#{self.class}#ignore"
|
227
|
+
end
|
107
228
|
end
|
108
229
|
end
|
109
230
|
end
|
data/lib/remap/rule/set.rb
CHANGED
@@ -2,41 +2,31 @@
|
|
2
2
|
|
3
3
|
module Remap
|
4
4
|
class Rule
|
5
|
-
|
6
|
-
using State::Extension
|
5
|
+
using State::Extension
|
7
6
|
|
8
|
-
|
9
|
-
|
7
|
+
# Set path to a static value
|
8
|
+
#
|
9
|
+
# @example Set path [:a, :b] to value "C"
|
10
|
+
# value = Remap::Static::Fixed.new(value: "a value")
|
11
|
+
# set = Remap::Rule::Set.new(value: value, path: [:a, :b])
|
12
|
+
# state = Remap::State.call("ANY VALUE")
|
13
|
+
# set.call(state).fetch(:value) # => { a: { b: "a value" } }
|
14
|
+
#
|
15
|
+
# @example Set path [:a, :b] to option :c
|
16
|
+
# value = Remap::Static::Option.new(name: :c)
|
17
|
+
# set = Remap::Rule::Set.new(value: value, path: [:a, :b])
|
18
|
+
# state = Remap::State.call("ANY VALUE", options: { c: "C" })
|
19
|
+
# set.call(state).fetch(:value) # => { a: { b: "C" } }
|
20
|
+
class Set < Concrete
|
21
|
+
# @return [Static]
|
22
|
+
attribute :value, Static, alias: :rule
|
10
23
|
|
11
|
-
#
|
12
|
-
|
13
|
-
|
14
|
-
#
|
15
|
-
|
16
|
-
|
17
|
-
# option :name
|
18
|
-
#
|
19
|
-
# define do
|
20
|
-
# set [:person, :name], to: option(:name)
|
21
|
-
# end
|
22
|
-
# end
|
23
|
-
#
|
24
|
-
# Mapper.call(input, name: "John") # => { person: { name: "John" } }
|
25
|
-
#
|
26
|
-
# @example Given a value
|
27
|
-
# class Mapper < Remap::Base
|
28
|
-
# define do
|
29
|
-
# set [:api_key], to: value("ABC-123")
|
30
|
-
# end
|
31
|
-
# end
|
32
|
-
#
|
33
|
-
# Mapper.call(input) # => { api_key: "ABC-123" }
|
34
|
-
#
|
35
|
-
# @return [State]
|
36
|
-
def call(state)
|
37
|
-
path.call(state) do
|
38
|
-
value.call(state)
|
39
|
-
end
|
24
|
+
# @return [Path::Output]
|
25
|
+
attribute :path, Path::Output
|
26
|
+
|
27
|
+
# @see Rule#call
|
28
|
+
def call(...)
|
29
|
+
rule.call(...).then(&path)
|
40
30
|
end
|
41
31
|
end
|
42
32
|
end
|
@@ -3,19 +3,19 @@
|
|
3
3
|
module Remap
|
4
4
|
class Rule
|
5
5
|
class Collection
|
6
|
-
|
7
|
-
using State::Extension
|
6
|
+
using State::Extension
|
8
7
|
|
9
|
-
|
8
|
+
# Represents an empty rule block
|
9
|
+
class Empty < Unit
|
10
|
+
attribute? :rules, Value(EMPTY_ARRAY), default: EMPTY_ARRAY
|
10
11
|
|
11
12
|
# Represents an empty define block, without any rules
|
12
13
|
#
|
13
|
-
# @param
|
14
|
-
# @param state [State]
|
14
|
+
# @param state [State<T>]
|
15
15
|
#
|
16
|
-
# @return [
|
16
|
+
# @return [State<T>]
|
17
17
|
def call(state)
|
18
|
-
state.
|
18
|
+
state.notice!("No rules, empty block")
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|
@@ -3,23 +3,36 @@
|
|
3
3
|
module Remap
|
4
4
|
class Rule
|
5
5
|
class Collection
|
6
|
-
|
7
|
-
using State::Extension
|
6
|
+
using State::Extension
|
8
7
|
|
8
|
+
# Represents a non-empty rule block
|
9
|
+
#
|
10
|
+
# @example A collection containing a single rule
|
11
|
+
# state = Remap::State.call("A")
|
12
|
+
# void = Remap::Rule::Void.call({})
|
13
|
+
# rule = Remap::Rule::Collection.call([void])
|
14
|
+
# error = -> failure { raise failure.exception }
|
15
|
+
# rule.call(state, &error).fetch(:value) # => "A"
|
16
|
+
class Filled < Unit
|
17
|
+
# @return [Array<Rule>]
|
9
18
|
attribute :rules, [Types.Interface(:call)], min_size: 1
|
10
19
|
|
11
20
|
# Represents a non-empty define block with one or more rules
|
12
|
-
# Calls every {#rules} with
|
21
|
+
# Calls every {#rules} with state and merges the output
|
13
22
|
#
|
14
23
|
# @param state [State]
|
15
24
|
#
|
16
25
|
# @return [State]
|
17
|
-
def call(state)
|
18
|
-
|
19
|
-
|
20
|
-
end.map(&:value).reduce do |acc, inner_state|
|
21
|
-
acc.merged(inner_state)
|
26
|
+
def call(state, &error)
|
27
|
+
unless error
|
28
|
+
raise ArgumentError, "Collection::Filled#call(state, &error) requires a block"
|
22
29
|
end
|
30
|
+
|
31
|
+
rules.map do |rule|
|
32
|
+
rule.call(state) do |failure|
|
33
|
+
return error[failure]
|
34
|
+
end
|
35
|
+
end.reduce(&:combine)
|
23
36
|
end
|
24
37
|
end
|
25
38
|
end
|
@@ -2,9 +2,17 @@
|
|
2
2
|
|
3
3
|
module Remap
|
4
4
|
class Rule
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
# Represents a block defined by a rule
|
6
|
+
class Collection < Abstract
|
7
|
+
attribute :rules, Array
|
8
|
+
|
9
|
+
# @param state [State]
|
10
|
+
#
|
11
|
+
# @return [State]
|
12
|
+
#
|
13
|
+
# @abstract
|
14
|
+
def call(state)
|
15
|
+
raise NotImplementedError, "#{self.class}#call not implemented"
|
8
16
|
end
|
9
17
|
end
|
10
18
|
end
|
@@ -2,17 +2,32 @@
|
|
2
2
|
|
3
3
|
module Remap
|
4
4
|
class Rule
|
5
|
-
class Enum
|
6
|
-
include Dry::Core::Constants
|
5
|
+
class Enum < Proxy
|
7
6
|
include Dry::Monads[:maybe]
|
8
7
|
|
9
|
-
|
10
|
-
|
8
|
+
# @return [Hash]
|
11
9
|
option :mappings, default: -> { Hash.new { default } }
|
10
|
+
|
11
|
+
# @return [Maybe]
|
12
12
|
option :default, default: -> { None() }
|
13
13
|
|
14
14
|
alias execute instance_eval
|
15
15
|
|
16
|
+
# Builds an enumeration using the block as context
|
17
|
+
#
|
18
|
+
# @example
|
19
|
+
# enum = Remap::Rule::Enum.call do
|
20
|
+
# from "B", to: "C"
|
21
|
+
# value "A"
|
22
|
+
# otherwise "D"
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# enum.get("A") # => "A"
|
26
|
+
# enum.get("B") # => "C"
|
27
|
+
# enum.get("C") # => "C"
|
28
|
+
# enum.get("MISSING") # => "D"
|
29
|
+
#
|
30
|
+
# @return [Any]
|
16
31
|
def self.call(&block)
|
17
32
|
unless block
|
18
33
|
raise ArgumentError, "no block given"
|
@@ -21,40 +36,48 @@ module Remap
|
|
21
36
|
new.tap { _1.execute(&block) }
|
22
37
|
end
|
23
38
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
39
|
+
# Translates key into a value using predefined mappings
|
40
|
+
#
|
41
|
+
# @param key [#hash]
|
42
|
+
#
|
43
|
+
# @yield [String]
|
44
|
+
# If the key is not found & no default value is set
|
45
|
+
#
|
46
|
+
# @return [Any]
|
28
47
|
def get(key, &error)
|
29
48
|
unless error
|
30
49
|
return get(key) { raise Error, _1 }
|
31
50
|
end
|
32
51
|
|
33
|
-
|
52
|
+
self[key].bind { return _1 }.or do
|
34
53
|
error["Enum key [#{key}] not found among [#{mappings.keys.inspect}]"]
|
35
54
|
end
|
36
55
|
end
|
37
56
|
alias call get
|
38
57
|
|
39
|
-
#
|
40
|
-
|
41
|
-
|
58
|
+
# @return [Maybe]
|
59
|
+
def [](key)
|
60
|
+
mappings[key]
|
61
|
+
end
|
62
|
+
|
63
|
+
# @return [void]
|
42
64
|
def from(*keys, to:)
|
65
|
+
value = Some(to)
|
66
|
+
|
43
67
|
keys.each do |key|
|
44
|
-
mappings[key] =
|
68
|
+
mappings[key] = value
|
69
|
+
mappings[to] = value
|
45
70
|
end
|
46
71
|
end
|
47
72
|
|
48
|
-
#
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
73
|
+
# @return [void]
|
74
|
+
def value(*ids)
|
75
|
+
ids.each do |id|
|
76
|
+
from(id, to: id)
|
77
|
+
end
|
53
78
|
end
|
54
79
|
|
55
|
-
#
|
56
|
-
#
|
57
|
-
# @return [Void]
|
80
|
+
# @return [void]
|
58
81
|
def otherwise(value)
|
59
82
|
mappings.default = Some(value)
|
60
83
|
end
|
data/lib/remap/rule/void.rb
CHANGED
@@ -2,27 +2,26 @@
|
|
2
2
|
|
3
3
|
module Remap
|
4
4
|
class Rule
|
5
|
-
|
6
|
-
using State::Extension
|
5
|
+
using State::Extension
|
7
6
|
|
8
|
-
|
7
|
+
# Represents a mapping without block
|
8
|
+
#
|
9
|
+
# @example Maps "A" to "A"
|
10
|
+
# class Mapper < Remap::Base
|
11
|
+
# define do
|
12
|
+
# map
|
13
|
+
# end
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# Mapper.call("A") # => "A"
|
17
|
+
class Void < Concrete
|
18
|
+
# @param state [State<T>]
|
9
19
|
#
|
10
|
-
# @
|
11
|
-
#
|
12
|
-
# @example An empty rule
|
13
|
-
# class Mapper < Remap::Base
|
14
|
-
# define do
|
15
|
-
# map do
|
16
|
-
# # Empty ...
|
17
|
-
# end
|
18
|
-
# end
|
19
|
-
# end
|
20
|
-
#
|
21
|
-
# Mapper.call(input) # => input
|
22
|
-
#
|
23
|
-
# @return [State]
|
20
|
+
# @return [State<T>]
|
24
21
|
def call(state)
|
25
|
-
state.bind
|
22
|
+
state.bind do |value, inner_state|
|
23
|
+
inner_state.set(value)
|
24
|
+
end
|
26
25
|
end
|
27
26
|
end
|
28
27
|
end
|
data/lib/remap/rule/wrap.rb
CHANGED
@@ -1,29 +1,37 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/core_ext/array/wrap"
|
4
|
-
|
5
3
|
module Remap
|
6
4
|
class Rule
|
7
|
-
|
8
|
-
using State::Extension
|
5
|
+
using State::Extension
|
9
6
|
|
7
|
+
# Wraps rule in a type
|
8
|
+
#
|
9
|
+
# @example Maps { name: "Ford" } to { cars: ["Ford"] }
|
10
|
+
# class Mapper < Remap::Base
|
11
|
+
# define do
|
12
|
+
# to :cars do
|
13
|
+
# wrap(:array) do
|
14
|
+
# map :name
|
15
|
+
# end
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# Mapper.call({ name: "Ford" }) # => { cars: ["Ford"] }
|
21
|
+
class Wrap < Concrete
|
22
|
+
# @return [:array]
|
10
23
|
attribute :type, Value(:array)
|
11
|
-
|
24
|
+
|
25
|
+
# @return [Rule]
|
26
|
+
attribute :rule, Types::Rule
|
12
27
|
|
13
28
|
# Wraps the output from {#rule} in a {#type}
|
14
29
|
#
|
15
|
-
# @
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
# map :car
|
21
|
-
# end
|
22
|
-
# end
|
23
|
-
#
|
24
|
-
# @return [State]
|
25
|
-
def call(state)
|
26
|
-
rule.call(state).fmap { Array.wrap(_1) }
|
30
|
+
# @see Rule#call
|
31
|
+
def call(...)
|
32
|
+
rule.call(...).fmap do |value|
|
33
|
+
Array.wrap(value)
|
34
|
+
end
|
27
35
|
end
|
28
36
|
end
|
29
37
|
end
|
data/lib/remap/rule.rb
CHANGED
@@ -1,8 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Remap
|
4
|
-
class Rule < Dry::
|
4
|
+
class Rule < Dry::Interface
|
5
5
|
defines :requirement
|
6
6
|
requirement Types::Any
|
7
|
+
|
8
|
+
# @param state [State]
|
9
|
+
#
|
10
|
+
# @abstract
|
11
|
+
def call(state)
|
12
|
+
raise NotImplementedError, "#{self.class}#call not implemented"
|
13
|
+
end
|
7
14
|
end
|
8
15
|
end
|