dry-schema 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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
  - - ">="