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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 526ddded05ad56900a9f6d1276069c48297adc6f5cb32ef08b955949bf9ee426
4
- data.tar.gz: 239295549c9f0365453d19254fe21ff046755b6066f86a81596abaf102a98bbb
3
+ metadata.gz: 88204af4f42ce85893ec029d953e2e6c417bbacba673522eedadca9561f8f749
4
+ data.tar.gz: 9e3e6040baf0426590b4c920d33f0979e74a084a19bbd87079d474a9e251663a
5
5
  SHA512:
6
- metadata.gz: 1c8d02457838ffe470359e5b9ff97cd2a31288928d238362eb38d85c190160b430242d2cfb401e9f7dbb418be4838dd6cbb1c282b68a7eababf5ad2d48030440
7
- data.tar.gz: 191f1570f40e582c31e724e788882b54f83ff82e6d37931519451975355ceab5fb708260352523ddc10c849daa86d31c915221e9d539f2c069288462ca5dc45b
6
+ metadata.gz: 612cf547b8207f305cf9b1f4788d3b36c0d487f0c42bdbf657336c04982060f6dd46a0cfc2a57c39588cef15287ede98205ab5beb46c9245b3270a99b586934d
7
+ data.tar.gz: a11492555b465f2d9f2db0611ed8d6457579dc6546805a9a867fc7b951061572f0faae84caec4be50907efa99e15647a8ae52aefd0de14362d29d6fea45cb166
@@ -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::Void.new
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.rule
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 Rule::Map::Required.call(
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 Rule::Map::Optional.call(
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
- map(path, to: path, backtrace: backtrace, &block)
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
- map?(path, to: path, backtrace: backtrace, &block)
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
- add Rule::Embed.new(mapper: mapper)
193
- rescue Dry::Struct::Error
194
- raise ArgumentError, "Embeded mapper must be [Remap::Mapper], got [#{mapper}]"
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 Rule::Set.new(path: path.flatten, value: to)
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
- map(*map, to: path, backtrace: backtrace, &block)
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
- map?(*map, to: path, &block)
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 Rule::Each.new(rule: call(&block))
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 Rule::Wrap.new(type: type, rule: call(&block))
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
@@ -38,6 +38,8 @@ module Remap
38
38
  end
39
39
 
40
40
  [current_path + [key], value]
41
+ rescue TypeError
42
+ raise PathError, current_path + [key]
41
43
  end
42
44
 
43
45
  result
@@ -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
@@ -31,7 +31,7 @@ module Remap
31
31
  #
32
32
  # @return [State]
33
33
  def call(state, &error)
34
- unless error
34
+ unless block_given?
35
35
  raise ArgumentError, "map.call(state, &error) requires a block"
36
36
  end
37
37
 
@@ -43,15 +43,19 @@ module Remap
43
43
  #
44
44
  # @abstract
45
45
  def call(state, &error)
46
- unless error
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.then(&callback)
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
- -> state do
199
- fn.reduce(state) do |inner, fn|
200
- fn[inner]
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
@@ -5,6 +5,8 @@ module Remap
5
5
  defines :requirement
6
6
  requirement Types::Any
7
7
 
8
+ VOID = Void.new(EMPTY_HASH)
9
+
8
10
  # @param state [State]
9
11
  #
10
12
  # @abstract
@@ -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
- # result = Remap::Selector::Index.new(1).call(state)
12
- # result.fetch(:value) # => :two
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
- return call(outer_state, &:itself) unless block
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
@@ -17,7 +17,6 @@ require "zeitwerk"
17
17
 
18
18
  module Remap
19
19
  loader = Zeitwerk::Loader.for_gem
20
- loader.collapse("#{__dir__}/remap/rule/support")
21
20
  loader.collapse("#{__dir__}/remap/mapper/support")
22
21
  loader.setup
23
22
  loader.eager_load
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.13
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/each.rb
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
@@ -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
@@ -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
@@ -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
@@ -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