light_service-validated_context 0.2.2 → 0.3.1
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/Gemfile.lock +1 -1
- data/README.md +135 -27
- data/lib/light_service/validated_context/context.rb +6 -4
- data/lib/light_service/validated_context/expected_key_verifier.rb +19 -19
- data/lib/light_service/validated_context/fail_on_validation_error.rb +10 -0
- data/lib/light_service/validated_context/key_verifier.rb +41 -20
- data/lib/light_service/validated_context/promised_key_verifier.rb +19 -19
- data/lib/light_service/validated_context/validated_key.rb +17 -7
- data/lib/light_service/validated_context/version.rb +1 -1
- data/lib/light_service/validated_context.rb +14 -8
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 859cf8786c692bedc1d764b0656629bc7f9e0ddb741a10874d290c723b708e3d
|
4
|
+
data.tar.gz: 18059f28fcbaaa2d54373bdf2cea6c6f8387fc68b07f83f338631e445ba29e5f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7d7a6568947199bf4e96296d03825a65b7485227083d02b72b450598db273e72bae5547b19dd9d32d5ca9a85e9b5e676cc5af4f257f974ec4d4d9e59a8c3ed7f
|
7
|
+
data.tar.gz: eb44c15324105179fb1426fc201d2f34d8bb92e5ccc5e1ed2a265e8c8d85eaf66625b287717c6ec452a8789afa240b69b395fa3050c0a1661ed2026a0fb6e5d0
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -23,7 +23,7 @@ AFAIK this is the only way to achieve the goal. Because of this fact I consider
|
|
23
23
|
## Goals
|
24
24
|
|
25
25
|
- implement an advanced and flexible interface to declare,
|
26
|
-
type-check, coerce and describe action's arguments without reinventing the wheel (the wheel we use under the wood is [`dry-types`](https://dry-rb.org/gems/dry-types))
|
26
|
+
type-check, coerce and describe action's arguments without reinventing the wheel (the wheel we use under the wood is [`dry-types`](https://dry-rb.org/gems/dry-types/main/custom-types/))
|
27
27
|
- testing DX and interfaces
|
28
28
|
- study what parts of code are involved into this area of `light-service`'s code base
|
29
29
|
|
@@ -47,35 +47,66 @@ require 'light_service/validated_context'
|
|
47
47
|
|
48
48
|
## Usage
|
49
49
|
|
50
|
+
The plugin enables you to pass `VK` (`ValidatedKeys`) objects as arguments to built-ins `expects` and
|
51
|
+
`promises` macros.
|
52
|
+
|
53
|
+
This is how you'd usually write an `Action` in LightService:
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
class ActionOne
|
57
|
+
extend LightService::Action
|
58
|
+
|
59
|
+
expects :age
|
60
|
+
promises :text
|
61
|
+
|
62
|
+
executed do |context|
|
63
|
+
validate_age!(context)
|
64
|
+
|
65
|
+
# Do something...
|
66
|
+
|
67
|
+
context.text = 'Long live and prosperity'
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.validate_age!(context)
|
71
|
+
context.fail_and_return!(':age must be an Integer') unless context.age.is_a? Integer
|
72
|
+
context.fail_and_return!('Sorry, you are too young m8') if (context.age <= 30)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
```
|
76
|
+
|
77
|
+
and this is how `light_service-validated_context` enables you to write
|
78
|
+
|
50
79
|
```ruby
|
51
80
|
class ActionOne
|
52
81
|
extend LightService::Action
|
53
82
|
|
54
|
-
expects VK.new(:email, Types::Strict::String)
|
55
83
|
expects VK.new(:age, Types::Coercible::Integer.constrained(gt: 30))
|
56
|
-
|
57
|
-
promises VK.new(:text, Types::Strict::String.constrained(max_size: 10).default('foobar'))
|
84
|
+
promises VK.new(:text, Types::Strict::String.constrained(max_size: 10).default('Long live and prosperity'))
|
58
85
|
|
59
86
|
executed do |context|
|
60
|
-
# something
|
87
|
+
# Do something
|
61
88
|
end
|
62
89
|
end
|
90
|
+
```
|
63
91
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
92
|
+
and you'll get validations for free
|
93
|
+
|
94
|
+
```ruby
|
95
|
+
ActionOne.execute(age: '19')
|
96
|
+
# [App::ActionOne][:age] "19" violates constraints (gt?(30, 19) failed) (LightService::ExpectedKeysNotInContextError)
|
97
|
+
ActionOne.execute(age: 37)
|
98
|
+
# LightService::Context({:age=>37, :text=>"Long live and prosperity"}, success: true, message: '', error_code: nil, skip_remaining: false, aliases: {})
|
99
|
+
ActionOne.execute(age: 37, text: 'Too long too pass the constrain')
|
100
|
+
# [App::ActionOne][:text] "Too long too pass the constrain" violates constraints (max_size?(24, "Too long too pass the constrain") failed) (LightService::PromisedKeysNotInContextError)
|
70
101
|
```
|
71
102
|
|
72
103
|
Since all the validation and coercion logic is delegated to `dry-types`, you can
|
73
|
-
read more about what you can achieve at https://dry-rb.org/gems/dry-types/
|
104
|
+
read more about what you can achieve at https://dry-rb.org/gems/dry-types/main/custom-types/
|
74
105
|
|
75
106
|
`VK` objects needs to be created with 2 positional arguments:
|
76
107
|
|
77
108
|
- key name as a symbol
|
78
|
-
- A type
|
109
|
+
- A type declaration from `dry-types` (`Tyeps` namespace is already setup for you)
|
79
110
|
|
80
111
|
`VK` and `ValidatedKey` (equivalent) are short aliases for `LightService::Context::ValidatedKey`.
|
81
112
|
They are created only if not already defined in the global space. You're free to use the namespaced
|
@@ -83,20 +114,91 @@ form to avoid name collisions.
|
|
83
114
|
|
84
115
|
You can find more usage example in `spec/support/test_doubles.rb`
|
85
116
|
|
86
|
-
|
117
|
+
### Custom validation error message
|
87
118
|
|
88
|
-
|
89
|
-
invalid object whenever the object self has the concept of _validity_ for itself. This rule takes
|
90
|
-
sense to my eyes whenever I'm working with an object already initialized and in memory, but I cannot
|
91
|
-
trust its internal status.
|
119
|
+
You can set a custom validation error message when instantiating a `VK` object
|
92
120
|
|
93
|
-
|
94
|
-
|
95
|
-
|
121
|
+
```ruby
|
122
|
+
VK.new(:my_integer, Types::Strict::Integer, message: 'Custom validation message for :my_integer key')
|
123
|
+
```
|
96
124
|
|
97
|
-
|
98
|
-
|
99
|
-
|
125
|
+
Messages translated via `I18n` are supported too, following standard `light-service`'s
|
126
|
+
[configuration](https://github.com/adomokos/light-service/#localizing-messages)
|
127
|
+
|
128
|
+
```ruby
|
129
|
+
VK.new(:my_integer, Types::Strict::Integer, message: :my_integer_error_message)
|
130
|
+
```
|
131
|
+
|
132
|
+
### Raise vs fail
|
133
|
+
|
134
|
+
By default, following original `light-service` implementation, a validation error will raise a
|
135
|
+
`LightService::ExpectedKeysNotInContextError` or `LightService::PromisedKeysNotInContextError`.
|
136
|
+
|
137
|
+
> NOTE: I know that raised exceptions do not express the concept of "invalid", but I opted
|
138
|
+
to preserve the original one in order to make this plugin more droppable-in as possible, thus
|
139
|
+
w/o breaking code relying on, for example, rescueing those specific excpetions.
|
140
|
+
|
141
|
+
May you prefere to fail the action, populating outcome's message with error message, just do
|
142
|
+
`extend LightService::Context::FailOnValidationError` into you action:
|
143
|
+
|
144
|
+
```ruby
|
145
|
+
class ActionFailInsteadOfRaise
|
146
|
+
extend LightService::Action
|
147
|
+
extend LightService::Context::FailOnValidationError
|
148
|
+
|
149
|
+
expects VK.new(:foo, Types::String)
|
150
|
+
|
151
|
+
executed do |context|
|
152
|
+
# do something
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
result = ActionFailInsteadOfRaise.execute(foo: 12)
|
157
|
+
result.message # Here you'll find the validation(s) message(s)
|
158
|
+
```
|
159
|
+
|
160
|
+
### Custom types
|
161
|
+
|
162
|
+
As documented in [dry-types doc](https://dry-rb.org/gems/dry-types/main/getting-started/#creating-your-first-type),
|
163
|
+
you can be more expressive defining custom types; you can define them reopening the already defined `LightService::Types` module
|
164
|
+
(or simply `Types` in the global namespace if it does not conflict with your domain's namespace), e.g.:
|
165
|
+
|
166
|
+
```ruby
|
167
|
+
module LightService::Types
|
168
|
+
MyExpressiveThing = Hash.schema(
|
169
|
+
name: String,
|
170
|
+
age: Coercible::Integer,
|
171
|
+
foo: Symbol.constrained(included_in: %i[bar baz])
|
172
|
+
)
|
173
|
+
end
|
174
|
+
|
175
|
+
class ActionOne
|
176
|
+
extend LightService::Action
|
177
|
+
extend LightService::Context::FailOnValidationError
|
178
|
+
|
179
|
+
expects VK.new(:foo, Types::MyBusinessHash)
|
180
|
+
|
181
|
+
executed do |context|
|
182
|
+
# do something...
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
result = App::ActionOne.execute(foo: {
|
187
|
+
name: 'Alessandro',
|
188
|
+
age: '37',
|
189
|
+
foo: :bar
|
190
|
+
})
|
191
|
+
```
|
192
|
+
|
193
|
+
Custom types will be reusable, more expressive and moreover will clean your action up a bit.
|
194
|
+
|
195
|
+
## Why validation matters?
|
196
|
+
|
197
|
+
In OO programming there's a rule that says to never instantiate an
|
198
|
+
invalid object.
|
199
|
+
|
200
|
+
If you cannot trust the state, given the state is internal or delegated to a context object,
|
201
|
+
you'll have to do a bunch of validation-oriented logical branches into your logic. E.g.:
|
100
202
|
|
101
203
|
```ruby
|
102
204
|
class HugAFriend
|
@@ -110,7 +212,7 @@ class HugAFriend
|
|
110
212
|
end
|
111
213
|
```
|
112
214
|
|
113
|
-
The `if` in this uber-trivial example exists just due to
|
215
|
+
The `if` in this uber-trivial example exists just due to untrusted state.
|
114
216
|
|
115
217
|
Let's re-imagine the code given an `executed` block that totally trusts the context:
|
116
218
|
|
@@ -122,6 +224,7 @@ class HugAFriend
|
|
122
224
|
expects VK.new(:friend, Types.Instance(Friend))
|
123
225
|
# Or a less usual approach could be to trust duck typing
|
124
226
|
# expects VK.new(:friend, Types::Interface(:hug))
|
227
|
+
# Actually not all friends do appreciate hugs nor other forms of physical contact :P
|
125
228
|
|
126
229
|
executed do |context|
|
127
230
|
context.friend.hug
|
@@ -131,6 +234,8 @@ end
|
|
131
234
|
|
132
235
|
## Comparison with similar gems
|
133
236
|
|
237
|
+
A brief comparison about what similar gems offer to work with validation.
|
238
|
+
|
134
239
|
This is a comparison table I've done using my own limited experience w/ other solutions
|
135
240
|
and/or reading projects' READMEs. Don't take my word for it. And if I was wrong understanding
|
136
241
|
some features, feel free to drop me a line on Mastodon [@alessandrofazzi@mastodon.uno](https://mastodon.uno/@alessandrofazzi)
|
@@ -140,12 +245,15 @@ some features, feel free to drop me a line on Mastodon [@alessandrofazzi@mastodo
|
|
140
245
|
| presence | ✅ | ✅ | ❌ | ⚠️ Only input, not output | ✅ |
|
141
246
|
| static default | ✅ | ✅ | ❌ | ✅ | ✅ |
|
142
247
|
| dynamic default | ✅ | ✅ | ❌ | ✅ | ✅ |
|
143
|
-
| raise or fail control | ❌ | ✅ | ❌ | ❓ |
|
248
|
+
| raise or fail control | ❌ | ✅ | ❌ | ❓ | ✅ |
|
144
249
|
| type check | ❌ | ✅ | ❌ | ✅ | ✅ |
|
145
250
|
| data structure type check | ❌ | ❌ | ❌ | ❌ | ✅ |
|
146
251
|
| optional | ⚠️ through `default` | ✅ through `allow_nil` (which defaults to `true` 🤔 ❓) | ❌ | ⚠️ through `default` | ✅ |
|
147
|
-
|
|
252
|
+
| 1st party code | ✅ | ✅ | ✅ | ⚠️ ActiveModel::Validation | ❌ Dry::Types |
|
148
253
|
|
254
|
+
> NOTE: in `active_interaction` the fact that validation code isn't first party isn't an issue, since
|
255
|
+
> the gem is a Rails-only gem and validation is delegated to Rails, thus no additional dependencies
|
256
|
+
> are required. `light_service-validated_context` depends on additional gems from the dry-rb ecosystem
|
149
257
|
|
150
258
|
## Development
|
151
259
|
|
@@ -1,9 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
4
|
-
module
|
5
|
-
|
6
|
-
|
3
|
+
module LightService
|
4
|
+
module ValidatedContext
|
5
|
+
module Context
|
6
|
+
def define_accessor_methods_for_keys(keys)
|
7
|
+
super keys.map(&:to_sym)
|
8
|
+
end
|
7
9
|
end
|
8
10
|
end
|
9
11
|
end
|
@@ -1,31 +1,31 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
4
|
-
module
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
module LightService
|
4
|
+
module ValidatedContext
|
5
|
+
module ExpectedKeyVerifier
|
6
|
+
def keys
|
7
|
+
keys_as_symbols
|
8
|
+
end
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
|
10
|
+
def keys_as_symbols
|
11
|
+
action.expected_keys.map do |key|
|
12
|
+
next key unless key.is_a?(LightService::Context::ValidatedKey)
|
12
13
|
|
13
|
-
|
14
|
+
key.to_sym
|
15
|
+
end
|
14
16
|
end
|
15
|
-
end
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
def throw_error_predicate(keys)
|
22
|
-
type_check_and_coerce_keys!(raw_keys)
|
18
|
+
def raw_keys
|
19
|
+
action.expected_keys
|
20
|
+
end
|
23
21
|
|
24
|
-
|
22
|
+
def throw_error_predicate(_keys)
|
23
|
+
type_check_and_coerce_keys!(raw_keys)
|
25
24
|
|
26
|
-
|
25
|
+
return false if are_all_keys_valid?
|
27
26
|
|
28
|
-
|
27
|
+
should_throw_on_validation_error?
|
28
|
+
end
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
@@ -1,29 +1,50 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
4
|
-
module
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
3
|
+
module LightService
|
4
|
+
module ValidatedContext
|
5
|
+
module KeyVerifier
|
6
|
+
def initialize(context, action)
|
7
|
+
@validation_errors = []
|
8
|
+
|
9
|
+
super(context, action)
|
10
|
+
end
|
11
|
+
|
12
|
+
# rubocop:disable Metrics/AbcSize
|
13
|
+
# Refactoring this is out of my scope ATM
|
14
|
+
def type_check_and_coerce_keys!(keys)
|
15
|
+
errors = []
|
16
|
+
|
17
|
+
keys.each do |key|
|
18
|
+
next unless key.is_a?(LightService::Context::ValidatedKey)
|
19
|
+
|
20
|
+
begin
|
21
|
+
context[key.label] = key.type[context[key.label] || Dry::Types::Undefined]
|
22
|
+
rescue Dry::Types::CoercionError => e
|
23
|
+
errors << (
|
24
|
+
LightService::Configuration.localization_adapter.failure(key.message, action) ||
|
25
|
+
"[#{action}][:#{key.label}] #{e.message}"
|
26
|
+
)
|
27
|
+
end
|
15
28
|
end
|
29
|
+
|
30
|
+
@validation_errors = errors
|
16
31
|
end
|
17
|
-
#
|
18
|
-
@validation_errors = errors
|
19
|
-
end
|
32
|
+
# rubocop:enable Metrics/AbcSize
|
20
33
|
|
21
|
-
|
22
|
-
|
23
|
-
|
34
|
+
def are_all_keys_valid?
|
35
|
+
@validation_errors.none?
|
36
|
+
end
|
37
|
+
|
38
|
+
def error_message
|
39
|
+
@validation_errors.join(', ')
|
40
|
+
end
|
41
|
+
|
42
|
+
def should_throw_on_validation_error?
|
43
|
+
return true unless action.respond_to?(:fail_on_validation_error?) && action.fail_on_validation_error?
|
24
44
|
|
25
|
-
|
26
|
-
|
45
|
+
context.fail!(error_message)
|
46
|
+
false
|
47
|
+
end
|
27
48
|
end
|
28
49
|
end
|
29
50
|
end
|
@@ -1,31 +1,31 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
4
|
-
module
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
module LightService
|
4
|
+
module ValidatedContext
|
5
|
+
module PromisedKeyVerifier
|
6
|
+
def keys
|
7
|
+
keys_as_symbols
|
8
|
+
end
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
|
10
|
+
def keys_as_symbols
|
11
|
+
raw_keys.map do |key|
|
12
|
+
next key unless key.is_a?(LightService::Context::ValidatedKey)
|
12
13
|
|
13
|
-
|
14
|
+
key.to_sym
|
15
|
+
end
|
14
16
|
end
|
15
|
-
end
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
def throw_error_predicate(keys)
|
22
|
-
type_check_and_coerce_keys!(raw_keys)
|
18
|
+
def raw_keys
|
19
|
+
action.promised_keys
|
20
|
+
end
|
23
21
|
|
24
|
-
|
22
|
+
def throw_error_predicate(_keys)
|
23
|
+
type_check_and_coerce_keys!(raw_keys)
|
25
24
|
|
26
|
-
|
25
|
+
return false if are_all_keys_valid?
|
27
26
|
|
28
|
-
|
27
|
+
should_throw_on_validation_error?
|
28
|
+
end
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
@@ -1,13 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
4
|
-
|
5
|
-
|
6
|
-
label
|
7
|
-
|
3
|
+
module LightService
|
4
|
+
module ValidatedContext
|
5
|
+
class ValidatedKey
|
6
|
+
attr_reader :label, :type, :message
|
7
|
+
|
8
|
+
def initialize(label, type, message: nil)
|
9
|
+
@label = label
|
10
|
+
@type = type
|
11
|
+
@message = message
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_sym
|
15
|
+
label.to_sym
|
16
|
+
end
|
8
17
|
|
9
|
-
|
10
|
-
|
18
|
+
def to_s
|
19
|
+
label.to_s
|
20
|
+
end
|
11
21
|
end
|
12
22
|
end
|
13
23
|
end
|
@@ -1,29 +1,35 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "zeitwerk"
|
4
|
-
loader = Zeitwerk::Loader.
|
4
|
+
loader = Zeitwerk::Loader.new
|
5
|
+
loader.tag = 'LightService::I18n'
|
6
|
+
loader.inflector = Zeitwerk::GemInflector.new(__FILE__)
|
7
|
+
loader.push_dir(__dir__, :namespace => LightService)
|
5
8
|
loader.setup
|
6
9
|
|
7
10
|
require 'light-service'
|
8
11
|
require 'dry-types'
|
9
12
|
|
10
|
-
module
|
13
|
+
module LightService
|
14
|
+
module ValidatedContext; end
|
15
|
+
end
|
11
16
|
|
12
17
|
module LightService
|
13
18
|
class Context
|
14
|
-
ValidatedKey = ::ValidatedContext::ValidatedKey
|
15
|
-
|
19
|
+
ValidatedKey = LightService::ValidatedContext::ValidatedKey
|
20
|
+
FailOnValidationError = LightService::ValidatedContext::FailOnValidationError
|
21
|
+
prepend LightService::ValidatedContext::Context
|
16
22
|
|
17
23
|
class KeyVerifier
|
18
|
-
prepend ::ValidatedContext::KeyVerifier
|
24
|
+
prepend LightService::ValidatedContext::KeyVerifier
|
19
25
|
end
|
20
26
|
|
21
27
|
class ExpectedKeyVerifier
|
22
|
-
prepend ::ValidatedContext::ExpectedKeyVerifier
|
28
|
+
prepend LightService::ValidatedContext::ExpectedKeyVerifier
|
23
29
|
end
|
24
30
|
|
25
31
|
class PromisedKeyVerifier
|
26
|
-
prepend ::ValidatedContext::PromisedKeyVerifier
|
32
|
+
prepend LightService::ValidatedContext::PromisedKeyVerifier
|
27
33
|
end
|
28
34
|
end
|
29
35
|
|
@@ -32,7 +38,7 @@ module LightService
|
|
32
38
|
end
|
33
39
|
end
|
34
40
|
|
35
|
-
# Convenience
|
41
|
+
# Convenience alias for implementor
|
36
42
|
Types = LightService::Types unless Module.const_defined?('Types')
|
37
43
|
|
38
44
|
# Convenience alias for implementor
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: light_service-validated_context
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- "'Alessandro Fazzi'"
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-12-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dry-types
|
@@ -69,6 +69,7 @@ files:
|
|
69
69
|
- lib/light_service/validated_context.rb
|
70
70
|
- lib/light_service/validated_context/context.rb
|
71
71
|
- lib/light_service/validated_context/expected_key_verifier.rb
|
72
|
+
- lib/light_service/validated_context/fail_on_validation_error.rb
|
72
73
|
- lib/light_service/validated_context/key_verifier.rb
|
73
74
|
- lib/light_service/validated_context/promised_key_verifier.rb
|
74
75
|
- lib/light_service/validated_context/validated_key.rb
|