dry-schema 0.2.0 → 0.3.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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +17 -0
  3. data/LICENSE +1 -1
  4. data/README.md +11 -2
  5. data/lib/dry-schema.rb +2 -0
  6. data/lib/dry/schema.rb +2 -0
  7. data/lib/dry/schema/compiler.rb +2 -0
  8. data/lib/dry/schema/config.rb +2 -0
  9. data/lib/dry/schema/constants.rb +4 -2
  10. data/lib/dry/schema/dsl.rb +5 -3
  11. data/lib/dry/schema/extensions.rb +2 -0
  12. data/lib/dry/schema/extensions/hints.rb +2 -0
  13. data/lib/dry/schema/extensions/hints/message_compiler_methods.rb +10 -3
  14. data/lib/dry/schema/extensions/hints/message_set_methods.rb +3 -1
  15. data/lib/dry/schema/extensions/hints/result_methods.rb +2 -0
  16. data/lib/dry/schema/extensions/monads.rb +3 -2
  17. data/lib/dry/schema/json.rb +3 -1
  18. data/lib/dry/schema/key.rb +3 -1
  19. data/lib/dry/schema/key_coercer.rb +2 -0
  20. data/lib/dry/schema/key_map.rb +3 -1
  21. data/lib/dry/schema/macros.rb +3 -0
  22. data/lib/dry/schema/macros/array.rb +27 -0
  23. data/lib/dry/schema/macros/core.rb +2 -0
  24. data/lib/dry/schema/macros/dsl.rb +3 -2
  25. data/lib/dry/schema/macros/each.rb +2 -0
  26. data/lib/dry/schema/macros/filled.rb +4 -2
  27. data/lib/dry/schema/macros/hash.rb +2 -0
  28. data/lib/dry/schema/macros/key.rb +7 -3
  29. data/lib/dry/schema/macros/maybe.rb +4 -2
  30. data/lib/dry/schema/macros/optional.rb +2 -0
  31. data/lib/dry/schema/macros/required.rb +2 -0
  32. data/lib/dry/schema/macros/schema.rb +2 -0
  33. data/lib/dry/schema/macros/value.rb +10 -3
  34. data/lib/dry/schema/message.rb +14 -0
  35. data/lib/dry/schema/message_compiler.rb +4 -2
  36. data/lib/dry/schema/message_compiler/visitor_opts.rb +2 -0
  37. data/lib/dry/schema/message_set.rb +2 -0
  38. data/lib/dry/schema/messages.rb +2 -0
  39. data/lib/dry/schema/messages/abstract.rb +5 -3
  40. data/lib/dry/schema/messages/i18n.rb +3 -1
  41. data/lib/dry/schema/messages/namespaced.rb +3 -1
  42. data/lib/dry/schema/messages/template.rb +3 -1
  43. data/lib/dry/schema/messages/yaml.rb +7 -3
  44. data/lib/dry/schema/namespaced_rule.rb +2 -0
  45. data/lib/dry/schema/params.rb +3 -1
  46. data/lib/dry/schema/path.rb +21 -2
  47. data/lib/dry/schema/predicate.rb +2 -0
  48. data/lib/dry/schema/predicate_inferrer.rb +69 -20
  49. data/lib/dry/schema/predicate_registry.rb +2 -0
  50. data/lib/dry/schema/processor.rb +11 -0
  51. data/lib/dry/schema/result.rb +3 -1
  52. data/lib/dry/schema/rule_applier.rb +2 -0
  53. data/lib/dry/schema/trace.rb +2 -0
  54. data/lib/dry/schema/type_registry.rb +3 -1
  55. data/lib/dry/schema/types.rb +2 -0
  56. data/lib/dry/schema/value_coercer.rb +2 -0
  57. data/lib/dry/schema/version.rb +3 -1
  58. metadata +24 -23
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bfbb04d5a9d9537294ec0e1d6fce172c2a6feb8a26ec13157ccc3f15120eee6f
4
- data.tar.gz: 1c85541e6b71d1d44fc6abeb99350ef51abf7f8e2279556055f8f66cbb9e2373
3
+ metadata.gz: 149b82a73e8cd4d31c55fe1cf2bee1a7ebfb2afd696677522293da435f0224b1
4
+ data.tar.gz: ca76ca603a34906e61cfbd075e9667c97ee191591520e89b8a5d2e949c124426
5
5
  SHA512:
6
- metadata.gz: c8b8b1023ed9256358d8ed96998be33070fe82c983e7d511e38f01d18da1fc1702ac2ea82f3fa02a83d9494d3822a3ce304662cc806ec6f4a16198d1db040444
7
- data.tar.gz: fe668ebfb35ecee7ddc41c34d77fbde0abb9d3c8e98c192657036e8503bbde708c72b783a9f5ae1e6b9a366bee26b2217c78b4652e17d88219b3c4edaa74d6b9
6
+ metadata.gz: 0b94f326035f884457e2b6ce84ed427d2ec31011529cb8c4a987ff8c26a1bf4b66581ccd1e14ebe91cd4a0efbd05c9c04be6c47cfe959fa0f08687515f02d364
7
+ data.tar.gz: 356ae43e85fc3afdc0e8abd2628c06315ce5ed97d3ec74c40a3a32dd73b1300851c0f1f8c674abb73d3d8723292dfe0bf370ec5f5fcf1fd7f21fc5a8eb16633c
data/CHANGELOG.md CHANGED
@@ -1,3 +1,20 @@
1
+ # 0.3.0 2018-03-04
2
+
3
+ ### Fixed
4
+
5
+ * Configuration is properly inherited from a parent schema (skryukov)
6
+ * `Result#error?` returns `true` when a preceding key has errors (solnic)
7
+ * Predicate inferrer no longer chokes on sum, constructor and enum types (solnic)
8
+ * Predicate inferrer infers `:bool?` from boolean types (solnic)
9
+ * Block-based definitions using `array` works correctly (solnic)
10
+ * Using a disjunction with `array` and `hash` produces correct errors when element validation for array failed (solnic)
11
+
12
+ ### Changed
13
+
14
+ * Required ruby version was removed from gemspec for people who are stuck on MRI 2.3.x (solnic)
15
+
16
+ [Compare v0.2.0...v0.3.0](https://github.com/dry-rb/dry-schema/compare/v0.2.0...v0.3.0)
17
+
1
18
  # 0.2.0 2019-02-26
2
19
 
3
20
  ### Added
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2015 Dryrb Team
3
+ Copyright (c) 2019 dry-rb team
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy of
6
6
  this software and associated documentation files (the "Software"), to deal in
data/README.md CHANGED
@@ -12,9 +12,18 @@
12
12
  [![Test Coverage](https://codeclimate.com/github/dry-rb/dry-schema/badges/coverage.svg)][codeclimate]
13
13
  [![Inline docs](http://inch-ci.org/github/dry-rb/dry-schema.svg?branch=master)][inchpages]
14
14
 
15
- <!-- ## Links
15
+ ## Links
16
16
 
17
- * [Documentation](http://dry-rb.org/gems/dry-schema) -->
17
+ * [Documentation](http://dry-rb.org/gems/dry-schema)
18
+
19
+ ## Supported Ruby versions
20
+
21
+ This library officially supports following Ruby versions:
22
+
23
+ * MRI >= `2.4`
24
+ * jruby >= `9.2`
25
+
26
+ It **should** work on MRI `2.3.x` too, but there's no official support for this version.
18
27
 
19
28
  ## License
20
29
 
data/lib/dry-schema.rb CHANGED
@@ -1 +1,3 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/schema'
data/lib/dry/schema.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/core/extensions'
2
4
 
3
5
  require 'dry/schema/constants'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/logic/rule_compiler'
2
4
  require 'dry/schema/namespaced_rule'
3
5
  require 'dry/schema/predicate_registry'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'delegate'
2
4
  require 'dry/configurable'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/core/constants'
2
4
 
3
5
  module Dry
@@ -7,7 +9,7 @@ module Dry
7
9
  InvalidSchemaError = Class.new(StandardError)
8
10
  MissingMessageError = Class.new(StandardError)
9
11
 
10
- QUESTION_MARK = '?'.freeze
11
- DOT = '.'.freeze
12
+ QUESTION_MARK = '?'
13
+ DOT = '.'
12
14
  end
13
15
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/initializer'
2
4
 
3
5
  require 'dry/schema/constants'
@@ -72,7 +74,7 @@ module Dry
72
74
 
73
75
  # @!attribute [r] config
74
76
  # @return [Config] Configuration object exposed via `#configure` method
75
- option :config, optional: true, default: -> { Config.new }
77
+ option :config, optional: true, default: proc { parent ? parent.config.dup : Config.new }
76
78
 
77
79
  # Build a new DSL object and evaluate provided block
78
80
  #
@@ -203,7 +205,7 @@ module Dry
203
205
  #
204
206
  # @api public
205
207
  def array
206
- -> member_type { type_registry["array"].of(resolve_type(member_type)) }
208
+ -> member_type { type_registry['array'].of(resolve_type(member_type)) }
207
209
  end
208
210
 
209
211
  # Return type schema used by the value coercer
@@ -212,7 +214,7 @@ module Dry
212
214
  #
213
215
  # @api private
214
216
  def type_schema
215
- type_registry["hash"].schema(types.merge(parent_types)).safe
217
+ type_registry['hash'].schema(types.merge(parent_types)).safe
216
218
  end
217
219
 
218
220
  # Return a new DSL instance using the same processor type
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  Dry::Schema.register_extension(:monads) do
2
4
  require 'dry/schema/extensions/monads'
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/schema/message'
2
4
  require 'dry/schema/message_compiler'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dry
2
4
  module Schema
3
5
  module Extensions
@@ -30,14 +32,19 @@ module Dry
30
32
  # @api private
31
33
  def exclude?(messages, opts)
32
34
  Array(messages).all? do |msg|
33
- hints = opts.hints.reject { |hint| msg == hint }.reject { |hint| hint.predicate == :filled? }
35
+ hints = opts
36
+ .hints
37
+ .reject { |hint| msg == hint }
38
+ .reject { |hint| hint.predicate == :filled? }
39
+
34
40
  key_failure = opts.key_failure?(msg.path)
35
41
  predicate = msg.predicate
36
42
 
37
43
  (HINT_TYPE_EXCLUSION.include?(predicate) && !key_failure) ||
38
44
  (msg.predicate == :filled? && key_failure) ||
39
- (!key_failure && HINT_TYPE_EXCLUSION.include?(predicate) && !hints.empty? && hints.any? { |hint| hint.path == msg.path }) ||
40
- HINT_OTHER_EXCLUSION.include?(predicate)
45
+ (!key_failure && HINT_TYPE_EXCLUSION.include?(predicate) &&
46
+ !hints.empty? && hints.any? { |hint| hint.path == msg.path }) ||
47
+ HINT_OTHER_EXCLUSION.include?(predicate)
41
48
  end
42
49
  end
43
50
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dry
2
4
  module Schema
3
5
  module Extensions
@@ -26,4 +28,4 @@ module Dry
26
28
  end
27
29
  end
28
30
  end
29
- end
31
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dry
2
4
  module Schema
3
5
  module Extensions
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/monads/result'
2
4
 
3
5
  module Dry
@@ -9,10 +11,9 @@ module Dry
9
11
  if success?
10
12
  Success(output)
11
13
  else
12
- Failure(messages(options))
14
+ Failure(message_set(options).dump)
13
15
  end
14
16
  end
15
- alias_method :to_result, :to_monad
16
17
  end
17
18
  end
18
19
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/schema/processor'
2
4
 
3
5
  module Dry
@@ -13,4 +15,4 @@ module Dry
13
15
  config.type_registry = config.type_registry.namespaced(:json)
14
16
  end
15
17
  end
16
- end
18
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dry
2
4
  module Schema
3
5
  # Key objects used by key maps
@@ -163,4 +165,4 @@ module Dry
163
165
  end
164
166
  end
165
167
  end
166
- end
168
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/core/cache'
2
4
  require 'dry/equalizer'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/equalizer'
2
4
  require 'dry/core/cache'
3
5
  require 'dry/schema/constants'
@@ -130,4 +132,4 @@ module Dry
130
132
  end
131
133
  end
132
134
  end
133
- end
135
+ end
@@ -1,3 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry/schema/macros/array'
1
4
  require 'dry/schema/macros/each'
2
5
  require 'dry/schema/macros/filled'
3
6
  require 'dry/schema/macros/schema'
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry/schema/macros/dsl'
4
+
5
+ module Dry
6
+ module Schema
7
+ module Macros
8
+ # Macro used to specify predicates for each element of an array
9
+ #
10
+ # @api public
11
+ class Array < DSL
12
+ # @api private
13
+ def value(*args, &block)
14
+ schema_dsl.set_type(name, :array)
15
+ super
16
+ end
17
+
18
+ # @api private
19
+ def to_ast(*)
20
+ [:and, [trace.array?.to_ast, [:each, trace.to_ast]]]
21
+ end
22
+
23
+ alias_method :ast, :to_ast
24
+ end
25
+ end
26
+ end
27
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/initializer'
2
4
 
3
5
  require 'dry/schema/constants'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/logic/operators'
2
4
 
3
5
  require 'dry/schema/macros/core'
@@ -68,8 +70,7 @@ module Dry
68
70
  #
69
71
  # @api public
70
72
  def array(*args, &block)
71
- value(:array)
72
- append_macro(Macros::Each) do |macro|
73
+ append_macro(Macros::Array) do |macro|
73
74
  macro.value(*args, &block)
74
75
  end
75
76
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/schema/macros/dsl'
2
4
 
3
5
  module Dry
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/schema/macros/value'
2
4
 
3
5
  module Dry
@@ -9,11 +11,11 @@ module Dry
9
11
  class Filled < Value
10
12
  def call(*predicates, **opts, &block)
11
13
  if predicates.include?(:empty?)
12
- raise ::Dry::Schema::InvalidSchemaError, "Using filled with empty? predicate is invalid"
14
+ raise ::Dry::Schema::InvalidSchemaError, 'Using filled with empty? predicate is invalid'
13
15
  end
14
16
 
15
17
  if predicates.include?(:filled?)
16
- raise ::Dry::Schema::InvalidSchemaError, "Using filled with filled? is redundant"
18
+ raise ::Dry::Schema::InvalidSchemaError, 'Using filled with filled? is redundant'
17
19
  end
18
20
 
19
21
  if opts[:type_spec].equal?(true)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/schema/macros/schema'
2
4
 
3
5
  module Dry
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/schema/predicate_inferrer'
2
4
  require 'dry/schema/processor'
3
5
  require 'dry/schema/macros/dsl'
@@ -104,9 +106,11 @@ module Dry
104
106
  def extract_type_spec(*args, nullable: false)
105
107
  type_spec = args[0]
106
108
 
107
- if type_spec.kind_of?(Dry::Schema::Processor) || type_spec.is_a?(Symbol) && type_spec.to_s.end_with?(QUESTION_MARK)
108
- type_spec = nil
109
- end
109
+ is_type_spec = type_spec.kind_of?(Dry::Schema::Processor) ||
110
+ type_spec.is_a?(Symbol) &&
111
+ type_spec.to_s.end_with?(QUESTION_MARK)
112
+
113
+ type_spec = nil if is_type_spec
110
114
 
111
115
  predicates = Array(type_spec ? args[1..-1] : args)
112
116
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/schema/macros/dsl'
2
4
 
3
5
  module Dry
@@ -10,11 +12,11 @@ module Dry
10
12
  # @api private
11
13
  def call(*args, **opts, &block)
12
14
  if args.include?(:empty?)
13
- raise ::Dry::Schema::InvalidSchemaError, "Using maybe with empty? predicate is invalid"
15
+ raise ::Dry::Schema::InvalidSchemaError, 'Using maybe with empty? predicate is invalid'
14
16
  end
15
17
 
16
18
  if args.include?(:nil?)
17
- raise ::Dry::Schema::InvalidSchemaError, "Using maybe with nil? predicate is redundant"
19
+ raise ::Dry::Schema::InvalidSchemaError, 'Using maybe with nil? predicate is redundant'
18
20
  end
19
21
 
20
22
  value(*args, **opts, &block)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/schema/macros/key'
2
4
 
3
5
  module Dry
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/schema/macros/key'
2
4
 
3
5
  module Dry
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/schema/macros/value'
2
4
 
3
5
  module Dry
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/schema/macros/dsl'
2
4
 
3
5
  module Dry
@@ -13,13 +15,18 @@ module Dry
13
15
 
14
16
  if schema
15
17
  current_type = schema_dsl.types[name]
16
- updated_type = current_type.respond_to?(:of) ? current_type.of(schema.type_schema) : schema.type_schema
18
+
19
+ updated_type =
20
+ if current_type.respond_to?(:of)
21
+ current_type.of(schema.type_schema)
22
+ else
23
+ schema.type_schema
24
+ end
17
25
 
18
26
  schema_dsl.set_type(name, updated_type)
19
27
  end
20
28
 
21
- trace.evaluate(*predicates, **opts, &block)
22
-
29
+ trace.evaluate(*predicates, **opts)
23
30
  trace.append(new(chain: false).instance_exec(&block)) if block
24
31
 
25
32
  if trace.captures.empty?
@@ -1,4 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/equalizer'
4
+ require 'dry/schema/path'
2
5
 
3
6
  module Dry
4
7
  module Schema
@@ -86,6 +89,17 @@ module Dry
86
89
  def eql?(other)
87
90
  other.is_a?(String) ? text == other : super
88
91
  end
92
+
93
+ def <=>(other)
94
+ l_path = Path[path]
95
+ r_path = Path[other.path]
96
+
97
+ unless l_path.include?(r_path)
98
+ raise ArgumentError, 'Cannot compare messages from different root paths'
99
+ end
100
+
101
+ l_path <=> r_path
102
+ end
89
103
  end
90
104
  end
91
105
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/schema/constants'
2
4
  require 'dry/schema/message'
3
5
  require 'dry/schema/message_set'
@@ -12,7 +14,7 @@ module Dry
12
14
  attr_reader :messages, :options, :locale, :default_lookup_options
13
15
 
14
16
  EMPTY_OPTS = VisitorOpts.new
15
- LIST_SEPARATOR = ', '.freeze
17
+ LIST_SEPARATOR = ', '
16
18
 
17
19
  # @api private
18
20
  def initialize(messages, options = {})
@@ -83,7 +85,7 @@ module Dry
83
85
  elsif right.is_a?(Array)
84
86
  right
85
87
  else
86
- [left, right]
88
+ [left, right].flatten.max
87
89
  end
88
90
  end
89
91
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/schema/constants'
2
4
  require 'dry/schema/message'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dry
2
4
  module Schema
3
5
  # A set of messages used to generate errors
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dry
2
4
  module Schema
3
5
  # An API for configuring message backends
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'pathname'
2
4
  require 'concurrent/map'
3
5
  require 'dry/equalizer'
@@ -19,7 +21,7 @@ module Dry
19
21
  DEFAULT_PATH = Pathname(__dir__).join('../../../../config/errors.yml').realpath.freeze
20
22
 
21
23
  setting :paths, [DEFAULT_PATH]
22
- setting :root, 'errors'.freeze
24
+ setting :root, 'errors'
23
25
  setting :lookup_options, [:root, :predicate, :path, :val_type, :arg_type].freeze
24
26
 
25
27
  setting :lookup_paths, %w(
@@ -38,8 +40,8 @@ module Dry
38
40
  rules.%{name}
39
41
  ).freeze
40
42
 
41
- setting :arg_type_default, 'default'.freeze
42
- setting :val_type_default, 'default'.freeze
43
+ setting :arg_type_default, 'default'
44
+ setting :val_type_default, 'default'
43
45
 
44
46
  setting :arg_types, Hash.new { |*| config.arg_type_default }.update(
45
47
  Range => 'range'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'i18n'
2
4
  require 'dry/schema/messages/abstract'
3
5
 
@@ -10,7 +12,7 @@ module Dry
10
12
  attr_reader :t
11
13
 
12
14
  configure do |config|
13
- config.root = 'dry_schema.errors'.freeze
15
+ config.root = 'dry_schema.errors'
14
16
  config.rule_lookup_paths = config.rule_lookup_paths.map { |path| "dry_schema.#{path}" }
15
17
  end
16
18
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dry
2
4
  module Schema
3
5
  module Messages
@@ -60,7 +62,7 @@ module Dry
60
62
 
61
63
  def rule_lookup_paths(tokens)
62
64
  base_paths = messages.rule_lookup_paths(tokens)
63
- base_paths.map { |key| key.gsub("dry_schema", "dry_schema.#{namespace}") } + base_paths
65
+ base_paths.map { |key| key.gsub('dry_schema', "dry_schema.#{namespace}") } + base_paths
64
66
  end
65
67
  end
66
68
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/equalizer'
2
4
 
3
5
  require 'dry/schema/constants'
@@ -63,4 +65,4 @@ module Dry
63
65
  end
64
66
  end
65
67
  end
66
- end
68
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'yaml'
2
4
  require 'pathname'
3
5
 
@@ -16,8 +18,10 @@ module Dry
16
18
 
17
19
  # @api private
18
20
  configure do |config|
19
- config.root = '%{locale}.dry_schema.errors'.freeze
20
- config.rule_lookup_paths = config.rule_lookup_paths.map { |path| "%{locale}.dry_schema.#{path}" }
21
+ config.root = '%{locale}.dry_schema.errors'
22
+ config.rule_lookup_paths = config.rule_lookup_paths.map { |path|
23
+ "%{locale}.dry_schema.#{path}"
24
+ }
21
25
  end
22
26
 
23
27
  # @api private
@@ -32,7 +36,7 @@ module Dry
32
36
 
33
37
  # @api private
34
38
  def self.flat_hash(h, f = [], g = {})
35
- return g.update(f.join('.'.freeze) => h) unless h.is_a? Hash
39
+ return g.update(f.join('.') => h) unless h.is_a? Hash
36
40
  h.each { |k, r| flat_hash(r, f + [k], g) }
37
41
  g
38
42
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dry
2
4
  module Schema
3
5
  class NamespacedRule
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/schema/processor'
2
4
 
3
5
  module Dry
@@ -13,4 +15,4 @@ module Dry
13
15
  config.type_registry = config.type_registry.namespaced(:params)
14
16
  end
15
17
  end
16
- end
18
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/schema/constants'
2
4
 
3
5
  module Dry
@@ -6,6 +8,8 @@ module Dry
6
8
  #
7
9
  # @api private
8
10
  class Path
11
+ include Enumerable
12
+
9
13
  # !@attribute [r] keys
10
14
  # @return [Array<Symbol>]
11
15
  attr_reader :keys
@@ -47,8 +51,23 @@ module Dry
47
51
  end
48
52
 
49
53
  # @api private
50
- def ==(other)
51
- keys == Path[other].keys
54
+ def each(&block)
55
+ keys.each(&block)
56
+ end
57
+
58
+ # @api private
59
+ def index(key)
60
+ keys.index(key)
61
+ end
62
+
63
+ # @api private
64
+ def include?(other)
65
+ !find { |key| (idx = other.index(key)) && keys[idx].equal?(key) }.nil?
66
+ end
67
+
68
+ # @api private
69
+ def <=>(other)
70
+ keys.count <=> other.count
52
71
  end
53
72
  end
54
73
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/equalizer'
2
4
  require 'dry/logic/operators'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/core/cache'
2
4
 
3
5
  module Dry
@@ -9,23 +11,71 @@ module Dry
9
11
  class PredicateInferrer
10
12
  extend Dry::Core::Cache
11
13
 
12
- TYPE_TO_PREDICATE = Hash.new do |hash, type|
13
- primitive = type.meta[:maybe] ? type.right.primitive : type.primitive
14
-
15
- if hash.key?(primitive)
16
- hash[primitive]
17
- else
18
- :"#{primitive.name.split('::').last.downcase}?"
19
- end
20
- end
21
-
22
- TYPE_TO_PREDICATE.update(
14
+ TYPE_TO_PREDICATE = {
23
15
  FalseClass => :false?,
24
16
  Integer => :int?,
25
17
  NilClass => :nil?,
26
18
  String => :str?,
27
19
  TrueClass => :true?
28
- ).freeze
20
+ }.freeze
21
+
22
+ REDUCED_TYPES = {
23
+ %i[true? false?] => :bool?
24
+ }.freeze
25
+
26
+ # Compiler reduces type AST into a list of predicates
27
+ #
28
+ # @api private
29
+ class Compiler
30
+ def visit(node)
31
+ meth, rest = node
32
+ public_send(:"visit_#{meth}", rest)
33
+ end
34
+
35
+ def visit_definition(node)
36
+ type = node[0]
37
+
38
+ TYPE_TO_PREDICATE.fetch(type) {
39
+ :"#{type.name.split('::').last.downcase}?"
40
+ }
41
+ end
42
+
43
+ def visit_array(*)
44
+ :array?
45
+ end
46
+
47
+ def visit_safe(node)
48
+ other, * = node
49
+ visit(other)
50
+ end
51
+
52
+ def visit_constructor(node)
53
+ other, * = node
54
+ visit(other)
55
+ end
56
+
57
+ def visit_enum(node)
58
+ other, * = node
59
+ visit(other)
60
+ end
61
+
62
+ def visit_sum(node)
63
+ left, right = node
64
+
65
+ predicates = [visit(left), visit(right)]
66
+
67
+ if predicates.first == :nil?
68
+ predicates[1..predicates.size - 1]
69
+ else
70
+ predicates
71
+ end
72
+ end
73
+
74
+ def visit_constrained(node)
75
+ other, * = node
76
+ visit(other)
77
+ end
78
+ end
29
79
 
30
80
  # Infer predicate identifier from the provided type
31
81
  #
@@ -34,16 +84,15 @@ module Dry
34
84
  # @api private
35
85
  def self.[](type)
36
86
  fetch_or_store(type.hash) {
37
- predicates =
38
- if type.is_a?(Dry::Types::Sum) && !type.meta[:maybe]
39
- [self[type.left], self[type.right]]
40
- else
41
- TYPE_TO_PREDICATE[type]
42
- end
43
-
44
- Array(predicates).flatten
87
+ predicates = Array(compiler.visit(type.to_ast)).flatten
88
+ Array(REDUCED_TYPES[predicates] || predicates).flatten
45
89
  }
46
90
  end
91
+
92
+ # @api private
93
+ def self.compiler
94
+ @compiler ||= Compiler.new
95
+ end
47
96
  end
48
97
  end
49
98
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/logic/predicates'
2
4
 
3
5
  module Dry
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/configurable'
2
4
  require 'dry/initializer'
3
5
 
@@ -113,6 +115,15 @@ module Dry
113
115
  @__type_schema__ ||= steps.detect { |s| s.is_a?(ValueCoercer) }.type_schema
114
116
  end
115
117
 
118
+ # Return the rules config
119
+ #
120
+ # @return [Dry::Types::Config]
121
+ #
122
+ # @api private
123
+ def config
124
+ @__config__ ||= steps.detect { |s| s.is_a?(RuleApplier) }.config
125
+ end
126
+
116
127
  # Return AST representation of the rules
117
128
  #
118
129
  # @api private
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/initializer'
2
4
  require 'dry/equalizer'
3
5
 
@@ -76,7 +78,7 @@ module Dry
76
78
  #
77
79
  # @api public
78
80
  def error?(spec)
79
- message_set.any? { |msg| Path[spec] == msg.path }
81
+ message_set.any? { |msg| Path[msg.path].include?(Path[spec]) }
80
82
  end
81
83
 
82
84
  # Check if the result is successful
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/initializer'
2
4
 
3
5
  require 'dry/schema/constants'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/schema/constants'
2
4
  require 'dry/schema/compiler'
3
5
  require 'dry/schema/predicate'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/schema/constants'
2
4
  require 'dry/schema/types'
3
5
 
@@ -39,4 +41,4 @@ module Dry
39
41
  end
40
42
  end
41
43
  end
42
- end
44
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/types'
2
4
 
3
5
  module Dry
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry/equalizer'
2
4
  require 'dry/initializer'
3
5
 
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dry
2
4
  module Schema
3
- VERSION = '0.2.0'.freeze
5
+ VERSION = '0.3.0'
4
6
  end
5
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dry-schema
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Solnica
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-02-26 00:00:00.000000000 Z
11
+ date: 2019-03-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -44,6 +44,26 @@ dependencies:
44
44
  - - ">="
45
45
  - !ruby/object:Gem::Version
46
46
  version: 0.1.3
47
+ - !ruby/object:Gem::Dependency
48
+ name: dry-core
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '0.2'
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: 0.2.1
57
+ type: :runtime
58
+ prerelease: false
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - "~>"
62
+ - !ruby/object:Gem::Version
63
+ version: '0.2'
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: 0.2.1
47
67
  - !ruby/object:Gem::Dependency
48
68
  name: dry-equalizer
49
69
  requirement: !ruby/object:Gem::Requirement
@@ -112,26 +132,6 @@ dependencies:
112
132
  - - "~>"
113
133
  - !ruby/object:Gem::Version
114
134
  version: '0.14'
115
- - !ruby/object:Gem::Dependency
116
- name: dry-core
117
- requirement: !ruby/object:Gem::Requirement
118
- requirements:
119
- - - "~>"
120
- - !ruby/object:Gem::Version
121
- version: '0.2'
122
- - - ">="
123
- - !ruby/object:Gem::Version
124
- version: 0.2.1
125
- type: :runtime
126
- prerelease: false
127
- version_requirements: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - "~>"
130
- - !ruby/object:Gem::Version
131
- version: '0.2'
132
- - - ">="
133
- - !ruby/object:Gem::Version
134
- version: 0.2.1
135
135
  - !ruby/object:Gem::Dependency
136
136
  name: bundler
137
137
  requirement: !ruby/object:Gem::Requirement
@@ -202,6 +202,7 @@ files:
202
202
  - lib/dry/schema/key_coercer.rb
203
203
  - lib/dry/schema/key_map.rb
204
204
  - lib/dry/schema/macros.rb
205
+ - lib/dry/schema/macros/array.rb
205
206
  - lib/dry/schema/macros/core.rb
206
207
  - lib/dry/schema/macros/dsl.rb
207
208
  - lib/dry/schema/macros/each.rb
@@ -249,7 +250,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
249
250
  requirements:
250
251
  - - ">="
251
252
  - !ruby/object:Gem::Version
252
- version: '2.4'
253
+ version: '2.3'
253
254
  required_rubygems_version: !ruby/object:Gem::Requirement
254
255
  requirements:
255
256
  - - ">="