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,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/types/builder_methods"
4
+
5
+ module Dry
6
+ module Types
7
+ # Export types registered in a container as module constants.
8
+ # @example
9
+ # module Types
10
+ # include Dry.Types(:strict, :coercible, :nominal, default: :strict)
11
+ # end
12
+ #
13
+ # Types.constants
14
+ # # => [:Class, :Strict, :Symbol, :Integer, :Float, :String, :Array, :Hash,
15
+ # # :Decimal, :Nil, :True, :False, :Bool, :Date, :Nominal, :DateTime, :Range,
16
+ # # :Coercible, :Time]
17
+ #
18
+ # @api public
19
+ class Module < ::Module
20
+ def initialize(registry, *args, **kwargs)
21
+ @registry = registry
22
+ check_parameters(*args, **kwargs)
23
+ constants = type_constants(*args, **kwargs)
24
+ define_constants(constants)
25
+ extend(BuilderMethods)
26
+
27
+ if constants.key?(:Nominal)
28
+ singleton_class.define_method(:included) do |base|
29
+ super(base)
30
+ base.instance_exec(const_get(:Nominal, false)) do |nominal|
31
+ extend Dry::Core::Deprecations[:"dry-types"]
32
+ const_set(:Definition, nominal)
33
+ deprecate_constant(:Definition, message: "Nominal")
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ # @api private
40
+ # rubocop:disable Metrics/AbcSize
41
+ # rubocop:disable Metrics/PerceivedComplexity
42
+ def type_constants(*namespaces, default: Undefined, **aliases)
43
+ if namespaces.empty? && aliases.empty? && Undefined.equal?(default)
44
+ default_ns = :Strict
45
+ elsif Undefined.equal?(default)
46
+ default_ns = Undefined
47
+ else
48
+ default_ns = Types::Inflector.camelize(default).to_sym
49
+ end
50
+
51
+ tree = registry_tree
52
+
53
+ if namespaces.empty? && aliases.empty?
54
+ modules = tree.select { _2.is_a?(::Hash) }.map(&:first)
55
+ else
56
+ modules = (namespaces + aliases.keys).map { |n|
57
+ Types::Inflector.camelize(n).to_sym
58
+ }
59
+ end
60
+
61
+ tree.each_with_object({}) do |(key, value), constants|
62
+ if modules.include?(key)
63
+ name = aliases.fetch(Inflector.underscore(key).to_sym, key)
64
+ constants[name] = value
65
+ end
66
+
67
+ constants.update(value) if key == default_ns
68
+ end
69
+ end
70
+ # rubocop:enable Metrics/AbcSize
71
+ # rubocop:enable Metrics/PerceivedComplexity
72
+
73
+ # @api private
74
+ def registry_tree
75
+ @registry_tree ||= @registry.keys.each_with_object({}) { |key, tree|
76
+ type = @registry[key]
77
+ *modules, const_name = key.split(".").map { |part|
78
+ Types::Inflector.camelize(part).to_sym
79
+ }
80
+ next if modules.empty?
81
+
82
+ modules.reduce(tree) { |br, name| br[name] ||= {} }[const_name] = type
83
+ }.freeze
84
+ end
85
+
86
+ private
87
+
88
+ # @api private
89
+ def check_parameters(*namespaces, default: Undefined, **aliases)
90
+ referenced = namespaces.dup
91
+ referenced << default unless false.equal?(default) || Undefined.equal?(default)
92
+ referenced.concat(aliases.keys)
93
+
94
+ known = @registry.keys.map { |k|
95
+ ns, *path = k.split(".")
96
+ ns.to_sym unless path.empty?
97
+ }.compact.uniq
98
+
99
+ unknown = (referenced.uniq - known).first
100
+
101
+ if unknown
102
+ raise ::ArgumentError,
103
+ "#{unknown.inspect} is not a known type namespace. " \
104
+ "Supported options are #{known.map(&:inspect).join(", ")}"
105
+ end
106
+ end
107
+
108
+ # @api private
109
+ def define_constants(constants, mod = self)
110
+ constants.each do |name, value|
111
+ case value
112
+ when ::Hash
113
+ if mod.const_defined?(name, false)
114
+ define_constants(value, mod.const_get(name, false))
115
+ else
116
+ m = ::Module.new
117
+ mod.const_set(name, m)
118
+ define_constants(value, m)
119
+ end
120
+ else
121
+ mod.const_set(name, value)
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,201 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dry
4
+ module Types
5
+ # Nominal types define a primitive class and do not apply any constructors or constraints
6
+ #
7
+ # Use these types for annotations and the base for building more complex types on top of them.
8
+ #
9
+ # @api public
10
+ class Nominal
11
+ include Type
12
+ include Options
13
+ include Meta
14
+ include Builder
15
+ include Printable
16
+ include ::Dry::Equalizer(:primitive, :options, :meta, inspect: false, immutable: true)
17
+
18
+ # @return [Class]
19
+ attr_reader :primitive
20
+
21
+ # @return [String, nil]
22
+ attr_reader :namespace
23
+
24
+ # @param [Class] primitive
25
+ #
26
+ # @return [Type]
27
+ #
28
+ # @api private
29
+ def self.[](primitive)
30
+ if primitive == ::Array
31
+ Types::Array
32
+ elsif primitive == ::Hash
33
+ Types::Hash
34
+ else
35
+ self
36
+ end
37
+ end
38
+
39
+ ALWAYS = proc { true }
40
+
41
+ # @param [Type,Class] primitive
42
+ # @param [Hash] options
43
+ #
44
+ # @api private
45
+ def initialize(primitive, **options)
46
+ super
47
+ @primitive = primitive
48
+ @namespace = options[:namespace]
49
+ freeze
50
+ end
51
+
52
+ # @return [String]
53
+ #
54
+ # @api public
55
+ def name = primitive.name
56
+
57
+ # @return [false]
58
+ #
59
+ # @api public
60
+ def default? = false
61
+
62
+ # @return [false]
63
+ #
64
+ # @api public
65
+ def constrained? = false
66
+
67
+ # @return [false]
68
+ #
69
+ # @api public
70
+ def optional? = false
71
+
72
+ # @param [BasicObject] input
73
+ #
74
+ # @return [BasicObject]
75
+ #
76
+ # @api private
77
+ def call_unsafe(input) = input
78
+
79
+ # @param [BasicObject] input
80
+ #
81
+ # @return [BasicObject]
82
+ #
83
+ # @api private
84
+ def call_safe(input, &) = input
85
+
86
+ # @param [Object] input
87
+ #
88
+ # @yieldparam [Failure] failure
89
+ # @yieldreturn [Result]
90
+ #
91
+ # @return [Result,Logic::Result] when a block is not provided
92
+ # @return [nil] otherwise
93
+ #
94
+ # @api public
95
+ def try(input, &) = success(input)
96
+
97
+ # @param (see Dry::Types::Success#initialize)
98
+ #
99
+ # @return [Result::Success]
100
+ #
101
+ # @api public
102
+ def success(input) = Result::Success.new(input)
103
+
104
+ # @param (see Failure#initialize)
105
+ #
106
+ # @return [Result::Failure]
107
+ #
108
+ # @api public
109
+ def failure(input, error)
110
+ raise ::ArgumentError, "error must be a CoercionError" unless error.is_a?(CoercionError)
111
+
112
+ Result::Failure.new(input, error)
113
+ end
114
+
115
+ # Checks whether value is of a #primitive class
116
+ #
117
+ # @param [Object] value
118
+ #
119
+ # @return [Boolean]
120
+ #
121
+ # @api public
122
+ def primitive?(value) = value.is_a?(primitive)
123
+
124
+ # @api private
125
+ def coerce(input, &)
126
+ if primitive?(input)
127
+ input
128
+ elsif block_given?
129
+ yield
130
+ else
131
+ raise CoercionError, "#{input.inspect} must be an instance of #{primitive}"
132
+ end
133
+ end
134
+
135
+ # @api private
136
+ def try_coerce(input)
137
+ result = success(input)
138
+
139
+ coerce(input) do
140
+ result = failure(
141
+ input,
142
+ CoercionError.new("#{input.inspect} must be an instance of #{primitive}")
143
+ )
144
+ end
145
+
146
+ if block_given?
147
+ yield(result)
148
+ else
149
+ result
150
+ end
151
+ end
152
+
153
+ # Return AST representation of a type nominal
154
+ #
155
+ # @return [Array]
156
+ #
157
+ # @api public
158
+ def to_ast(meta: true)
159
+ [:nominal, [primitive, namespace_ast, meta_ast(meta)]]
160
+ end
161
+
162
+ # Return self. Nominal types are lax by definition
163
+ #
164
+ # @return [Nominal]
165
+ #
166
+ # @api public
167
+ def lax = self
168
+
169
+ # Wrap the type with a proc
170
+ #
171
+ # @return [Proc]
172
+ #
173
+ # @api public
174
+ def to_proc = ALWAYS
175
+
176
+ private
177
+
178
+ # @api private
179
+ def namespace_ast
180
+ if @namespace
181
+ {namespace: @namespace}
182
+ else
183
+ EMPTY_HASH
184
+ end
185
+ end
186
+
187
+ # @api private
188
+ def meta_ast(meta)
189
+ if meta
190
+ self.meta
191
+ else
192
+ EMPTY_HASH
193
+ end
194
+ end
195
+ end
196
+
197
+ extend ::Dry::Core::Deprecations[:"dry-types"]
198
+ Definition = Nominal
199
+ deprecate_constant(:Definition, message: "Nominal")
200
+ end
201
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dry
4
+ module Types
5
+ # Common API for types with options
6
+ #
7
+ # @api private
8
+ module Options
9
+ # @return [Hash]
10
+ attr_reader :options
11
+
12
+ # @see Nominal#initialize
13
+ #
14
+ # @api private
15
+ def initialize(*args, **options)
16
+ @__args__ = args.freeze
17
+ @options = options.freeze
18
+ end
19
+
20
+ # @param [Hash] new_options
21
+ #
22
+ # @return [Type]
23
+ #
24
+ # @api private
25
+ def with(**new_options)
26
+ if new_options.empty?
27
+ self
28
+ else
29
+ self.class.new(*@__args__, **options, **new_options)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/types/coercions/params"
4
+
5
+ module Dry
6
+ module Types
7
+ options = {namespace: "params"}
8
+
9
+ {
10
+ "nil" => :to_nil,
11
+ "date" => :to_date,
12
+ "date_time" => :to_date_time,
13
+ "time" => :to_time,
14
+ "true" => :to_true,
15
+ "false" => :to_false,
16
+ "integer" => :to_int,
17
+ "float" => :to_float,
18
+ "decimal" => :to_decimal,
19
+ "array" => :to_ary,
20
+ "hash" => :to_hash,
21
+ "symbol" => :to_symbol
22
+ }.each do |name, method|
23
+ register("params.#{name}") do
24
+ self["nominal.#{name}"].with(**options).constructor(Coercions::Params.method(method))
25
+ end
26
+ end
27
+
28
+ register("params.bool") do
29
+ self["params.true"] | self["params.false"]
30
+ end
31
+
32
+ register("params.string", self["string"].with(**options))
33
+
34
+ COERCIBLE.each_key do |name|
35
+ register("optional.params.#{name}", self["params.nil"] | self["params.#{name}"])
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,235 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dry
4
+ module Types
5
+ # PredicateInferrer returns the list of predicates used by a type.
6
+ #
7
+ # @api public
8
+ class PredicateInferrer
9
+ extend Core::Cache
10
+
11
+ TYPE_TO_PREDICATE = {
12
+ ::DateTime => :date_time?,
13
+ ::Date => :date?,
14
+ ::Time => :time?,
15
+ ::FalseClass => :false?,
16
+ ::Integer => :int?,
17
+ ::Float => :float?,
18
+ ::NilClass => :nil?,
19
+ ::String => :str?,
20
+ ::TrueClass => :true?,
21
+ ::BigDecimal => :decimal?,
22
+ ::Array => :array?
23
+ }.freeze
24
+
25
+ REDUCED_TYPES = {
26
+ [[[:true?], [:false?]]] => %i[bool?]
27
+ }.freeze
28
+
29
+ HASH = %i[hash?].freeze
30
+
31
+ ARRAY = %i[array?].freeze
32
+
33
+ NIL = %i[nil?].freeze
34
+
35
+ # Compiler reduces type AST into a list of predicates
36
+ #
37
+ # @api private
38
+ class Compiler
39
+ extend Core::ClassAttributes
40
+
41
+ defines :infer_predicate_by_class_name
42
+ infer_predicate_by_class_name nil
43
+
44
+ # @return [PredicateRegistry]
45
+ # @api private
46
+ attr_reader :registry
47
+
48
+ # @api private
49
+ def initialize(registry)
50
+ @registry = registry
51
+ end
52
+
53
+ # @api private
54
+ def infer_predicate(type) # rubocop:disable Metrics/PerceivedComplexity
55
+ pred = TYPE_TO_PREDICATE.fetch(type) do
56
+ if type.name.nil? || self.class.infer_predicate_by_class_name.equal?(false)
57
+ nil
58
+ else
59
+ candidate = :"#{type.name.split("::").last.downcase}?"
60
+
61
+ if registry.key?(candidate)
62
+ if self.class.infer_predicate_by_class_name
63
+ candidate
64
+ else
65
+ raise ::KeyError, <<~MESSAGE
66
+ Automatic predicate inferring from class names is deprecated
67
+ and will be removed in dry-types 2.0.
68
+ Use `Dry::Types::PredicateInferrer::Compiler.infer_predicate_by_class_name true`
69
+ to restore the previous behavior
70
+ or `Dry::Types::PredicateInferrer::Compiler.infer_predicate_by_class_name false`
71
+ to explicitly opt-out (i.e. no exception + no inferring).
72
+ Note: for dry-schema and dry-validation use Dry::Schema::PredicateInferrer::Compiler.
73
+ MESSAGE
74
+ end
75
+ else
76
+ nil
77
+ end
78
+ end
79
+ end
80
+
81
+ if pred.nil?
82
+ EMPTY_ARRAY
83
+ else
84
+ [pred]
85
+ end
86
+ end
87
+
88
+ # @api private
89
+ def visit(node)
90
+ meth, rest = node
91
+ public_send(:"visit_#{meth}", rest)
92
+ end
93
+
94
+ # @api private
95
+ def visit_nominal(node)
96
+ type = node[0]
97
+ predicate = infer_predicate(type)
98
+
99
+ if !predicate.empty? && registry.key?(predicate[0])
100
+ predicate
101
+ else
102
+ [type?: type]
103
+ end
104
+ end
105
+
106
+ # @api private
107
+ def visit_hash(_)
108
+ HASH
109
+ end
110
+ alias_method :visit_schema, :visit_hash
111
+
112
+ # @api private
113
+ def visit_array(_)
114
+ ARRAY
115
+ end
116
+
117
+ # @api private
118
+ def visit_lax(node)
119
+ visit(node)
120
+ end
121
+
122
+ # @api private
123
+ def visit_constructor(node)
124
+ other, * = node
125
+ visit(other)
126
+ end
127
+
128
+ # @api private
129
+ def visit_enum(node)
130
+ other, * = node
131
+ visit(other)
132
+ end
133
+
134
+ # @api private
135
+ def visit_sum(node)
136
+ left_node, right_node, = node
137
+ left = visit(left_node)
138
+ right = visit(right_node)
139
+
140
+ if left.eql?(NIL)
141
+ right
142
+ else
143
+ [[left, right]]
144
+ end
145
+ end
146
+
147
+ # @api private
148
+ def visit_constrained(node)
149
+ other, rules = node
150
+ predicates = visit(rules)
151
+
152
+ if predicates.empty?
153
+ visit(other)
154
+ else
155
+ [*visit(other), *merge_predicates(predicates)]
156
+ end
157
+ end
158
+
159
+ # @api private
160
+ def visit_any(_) = EMPTY_ARRAY
161
+
162
+ # @api private
163
+ def visit_and(node)
164
+ left, right = node
165
+ visit(left) + visit(right)
166
+ end
167
+
168
+ # @api private
169
+ def visit_predicate(node)
170
+ pred, args = node
171
+
172
+ if pred.equal?(:type?) || !registry.key?(pred)
173
+ EMPTY_ARRAY
174
+ else
175
+ *curried, _ = args
176
+ values = curried.map { |_, v| v }
177
+
178
+ if values.empty?
179
+ [pred]
180
+ else
181
+ [pred => values[0]]
182
+ end
183
+ end
184
+ end
185
+
186
+ # @api private
187
+ def visit_map(_node)
188
+ raise ::NotImplementedError, "map types are not supported yet"
189
+ end
190
+
191
+ private
192
+
193
+ # @api private
194
+ def merge_predicates(nodes)
195
+ preds, merged = nodes.each_with_object([[], {}]) do |predicate, (ps, h)|
196
+ if predicate.is_a?(::Hash)
197
+ h.update(predicate)
198
+ else
199
+ ps << predicate
200
+ end
201
+ end
202
+
203
+ merged.empty? ? preds : [*preds, merged]
204
+ end
205
+ end
206
+
207
+ # @return [Compiler]
208
+ # @api private
209
+ attr_reader :compiler
210
+
211
+ # @api private
212
+ def initialize(registry = PredicateRegistry.new)
213
+ @compiler = Compiler.new(registry)
214
+ end
215
+
216
+ # Infer predicate identifier from the provided type
217
+ #
218
+ # @param [Type] type
219
+ # @return [Symbol]
220
+ #
221
+ # @api private
222
+ def [](type)
223
+ self.class.fetch_or_store(type) do
224
+ predicates = compiler.visit(type.to_ast)
225
+
226
+ if predicates.is_a?(::Hash)
227
+ predicates
228
+ else
229
+ REDUCED_TYPES[predicates] || predicates
230
+ end
231
+ end
232
+ end
233
+ end
234
+ end
235
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dry
4
+ module Types
5
+ # A registry with predicate objects from `Dry::Logic::Predicates`
6
+ #
7
+ # @api private
8
+ class PredicateRegistry
9
+ # @api private
10
+ attr_reader :predicates
11
+
12
+ # @api private
13
+ attr_reader :has_predicate
14
+
15
+ KERNEL_RESPOND_TO = ::Kernel.instance_method(:respond_to?)
16
+ private_constant(:KERNEL_RESPOND_TO)
17
+
18
+ # @api private
19
+ def initialize(predicates = Logic::Predicates)
20
+ @predicates = predicates
21
+ end
22
+
23
+ # @api private
24
+ def key?(name)
25
+ KERNEL_RESPOND_TO.bind_call(@predicates, name)
26
+ end
27
+
28
+ # @api private
29
+ def [](name) = predicates[name]
30
+ end
31
+ end
32
+ end