dry-schema 1.4.3 → 1.5.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +170 -97
- data/config/errors.yml +4 -0
- data/dry-schema.gemspec +46 -0
- data/lib/dry-schema.rb +1 -1
- data/lib/dry/schema.rb +19 -6
- data/lib/dry/schema/compiler.rb +4 -4
- data/lib/dry/schema/config.rb +15 -6
- data/lib/dry/schema/constants.rb +16 -7
- data/lib/dry/schema/dsl.rb +88 -27
- data/lib/dry/schema/extensions.rb +10 -2
- data/lib/dry/schema/extensions/hints.rb +15 -8
- data/lib/dry/schema/extensions/hints/message_compiler_methods.rb +1 -1
- data/lib/dry/schema/extensions/hints/message_set_methods.rb +0 -47
- data/lib/dry/schema/extensions/info.rb +27 -0
- data/lib/dry/schema/extensions/info/schema_compiler.rb +105 -0
- data/lib/dry/schema/extensions/monads.rb +1 -1
- data/lib/dry/schema/extensions/struct.rb +32 -0
- data/lib/dry/schema/json.rb +1 -1
- data/lib/dry/schema/key.rb +16 -1
- data/lib/dry/schema/key_coercer.rb +4 -4
- data/lib/dry/schema/key_map.rb +9 -4
- data/lib/dry/schema/key_validator.rb +66 -0
- data/lib/dry/schema/macros.rb +8 -8
- data/lib/dry/schema/macros/array.rb +17 -4
- data/lib/dry/schema/macros/core.rb +9 -4
- data/lib/dry/schema/macros/dsl.rb +34 -19
- data/lib/dry/schema/macros/each.rb +4 -4
- data/lib/dry/schema/macros/filled.rb +5 -5
- data/lib/dry/schema/macros/hash.rb +21 -3
- data/lib/dry/schema/macros/key.rb +9 -9
- data/lib/dry/schema/macros/maybe.rb +3 -3
- data/lib/dry/schema/macros/optional.rb +1 -1
- data/lib/dry/schema/macros/required.rb +1 -1
- data/lib/dry/schema/macros/schema.rb +23 -2
- data/lib/dry/schema/macros/value.rb +32 -10
- data/lib/dry/schema/message.rb +35 -9
- data/lib/dry/schema/message/or.rb +18 -39
- data/lib/dry/schema/message/or/abstract.rb +28 -0
- data/lib/dry/schema/message/or/multi_path.rb +37 -0
- data/lib/dry/schema/message/or/single_path.rb +64 -0
- data/lib/dry/schema/message_compiler.rb +37 -17
- data/lib/dry/schema/message_compiler/visitor_opts.rb +2 -2
- data/lib/dry/schema/message_set.rb +25 -36
- data/lib/dry/schema/messages.rb +6 -6
- data/lib/dry/schema/messages/abstract.rb +54 -56
- data/lib/dry/schema/messages/i18n.rb +29 -27
- data/lib/dry/schema/messages/namespaced.rb +12 -2
- data/lib/dry/schema/messages/template.rb +19 -44
- data/lib/dry/schema/messages/yaml.rb +60 -13
- data/lib/dry/schema/params.rb +1 -1
- data/lib/dry/schema/path.rb +44 -5
- data/lib/dry/schema/predicate.rb +2 -2
- data/lib/dry/schema/predicate_inferrer.rb +4 -184
- data/lib/dry/schema/predicate_registry.rb +2 -2
- data/lib/dry/schema/primitive_inferrer.rb +16 -0
- data/lib/dry/schema/processor.rb +49 -28
- data/lib/dry/schema/processor_steps.rb +50 -27
- data/lib/dry/schema/result.rb +43 -5
- data/lib/dry/schema/rule_applier.rb +8 -7
- data/lib/dry/schema/step.rb +79 -0
- data/lib/dry/schema/trace.rb +5 -4
- data/lib/dry/schema/type_container.rb +3 -3
- data/lib/dry/schema/type_registry.rb +2 -2
- data/lib/dry/schema/types.rb +1 -1
- data/lib/dry/schema/value_coercer.rb +2 -2
- data/lib/dry/schema/version.rb +1 -1
- metadata +22 -8
data/config/errors.yml
CHANGED
@@ -3,6 +3,8 @@ en:
|
|
3
3
|
or: "or"
|
4
4
|
|
5
5
|
errors:
|
6
|
+
unexpected_key: "is not allowed"
|
7
|
+
|
6
8
|
array?: "must be an array"
|
7
9
|
|
8
10
|
empty?: "must be empty"
|
@@ -101,5 +103,7 @@ en:
|
|
101
103
|
default: "must be %{size} bytes long"
|
102
104
|
range: "must be within %{size_left} - %{size_right} bytes long"
|
103
105
|
|
106
|
+
uuid_v4?: "is not a valid UUID"
|
107
|
+
|
104
108
|
not:
|
105
109
|
empty?: "cannot be empty"
|
data/dry-schema.gemspec
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# this file is managed by dry-rb/devtools project
|
3
|
+
|
4
|
+
lib = File.expand_path('lib', __dir__)
|
5
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
6
|
+
require 'dry/schema/version'
|
7
|
+
|
8
|
+
Gem::Specification.new do |spec|
|
9
|
+
spec.name = 'dry-schema'
|
10
|
+
spec.authors = ["Piotr Solnica"]
|
11
|
+
spec.email = ["piotr.solnica@gmail.com"]
|
12
|
+
spec.license = 'MIT'
|
13
|
+
spec.version = Dry::Schema::VERSION.dup
|
14
|
+
|
15
|
+
spec.summary = "Coercion and validation for data structures"
|
16
|
+
spec.description = <<~TEXT
|
17
|
+
dry-schema provides a DSL for defining schemas with keys and rules that should be applied to
|
18
|
+
values. It supports coercion, input sanitization, custom types and localized error messages
|
19
|
+
(with or without I18n gem). It's also used as the schema engine in dry-validation.
|
20
|
+
TEXT
|
21
|
+
spec.homepage = 'https://dry-rb.org/gems/dry-schema'
|
22
|
+
spec.files = Dir["CHANGELOG.md", "LICENSE", "README.md", "dry-schema.gemspec", "lib/**/*", "config/*.yml"]
|
23
|
+
spec.bindir = 'bin'
|
24
|
+
spec.executables = []
|
25
|
+
spec.require_paths = ['lib']
|
26
|
+
|
27
|
+
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
28
|
+
spec.metadata['changelog_uri'] = 'https://github.com/dry-rb/dry-schema/blob/master/CHANGELOG.md'
|
29
|
+
spec.metadata['source_code_uri'] = 'https://github.com/dry-rb/dry-schema'
|
30
|
+
spec.metadata['bug_tracker_uri'] = 'https://github.com/dry-rb/dry-schema/issues'
|
31
|
+
|
32
|
+
spec.required_ruby_version = ">= 2.4.0"
|
33
|
+
|
34
|
+
# to update dependencies edit project.yml
|
35
|
+
spec.add_runtime_dependency "concurrent-ruby", "~> 1.0"
|
36
|
+
spec.add_runtime_dependency "dry-configurable", "~> 0.8", ">= 0.8.3"
|
37
|
+
spec.add_runtime_dependency "dry-core", "~> 0.4"
|
38
|
+
spec.add_runtime_dependency "dry-equalizer", "~> 0.2"
|
39
|
+
spec.add_runtime_dependency "dry-initializer", "~> 3.0"
|
40
|
+
spec.add_runtime_dependency "dry-logic", "~> 1.0"
|
41
|
+
spec.add_runtime_dependency "dry-types", "~> 1.4"
|
42
|
+
|
43
|
+
spec.add_development_dependency "bundler"
|
44
|
+
spec.add_development_dependency "rake"
|
45
|
+
spec.add_development_dependency "rspec"
|
46
|
+
end
|
data/lib/dry-schema.rb
CHANGED
data/lib/dry/schema.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "dry/core/extensions"
|
4
4
|
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
5
|
+
require "dry/schema/config"
|
6
|
+
require "dry/schema/constants"
|
7
|
+
require "dry/schema/dsl"
|
8
|
+
require "dry/schema/params"
|
9
|
+
require "dry/schema/json"
|
9
10
|
|
10
11
|
module Dry
|
11
12
|
# Main interface
|
@@ -14,6 +15,18 @@ module Dry
|
|
14
15
|
module Schema
|
15
16
|
extend Dry::Core::Extensions
|
16
17
|
|
18
|
+
# Configuration
|
19
|
+
#
|
20
|
+
# @example
|
21
|
+
# Dry::Schema.config.messages.backend = :i18n
|
22
|
+
#
|
23
|
+
# @return [Config]
|
24
|
+
#
|
25
|
+
# @api public
|
26
|
+
def self.config
|
27
|
+
@config ||= Config.new
|
28
|
+
end
|
29
|
+
|
17
30
|
# Define a schema
|
18
31
|
#
|
19
32
|
# @example
|
@@ -74,4 +87,4 @@ module Dry
|
|
74
87
|
end
|
75
88
|
end
|
76
89
|
|
77
|
-
require
|
90
|
+
require "dry/schema/extensions"
|
data/lib/dry/schema/compiler.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
3
|
+
require "dry/logic/rule_compiler"
|
4
|
+
require "dry/schema/namespaced_rule"
|
5
|
+
require "dry/schema/predicate_registry"
|
6
6
|
|
7
7
|
module Dry
|
8
8
|
module Schema
|
@@ -35,7 +35,7 @@ module Dry
|
|
35
35
|
# @return [NamespacedRule]
|
36
36
|
#
|
37
37
|
# @api private
|
38
|
-
def visit_namespace(node,
|
38
|
+
def visit_namespace(node, _opts = EMPTY_HASH)
|
39
39
|
namespace, rest = node
|
40
40
|
NamespacedRule.new(namespace, visit(rest))
|
41
41
|
end
|
data/lib/dry/schema/config.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "dry/equalizer"
|
4
|
+
require "dry/configurable"
|
5
5
|
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
6
|
+
require "dry/schema/constants"
|
7
|
+
require "dry/schema/predicate_registry"
|
8
|
+
require "dry/schema/type_container"
|
9
9
|
|
10
10
|
module Dry
|
11
11
|
module Schema
|
@@ -51,6 +51,15 @@ module Dry
|
|
51
51
|
setting(:default_locale, nil)
|
52
52
|
end
|
53
53
|
|
54
|
+
# @!method validate_keys
|
55
|
+
#
|
56
|
+
# On/off switch for key validator
|
57
|
+
#
|
58
|
+
# @return [Boolean]
|
59
|
+
#
|
60
|
+
# @api public
|
61
|
+
setting(:validate_keys, false)
|
62
|
+
|
54
63
|
# @api private
|
55
64
|
def respond_to_missing?(meth, include_private = false)
|
56
65
|
super || config.respond_to?(meth, include_private)
|
@@ -58,7 +67,7 @@ module Dry
|
|
58
67
|
|
59
68
|
# @api private
|
60
69
|
def inspect
|
61
|
-
"#<#{self.class} #{to_h.map { |k, v| ["#{k}=", v.inspect] }.map(&:join).join(
|
70
|
+
"#<#{self.class} #{to_h.map { |k, v| ["#{k}=", v.inspect] }.map(&:join).join(" ")}>"
|
62
71
|
end
|
63
72
|
|
64
73
|
private
|
data/lib/dry/schema/constants.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "pathname"
|
4
|
+
require "dry/core/constants"
|
5
5
|
|
6
6
|
module Dry
|
7
7
|
# Common constants used across the library
|
@@ -10,15 +10,24 @@ module Dry
|
|
10
10
|
module Schema
|
11
11
|
include Core::Constants
|
12
12
|
|
13
|
-
LIST_SEPARATOR =
|
14
|
-
QUESTION_MARK =
|
15
|
-
DOT =
|
13
|
+
LIST_SEPARATOR = ", "
|
14
|
+
QUESTION_MARK = "?"
|
15
|
+
DOT = "."
|
16
|
+
|
17
|
+
# core processor steps in the default execution order
|
18
|
+
STEPS_IN_ORDER = %i[
|
19
|
+
key_validator
|
20
|
+
key_coercer
|
21
|
+
filter_schema
|
22
|
+
value_coercer
|
23
|
+
rule_applier
|
24
|
+
].freeze
|
16
25
|
|
17
26
|
# Path to the default set of localized messages bundled within the gem
|
18
|
-
DEFAULT_MESSAGES_PATH = Pathname(__dir__).join(
|
27
|
+
DEFAULT_MESSAGES_PATH = Pathname(__dir__).join("../../../config/errors.yml").realpath.freeze
|
19
28
|
|
20
29
|
# Default namespace used for localized messages in YAML files
|
21
|
-
DEFAULT_MESSAGES_ROOT =
|
30
|
+
DEFAULT_MESSAGES_ROOT = "dry_schema"
|
22
31
|
|
23
32
|
# An error raised when DSL is used in an incorrect way
|
24
33
|
InvalidSchemaError = Class.new(StandardError)
|
data/lib/dry/schema/dsl.rb
CHANGED
@@ -1,19 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
|
11
|
-
require
|
12
|
-
|
13
|
-
require
|
14
|
-
require
|
15
|
-
require
|
16
|
-
require
|
3
|
+
require "dry/initializer"
|
4
|
+
|
5
|
+
require "dry/schema"
|
6
|
+
require "dry/schema/constants"
|
7
|
+
require "dry/schema/path"
|
8
|
+
require "dry/schema/config"
|
9
|
+
require "dry/schema/compiler"
|
10
|
+
require "dry/schema/types"
|
11
|
+
require "dry/schema/macros"
|
12
|
+
|
13
|
+
require "dry/schema/processor"
|
14
|
+
require "dry/schema/processor_steps"
|
15
|
+
require "dry/schema/key_map"
|
16
|
+
require "dry/schema/key_coercer"
|
17
|
+
require "dry/schema/key_validator"
|
18
|
+
require "dry/schema/value_coercer"
|
19
|
+
require "dry/schema/rule_applier"
|
17
20
|
|
18
21
|
module Dry
|
19
22
|
module Schema
|
@@ -67,10 +70,13 @@ module Dry
|
|
67
70
|
option :parent, Types::Coercible::Array, default: -> { EMPTY_ARRAY.dup }, as: :parents
|
68
71
|
|
69
72
|
# @return [Config] Configuration object exposed via `#configure` method
|
70
|
-
option :config, optional: true, default: proc {
|
73
|
+
option :config, optional: true, default: proc { default_config }
|
71
74
|
|
72
75
|
# @return [ProcessorSteps] Steps for the processor
|
73
|
-
option :steps, default: proc {
|
76
|
+
option :steps, default: proc { ProcessorSteps.new }
|
77
|
+
|
78
|
+
# @return [Path, Array] Path under which the schema is defined
|
79
|
+
option :path, -> *args { Path[*args] if args.any? }, default: proc { EMPTY_ARRAY }
|
74
80
|
|
75
81
|
# Build a new DSL object and evaluate provided block
|
76
82
|
#
|
@@ -171,7 +177,7 @@ module Dry
|
|
171
177
|
def key(name, macro:, &block)
|
172
178
|
raise ArgumentError, "Key +#{name}+ is not a symbol" unless name.is_a?(::Symbol)
|
173
179
|
|
174
|
-
set_type(name, Types::Any)
|
180
|
+
set_type(name, Types::Any.meta(default: true))
|
175
181
|
|
176
182
|
macro = macro.new(
|
177
183
|
name: name,
|
@@ -191,12 +197,31 @@ module Dry
|
|
191
197
|
#
|
192
198
|
# @api private
|
193
199
|
def call
|
194
|
-
steps[
|
195
|
-
|
196
|
-
|
197
|
-
|
200
|
+
all_steps = parents.map(&:steps) + [steps]
|
201
|
+
|
202
|
+
result_steps = all_steps.inject { |result, steps| result.merge(steps) }
|
203
|
+
|
204
|
+
result_steps[:key_validator] = key_validator if config.validate_keys
|
205
|
+
result_steps[:key_coercer] = key_coercer
|
206
|
+
result_steps[:value_coercer] = value_coercer
|
207
|
+
result_steps[:rule_applier] = rule_applier
|
208
|
+
result_steps[:filter_schema] = filter_schema.rule_applier if filter_rules?
|
209
|
+
|
210
|
+
processor_type.new(schema_dsl: self, steps: result_steps)
|
211
|
+
end
|
198
212
|
|
199
|
-
|
213
|
+
# Merge with another dsl
|
214
|
+
#
|
215
|
+
# @return [DSL]
|
216
|
+
#
|
217
|
+
# @api private
|
218
|
+
def merge(other)
|
219
|
+
new(
|
220
|
+
parent: parents + other.parents,
|
221
|
+
macros: macros + other.macros,
|
222
|
+
types: types.merge(other.types),
|
223
|
+
steps: steps.merge(other.steps)
|
224
|
+
)
|
200
225
|
end
|
201
226
|
|
202
227
|
# Cast this DSL into a rule object
|
@@ -215,7 +240,7 @@ module Dry
|
|
215
240
|
#
|
216
241
|
# @api public
|
217
242
|
def array
|
218
|
-
-> member_type { type_registry[
|
243
|
+
-> member_type { type_registry["array"].of(resolve_type(member_type)) }
|
219
244
|
end
|
220
245
|
|
221
246
|
# Method allows steps injection to the processor
|
@@ -263,7 +288,7 @@ module Dry
|
|
263
288
|
#
|
264
289
|
# @api private
|
265
290
|
def type_schema
|
266
|
-
our_schema = type_registry[
|
291
|
+
our_schema = type_registry["hash"].schema(types).lax
|
267
292
|
schemas = [*parents.map(&:type_schema), our_schema]
|
268
293
|
schemas.inject { |result, schema| result.schema(schema.to_a) }
|
269
294
|
end
|
@@ -287,11 +312,20 @@ module Dry
|
|
287
312
|
# @api private
|
288
313
|
def set_type(name, spec)
|
289
314
|
type = resolve_type(spec)
|
290
|
-
meta = {
|
315
|
+
meta = {required: false, maybe: type.optional?}
|
291
316
|
|
292
317
|
types[name] = type.meta(meta)
|
293
318
|
end
|
294
319
|
|
320
|
+
# Check if a custom type was set under provided key name
|
321
|
+
#
|
322
|
+
# @return [Bool]
|
323
|
+
#
|
324
|
+
# @api private
|
325
|
+
def custom_type?(name)
|
326
|
+
!types[name].meta[:default].equal?(true)
|
327
|
+
end
|
328
|
+
|
295
329
|
# Resolve type object from the provided spec
|
296
330
|
#
|
297
331
|
# @param [Symbol, Array<Symbol>, Dry::Types::Type] spec
|
@@ -326,7 +360,7 @@ module Dry
|
|
326
360
|
#
|
327
361
|
# @api private
|
328
362
|
def filter_rules?
|
329
|
-
if instance_variable_defined?(
|
363
|
+
if instance_variable_defined?("@filter_schema_dsl") && !filter_schema_dsl.macros.empty?
|
330
364
|
return true
|
331
365
|
end
|
332
366
|
|
@@ -374,6 +408,15 @@ module Dry
|
|
374
408
|
parents.select(&:filter_rules?).map(&:filter_schema)
|
375
409
|
end
|
376
410
|
|
411
|
+
# Build a key validator
|
412
|
+
#
|
413
|
+
# @return [KeyValidator]
|
414
|
+
#
|
415
|
+
# @api private
|
416
|
+
def key_validator
|
417
|
+
KeyValidator.new(key_map: key_map + parent_key_map)
|
418
|
+
end
|
419
|
+
|
377
420
|
# Build a key coercer
|
378
421
|
#
|
379
422
|
# @return [KeyCoercer]
|
@@ -411,13 +454,19 @@ module Dry
|
|
411
454
|
|
412
455
|
# Build a key spec needed by the key map
|
413
456
|
#
|
457
|
+
# TODO: we need a key-map compiler using Types AST
|
458
|
+
#
|
414
459
|
# @api private
|
415
460
|
def key_spec(name, type)
|
416
461
|
if type.respond_to?(:keys)
|
417
|
-
{
|
462
|
+
{name => key_map(type.name_key_map)}
|
418
463
|
elsif type.respond_to?(:member)
|
419
464
|
kv = key_spec(name, type.member)
|
420
465
|
kv.equal?(name) ? name : kv.flatten(1)
|
466
|
+
elsif type.meta[:maybe] && type.respond_to?(:right)
|
467
|
+
key_spec(name, type.right)
|
468
|
+
elsif type.respond_to?(:type)
|
469
|
+
key_spec(name, type.type)
|
421
470
|
else
|
422
471
|
name
|
423
472
|
end
|
@@ -432,6 +481,18 @@ module Dry
|
|
432
481
|
def parent_key_map
|
433
482
|
parents.reduce([]) { |key_map, parent| parent.key_map + key_map }
|
434
483
|
end
|
484
|
+
|
485
|
+
# @api private
|
486
|
+
def default_config
|
487
|
+
parents.each_cons(2) do |left, right|
|
488
|
+
unless left.config == right.config
|
489
|
+
raise ArgumentError,
|
490
|
+
"Parent configs differ, left=#{left.inspect}, right=#{right.inspect}"
|
491
|
+
end
|
492
|
+
end
|
493
|
+
|
494
|
+
(parent || Schema).config.dup
|
495
|
+
end
|
435
496
|
end
|
436
497
|
end
|
437
498
|
end
|
@@ -1,9 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
Dry::Schema.register_extension(:monads) do
|
4
|
-
require
|
4
|
+
require "dry/schema/extensions/monads"
|
5
5
|
end
|
6
6
|
|
7
7
|
Dry::Schema.register_extension(:hints) do
|
8
|
-
require
|
8
|
+
require "dry/schema/extensions/hints"
|
9
|
+
end
|
10
|
+
|
11
|
+
Dry::Schema.register_extension(:struct) do
|
12
|
+
require "dry/schema/extensions/struct"
|
13
|
+
end
|
14
|
+
|
15
|
+
Dry::Schema.register_extension(:info) do
|
16
|
+
require "dry/schema/extensions/info"
|
9
17
|
end
|
@@ -1,13 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
3
|
+
require "dry/schema/compiler"
|
4
|
+
require "dry/schema/message"
|
5
|
+
require "dry/schema/message_compiler"
|
6
6
|
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
7
|
+
require "dry/schema/extensions/hints/compiler_methods"
|
8
|
+
require "dry/schema/extensions/hints/message_compiler_methods"
|
9
|
+
require "dry/schema/extensions/hints/message_set_methods"
|
10
|
+
require "dry/schema/extensions/hints/result_methods"
|
11
11
|
|
12
12
|
module Dry
|
13
13
|
module Schema
|
@@ -22,7 +22,14 @@ module Dry
|
|
22
22
|
# @see Message::Or
|
23
23
|
#
|
24
24
|
# @api public
|
25
|
-
class Or
|
25
|
+
class Or::SinglePath
|
26
|
+
# @api private
|
27
|
+
def hint?
|
28
|
+
false
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class Or::MultiPath
|
26
33
|
# @api private
|
27
34
|
def hint?
|
28
35
|
false
|