remap 2.1.13 → 2.1.14
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/remap/compiler.rb +48 -40
- data/lib/remap/extensions/enumerable.rb +2 -0
- data/lib/remap/rule/block.rb +34 -0
- data/lib/remap/rule/map/enum.rb +88 -0
- data/lib/remap/rule/map/optional.rb +1 -1
- data/lib/remap/rule/map.rb +17 -9
- data/lib/remap/rule.rb +2 -0
- data/lib/remap/selector/index.rb +12 -3
- data/lib/remap/state/extension.rb +2 -2
- data/lib/remap/types.rb +1 -1
- data/lib/remap.rb +0 -1
- metadata +3 -9
- data/lib/remap/rule/each.rb +0 -38
- data/lib/remap/rule/embed.rb +0 -47
- data/lib/remap/rule/set.rb +0 -33
- data/lib/remap/rule/support/collection/empty.rb +0 -23
- data/lib/remap/rule/support/collection/filled.rb +0 -40
- data/lib/remap/rule/support/collection.rb +0 -19
- data/lib/remap/rule/support/enum.rb +0 -86
- data/lib/remap/rule/wrap.rb +0 -38
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 88204af4f42ce85893ec029d953e2e6c417bbacba673522eedadca9561f8f749
|
4
|
+
data.tar.gz: 9e3e6040baf0426590b4c920d33f0979e74a084a19bbd87079d474a9e251663a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 612cf547b8207f305cf9b1f4788d3b36c0d487f0c42bdbf657336c04982060f6dd46a0cfc2a57c39588cef15287ede98205ab5beb46c9245b3270a99b586934d
|
7
|
+
data.tar.gz: a11492555b465f2d9f2db0611ed8d6457579dc6546805a9a867fc7b951061572f0faae84caec4be50907efa99e15647a8ae52aefd0de14362d29d6fea45cb166
|
data/lib/remap/compiler.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Remap
|
4
|
+
using State::Extension
|
5
|
+
|
4
6
|
# Constructs a {Rule} from the block passed to {Remap::Base.define}
|
5
7
|
class Compiler < Proxy
|
6
8
|
# @return [Array<Rule>]
|
@@ -29,12 +31,18 @@ module Remap
|
|
29
31
|
# @return [Rule]
|
30
32
|
def self.call(&block)
|
31
33
|
unless block
|
32
|
-
return Rule::
|
34
|
+
return Rule::VOID
|
33
35
|
end
|
34
36
|
|
35
|
-
new([]).tap do |compiler|
|
37
|
+
rules = new([]).tap do |compiler|
|
36
38
|
compiler.instance_exec(&block)
|
37
|
-
end.
|
39
|
+
end.rules
|
40
|
+
|
41
|
+
if rules.empty?
|
42
|
+
return Rule::VOID
|
43
|
+
end
|
44
|
+
|
45
|
+
Rule::Block.new(rules)
|
38
46
|
end
|
39
47
|
|
40
48
|
# Maps input path [input] to output path [to]
|
@@ -59,13 +67,7 @@ module Remap
|
|
59
67
|
#
|
60
68
|
# @return [Rule::Map::Required]
|
61
69
|
def map(*path, to: EMPTY_ARRAY, backtrace: Kernel.caller, &block)
|
62
|
-
add
|
63
|
-
path: {
|
64
|
-
output: [to].flatten,
|
65
|
-
input: path.flatten
|
66
|
-
},
|
67
|
-
backtrace: backtrace,
|
68
|
-
rule: call(&block))
|
70
|
+
add rule(*path, to: to, backtrace: backtrace, &block)
|
69
71
|
end
|
70
72
|
|
71
73
|
# Optional version of {#map}
|
@@ -92,13 +94,7 @@ module Remap
|
|
92
94
|
#
|
93
95
|
# @return [Rule::Map::Optional]
|
94
96
|
def map?(*path, to: EMPTY_ARRAY, backtrace: Kernel.caller, &block)
|
95
|
-
add
|
96
|
-
path: {
|
97
|
-
output: [to].flatten,
|
98
|
-
input: path.flatten
|
99
|
-
},
|
100
|
-
backtrace: backtrace,
|
101
|
-
rule: call(&block))
|
97
|
+
add rule?(*path, to: to, backtrace: backtrace, &block)
|
102
98
|
end
|
103
99
|
|
104
100
|
# Select a path and uses the same path as output
|
@@ -122,7 +118,7 @@ module Remap
|
|
122
118
|
#
|
123
119
|
# @return [Rule::Map::Required]
|
124
120
|
def get(*path, backtrace: Kernel.caller, &block)
|
125
|
-
|
121
|
+
add rule(path, to: path, backtrace: backtrace, &block)
|
126
122
|
end
|
127
123
|
|
128
124
|
# Optional version of {#get}
|
@@ -147,7 +143,7 @@ module Remap
|
|
147
143
|
#
|
148
144
|
# @return [Rule::Map::Optional]
|
149
145
|
def get?(*path, backtrace: Kernel.caller, &block)
|
150
|
-
|
146
|
+
add rule?(path, to: path, backtrace: backtrace, &block)
|
151
147
|
end
|
152
148
|
|
153
149
|
# Maps using mapper
|
@@ -189,9 +185,13 @@ module Remap
|
|
189
185
|
raise ArgumentError, "#embed does not take a block"
|
190
186
|
end
|
191
187
|
|
192
|
-
|
193
|
-
|
194
|
-
|
188
|
+
embeding = rule(&block).add do |state, &error|
|
189
|
+
mapper.call!(state.set(mapper: mapper)) do |failure|
|
190
|
+
next error[failure]
|
191
|
+
end.except(:mapper, :scope)
|
192
|
+
end
|
193
|
+
|
194
|
+
add embeding
|
195
195
|
end
|
196
196
|
|
197
197
|
# Set a static value
|
@@ -234,9 +234,7 @@ module Remap
|
|
234
234
|
raise ArgumentError, "#set does not take a block"
|
235
235
|
end
|
236
236
|
|
237
|
-
add
|
238
|
-
rescue Dry::Struct::Error => e
|
239
|
-
raise ArgumentError, e.message
|
237
|
+
add rule(to: path).add { to.call(_1) }
|
240
238
|
end
|
241
239
|
|
242
240
|
# Maps to path from map with block in between
|
@@ -261,7 +259,7 @@ module Remap
|
|
261
259
|
#
|
262
260
|
# @return [Rule::Map]
|
263
261
|
def to(*path, map: EMPTY_ARRAY, backtrace: Kernel.caller, &block)
|
264
|
-
|
262
|
+
add rule(*map, to: path, backtrace: backtrace, &block)
|
265
263
|
end
|
266
264
|
|
267
265
|
# Optional version of {#to}
|
@@ -287,7 +285,7 @@ module Remap
|
|
287
285
|
#
|
288
286
|
# @return [Rule::Map::Optional]
|
289
287
|
def to?(*path, map: EMPTY_ARRAY, &block)
|
290
|
-
|
288
|
+
add rule?(*map, to: path, &block)
|
291
289
|
end
|
292
290
|
|
293
291
|
# Iterates over the input value, passes each value
|
@@ -319,7 +317,7 @@ module Remap
|
|
319
317
|
raise ArgumentError, "#each requires a block"
|
320
318
|
end
|
321
319
|
|
322
|
-
add
|
320
|
+
add rule(all, &block)
|
323
321
|
end
|
324
322
|
|
325
323
|
# Wraps output in type
|
@@ -352,9 +350,7 @@ module Remap
|
|
352
350
|
raise ArgumentError, "#wrap requires a block"
|
353
351
|
end
|
354
352
|
|
355
|
-
add
|
356
|
-
rescue Dry::Struct::Error => e
|
357
|
-
raise ArgumentError, e.message
|
353
|
+
add rule(&block).then { Array.wrap(_1) }
|
358
354
|
end
|
359
355
|
|
360
356
|
# Selects all elements
|
@@ -521,19 +517,31 @@ module Remap
|
|
521
517
|
at(-1)
|
522
518
|
end
|
523
519
|
|
524
|
-
# The final rule
|
525
|
-
#
|
526
|
-
# @return [Rule]
|
527
|
-
#
|
528
|
-
# @private
|
529
|
-
def rule
|
530
|
-
Rule::Collection.call(rules: rules)
|
531
|
-
end
|
532
|
-
|
533
520
|
private
|
534
521
|
|
535
522
|
def add(rule)
|
536
523
|
rule.tap { rules << rule }
|
537
524
|
end
|
525
|
+
|
526
|
+
def rule(*path, to: EMPTY_ARRAY, backtrace: Kernel.caller, &block)
|
527
|
+
Rule::Map::Required.call({
|
528
|
+
path: {
|
529
|
+
output: [to].flatten,
|
530
|
+
input: path.flatten
|
531
|
+
},
|
532
|
+
backtrace: backtrace,
|
533
|
+
rule: call(&block)
|
534
|
+
})
|
535
|
+
end
|
536
|
+
|
537
|
+
def rule?(*path, to: EMPTY_ARRAY, backtrace: Kernel.caller, &block)
|
538
|
+
Rule::Map::Optional.call({
|
539
|
+
path: {
|
540
|
+
output: [to].flatten,
|
541
|
+
input: path.flatten
|
542
|
+
},
|
543
|
+
rule: call(&block)
|
544
|
+
})
|
545
|
+
end
|
538
546
|
end
|
539
547
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Remap
|
4
|
+
class Rule
|
5
|
+
using State::Extension
|
6
|
+
|
7
|
+
class Block < Unit
|
8
|
+
# @return [Array<Rule>]
|
9
|
+
attribute :rules, [Types::Rule]
|
10
|
+
|
11
|
+
# Represents a non-empty define block with one or more rules
|
12
|
+
# Calls every {#rules} with state and merges the output
|
13
|
+
#
|
14
|
+
# @param state [State]
|
15
|
+
#
|
16
|
+
# @return [State]
|
17
|
+
def call(state, &error)
|
18
|
+
unless block_given?
|
19
|
+
raise ArgumentError, "Block#call(state, &error) requires a block"
|
20
|
+
end
|
21
|
+
|
22
|
+
if rules.empty?
|
23
|
+
return state.except(:value)
|
24
|
+
end
|
25
|
+
|
26
|
+
rules.map do |rule|
|
27
|
+
rule.call(state) do |failure|
|
28
|
+
return error[failure]
|
29
|
+
end
|
30
|
+
end.reduce(&:combine)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Remap
|
4
|
+
class Rule
|
5
|
+
class Map
|
6
|
+
class Enum < Proxy
|
7
|
+
include Dry::Monads[:maybe]
|
8
|
+
|
9
|
+
# @return [Hash]
|
10
|
+
option :mappings, default: -> { Hash.new { default } }
|
11
|
+
|
12
|
+
# @return [Maybe]
|
13
|
+
option :default, default: -> { None() }
|
14
|
+
|
15
|
+
alias execute instance_eval
|
16
|
+
|
17
|
+
# Builds an enumeration using the block as context
|
18
|
+
#
|
19
|
+
# @example
|
20
|
+
# enum = Remap::Rule::Map::Enum.call do
|
21
|
+
# from "B", to: "C"
|
22
|
+
# value "A"
|
23
|
+
# otherwise "D"
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# enum.get("A") # => "A"
|
27
|
+
# enum.get("B") # => "C"
|
28
|
+
# enum.get("C") # => "C"
|
29
|
+
# enum.get("MISSING") # => "D"
|
30
|
+
#
|
31
|
+
# @return [Any]
|
32
|
+
def self.call(&block)
|
33
|
+
unless block
|
34
|
+
raise ArgumentError, "no block given"
|
35
|
+
end
|
36
|
+
|
37
|
+
new.tap { _1.execute(&block) }
|
38
|
+
end
|
39
|
+
|
40
|
+
# Translates key into a value using predefined mappings
|
41
|
+
#
|
42
|
+
# @param key [#hash]
|
43
|
+
#
|
44
|
+
# @yield [String]
|
45
|
+
# If the key is not found & no default value is set
|
46
|
+
#
|
47
|
+
# @return [Any]
|
48
|
+
def get(key, &error)
|
49
|
+
unless error
|
50
|
+
return get(key) { raise Error, _1 }
|
51
|
+
end
|
52
|
+
|
53
|
+
self[key].bind { return _1 }.or do
|
54
|
+
error["Enum key [#{key}] not found among [#{mappings.keys.inspect}]"]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
alias call get
|
58
|
+
|
59
|
+
# @return [Maybe]
|
60
|
+
def [](key)
|
61
|
+
mappings[key]
|
62
|
+
end
|
63
|
+
|
64
|
+
# @return [void]
|
65
|
+
def from(*keys, to:)
|
66
|
+
value = Some(to)
|
67
|
+
|
68
|
+
keys.each do |key|
|
69
|
+
mappings[key] = value
|
70
|
+
mappings[to] = value
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# @return [void]
|
75
|
+
def value(*ids)
|
76
|
+
ids.each do |id|
|
77
|
+
from(id, to: id)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# @return [void]
|
82
|
+
def otherwise(value)
|
83
|
+
mappings.default = Some(value)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/remap/rule/map.rb
CHANGED
@@ -43,15 +43,19 @@ module Remap
|
|
43
43
|
#
|
44
44
|
# @abstract
|
45
45
|
def call(state, &error)
|
46
|
-
unless
|
46
|
+
unless block_given?
|
47
47
|
raise ArgumentError, "Map#call(state, &error) requires error handler block"
|
48
48
|
end
|
49
49
|
|
50
50
|
notice = catch :fatal do
|
51
51
|
return path.input.call(state) do |inner_state|
|
52
|
-
rule.call(inner_state) do |failure|
|
52
|
+
other_state = rule.call(inner_state) do |failure|
|
53
53
|
return error[failure]
|
54
|
-
end
|
54
|
+
end
|
55
|
+
|
56
|
+
callback(other_state) do |failure|
|
57
|
+
return error[failure]
|
58
|
+
end
|
55
59
|
end.then(&path.output)
|
56
60
|
end
|
57
61
|
|
@@ -181,23 +185,27 @@ module Remap
|
|
181
185
|
end
|
182
186
|
end
|
183
187
|
|
184
|
-
private
|
185
|
-
|
186
188
|
# @return [self]
|
187
189
|
def add(&block)
|
188
190
|
tap { fn << block }
|
189
191
|
end
|
190
192
|
|
193
|
+
private
|
194
|
+
|
191
195
|
# @return [Array<Proc>]
|
192
196
|
def fn
|
193
197
|
@fn ||= []
|
194
198
|
end
|
195
199
|
|
196
200
|
# @return [Proc]
|
197
|
-
def callback
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
+
def callback(state, &error)
|
202
|
+
unless block_given?
|
203
|
+
raise ArgumentError, "Map#callback(state, &error) requires error handler block"
|
204
|
+
end
|
205
|
+
|
206
|
+
fn.reduce(state) do |inner, fn|
|
207
|
+
fn[inner] do |failure|
|
208
|
+
return error[failure]
|
201
209
|
end
|
202
210
|
end
|
203
211
|
end
|
data/lib/remap/rule.rb
CHANGED
data/lib/remap/selector/index.rb
CHANGED
@@ -8,8 +8,15 @@ module Remap
|
|
8
8
|
#
|
9
9
|
# @example Select the value at index 1 from a array
|
10
10
|
# state = Remap::State.call([:one, :two, :tree])
|
11
|
-
#
|
12
|
-
#
|
11
|
+
# index = Remap::Selector::Index.new(1)
|
12
|
+
#
|
13
|
+
# result = index.call(state) do |element|
|
14
|
+
# element.fmap do |value|
|
15
|
+
# value.upcase
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
|
19
|
+
# result.fetch(:value) # => :TWO
|
13
20
|
class Index < Unit
|
14
21
|
# @return [Integer]
|
15
22
|
attribute :index, Integer
|
@@ -25,7 +32,9 @@ module Remap
|
|
25
32
|
#
|
26
33
|
# @return [State<U>]
|
27
34
|
def call(outer_state, &block)
|
28
|
-
|
35
|
+
unless block_given?
|
36
|
+
raise ArgumentError, "The index selector requires an iteration block"
|
37
|
+
end
|
29
38
|
|
30
39
|
outer_state.bind(index: index) do |array, state|
|
31
40
|
requirement[array] do
|
@@ -351,7 +351,7 @@ module Remap
|
|
351
351
|
#
|
352
352
|
# @return [Struct]
|
353
353
|
def context(value, context: self, &error)
|
354
|
-
::Struct.new(*keys, *options.keys, keyword_init: true) do
|
354
|
+
::Struct.new(*keys, *options.keys, :state, keyword_init: true) do
|
355
355
|
define_method :method_missing do |name, *|
|
356
356
|
error["Method [#{name}] not defined"]
|
357
357
|
end
|
@@ -359,7 +359,7 @@ module Remap
|
|
359
359
|
define_method :skip! do |message = "Manual skip!"|
|
360
360
|
context.ignore!(message)
|
361
361
|
end
|
362
|
-
end.new(**to_hash, **options, value: value)
|
362
|
+
end.new(**to_hash, **options, value: value, state: self)
|
363
363
|
end
|
364
364
|
end
|
365
365
|
end
|
data/lib/remap/types.rb
CHANGED
@@ -15,7 +15,7 @@ module Remap
|
|
15
15
|
Enumerable = Any.constrained(type: Enumerable)
|
16
16
|
Nothing = Constant(Remap::Nothing)
|
17
17
|
Mapper = Interface(:call!)
|
18
|
-
Rule = Interface(:call)
|
18
|
+
Rule = Interface(:call) | Instance(Proc)
|
19
19
|
Key = Interface(:hash)
|
20
20
|
|
21
21
|
# Validates a state according to State::Schema
|
data/lib/remap.rb
CHANGED
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.1.
|
4
|
+
version: 2.1.14
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Linus Oleander
|
@@ -279,18 +279,12 @@ files:
|
|
279
279
|
- lib/remap/path_error.rb
|
280
280
|
- lib/remap/proxy.rb
|
281
281
|
- lib/remap/rule.rb
|
282
|
-
- lib/remap/rule/
|
283
|
-
- lib/remap/rule/embed.rb
|
282
|
+
- lib/remap/rule/block.rb
|
284
283
|
- lib/remap/rule/map.rb
|
284
|
+
- lib/remap/rule/map/enum.rb
|
285
285
|
- lib/remap/rule/map/optional.rb
|
286
286
|
- lib/remap/rule/map/required.rb
|
287
|
-
- lib/remap/rule/set.rb
|
288
|
-
- lib/remap/rule/support/collection.rb
|
289
|
-
- lib/remap/rule/support/collection/empty.rb
|
290
|
-
- lib/remap/rule/support/collection/filled.rb
|
291
|
-
- lib/remap/rule/support/enum.rb
|
292
287
|
- lib/remap/rule/void.rb
|
293
|
-
- lib/remap/rule/wrap.rb
|
294
288
|
- lib/remap/selector.rb
|
295
289
|
- lib/remap/selector/all.rb
|
296
290
|
- lib/remap/selector/index.rb
|
data/lib/remap/rule/each.rb
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Remap
|
4
|
-
class Rule
|
5
|
-
using State::Extension
|
6
|
-
|
7
|
-
# Iterates over a rule, even if the rule is not a collection
|
8
|
-
#
|
9
|
-
# @example Upcase each value in an array
|
10
|
-
# state = Remap::State.call(["John", "Jane"])
|
11
|
-
# upcase = Remap::Rule::Map.call({}).then(&:upcase)
|
12
|
-
# each = Remap::Rule::Each.call(rule: upcase)
|
13
|
-
# error = -> failure { raise failure.exception }
|
14
|
-
# each.call(state, &error).fetch(:value) # => ["JOHN", "JANE"]
|
15
|
-
class Each < Unit
|
16
|
-
# @return [Rule]
|
17
|
-
attribute :rule, Types::Rule
|
18
|
-
|
19
|
-
# Iterates over state and passes each value to rule
|
20
|
-
# Restores element, key & index before returning state
|
21
|
-
#
|
22
|
-
# @param state [State<Enumerable>]
|
23
|
-
#
|
24
|
-
# @return [State<Enumerable>]
|
25
|
-
def call(state, &error)
|
26
|
-
unless error
|
27
|
-
raise ArgumentError, "Each#call(state, &error) requires a block"
|
28
|
-
end
|
29
|
-
|
30
|
-
state.map do |inner_state|
|
31
|
-
rule.call(inner_state) do |failure|
|
32
|
-
return error[failure]
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
data/lib/remap/rule/embed.rb
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Remap
|
4
|
-
class Rule
|
5
|
-
using State::Extension
|
6
|
-
|
7
|
-
# Embed mappers into each other
|
8
|
-
#
|
9
|
-
# @example Embed Mapper A into B
|
10
|
-
# class Car < Remap::Base
|
11
|
-
# define do
|
12
|
-
# map :name, to: :model
|
13
|
-
# end
|
14
|
-
# end
|
15
|
-
#
|
16
|
-
# class Person < Remap::Base
|
17
|
-
# define do
|
18
|
-
# to :person do
|
19
|
-
# to :car do
|
20
|
-
# embed Car
|
21
|
-
# end
|
22
|
-
# end
|
23
|
-
# end
|
24
|
-
# end
|
25
|
-
#
|
26
|
-
# Person.call({name: "Volvo"}) # => { person: { car: { model: "Volvo" } } }
|
27
|
-
class Embed < Unit
|
28
|
-
# @return [#call!]
|
29
|
-
attribute :mapper, Types::Mapper
|
30
|
-
|
31
|
-
# Evaluates input against mapper and returns the result
|
32
|
-
#
|
33
|
-
# @param state [State<T>]
|
34
|
-
#
|
35
|
-
# @return [State<U>]
|
36
|
-
def call(state, &error)
|
37
|
-
unless error
|
38
|
-
raise ArgumentError, "A block is required to evaluate the embed"
|
39
|
-
end
|
40
|
-
|
41
|
-
mapper.call!(state.set(mapper: mapper)) do |failure|
|
42
|
-
return error[failure]
|
43
|
-
end.except(:mapper, :scope)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
data/lib/remap/rule/set.rb
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Remap
|
4
|
-
class Rule
|
5
|
-
using State::Extension
|
6
|
-
|
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
|
23
|
-
|
24
|
-
# @return [Path::Output]
|
25
|
-
attribute :path, Path::Output
|
26
|
-
|
27
|
-
# @see Rule#call
|
28
|
-
def call(...)
|
29
|
-
rule.call(...).then(&path)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Remap
|
4
|
-
class Rule
|
5
|
-
class Collection
|
6
|
-
using State::Extension
|
7
|
-
|
8
|
-
# Represents an empty rule block
|
9
|
-
class Empty < Unit
|
10
|
-
attribute? :rules, Value(EMPTY_ARRAY), default: EMPTY_ARRAY
|
11
|
-
|
12
|
-
# Represents an empty define block, without any rules
|
13
|
-
#
|
14
|
-
# @param state [State<T>]
|
15
|
-
#
|
16
|
-
# @return [State<T>]
|
17
|
-
def call(state)
|
18
|
-
state.notice!("No rules, empty block")
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,40 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Remap
|
4
|
-
class Rule
|
5
|
-
class Collection
|
6
|
-
using State::Extension
|
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>]
|
18
|
-
attribute :rules, [Types.Interface(:call)], min_size: 1
|
19
|
-
|
20
|
-
# Represents a non-empty define block with one or more rules
|
21
|
-
# Calls every {#rules} with state and merges the output
|
22
|
-
#
|
23
|
-
# @param state [State]
|
24
|
-
#
|
25
|
-
# @return [State]
|
26
|
-
def call(state, &error)
|
27
|
-
unless error
|
28
|
-
raise ArgumentError, "Collection::Filled#call(state, &error) requires a block"
|
29
|
-
end
|
30
|
-
|
31
|
-
rules.map do |rule|
|
32
|
-
rule.call(state) do |failure|
|
33
|
-
return error[failure]
|
34
|
-
end
|
35
|
-
end.reduce(&:combine)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Remap
|
4
|
-
class Rule
|
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"
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
@@ -1,86 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Remap
|
4
|
-
class Rule
|
5
|
-
class Enum < Proxy
|
6
|
-
include Dry::Monads[:maybe]
|
7
|
-
|
8
|
-
# @return [Hash]
|
9
|
-
option :mappings, default: -> { Hash.new { default } }
|
10
|
-
|
11
|
-
# @return [Maybe]
|
12
|
-
option :default, default: -> { None() }
|
13
|
-
|
14
|
-
alias execute instance_eval
|
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]
|
31
|
-
def self.call(&block)
|
32
|
-
unless block
|
33
|
-
raise ArgumentError, "no block given"
|
34
|
-
end
|
35
|
-
|
36
|
-
new.tap { _1.execute(&block) }
|
37
|
-
end
|
38
|
-
|
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]
|
47
|
-
def get(key, &error)
|
48
|
-
unless error
|
49
|
-
return get(key) { raise Error, _1 }
|
50
|
-
end
|
51
|
-
|
52
|
-
self[key].bind { return _1 }.or do
|
53
|
-
error["Enum key [#{key}] not found among [#{mappings.keys.inspect}]"]
|
54
|
-
end
|
55
|
-
end
|
56
|
-
alias call get
|
57
|
-
|
58
|
-
# @return [Maybe]
|
59
|
-
def [](key)
|
60
|
-
mappings[key]
|
61
|
-
end
|
62
|
-
|
63
|
-
# @return [void]
|
64
|
-
def from(*keys, to:)
|
65
|
-
value = Some(to)
|
66
|
-
|
67
|
-
keys.each do |key|
|
68
|
-
mappings[key] = value
|
69
|
-
mappings[to] = value
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
# @return [void]
|
74
|
-
def value(*ids)
|
75
|
-
ids.each do |id|
|
76
|
-
from(id, to: id)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
# @return [void]
|
81
|
-
def otherwise(value)
|
82
|
-
mappings.default = Some(value)
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
data/lib/remap/rule/wrap.rb
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Remap
|
4
|
-
class Rule
|
5
|
-
using State::Extension
|
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]
|
23
|
-
attribute :type, Value(:array)
|
24
|
-
|
25
|
-
# @return [Rule]
|
26
|
-
attribute :rule, Types::Rule
|
27
|
-
|
28
|
-
# Wraps the output from {#rule} in a {#type}
|
29
|
-
#
|
30
|
-
# @see Rule#call
|
31
|
-
def call(...)
|
32
|
-
rule.call(...).fmap do |value|
|
33
|
-
Array.wrap(value)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|