remap 2.0.3 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/lib/remap/base.rb +229 -75
  3. data/lib/remap/compiler.rb +127 -37
  4. data/lib/remap/constructor/argument.rb +20 -6
  5. data/lib/remap/constructor/keyword.rb +20 -4
  6. data/lib/remap/constructor/none.rb +3 -4
  7. data/lib/remap/constructor.rb +12 -5
  8. data/lib/remap/contract.rb +27 -0
  9. data/lib/remap/extensions/enumerable.rb +48 -0
  10. data/lib/remap/extensions/hash.rb +13 -0
  11. data/lib/remap/extensions/object.rb +37 -0
  12. data/lib/remap/failure.rb +25 -15
  13. data/lib/remap/iteration/array.rb +20 -11
  14. data/lib/remap/iteration/hash.rb +21 -13
  15. data/lib/remap/iteration/other.rb +7 -7
  16. data/lib/remap/iteration.rb +8 -2
  17. data/lib/remap/mapper/and.rb +29 -7
  18. data/lib/remap/mapper/binary.rb +3 -6
  19. data/lib/remap/mapper/or.rb +29 -6
  20. data/lib/remap/mapper/support/operations.rb +40 -0
  21. data/lib/remap/mapper/xor.rb +29 -7
  22. data/lib/remap/mapper.rb +1 -48
  23. data/lib/remap/notice/traced.rb +19 -0
  24. data/lib/remap/notice/untraced.rb +11 -0
  25. data/lib/remap/notice.rb +34 -0
  26. data/lib/remap/operation.rb +26 -13
  27. data/lib/remap/path/input.rb +37 -0
  28. data/lib/remap/path/output.rb +26 -0
  29. data/lib/remap/path.rb +22 -0
  30. data/lib/remap/path_error.rb +13 -0
  31. data/lib/remap/proxy.rb +18 -0
  32. data/lib/remap/rule/each.rb +25 -24
  33. data/lib/remap/rule/embed.rb +33 -28
  34. data/lib/remap/rule/map/optional.rb +42 -0
  35. data/lib/remap/rule/map/required.rb +35 -0
  36. data/lib/remap/rule/map.rb +176 -55
  37. data/lib/remap/rule/set.rb +23 -33
  38. data/lib/remap/rule/support/collection/empty.rb +7 -7
  39. data/lib/remap/rule/support/collection/filled.rb +21 -8
  40. data/lib/remap/rule/support/collection.rb +11 -3
  41. data/lib/remap/rule/support/enum.rb +44 -21
  42. data/lib/remap/rule/void.rb +17 -18
  43. data/lib/remap/rule/wrap.rb +25 -17
  44. data/lib/remap/rule.rb +8 -1
  45. data/lib/remap/selector/all.rb +29 -7
  46. data/lib/remap/selector/index.rb +24 -16
  47. data/lib/remap/selector/key.rb +31 -16
  48. data/lib/remap/selector.rb +17 -0
  49. data/lib/remap/state/extension.rb +182 -208
  50. data/lib/remap/state/schema.rb +1 -1
  51. data/lib/remap/state.rb +30 -4
  52. data/lib/remap/static/fixed.rb +14 -3
  53. data/lib/remap/static/option.rb +21 -6
  54. data/lib/remap/static.rb +13 -0
  55. data/lib/remap/struct.rb +1 -0
  56. data/lib/remap/types.rb +13 -28
  57. data/lib/remap.rb +15 -19
  58. metadata +91 -89
  59. data/lib/remap/result.rb +0 -11
  60. data/lib/remap/rule/support/path.rb +0 -45
  61. data/lib/remap/state/types.rb +0 -11
  62. data/lib/remap/success.rb +0 -29
  63. data/lib/remap/version.rb +0 -5
@@ -2,18 +2,40 @@
2
2
 
3
3
  module Remap
4
4
  class Selector
5
- class All < Concrete
6
- using State::Extension
5
+ using State::Extension
7
6
 
7
+ # Selects all elements from a state
8
+ #
9
+ # @example Select all keys from array hash
10
+ # state = Remap::State.call([{a: "A1"}, {a: "A2"}])
11
+ # all = Remap::Selector::All.new
12
+ # result = all.call(state) do |other_state|
13
+ # value = other_state.fetch(:value).class
14
+ # other_state.merge(value: value)
15
+ # end
16
+ # result.fetch(:value) # => [Hash, Hash]
17
+ class All < Concrete
8
18
  requirement Types::Enumerable
9
19
 
10
- def call(state, &block)
11
- state.bind(quantifier: "*") do |enumerable, inner_state, &error|
12
- requirement[enumerable] do
13
- return error["Expected an enumeration"]
20
+ # Iterates over state and passes each value to block
21
+ #
22
+ # @param outer_state [State<Enumerable<T>>]
23
+ #
24
+ # @yieldparam [State<T>]
25
+ # @yieldreturn [State<U>]
26
+ #
27
+ # @return [State<U>]
28
+ def call(outer_state, &block)
29
+ unless block_given?
30
+ raise ArgumentError, "All selector requires an iteration block"
31
+ end
32
+
33
+ outer_state.bind(quantifier: "*") do |enum, state|
34
+ requirement[enum] do
35
+ state.fatal!("Expected enumeration but got %p (%s)", enum, enum.class)
14
36
  end
15
37
 
16
- inner_state.map(&block)
38
+ state.map(&block)
17
39
  end
18
40
  end
19
41
  end
@@ -2,36 +2,44 @@
2
2
 
3
3
  module Remap
4
4
  class Selector
5
+ using State::Extension
6
+
7
+ # Selects value at given index
8
+ #
9
+ # @example Select the value at index 1 from a array
10
+ # state = Remap::State.call([:one, :two, :tree])
11
+ # result = Remap::Selector::Index.new(1).call(state)
12
+ # result.fetch(:value) # => :two
5
13
  class Index < Unit
6
- using State::Extension
7
-
14
+ # @return [Integer]
8
15
  attribute :index, Integer
9
16
 
10
17
  requirement Types::Array
11
18
 
12
- # Fetches {#input[value]} and passes it to {block}
19
+ # Selects the {#index}th element from state and passes it to block
13
20
  #
14
- # @param [State] state
21
+ # @param outer_state [State<Array<T>>]
15
22
  #
16
- # @yieldparam [State]
17
- # @yieldreturn [State<T>]
18
-
19
- # @return [State<T>]
20
- def call(state, &block)
21
- unless block
22
- raise ArgumentError, "no block given"
23
- end
23
+ # @yieldparam [State<T>]
24
+ # @yieldreturn [State<U>]
25
+ #
26
+ # @return [State<U>]
27
+ def call(outer_state, &block)
28
+ return call(outer_state, &:itself) unless block
24
29
 
25
- state.bind(index: index) do |array, inner_state, &error|
30
+ outer_state.bind(index: index) do |array, state|
26
31
  requirement[array] do
27
- return error["Expected an array"]
32
+ state.fatal!("Expected array but got %p (%s)", array, array.class)
28
33
  end
29
34
 
30
35
  element = array.fetch(index) do
31
- return error["No element on index at index #{index}"]
36
+ state.ignore!("Index %s in array %p (%s) not found",
37
+ index,
38
+ array,
39
+ array.class)
32
40
  end
33
41
 
34
- block[inner_state.set(element, index: index)]
42
+ state.set(element, index: index).then(&block)
35
43
  end
36
44
  end
37
45
  end
@@ -2,35 +2,50 @@
2
2
 
3
3
  module Remap
4
4
  class Selector
5
+ using State::Extension
6
+
7
+ # Selects value at key from state
8
+ #
9
+ # @example Select the value at key :name from a hash
10
+ # state = Remap::State.call({ name: "John" })
11
+ # selector = Remap::Selector::Key.new(:name)
12
+ #
13
+ # selector.call(state) do |state|
14
+ # state.fetch(:value)
15
+ # end
5
16
  class Key < Unit
6
- using State::Extension
17
+ # @return [#hash
18
+ attribute :key, Types::Key
7
19
 
8
- attribute :key, Types::Hash.not
9
- requirement Types::Hash.constrained(min_size: 1)
20
+ requirement Types::Hash
10
21
 
11
- # Fetches {#input[value]} and passes it to {block}
22
+ # Selects {#key} from state and passes it to block
12
23
  #
13
- # @param [State] state
24
+ # @param outer_state [State<Hash<K, V>>]
14
25
  #
15
- # @yieldparam [State]
16
- # @yieldreturn [State<T>]
17
-
18
- # @return [State<T>]
19
- def call(state, &block)
20
- unless block
21
- return call(state, &:itself)
26
+ # @yieldparam [State<V>]
27
+ # @yieldreturn [State<U>]
28
+ #
29
+ # @return [State<U>]
30
+ def call(outer_state, &block)
31
+ unless block_given?
32
+ raise ArgumentError, "The key selector requires an iteration block"
22
33
  end
23
34
 
24
- state.bind(key: key) do |hash, inner_state, &error|
35
+ outer_state.bind(key: key) do |hash, state|
25
36
  requirement[hash] do
26
- return error["Expected a hash"]
37
+ state.fatal!("Expected hash but got %p (%s)", hash, hash.class)
27
38
  end
28
39
 
29
40
  value = hash.fetch(key) do
30
- return error["Key [#{key}] not found"]
41
+ state.ignore!("Key %p (%s) not found in hash %p (%s)",
42
+ key,
43
+ key.class,
44
+ hash,
45
+ hash.class)
31
46
  end
32
47
 
33
- block[inner_state.set(value, key: key)]
48
+ state.set(value, key: key).then(&block)
34
49
  end
35
50
  end
36
51
  end
@@ -1,12 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Remap
4
+ # Defines how a path element, or selector
5
+ # Specifies how a value is extracted from a state
4
6
  class Selector < Dry::Interface
5
7
  defines :requirement, type: Types::Any.constrained(type: Dry::Types::Type)
6
8
  requirement Types::Any
7
9
 
10
+ # Selects value from state, package it as a state and passes it to block
11
+ #
12
+ # @param state [State]
13
+ #
14
+ # @yieldparam [State]
15
+ # @yieldreturn [State]
16
+ #
17
+ # @return [State]
18
+ #
19
+ # @abstract
20
+ def call(state)
21
+ raise NotImplementedError, "#{self.class}#call not implemented"
22
+ end
23
+
8
24
  private
9
25
 
26
+ # @return [Dry::Types::Type]
10
27
  def requirement
11
28
  self.class.requirement
12
29
  end