definition 0.1.0.rc2 → 0.1.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/.travis.yml +7 -0
- data/README.md +2 -2
- data/benchmark/coercion.rb +71 -0
- data/benchmark/complex_example.rb +175 -0
- data/benchmark/validation_only.rb +61 -0
- data/lib/definition/version.rb +1 -1
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 99098a9f77beb85c63ac542c0903112ea45ac698ace223d92d6c88c6abf2d372
|
4
|
+
data.tar.gz: 314c23a060b6867edf1a8883eaa3b28ae2b45bfe3b197dab8f86d95d05383204
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2876eb3d16401866eed9f6546b797d3824334d9aad5670d403b205c8995e7af9e63203ff4d4dd62a8156574a523943d0d572e777c2c934e6b0141367e38f62eb
|
7
|
+
data.tar.gz: a251ebc1e96ebfb89b0e49fb418e65cd051ab28a670d3dd2376d1cf4c4fe9992dab3fea8d02224241a82b885befdd668f4baab3ce43666a0f7219bd2d74ec9b7
|
data/.travis.yml
CHANGED
@@ -12,3 +12,10 @@ jobs:
|
|
12
12
|
- stage: linting
|
13
13
|
rvm: ruby-head
|
14
14
|
script: bundle exec rake rubocop
|
15
|
+
- stage: benchmark
|
16
|
+
script: bundle exec ruby benchmark/complex_example.rb
|
17
|
+
rvm: ruby-head
|
18
|
+
- script: bundle exec ruby benchmark/coercion.rb
|
19
|
+
rvm: ruby-head
|
20
|
+
- script: bundle exec ruby benchmark/validation_only.rb
|
21
|
+
rvm: ruby-head
|
data/README.md
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
[][travis]
|
4
4
|
[][rubygems]
|
5
5
|
|
6
|
-
Simple and composable validation and coercion of data structures. It also includes a ValueObject for
|
6
|
+
Simple and composable validation and coercion of data structures. It also includes a ValueObject for convenience.
|
7
7
|
|
8
8
|
## Installation
|
9
9
|
|
@@ -79,7 +79,7 @@ user[:username] # => "johndoe"
|
|
79
79
|
user.username = "Alice" # => NoMethodError (ValueObjects are immutable)
|
80
80
|
user[:username] = "Alice" # => FrozenError (ValueObjects are immutable)
|
81
81
|
|
82
|
-
User.new(username: "johndoe") # => Definition::InvalidValueObjectError: hash does not include :
|
82
|
+
User.new(username: "johndoe") # => Definition::InvalidValueObjectError: hash does not include :password
|
83
83
|
```
|
84
84
|
|
85
85
|
Value objects delegate all calls to the output value of the defined definition,
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/inline"
|
4
|
+
|
5
|
+
gemfile do
|
6
|
+
source "https://rubygems.org"
|
7
|
+
gem "definition"
|
8
|
+
gem "dry-validation"
|
9
|
+
gem "awesome_print"
|
10
|
+
gem "benchmark-ips"
|
11
|
+
gem "pry"
|
12
|
+
end
|
13
|
+
|
14
|
+
DryTimeCoercionType = Dry::Types["strict.string"].constructor do |value|
|
15
|
+
if value.is_a?(Integer)
|
16
|
+
Time.at(value).utc
|
17
|
+
else
|
18
|
+
value
|
19
|
+
end
|
20
|
+
end
|
21
|
+
DrySchema = Dry::Validation.Params do
|
22
|
+
configure do
|
23
|
+
config.type_specs = true
|
24
|
+
end
|
25
|
+
|
26
|
+
required(:name, :string).value(type?: String)
|
27
|
+
required(:time, DryTimeCoercionType).value(type?: Time)
|
28
|
+
end
|
29
|
+
|
30
|
+
DefinitionSchema = Definition.Keys do
|
31
|
+
required(:name, Definition.Type(String))
|
32
|
+
required(:time, Definition.Lambda(:time) do |value|
|
33
|
+
conform_with(Time.at(value).utc) if value.is_a?(Integer)
|
34
|
+
end)
|
35
|
+
end
|
36
|
+
|
37
|
+
puts "Benchmark with valid input data:"
|
38
|
+
valid_data = { name: "test", time: Time.now.to_i }
|
39
|
+
ap DefinitionSchema.conform(valid_data).value
|
40
|
+
ap DrySchema.call(valid_data)
|
41
|
+
Benchmark.ips do |x|
|
42
|
+
x.config(time: 5, warmup: 2)
|
43
|
+
|
44
|
+
x.report("definition") do
|
45
|
+
DefinitionSchema.conform(valid_data).value
|
46
|
+
end
|
47
|
+
|
48
|
+
x.report("dry-validation") do
|
49
|
+
DrySchema.call(valid_data)
|
50
|
+
end
|
51
|
+
|
52
|
+
x.compare!
|
53
|
+
end
|
54
|
+
|
55
|
+
puts "Benchmark with invalid input data:"
|
56
|
+
invalid_data = { name: 1, time: Time.now.to_s }
|
57
|
+
ap DefinitionSchema.conform(invalid_data).error_message
|
58
|
+
ap DrySchema.call(invalid_data).errors
|
59
|
+
Benchmark.ips do |x|
|
60
|
+
x.config(time: 5, warmup: 2)
|
61
|
+
|
62
|
+
x.report("definition") do
|
63
|
+
DefinitionSchema.conform(invalid_data)
|
64
|
+
end
|
65
|
+
|
66
|
+
x.report("dry-validation") do
|
67
|
+
DrySchema.call(invalid_data)
|
68
|
+
end
|
69
|
+
|
70
|
+
x.compare!
|
71
|
+
end
|
@@ -0,0 +1,175 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/inline"
|
4
|
+
|
5
|
+
gemfile do
|
6
|
+
source "https://rubygems.org"
|
7
|
+
gem "definition"
|
8
|
+
gem "dry-validation"
|
9
|
+
gem "awesome_print"
|
10
|
+
gem "benchmark-ips"
|
11
|
+
gem "pry"
|
12
|
+
end
|
13
|
+
|
14
|
+
DryTimeCoercionType = Dry::Types["strict.string"].constructor do |value|
|
15
|
+
if value.is_a?(Integer)
|
16
|
+
Time.at(value / 1000.0).utc
|
17
|
+
else
|
18
|
+
value
|
19
|
+
end
|
20
|
+
end
|
21
|
+
DrySchema = Dry::Validation.Params do # rubocop:disable Metrics/BlockLength
|
22
|
+
configure do
|
23
|
+
config.type_specs = true
|
24
|
+
end
|
25
|
+
|
26
|
+
required(:data).schema do
|
27
|
+
required(:type, :string).value(Dry::Types["strict.string"].enum("article"))
|
28
|
+
required(:id, :string).value(type?: String)
|
29
|
+
required(:attributes).schema do
|
30
|
+
required(:title, :string).filled(max_size?: 1000)
|
31
|
+
required(:body, :string).filled(max_size?: 1000)
|
32
|
+
required(:publish_date, DryTimeCoercionType).value(type?: Time)
|
33
|
+
end
|
34
|
+
|
35
|
+
required(:relationships).schema do
|
36
|
+
required(:author).schema do
|
37
|
+
required(:data).schema do
|
38
|
+
required(:id, :string).value(type?: String)
|
39
|
+
required(:type, :string).value(Dry::Types["strict.string"].enum("people"))
|
40
|
+
end
|
41
|
+
end
|
42
|
+
optional(:comments).schema do
|
43
|
+
required(:data).each do
|
44
|
+
schema do
|
45
|
+
required(:id, :string).value(type?: String)
|
46
|
+
required(:type, :string).value(Dry::Types["strict.string"].enum("comment"))
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
MAX_LENGTH = Definition.Lambda(:max_length) do |value|
|
55
|
+
conform_with(value) if value.size <= 1000
|
56
|
+
end
|
57
|
+
MAX_STRING_LENGTH = Definition.And(
|
58
|
+
Definition.Type(String),
|
59
|
+
MAX_LENGTH
|
60
|
+
)
|
61
|
+
MILLISECONDS_TIME = Definition.Lambda(:milliseconds_time) do |v|
|
62
|
+
conform_with(Time.at(v / 1000.0).utc) if v.is_a?(Integer)
|
63
|
+
end
|
64
|
+
DefinitionSchema = Definition.Keys do
|
65
|
+
required(:data, Definition.Keys do
|
66
|
+
required :type, Definition.Enum("article")
|
67
|
+
required :id, Definition.Type(String)
|
68
|
+
required(:attributes, Definition.Keys do
|
69
|
+
required :title, MAX_STRING_LENGTH
|
70
|
+
required :body, MAX_STRING_LENGTH
|
71
|
+
required :publish_date, MILLISECONDS_TIME
|
72
|
+
end)
|
73
|
+
|
74
|
+
required(:relationships, Definition.Keys do
|
75
|
+
required(:author, Definition.Keys do
|
76
|
+
required(:data, Definition.Keys do
|
77
|
+
required :id, Definition.Type(String)
|
78
|
+
required :type, Definition.Enum("people")
|
79
|
+
end)
|
80
|
+
end)
|
81
|
+
optional(:comments, Definition.Keys do
|
82
|
+
required(:data, Definition.Each(
|
83
|
+
Definition.Keys do
|
84
|
+
required :id, Definition.Type(String)
|
85
|
+
required :type, Definition.Enum("comment")
|
86
|
+
end
|
87
|
+
))
|
88
|
+
end)
|
89
|
+
end)
|
90
|
+
end)
|
91
|
+
end
|
92
|
+
|
93
|
+
puts "Benchmark with valid input data:"
|
94
|
+
valid_data = {
|
95
|
+
"data": {
|
96
|
+
"type": "article",
|
97
|
+
"id": "1",
|
98
|
+
"attributes": {
|
99
|
+
"title": "JSON:API paints my bikeshed!",
|
100
|
+
"body": "The shortest article. Ever.",
|
101
|
+
"publish_date": Time.utc(2018).to_i * 1000
|
102
|
+
},
|
103
|
+
"relationships": {
|
104
|
+
"author": {
|
105
|
+
"data": { "id": "42", "type": "people" }
|
106
|
+
},
|
107
|
+
"comments": {
|
108
|
+
"data": [
|
109
|
+
{ "id": "1", "type": "comment" },
|
110
|
+
{ "id": "2", "type": "comment" }
|
111
|
+
]
|
112
|
+
}
|
113
|
+
}
|
114
|
+
}
|
115
|
+
}
|
116
|
+
ap DefinitionSchema.conform(valid_data).value
|
117
|
+
ap DrySchema.call(valid_data)
|
118
|
+
raise unless DefinitionSchema.conform(valid_data).passed?
|
119
|
+
raise unless DrySchema.call(valid_data).success?
|
120
|
+
|
121
|
+
Benchmark.ips do |x|
|
122
|
+
x.config(time: 5, warmup: 2)
|
123
|
+
|
124
|
+
x.report("definition") do
|
125
|
+
DefinitionSchema.conform(valid_data)
|
126
|
+
end
|
127
|
+
|
128
|
+
x.report("dry-validation") do
|
129
|
+
DrySchema.call(valid_data)
|
130
|
+
end
|
131
|
+
|
132
|
+
x.compare!
|
133
|
+
end
|
134
|
+
|
135
|
+
puts "Benchmark with invalid input data:"
|
136
|
+
invalid_data = {
|
137
|
+
"data": {
|
138
|
+
"type": "article",
|
139
|
+
"id": "1",
|
140
|
+
"attributes": {
|
141
|
+
"title": "JSON:API paints my bikeshed!",
|
142
|
+
"body": "The shortest article. Ever.",
|
143
|
+
"publish_date": Time.utc(2018).to_s
|
144
|
+
},
|
145
|
+
"relationships": {
|
146
|
+
"author": {
|
147
|
+
"data": { "id": "42", "type": "people" }
|
148
|
+
},
|
149
|
+
"comments": {
|
150
|
+
"data": [
|
151
|
+
{ "id": "1", "type": "comment" },
|
152
|
+
{ "id": "2", "type": "post" }
|
153
|
+
]
|
154
|
+
}
|
155
|
+
}
|
156
|
+
}
|
157
|
+
}
|
158
|
+
ap DefinitionSchema.conform(invalid_data).error_message
|
159
|
+
ap DrySchema.call(invalid_data).errors
|
160
|
+
raise if DefinitionSchema.conform(invalid_data).passed?
|
161
|
+
raise if DrySchema.call(invalid_data).success?
|
162
|
+
|
163
|
+
Benchmark.ips do |x|
|
164
|
+
x.config(time: 5, warmup: 2)
|
165
|
+
|
166
|
+
x.report("definition") do
|
167
|
+
DefinitionSchema.conform(invalid_data)
|
168
|
+
end
|
169
|
+
|
170
|
+
x.report("dry-validation") do
|
171
|
+
DrySchema.call(invalid_data)
|
172
|
+
end
|
173
|
+
|
174
|
+
x.compare!
|
175
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/inline"
|
4
|
+
|
5
|
+
gemfile do
|
6
|
+
source "https://rubygems.org"
|
7
|
+
gem "definition"
|
8
|
+
gem "dry-validation"
|
9
|
+
gem "awesome_print"
|
10
|
+
gem "benchmark-ips"
|
11
|
+
end
|
12
|
+
|
13
|
+
DrySchema = Dry::Validation.Params do
|
14
|
+
configure do
|
15
|
+
config.type_specs = true
|
16
|
+
end
|
17
|
+
|
18
|
+
required(:name, :string).value(type?: String)
|
19
|
+
required(:time, :time).value(type?: String)
|
20
|
+
end
|
21
|
+
|
22
|
+
DefinitionSchema = Definition.Keys do
|
23
|
+
required(:name, Definition.Type(String))
|
24
|
+
required(:time, Definition.Type(Time))
|
25
|
+
end
|
26
|
+
|
27
|
+
puts "Benchmark with valid input data:"
|
28
|
+
valid_data = { name: "test", time: Time.now }
|
29
|
+
ap DefinitionSchema.conform(valid_data).value
|
30
|
+
ap DrySchema.call(valid_data)
|
31
|
+
Benchmark.ips do |x|
|
32
|
+
x.config(time: 5, warmup: 2)
|
33
|
+
|
34
|
+
x.report("definition") do
|
35
|
+
DefinitionSchema.conform(valid_data)
|
36
|
+
end
|
37
|
+
|
38
|
+
x.report("dry-validation") do
|
39
|
+
DrySchema.call(valid_data)
|
40
|
+
end
|
41
|
+
|
42
|
+
x.compare!
|
43
|
+
end
|
44
|
+
|
45
|
+
puts "Benchmark with invalid input data:"
|
46
|
+
invalid_data = { name: 1, time: Time.now.to_s }
|
47
|
+
ap DefinitionSchema.conform(invalid_data).error_message
|
48
|
+
ap DrySchema.call(invalid_data).errors
|
49
|
+
Benchmark.ips do |x|
|
50
|
+
x.config(time: 5, warmup: 2)
|
51
|
+
|
52
|
+
x.report("definition") do
|
53
|
+
DefinitionSchema.conform(invalid_data)
|
54
|
+
end
|
55
|
+
|
56
|
+
x.report("dry-validation") do
|
57
|
+
DrySchema.call(invalid_data)
|
58
|
+
end
|
59
|
+
|
60
|
+
x.compare!
|
61
|
+
end
|
data/lib/definition/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: definition
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dominik Goltermann
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-01-
|
11
|
+
date: 2019-01-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: approvals
|
@@ -236,6 +236,9 @@ files:
|
|
236
236
|
- Guardfile
|
237
237
|
- README.md
|
238
238
|
- Rakefile
|
239
|
+
- benchmark/coercion.rb
|
240
|
+
- benchmark/complex_example.rb
|
241
|
+
- benchmark/validation_only.rb
|
239
242
|
- bin/console
|
240
243
|
- bin/setup
|
241
244
|
- definition.gemspec
|
@@ -269,9 +272,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
269
272
|
version: '0'
|
270
273
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
271
274
|
requirements:
|
272
|
-
- - "
|
275
|
+
- - ">="
|
273
276
|
- !ruby/object:Gem::Version
|
274
|
-
version:
|
277
|
+
version: '0'
|
275
278
|
requirements: []
|
276
279
|
rubyforge_project:
|
277
280
|
rubygems_version: 2.7.6
|