super-smart-tool 0.0.1

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.
Files changed (63) hide show
  1. checksums.yaml +7 -0
  2. data/dry-types-1.9.1/CHANGELOG.md +1145 -0
  3. data/dry-types-1.9.1/LICENSE +20 -0
  4. data/dry-types-1.9.1/README.md +17 -0
  5. data/dry-types-1.9.1/dry-types.gemspec +45 -0
  6. data/dry-types-1.9.1/lib/dry/types/any.rb +41 -0
  7. data/dry-types-1.9.1/lib/dry/types/array/constructor.rb +24 -0
  8. data/dry-types-1.9.1/lib/dry/types/array/member.rb +118 -0
  9. data/dry-types-1.9.1/lib/dry/types/array.rb +32 -0
  10. data/dry-types-1.9.1/lib/dry/types/builder.rb +221 -0
  11. data/dry-types-1.9.1/lib/dry/types/builder_methods.rb +138 -0
  12. data/dry-types-1.9.1/lib/dry/types/coercions/json.rb +57 -0
  13. data/dry-types-1.9.1/lib/dry/types/coercions/params.rb +168 -0
  14. data/dry-types-1.9.1/lib/dry/types/coercions.rb +105 -0
  15. data/dry-types-1.9.1/lib/dry/types/compat.rb +1 -0
  16. data/dry-types-1.9.1/lib/dry/types/compiler.rb +138 -0
  17. data/dry-types-1.9.1/lib/dry/types/composition.rb +138 -0
  18. data/dry-types-1.9.1/lib/dry/types/constrained/coercible.rb +59 -0
  19. data/dry-types-1.9.1/lib/dry/types/constrained.rb +146 -0
  20. data/dry-types-1.9.1/lib/dry/types/constraints.rb +30 -0
  21. data/dry-types-1.9.1/lib/dry/types/constructor/function.rb +203 -0
  22. data/dry-types-1.9.1/lib/dry/types/constructor/wrapper.rb +88 -0
  23. data/dry-types-1.9.1/lib/dry/types/constructor.rb +195 -0
  24. data/dry-types-1.9.1/lib/dry/types/container.rb +12 -0
  25. data/dry-types-1.9.1/lib/dry/types/core.rb +106 -0
  26. data/dry-types-1.9.1/lib/dry/types/decorator.rb +94 -0
  27. data/dry-types-1.9.1/lib/dry/types/default.rb +122 -0
  28. data/dry-types-1.9.1/lib/dry/types/enum.rb +121 -0
  29. data/dry-types-1.9.1/lib/dry/types/errors.rb +138 -0
  30. data/dry-types-1.9.1/lib/dry/types/extensions/maybe.rb +128 -0
  31. data/dry-types-1.9.1/lib/dry/types/extensions/monads.rb +34 -0
  32. data/dry-types-1.9.1/lib/dry/types/extensions.rb +9 -0
  33. data/dry-types-1.9.1/lib/dry/types/fn_container.rb +37 -0
  34. data/dry-types-1.9.1/lib/dry/types/hash/constructor.rb +25 -0
  35. data/dry-types-1.9.1/lib/dry/types/hash.rb +134 -0
  36. data/dry-types-1.9.1/lib/dry/types/implication.rb +64 -0
  37. data/dry-types-1.9.1/lib/dry/types/inflector.rb +9 -0
  38. data/dry-types-1.9.1/lib/dry/types/intersection.rb +102 -0
  39. data/dry-types-1.9.1/lib/dry/types/json.rb +35 -0
  40. data/dry-types-1.9.1/lib/dry/types/lax.rb +66 -0
  41. data/dry-types-1.9.1/lib/dry/types/map.rb +134 -0
  42. data/dry-types-1.9.1/lib/dry/types/meta.rb +53 -0
  43. data/dry-types-1.9.1/lib/dry/types/module.rb +127 -0
  44. data/dry-types-1.9.1/lib/dry/types/nominal.rb +201 -0
  45. data/dry-types-1.9.1/lib/dry/types/options.rb +34 -0
  46. data/dry-types-1.9.1/lib/dry/types/params.rb +38 -0
  47. data/dry-types-1.9.1/lib/dry/types/predicate_inferrer.rb +235 -0
  48. data/dry-types-1.9.1/lib/dry/types/predicate_registry.rb +32 -0
  49. data/dry-types-1.9.1/lib/dry/types/primitive_inferrer.rb +75 -0
  50. data/dry-types-1.9.1/lib/dry/types/printable.rb +14 -0
  51. data/dry-types-1.9.1/lib/dry/types/printer/composition.rb +44 -0
  52. data/dry-types-1.9.1/lib/dry/types/printer.rb +313 -0
  53. data/dry-types-1.9.1/lib/dry/types/result.rb +72 -0
  54. data/dry-types-1.9.1/lib/dry/types/schema/key.rb +138 -0
  55. data/dry-types-1.9.1/lib/dry/types/schema.rb +408 -0
  56. data/dry-types-1.9.1/lib/dry/types/spec/types.rb +164 -0
  57. data/dry-types-1.9.1/lib/dry/types/sum.rb +105 -0
  58. data/dry-types-1.9.1/lib/dry/types/type.rb +53 -0
  59. data/dry-types-1.9.1/lib/dry/types/version.rb +7 -0
  60. data/dry-types-1.9.1/lib/dry/types.rb +259 -0
  61. data/dry-types-1.9.1/lib/dry-types.rb +3 -0
  62. data/super-smart-tool.gemspec +11 -0
  63. metadata +101 -0
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dry
4
+ module Types
5
+ # Primitives with {Kernel} coercion methods
6
+ KERNEL_COERCIBLE = {
7
+ string: String,
8
+ integer: Integer,
9
+ float: Float,
10
+ decimal: BigDecimal,
11
+ array: ::Array,
12
+ hash: ::Hash
13
+ }.freeze
14
+
15
+ # Primitives with coercions through by convention `to_*` methods
16
+ METHOD_COERCIBLE = {
17
+ symbol: Symbol
18
+ }.freeze
19
+
20
+ # By convention methods to coerce {METHOD_COERCIBLE} primitives
21
+ METHOD_COERCIBLE_METHODS = {
22
+ symbol: :to_sym
23
+ }.freeze
24
+
25
+ # Primitives that are non-coercible
26
+ NON_COERCIBLE = {
27
+ nil: NilClass,
28
+ class: Class,
29
+ true: TrueClass,
30
+ false: FalseClass,
31
+ date: Date,
32
+ date_time: DateTime,
33
+ time: Time,
34
+ range: Range
35
+ }.freeze
36
+
37
+ # All built-in primitives
38
+ ALL_PRIMITIVES = [
39
+ KERNEL_COERCIBLE, METHOD_COERCIBLE, NON_COERCIBLE
40
+ ].reduce(&:merge).freeze
41
+
42
+ # All coercible types
43
+ COERCIBLE = KERNEL_COERCIBLE.merge(METHOD_COERCIBLE).freeze
44
+
45
+ # All built-in primitives except {NilClass}
46
+ NON_NIL = ALL_PRIMITIVES.except(:nil).freeze
47
+
48
+ # Register generic types for {ALL_PRIMITIVES}
49
+ ALL_PRIMITIVES.each do |name, primitive|
50
+ type = Nominal[primitive].new(primitive)
51
+ register("nominal.#{name}", type)
52
+ end
53
+
54
+ # Register strict types for {ALL_PRIMITIVES}
55
+ ALL_PRIMITIVES.each do |name, primitive|
56
+ type = self["nominal.#{name}"].constrained(type: primitive)
57
+ register(name.to_s, type)
58
+ register("strict.#{name}", type)
59
+ end
60
+
61
+ # Register {KERNEL_COERCIBLE} types
62
+ KERNEL_COERCIBLE.each do |name, primitive|
63
+ register(
64
+ "coercible.#{name}",
65
+ self["nominal.#{name}"].constructor(::Kernel.method(primitive.name))
66
+ )
67
+ end
68
+
69
+ # Register {METHOD_COERCIBLE} types
70
+ METHOD_COERCIBLE.each_key do |name|
71
+ register(
72
+ "coercible.#{name}",
73
+ self["nominal.#{name}"].constructor(&METHOD_COERCIBLE_METHODS[name])
74
+ )
75
+ end
76
+
77
+ # Register optional strict {NON_NIL} types
78
+ NON_NIL.each_key do |name|
79
+ type = self[name.to_s].optional
80
+ register("optional.strict.#{name}", type)
81
+ register("optional.#{name}", type)
82
+ end
83
+
84
+ # Register optional {COERCIBLE} types
85
+ COERCIBLE.each_key do |name|
86
+ register(
87
+ "optional.coercible.#{name}",
88
+ self["coercible.#{name}"].optional
89
+ )
90
+ end
91
+
92
+ # Register `:bool` since it's common and not a built-in Ruby type :(
93
+ register("nominal.bool", self["nominal.true"] | self["nominal.false"])
94
+ bool = self["strict.true"] | self["strict.false"]
95
+ register("strict.bool", bool)
96
+ register("bool", bool)
97
+
98
+ register("any", Any)
99
+ register("nominal.any", Any)
100
+ register("strict.any", Any)
101
+ end
102
+ end
103
+
104
+ require "dry/types/coercions"
105
+ require "dry/types/params"
106
+ require "dry/types/json"
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dry
4
+ module Types
5
+ # Common API for types
6
+ #
7
+ # @api public
8
+ module Decorator
9
+ include Options
10
+
11
+ # @return [Type]
12
+ attr_reader :type
13
+
14
+ # @param [Type] type
15
+ def initialize(type, *, **)
16
+ super
17
+ @type = type
18
+ end
19
+
20
+ # @param [Object] input
21
+ # @param [#call, nil] block
22
+ #
23
+ # @return [Result,Logic::Result]
24
+ # @return [Object] if block given and try fails
25
+ #
26
+ # @api public
27
+ def try(input, &) = type.try(input, &)
28
+
29
+ # @return [Boolean]
30
+ #
31
+ # @api public
32
+ def default? = type.default?
33
+
34
+ # @return [Boolean]
35
+ #
36
+ # @api public
37
+ def constrained? = type.constrained?
38
+
39
+ # @param [Symbol] meth
40
+ # @param [Boolean] include_private
41
+ #
42
+ # @return [Boolean]
43
+ #
44
+ # @api public
45
+ def respond_to_missing?(meth, include_private = false)
46
+ super || type.respond_to?(meth)
47
+ end
48
+
49
+ # Wrap the type with a proc
50
+ #
51
+ # @return [Proc]
52
+ #
53
+ # @api public
54
+ def to_proc = proc { |value| self.(value) }
55
+
56
+ private
57
+
58
+ # @param [Object] response
59
+ #
60
+ # @return [Boolean]
61
+ #
62
+ # @api private
63
+ def decorate?(response) = response.is_a?(type.class)
64
+
65
+ # Delegates missing methods to {#type}
66
+ #
67
+ # @param [Symbol] meth
68
+ # @param [Array] args
69
+ # @param [#call, nil] block
70
+ #
71
+ # @api private
72
+ def method_missing(meth, ...)
73
+ if type.respond_to?(meth)
74
+ response = type.public_send(meth, ...)
75
+
76
+ if decorate?(response)
77
+ __new__(response)
78
+ else
79
+ response
80
+ end
81
+ else
82
+ super
83
+ end
84
+ end
85
+
86
+ # Replace underlying type
87
+ #
88
+ # @api private
89
+ def __new__(type)
90
+ self.class.new(type, *@__args__.drop(1), **@options)
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dry
4
+ module Types
5
+ # Default types are useful when a missing value should be replaced by a default one
6
+ #
7
+ # @api public
8
+ class Default
9
+ # @api private
10
+ class Callable < Default
11
+ include ::Dry::Equalizer(:type, inspect: false, immutable: true)
12
+
13
+ # Evaluates given callable
14
+ # @return [Object]
15
+ def evaluate
16
+ value.call(type)
17
+ end
18
+
19
+ # @return [true]
20
+ def callable?
21
+ true
22
+ end
23
+ end
24
+
25
+ include Type
26
+ include Decorator
27
+ include Builder
28
+ include Printable
29
+ include ::Dry::Equalizer(:type, :value, inspect: false, immutable: true)
30
+
31
+ # @return [Object]
32
+ attr_reader :value
33
+
34
+ alias_method :evaluate, :value
35
+
36
+ # @param [Object, #call] value
37
+ #
38
+ # @return [Class] {Default} or {Default::Callable}
39
+ #
40
+ # @api private
41
+ def self.[](value)
42
+ if value.respond_to?(:call)
43
+ Callable
44
+ else
45
+ self
46
+ end
47
+ end
48
+
49
+ # @param [Type] type
50
+ # @param [Object] value
51
+ #
52
+ # @api private
53
+ def initialize(type, value, **)
54
+ super
55
+ @value = value
56
+ end
57
+
58
+ # Build a constrained type
59
+ #
60
+ # @param [Array] args see {Dry::Types::Builder#constrained}
61
+ #
62
+ # @return [Default]
63
+ #
64
+ # @api public
65
+ def constrained(...) = type.constrained(...).default(value)
66
+
67
+ # @return [true]
68
+ #
69
+ # @api public
70
+ def default? = true
71
+
72
+ # @param [Object] input
73
+ #
74
+ # @return [Result::Success]
75
+ #
76
+ # @api public
77
+ def try(input = Undefined, &)
78
+ if input.equal?(Undefined)
79
+ success(evaluate)
80
+ else
81
+ type.try(input)
82
+ end
83
+ end
84
+
85
+ # @return [Boolean]
86
+ #
87
+ # @api public
88
+ def valid?(value = Undefined) = Undefined.equal?(value) || super
89
+
90
+ # @param [Object] input
91
+ #
92
+ # @return [Object] value passed through {#type} or {#default} value
93
+ #
94
+ # @api private
95
+ def call_unsafe(input = Undefined)
96
+ if input.equal?(Undefined)
97
+ evaluate
98
+ else
99
+ Undefined.default(type.call_unsafe(input)) { evaluate }
100
+ end
101
+ end
102
+
103
+ # @param [Object] input
104
+ #
105
+ # @return [Object] value passed through {#type} or {#default} value
106
+ #
107
+ # @api private
108
+ def call_safe(input = Undefined, &)
109
+ if input.equal?(Undefined)
110
+ evaluate
111
+ else
112
+ Undefined.default(type.call_safe(input, &)) { evaluate }
113
+ end
114
+ end
115
+
116
+ # @return [false]
117
+ #
118
+ # @api private
119
+ def callable? = false
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dry
4
+ module Types
5
+ # Enum types can be used to define an enum on top of an existing type
6
+ #
7
+ # @api public
8
+ class Enum
9
+ include Type
10
+ include ::Dry::Equalizer(:type, :mapping, inspect: false, immutable: true)
11
+ include Decorator
12
+ include Builder
13
+
14
+ # @return [Array]
15
+ attr_reader :values
16
+
17
+ # @return [Hash]
18
+ attr_reader :mapping
19
+
20
+ # @return [Hash]
21
+ attr_reader :inverted_mapping
22
+
23
+ # @param [Type] type
24
+ # @param [Hash] options
25
+ # @option options [Array] :values
26
+ #
27
+ # @api private
28
+ def initialize(type, **options)
29
+ super
30
+ @mapping = options.fetch(:mapping).freeze
31
+ @values = @mapping.keys.freeze
32
+ @inverted_mapping = @mapping.invert.freeze
33
+ freeze
34
+ end
35
+
36
+ # @return [Object]
37
+ #
38
+ # @api private
39
+ def call_unsafe(input) = type.call_unsafe(map_value(input))
40
+
41
+ # @return [Object]
42
+ #
43
+ # @api private
44
+ def call_safe(input, &) = type.call_safe(map_value(input), &)
45
+
46
+ # @see Dry::Types::Constrained#try
47
+ #
48
+ # @api public
49
+ def try(input, &) = super(map_value(input))
50
+
51
+ # @api private
52
+ def default(*)
53
+ raise ".enum(*values).default(value) is not supported. Call " \
54
+ ".default(value).enum(*values) instead"
55
+ end
56
+
57
+ # Check whether a value is in the enum
58
+ alias_method :include?, :valid?
59
+
60
+ # @see Nominal#to_ast
61
+ #
62
+ # @api public
63
+ def to_ast(meta: true)
64
+ [:enum, [type.to_ast(meta: meta), mapping]]
65
+ end
66
+
67
+ # @return [String]
68
+ #
69
+ # @api public
70
+ def to_s = PRINTER.(self)
71
+
72
+ # Iterate over each enum value
73
+ #
74
+ # @return [Array, Enumerator]
75
+ #
76
+ # @api public
77
+ def each_value(&)
78
+ values.each(&)
79
+ end
80
+
81
+ alias_method :inspect, :to_s
82
+
83
+ # @return [String]
84
+ #
85
+ # @api public
86
+ def name = "#{super}(#{joined_values})"
87
+
88
+ # @return [String]
89
+ #
90
+ # @api private
91
+ def joined_values
92
+ mapping.keys.map { |value|
93
+ if value.is_a?(::String)
94
+ value
95
+ else
96
+ value.inspect
97
+ end
98
+ }.join("|")
99
+ end
100
+
101
+ private
102
+
103
+ # Maps a value
104
+ #
105
+ # @param [Object] input
106
+ #
107
+ # @return [Object]
108
+ #
109
+ # @api private
110
+ def map_value(input)
111
+ if input.equal?(Undefined)
112
+ type.call
113
+ elsif mapping.key?(input)
114
+ input
115
+ else
116
+ inverted_mapping.fetch(input, input)
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,138 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dry
4
+ module Types
5
+ extend ::Dry::Core::ClassAttributes
6
+
7
+ # @!attribute [r] namespace
8
+ # @return [Container{String => Nominal}]
9
+ defines :namespace
10
+
11
+ namespace self
12
+
13
+ # Base class for coercion errors raise by dry-types
14
+ #
15
+ class CoercionError < ::StandardError
16
+ # @api private
17
+ def self.handle(exception, meta: Undefined)
18
+ if block_given?
19
+ yield
20
+ else
21
+ raise new(
22
+ exception.message,
23
+ meta: meta,
24
+ backtrace: exception.backtrace
25
+ )
26
+ end
27
+ end
28
+
29
+ # Metadata associated with the error
30
+ #
31
+ # @return [Object]
32
+ attr_reader :meta
33
+
34
+ # @api private
35
+ def initialize(message, meta: Undefined, backtrace: Undefined)
36
+ unless message.is_a?(::String)
37
+ raise ::ArgumentError, "message must be a string, #{message.class} given"
38
+ end
39
+
40
+ super(message)
41
+ @meta = Undefined.default(meta, nil)
42
+ set_backtrace(backtrace) unless Undefined.equal?(backtrace)
43
+ end
44
+ end
45
+
46
+ # Collection of multiple errors
47
+ #
48
+ class MultipleError < CoercionError
49
+ # @return [Array<CoercionError>]
50
+ attr_reader :errors
51
+
52
+ # @param [Array<CoercionError>] errors
53
+ def initialize(errors)
54
+ super("")
55
+ @errors = errors
56
+ end
57
+
58
+ # @return string
59
+ def message = errors.map(&:message).join(", ")
60
+
61
+ # @return [Array]
62
+ def meta = errors.map(&:meta)
63
+ end
64
+
65
+ class SchemaError < CoercionError
66
+ # @return [String, Symbol]
67
+ attr_reader :key
68
+
69
+ # @return [Object]
70
+ attr_reader :value
71
+
72
+ # @param [String,Symbol] key
73
+ # @param [Object] value
74
+ # @param [String, #to_s] result
75
+ def initialize(key, value, result)
76
+ @key = key
77
+ @value = value
78
+ super(
79
+ "#{value.inspect} (#{value.class}) has invalid type " \
80
+ "for :#{key} violates constraints (#{result} failed)"
81
+ )
82
+ end
83
+ end
84
+
85
+ MapError = ::Class.new(CoercionError)
86
+
87
+ SchemaKeyError = ::Class.new(CoercionError)
88
+ private_constant(:SchemaKeyError)
89
+
90
+ class MissingKeyError < SchemaKeyError
91
+ # @return [Symbol]
92
+ attr_reader :key
93
+
94
+ # @param [String,Symbol] key
95
+ def initialize(key)
96
+ @key = key
97
+ super("#{key.inspect} is missing in Hash input")
98
+ end
99
+ end
100
+
101
+ class UnknownKeysError < SchemaKeyError
102
+ # @return [Array<Symbol>]
103
+ attr_reader :keys
104
+
105
+ # @param [<String, Symbol>] keys
106
+ def initialize(keys)
107
+ @keys = keys
108
+ super("unexpected keys #{keys.inspect} in Hash input")
109
+ end
110
+ end
111
+
112
+ class ConstraintError < CoercionError
113
+ # @return [String, #to_s]
114
+ attr_reader :result
115
+ # @return [Object]
116
+ attr_reader :input
117
+
118
+ # @param [String, #to_s] result
119
+ # @param [Object] input
120
+ def initialize(result, input)
121
+ @result = result
122
+ @input = input
123
+
124
+ if result.is_a?(::String)
125
+ super(result)
126
+ else
127
+ super(to_s)
128
+ end
129
+ end
130
+
131
+ # @return [String]
132
+ def message
133
+ "#{input.inspect} violates constraints (#{result} failed)"
134
+ end
135
+ alias_method :to_s, :message
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+ require "dry/monads/version"
5
+
6
+ if Gem::Version.new(Dry::Monads::VERSION) < Gem::Version.new("1.5.0")
7
+ raise "dry-types requires dry-monads >= 1.5.0"
8
+ end
9
+
10
+ module Dry
11
+ module Types
12
+ # Maybe extension provides Maybe types where values are wrapped using `Either` monad
13
+ #
14
+ # @api public
15
+ class Maybe
16
+ include Type
17
+ include ::Dry::Equalizer(:type, :options, inspect: false, immutable: true)
18
+ include Decorator
19
+ include Builder
20
+ include Printable
21
+ include ::Dry::Monads[:maybe]
22
+
23
+ # @param [Dry::Monads::Maybe, Object] input
24
+ #
25
+ # @return [Dry::Monads::Maybe]
26
+ #
27
+ # @api private
28
+ def call_unsafe(input = Undefined)
29
+ case input
30
+ when ::Dry::Monads::Maybe
31
+ input
32
+ when Undefined
33
+ None()
34
+ else
35
+ Maybe(type.call_unsafe(input))
36
+ end
37
+ end
38
+
39
+ # @param [Dry::Monads::Maybe, Object] input
40
+ #
41
+ # @return [Dry::Monads::Maybe]
42
+ #
43
+ # @api private
44
+ def call_safe(input = Undefined)
45
+ case input
46
+ when ::Dry::Monads::Maybe
47
+ input
48
+ when Undefined
49
+ None()
50
+ else
51
+ Maybe(type.call_safe(input) { |output = input| return yield(output) })
52
+ end
53
+ end
54
+
55
+ # @param [Object] input
56
+ #
57
+ # @return [Result::Success]
58
+ #
59
+ # @api public
60
+ def try(input = Undefined, &)
61
+ result = type.try(input)
62
+
63
+ if result.success?
64
+ Result::Success.new(Maybe(result.input))
65
+ else
66
+ result
67
+ end
68
+ end
69
+
70
+ # @return [true]
71
+ #
72
+ # @api public
73
+ def default? = true
74
+
75
+ # @param [Object] value
76
+ #
77
+ # @see Dry::Types::Builder#default
78
+ #
79
+ # @raise [ArgumentError] if nil provided as default value
80
+ #
81
+ # @api public
82
+ def default(value)
83
+ if value.nil?
84
+ raise ::ArgumentError, "nil cannot be used as a default of a maybe type"
85
+ else
86
+ super
87
+ end
88
+ end
89
+ end
90
+
91
+ module Builder
92
+ # Turn a type into a maybe type
93
+ #
94
+ # @return [Maybe]
95
+ #
96
+ # @api public
97
+ def maybe = Maybe.new(Types["nil"] | self)
98
+ end
99
+
100
+ # @api private
101
+ class Schema::Key # rubocop:disable Style/ClassAndModuleChildren
102
+ # @api private
103
+ def maybe = __new__(type.maybe)
104
+ end
105
+
106
+ # @api private
107
+ class Printer
108
+ MAPPING[Maybe] = :visit_maybe
109
+
110
+ # @api private
111
+ def visit_maybe(maybe)
112
+ visit(maybe.type) do |type|
113
+ yield "Maybe<#{type}>"
114
+ end
115
+ end
116
+ end
117
+
118
+ # Register non-coercible maybe types
119
+ NON_NIL.each_key do |name|
120
+ register("maybe.strict.#{name}", self[name.to_s].maybe)
121
+ end
122
+
123
+ # Register coercible maybe types
124
+ COERCIBLE.each_key do |name|
125
+ register("maybe.coercible.#{name}", self["coercible.#{name}"].maybe)
126
+ end
127
+ end
128
+ end