definition 0.7.1 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b16eba88381d8ea5594b51e4855b3ca4f0684196bf552f5498a5eb43f67458bd
4
- data.tar.gz: 238611bb117e46b6701fae5d6236b66ab9754424dd88a6363dd091601ee2b249
3
+ metadata.gz: 9e79beba1853328e9b03847f3b8f9b3a088d381965cba2fd1ccedd283b57bd0c
4
+ data.tar.gz: b0835b29633b6887e39bbb6b6d34146c6870a13ab82415492e70050a9727831c
5
5
  SHA512:
6
- metadata.gz: e4a1d3d64e85ba1a43356adf08413a6469d8f0f59acf35f395c43adc44320557e562a90b54c49f51236664ce94201f65b18a8e9c288edb709cf3ab85102dc12c
7
- data.tar.gz: 3e753b50686933ddb0c83afbcd394ce0a98b5f16fe9cee7799df94f3b968489f6e0828332b01f4c444ccc86ca575f3af27e6b35a34f391306c5328f721ee2906
6
+ metadata.gz: ca5aae1db840f6ee3b45fd59cf8698a66a83a5d40d7f5f06be1413c0ce40ee979932382e4e3c866423faffda6a113f6f926053b84a76bd5986ba68eb37cda2f8
7
+ data.tar.gz: 86c2aad58a186b58f71f43f4e5a137ced0e2f472d1ee5bcd970045b76e252fa6ef2b258e005d9ffa169b0cbe7dea028d6e4ec3cda21dd38d4e23dc337e3ad330
data/.gitignore CHANGED
@@ -10,3 +10,4 @@
10
10
  *.swp
11
11
  .approvals
12
12
  spec/examples.txt
13
+ tags
data/Changelog.md CHANGED
@@ -6,6 +6,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## Unreleased
8
8
 
9
+ ## [0.8.0] - 2022-10-05
10
+ ### Added
11
+ - A Definition::Initializer mixin that can be used to validate keyword arguments of a class constructor
12
+
13
+ ### Changes
14
+ - Include more information in the internal non-translated error messages. E.g. the max size of a LessThenEqual definition
15
+ - Renamed GreaterThen, GreaterThenEqual, LessThen and LessThenEqual to fix typo (Then VS Than) Backwards compatibility is ensured
16
+
17
+ ### Breaking changes
18
+ - The Definition::ValueObject was removed and replaced by Definition:Model which has a nicer DSL and only works with hash data structures. See [upgrade notes](./UpgradeNotes.md)
19
+
9
20
  ## [0.7.1] - 2022-03-04
10
21
  ### Fixed
11
22
  - Float coercion: check for nil before coercion
data/Gemfile.lock CHANGED
@@ -1,26 +1,27 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- definition (0.7.1)
4
+ definition (0.8.0)
5
5
  activesupport
6
6
  i18n
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- activesupport (7.0.2.2)
11
+ activesupport (7.0.4)
12
12
  concurrent-ruby (~> 1.0, >= 1.0.2)
13
13
  i18n (>= 1.6, < 2)
14
14
  minitest (>= 5.1)
15
15
  tzinfo (~> 2.0)
16
- approvals (0.0.25)
16
+ approvals (0.0.26)
17
+ json (~> 2.0)
17
18
  nokogiri (~> 1.8)
18
19
  thor (~> 1.0)
19
20
  ast (2.4.2)
20
21
  awesome_print (1.9.2)
21
22
  benchmark-ips (2.10.0)
22
23
  coderay (1.1.3)
23
- concurrent-ruby (1.1.9)
24
+ concurrent-ruby (1.1.10)
24
25
  diff-lcs (1.5.0)
25
26
  ffi (1.15.5)
26
27
  formatador (1.1.0)
@@ -41,37 +42,38 @@ GEM
41
42
  guard (~> 2.1)
42
43
  guard-compat (~> 1.1)
43
44
  rspec (>= 2.99.0, < 4.0)
44
- i18n (1.10.0)
45
+ i18n (1.12.0)
45
46
  concurrent-ruby (~> 1.0)
46
47
  jaro_winkler (1.5.4)
48
+ json (2.6.2)
47
49
  listen (3.7.1)
48
50
  rb-fsevent (~> 0.10, >= 0.10.3)
49
51
  rb-inotify (~> 0.9, >= 0.9.10)
50
52
  lumberjack (1.2.8)
51
53
  method_source (1.0.0)
52
54
  mini_portile2 (2.8.0)
53
- minitest (5.15.0)
55
+ minitest (5.16.3)
54
56
  nenv (0.3.0)
55
- nokogiri (1.13.3)
57
+ nokogiri (1.13.8)
56
58
  mini_portile2 (~> 2.8.0)
57
59
  racc (~> 1.4)
58
- nokogiri (1.13.3-x86_64-linux)
60
+ nokogiri (1.13.8-x86_64-linux)
59
61
  racc (~> 1.4)
60
62
  notiffany (0.1.3)
61
63
  nenv (~> 0.1)
62
64
  shellany (~> 0.0)
63
- parallel (1.21.0)
64
- parser (3.1.0.0)
65
+ parallel (1.22.1)
66
+ parser (3.1.2.1)
65
67
  ast (~> 2.4.1)
66
68
  pry (0.14.1)
67
69
  coderay (~> 1.1)
68
70
  method_source (~> 1.0)
69
- psych (4.0.3)
71
+ psych (4.0.6)
70
72
  stringio
71
73
  racc (1.6.0)
72
74
  rainbow (3.1.1)
73
75
  rake (13.0.6)
74
- rb-fsevent (0.11.1)
76
+ rb-fsevent (0.11.2)
75
77
  rb-inotify (0.10.1)
76
78
  ffi (~> 1.0)
77
79
  rspec (3.11.0)
@@ -80,17 +82,17 @@ GEM
80
82
  rspec-mocks (~> 3.11.0)
81
83
  rspec-core (3.11.0)
82
84
  rspec-support (~> 3.11.0)
83
- rspec-expectations (3.11.0)
85
+ rspec-expectations (3.11.1)
84
86
  diff-lcs (>= 1.2.0, < 2.0)
85
87
  rspec-support (~> 3.11.0)
86
88
  rspec-its (1.3.0)
87
89
  rspec-core (>= 3.0.0)
88
90
  rspec-expectations (>= 3.0.0)
89
- rspec-mocks (3.11.0)
91
+ rspec-mocks (3.11.1)
90
92
  diff-lcs (>= 1.2.0, < 2.0)
91
93
  rspec-support (~> 3.11.0)
92
- rspec-support (3.11.0)
93
- rspec_junit_formatter (0.5.1)
94
+ rspec-support (3.11.1)
95
+ rspec_junit_formatter (0.6.0)
94
96
  rspec-core (>= 2, < 4, != 2.12.0)
95
97
  rubocop (0.66.0)
96
98
  jaro_winkler (~> 1.5.1)
@@ -105,10 +107,10 @@ GEM
105
107
  rubocop_runner (2.2.0)
106
108
  ruby-progressbar (1.11.0)
107
109
  shellany (0.0.1)
108
- stringio (3.0.1)
110
+ stringio (3.0.2)
109
111
  thor (1.2.1)
110
- timecop (0.9.4)
111
- tzinfo (2.0.4)
112
+ timecop (0.9.5)
113
+ tzinfo (2.0.5)
112
114
  concurrent-ruby (~> 1.0)
113
115
  unicode-display_width (1.5.0)
114
116
 
data/README.md CHANGED
@@ -42,7 +42,7 @@ conform_result.error_hash # =>
42
42
  # {
43
43
  # :birthday => [
44
44
  # [0] <Definition::ConformError
45
- # desciption: "hash fails validation for key birthday: { Is of type String instead of Date }",
45
+ # description: "hash fails validation for key birthday: { Is of type String instead of Date }",
46
46
  # json_pointer: "/birthday">
47
47
  # ]
48
48
  # }
@@ -71,66 +71,60 @@ conform_result.value # => {title: "My first blog post", body: "Shortest one ever
71
71
  Because definitions do not only validate input but also transform input, we use
72
72
  the term `conform` which stands for validation and coercion.
73
73
 
74
- ### Value Objects
74
+ ### Handling errors
75
75
 
76
- ```ruby
77
- class User < Definition::ValueObject
78
- definition(Definition.Keys do
79
- required :username, Definition.Type(String)
80
- required :password, Definition.Type(String)
81
- end)
82
- end
83
-
84
- user = User.new(username: "johndoe", password: "zg(2ds8x2/")
85
- user.username # => "johndoe"
86
- user[:username] # => "johndoe"
87
- user.username = "Alice" # => NoMethodError (ValueObjects are immutable)
88
- user[:username] = "Alice" # => FrozenError (ValueObjects are immutable)
89
-
90
- User.new(username: "johndoe") # => Definition::InvalidValueObjectError: hash does not include :password
91
- ```
92
-
93
- Value objects delegate all calls to the output value of the defined definition,
94
- so in this example you can use all methods that are defined on `Hash` also on the
95
- user object. If you use a `Keys` definition, the value object additionally defines
96
- convenient accessor methods for all attributes.
97
-
98
- Value Objects can also be used for all other data structures that can be validated
99
- by a definition, for example arrays:
76
+ #### I18n translated errors
77
+ For end users you best use the translated errors that you get from definition:
100
78
 
101
79
  ```ruby
102
- class IntegerArray < Definition::ValueObject
103
- definition(Definition.Each(Definition.Type(Integer)))
80
+ schema = Definition.Keys do
81
+ required :title, Definition.NonEmptyString
82
+ required :body, Definition::And(
83
+ Definition.Type(String),
84
+ Definition.MinSize(100)
85
+ )
104
86
  end
105
87
 
106
- array = IntegerArray.new([1,2,3])
107
- array.first # => 1
108
-
109
- IntegerArray.new([1,2,"3"]) # => Definition::InvalidValueObjectError: Not all items conform with each: { Item "3" did not conform to each: { Is of type String instead of Integer } }
88
+ conform_result = schema.conform({title: "", body: "this is not long enough"})
89
+ conform_result.errors # => returns an array of Definition::ConformError
90
+ conform_result.errors.each do |error|
91
+ puts "----"
92
+ puts error.json_pointer # provides a path to the invalid value, also works with nested objects and arrays
93
+ puts error.translated_error
94
+ end
95
+ # =>
96
+ # ----
97
+ # /title
98
+ # Value is shorter than 1
99
+ # ----
100
+ # /body
101
+ # Value is shorter than 100
110
102
  ```
111
103
 
112
- You can access the conform result object via `InvalidValueObjectError#conform_result`
104
+ The error messages are only translated into English for now, but you can add or change translations by adding a yaml file like [this](./config/locales/en.yml) to your I18n load path.
113
105
 
114
- #### Nesting value Objects
106
+ #### Other ways of accessing errors
115
107
 
116
- Value objects can be nested by either using the value object itself as type definition,
117
- or by using the `CoercibleValueObject` Definition. The latter would convert input
118
- hashes that conform with the value objects schema to an instance of the value object.
108
+ To get a quick error summary during debugging, you can also use `conform_result.error_message`
119
109
 
120
- ```ruby
121
- class IntegerArray < Definition::ValueObject
122
- definition(Definition.Each(Definition.Type(Integer)))
123
- end
110
+ Instead of getting a flat array of all errors via `conform_result.errors`, you can also get a hierarchical representation:
124
111
 
125
- class User < Definition::ValueObject
126
- definition(Definition.Keys do
127
- required :username, Definition.Type(String)
128
- required :scores, Definition.CoercibleValueObject(IntegerArray)
129
- end)
130
- end
112
+ ```ruby
113
+ conform_result.error_hash
114
+ # =>
115
+ # {
116
+ # :title => [
117
+ # [0] <Definition::ConformError
118
+ # message: "hash fails validation for key title: { Not all definitions are valid for 'non_empty_string': { Did not pass test for min_size (1) } }",
119
+ # json_pointer: "/title">
120
+ # ],
121
+ # :body => [
122
+ # [0] <Definition::ConformError
123
+ # message: "hash fails validation for key body: { Not all definitions are valid for 'and': { Did not pass test for min_size (100) } }",
124
+ # json_pointer: "/body">
125
+ # ]
126
+ # }
131
127
 
132
- object = User.new(username: "John", scores: [1,2,3])
133
- object.scores.class.name # => IntegerArray
134
128
  ```
135
129
 
136
130
  ### Conforming Hashes
@@ -353,10 +347,10 @@ Definition.Regex(/^\d*$/).conform("123") # => pass
353
347
  #### Numerics
354
348
 
355
349
  ```ruby
356
- Definition.GreaterThen(5).conform(5.1) # => pass
357
- Definition.GreaterThenEqual(5).conform(5) # => pass
358
- Definition.LessThen(5).conform(4) # => pass
359
- Definition.LessThenEqual(5).conform(5) # => pass
350
+ Definition.GreaterThan(5).conform(5.1) # => pass
351
+ Definition.GreaterThanEqual(5).conform(5) # => pass
352
+ Definition.LessThan(5).conform(4) # => pass
353
+ Definition.LessThanEqual(5).conform(5) # => pass
360
354
  ```
361
355
 
362
356
  #### Strings, Array, Hashes
@@ -382,7 +376,7 @@ Definition.Nil.conform(nil) # => pass
382
376
  #### Boolean
383
377
 
384
378
  ```ruby
385
- Definition.Boolean.conform(tru) # => pass
379
+ Definition.Boolean.conform(true) # => pass
386
380
  ```
387
381
 
388
382
  #### All types
@@ -431,6 +425,92 @@ end
431
425
  schema.conform(input_hash).errors.first.translated_error # => Value is of wrong type, needs to be a String"
432
426
  ```
433
427
 
428
+ # Helpers / useful tools
429
+
430
+ ### Value Objects / Models
431
+
432
+ Provides simple immutable objects that can validate and hold your data so that it can be safely passed around in your application.
433
+
434
+ ```ruby
435
+ class User < Definition::Model
436
+ required :username, Definition.Type(String)
437
+ required :password, Definition.Type(String)
438
+ optional :age, Definition.Type(Integer)
439
+ end
440
+
441
+ user = User.new(username: "johndoe", password: "zg(2ds8x2/")
442
+ user.username # => "johndoe"
443
+ user.age # => nil
444
+ user.to_h # => { username: "johndoe", password: "zg(2ds8x2/" }
445
+ user.new(age: 21) # => new model instance with username and password from before plus the age set to 21
446
+
447
+ user.username = "Alice" # => raises NoMethodError (Models are immutable)
448
+
449
+ User.new(username: "johndoe") # => raises a Definition::InvalidModelError: hash is missing :password
450
+
451
+ ```
452
+
453
+ You can access the conform result of InvalidModel errors via their `conform_result` method.
454
+
455
+ #### Nesting Models
456
+
457
+ Models can be nested by either using the model object itself as type definition,
458
+ or by using the `CoercibleModel` Definition. The latter is less strict and will
459
+ convert input hashes that conform with the model schema to an instance of the model.
460
+
461
+ ```ruby
462
+ class Address < Definition::Model
463
+ required :street, Definition.Type(String)
464
+ required :postal_code, Definition.Type(String)
465
+ end
466
+
467
+ class User < Definition::Model
468
+ required :username, Definition.Type(String)
469
+ required :address, Definition.CoercibleModel(Address)
470
+ end
471
+
472
+ # Address is converted into an Address model automatically:
473
+ user = User.new(username: "John", address: { street: "123 Fakestreet", postal_code: "2dfx4" })
474
+ user.address.street # => "123 Fakestreet"
475
+
476
+ class UserNotCoercibleAddress < Definition::Model
477
+ required :username, Definition.Type(String)
478
+ required :address, Address
479
+ end
480
+
481
+ # Address is not converted automatically, instead it needs to be of type Address already:
482
+ UserNotCoercibleAddress.new(username: "John", address: { street: "123 Fakestreet", postal_code: "2dfx4" }) # => raises a Definition::InvalidModelError
483
+ UserNotCoercibleAddress.new(username: "John", address: Address.new(street: "123 Fakestreet", postal_code: "2dfx4")).address.street # => "123 Fakestreet"
484
+ ```
485
+
486
+ ### Intialization argument validation
487
+
488
+ Definition provides a mixin that allows you to validate keyword arguments of class initialization methods. This is meant to be used with classes that provide business logic whereas the models are meant to be used to pass data around.
489
+
490
+ The major differences to a Definition::Model are:
491
+ * The values are not frozen and can be changed by the classes internal business logic
492
+ * None of the getters for the attributes are public
493
+
494
+ ```ruby
495
+ class User
496
+ include Definition::Initializer
497
+
498
+ required :id, Definition.Type(Integer)
499
+ required :name, Definition.Type(String)
500
+ optional :phone, Definition.Type(String), default: nil
501
+
502
+ def hello
503
+ puts "Hello, I'm #{name}"
504
+ end
505
+ end
506
+
507
+ user = User.new(id: 1, name: "Joe")
508
+ user.hello # => "Hello, I'm Joe"
509
+ user.name # => raises NoMethodError
510
+
511
+ User.new(id: "1", name: "Joe") # => raises a Definition::Initializer::InvalidArgumentError
512
+ ```
513
+
434
514
  ## Development
435
515
 
436
516
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
data/UpgradeNotes.md ADDED
@@ -0,0 +1,27 @@
1
+ # Upgrade Notes
2
+
3
+ ## From version 0.7.1 and prior to version 0.8
4
+ ##### The Definition::ValueObject was removed and replaced by Definition:Model
5
+ If you used ValueObjects then you need to migrate them to Models. This will be very easy if you used the ValueObject with a `Definition.Keys` definition, which is most likely the case.
6
+
7
+ Before:
8
+ ```ruby
9
+ class User < Definition::ValueObject
10
+ definition(Definition.Keys do
11
+ required :username, Definition.Type(String)
12
+ required :password, Definition.Type(String)
13
+ end)
14
+ end
15
+ ```
16
+
17
+ After:
18
+ ```ruby
19
+ class User < Definition::Model
20
+ required :username, Definition.Type(String)
21
+ required :password, Definition.Type(String)
22
+ end
23
+ ```
24
+
25
+ If you use the `Definition.CoercibleValueObject` definition in your models, you just need to replace those with a `Definition.CoercibleModel` definition.
26
+
27
+ If you use ValueObjects that do not use a `Keys` definition then there is currently no built in replacement available.
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/inline"
4
+
5
+ gemfile do
6
+ source "https://rubygems.org"
7
+ gem "dry-initializer", "~> 3.1"
8
+ gem "dry-types", "~> 1.5"
9
+ gem "awesome_print"
10
+ gem "benchmark-ips"
11
+ gem "pry"
12
+ gem "ruby-prof"
13
+ gem "sorbet"
14
+ gem "sorbet-runtime"
15
+ gem "definition", path: File.expand_path("../.", __dir__)
16
+ end
17
+
18
+ class SorbetUseCase
19
+ extend T::Sig
20
+
21
+ sig { params(phone: String, admin: T::Boolean).void }
22
+ def initialize(phone:, admin: false)
23
+ self.phone = phone
24
+ self.admin = admin
25
+ end
26
+
27
+ private
28
+
29
+ attr_accessor :phone, :admin
30
+ end
31
+
32
+ class DryUseCase
33
+ extend Dry::Initializer
34
+
35
+ option :phone, Dry::Types["strict.string"]
36
+ option :admin, Dry::Types["strict.bool"], default: false, optional: true
37
+ end
38
+
39
+ class DefinitionUseCase
40
+ include Definition::Initializer
41
+
42
+ required :phone, Definition.Type(String)
43
+ optional :admin, Definition.Boolean, default: false
44
+ end
45
+
46
+ puts "Benchmark with valid input data:"
47
+ valid_data = { phone: "+49 3424 234234" }
48
+
49
+ Benchmark.ips do |x|
50
+ x.config(time: 5, warmup: 2)
51
+
52
+ x.report("sorbet") do
53
+ SorbetUseCase.new(**valid_data)
54
+ end
55
+
56
+ x.report("definition") do
57
+ DefinitionUseCase.new(**valid_data)
58
+ end
59
+
60
+ x.report("dry-struct") do
61
+ DryUseCase.new(**valid_data)
62
+ end
63
+
64
+ x.compare!
65
+ end
66
+
67
+ puts "Benchmark with invalid input data:"
68
+ invalid_data = { phone: "+49 3424 234234", admin: "yes" }
69
+ Benchmark.ips do |x|
70
+ x.config(time: 5, warmup: 2)
71
+
72
+ x.report("sorbet") do
73
+ SorbetUseCase.new(**invalid_data)
74
+ rescue TypeError
75
+ nil
76
+ end
77
+
78
+ x.report("definition") do
79
+ DefinitionUseCase.new(**invalid_data)
80
+ rescue Definition::Initializer::InvalidArgumentError
81
+ nil
82
+ end
83
+
84
+ x.report("dry-struct") do
85
+ DryUseCase.new(**invalid_data)
86
+ rescue Dry::Types::ConstraintError
87
+ nil
88
+ end
89
+
90
+ x.compare!
91
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/inline"
4
+
5
+ gemfile do
6
+ source "https://rubygems.org"
7
+ gem "dry-struct", "~> 1.4"
8
+ gem "awesome_print"
9
+ gem "benchmark-ips"
10
+ gem "pry"
11
+ gem "ruby-prof"
12
+ gem "definition", path: File.expand_path("../.", __dir__)
13
+ end
14
+
15
+ class DryStructModel < Dry::Struct
16
+ schema schema.strict
17
+
18
+ attribute :id, Dry::Types["strict.integer"]
19
+ attribute :app_key, Dry::Types["strict.string"]
20
+ attribute :app_version, Dry::Types["strict.string"]
21
+ attribute :app_name, Dry::Types["strict.string"].optional.default(nil)
22
+ attribute :app_branch, Dry::Types["strict.string"].optional.default(nil)
23
+ attribute :platform, Dry::Types["strict.string"].optional.default(nil)
24
+ end
25
+
26
+ class DefinitionModel < Definition::Model
27
+ required :id, Definition.Type(Integer)
28
+ required :app_key, Definition.Type(String)
29
+ required :app_version, Definition.Type(String)
30
+ optional :app_name, Definition.Type(String)
31
+ optional :app_branch, Definition.Type(String)
32
+ optional :platform, Definition.Type(String)
33
+ end
34
+
35
+ puts "Benchmark with valid input data:"
36
+ valid_data = { id: 1, app_key: "com.test", app_version: "1.0.0", app_name: "testapp" }
37
+
38
+ Benchmark.ips do |x|
39
+ x.config(time: 5, warmup: 2)
40
+
41
+ x.report("definition") do
42
+ DefinitionModel.new(**valid_data)
43
+ end
44
+
45
+ x.report("dry-struct") do
46
+ DryStructModel.new(**valid_data)
47
+ end
48
+
49
+ x.compare!
50
+ end
51
+
52
+ puts "Benchmark with invalid input data:"
53
+ invalid_data = { id: "abc", app_key: "com.test", app_name: "testapp" }
54
+ Benchmark.ips do |x|
55
+ x.config(time: 5, warmup: 2)
56
+
57
+ x.report("definition") do
58
+ DefinitionModel.new(**invalid_data)
59
+ rescue Definition::InvalidModelError
60
+ nil
61
+ end
62
+
63
+ x.report("dry-struct") do
64
+ DryStructModel.new(**invalid_data)
65
+ rescue Dry::Struct::Error
66
+ nil
67
+ end
68
+
69
+ x.compare!
70
+ end
@@ -4,22 +4,20 @@ require "bundler/inline"
4
4
 
5
5
  gemfile do
6
6
  source "https://rubygems.org"
7
- # FIXME: benchmark needs to be updated to work with dry-validation 1.0.0"
8
- gem "dry-validation", "< 1.0.0"
9
- gem "dry-types", "< 0.15"
7
+ gem "dry-validation", "~> 1.8"
8
+ gem "dry-types", "~> 1.5"
10
9
  gem "awesome_print"
11
10
  gem "benchmark-ips"
12
11
  gem "definition", path: File.expand_path("../.", __dir__)
13
12
  end
14
13
 
15
- DrySchema = Dry::Validation.Params do
16
- configure do
17
- config.type_specs = true
14
+ class DryContract < Dry::Validation::Contract
15
+ params do
16
+ required(:name).filled(:string)
17
+ required(:time).filled(:time)
18
18
  end
19
-
20
- required(:name, :string).value(type?: String)
21
- required(:time, :time).value(type?: String)
22
19
  end
20
+ DryContractInstance = DryContract.new
23
21
 
24
22
  DefinitionSchema = Definition.Keys do
25
23
  required(:name, Definition.Type(String))
@@ -29,7 +27,7 @@ end
29
27
  puts "Benchmark with valid input data:"
30
28
  valid_data = { name: "test", time: Time.now }
31
29
  ap DefinitionSchema.conform(valid_data).value
32
- ap DrySchema.call(valid_data)
30
+ ap DryContractInstance.call(valid_data)
33
31
  Benchmark.ips do |x|
34
32
  x.config(time: 5, warmup: 2)
35
33
 
@@ -38,7 +36,7 @@ Benchmark.ips do |x|
38
36
  end
39
37
 
40
38
  x.report("dry-validation") do
41
- DrySchema.call(valid_data)
39
+ DryContractInstance.call(valid_data)
42
40
  end
43
41
 
44
42
  x.compare!
@@ -47,7 +45,7 @@ end
47
45
  puts "Benchmark with invalid input data:"
48
46
  invalid_data = { name: 1, time: Time.now.to_s }
49
47
  ap DefinitionSchema.conform(invalid_data).error_message
50
- ap DrySchema.call(invalid_data).errors
48
+ ap DryContractInstance.call(invalid_data).errors
51
49
  Benchmark.ips do |x|
52
50
  x.config(time: 5, warmup: 2)
53
51
 
@@ -56,7 +54,7 @@ Benchmark.ips do |x|
56
54
  end
57
55
 
58
56
  x.report("dry-validation") do
59
- DrySchema.call(invalid_data)
57
+ DryContractInstance.call(invalid_data)
60
58
  end
61
59
 
62
60
  x.compare!
@@ -1,7 +1,7 @@
1
1
  en:
2
2
  definition:
3
- max_size: "Value is bigger than %{max_size}"
4
- min_size: "Value is smaller than %{min_size}"
3
+ max_size: "Value is longer than %{max_size}"
4
+ min_size: "Value is shorter than %{min_size}"
5
5
  greater_then: "Value must be greater than %{min_value}"
6
6
  greater_then_equal: "Value must be greater or equal to %{min_value}"
7
7
  less_then: "Value must be less than %{max_value}"