metaractor 2.0.0 → 2.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/README.md +137 -0
- data/lib/metaractor/failure_output.rb +39 -0
- data/lib/metaractor/version.rb +1 -1
- data/lib/metaractor.rb +1 -0
- 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: 6e1ab1a1cd9e5ab11a43462021e80787506646d87cf41816ce67396a3cf5da9d
|
4
|
+
data.tar.gz: e9b61e4f8181d10ae02d2b84f712f30eb9a36e457d1dac7dff6a43c802b93785
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eb29390b6649c80867a4455e642cd75bc1fbc6732b583e4441f5fc0a42b3dee14ede6ceaad933322073e3f0dcc328e936e2d9c3f120ea97e75e38acb01cbe1d8
|
7
|
+
data.tar.gz: faa366cc5ad09fed640918a295696e3089a9ef96de61ce3cb073c0a6ee029be58c73db16bc056f781f9b795c776149437c7cfddc0bd84d2182d7ca5da3dabb96
|
data/README.md
CHANGED
@@ -104,6 +104,143 @@ before do
|
|
104
104
|
end
|
105
105
|
```
|
106
106
|
|
107
|
+
### Structured Errors
|
108
|
+
As of v2.0.0, metaractor supports structured errors.
|
109
|
+
```ruby
|
110
|
+
class UpdateUser
|
111
|
+
include Metaractor
|
112
|
+
|
113
|
+
optional :is_admin
|
114
|
+
optional :user
|
115
|
+
|
116
|
+
def call
|
117
|
+
fail_with_error!(
|
118
|
+
errors: {
|
119
|
+
base: 'Invalid configuration',
|
120
|
+
is_admin: 'must be true or false',
|
121
|
+
user: [ title: 'cannot be blank', username: ['must be unique', 'must not be blank'] ]
|
122
|
+
}
|
123
|
+
)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
result = UpdateUser.call
|
128
|
+
result.error_messages
|
129
|
+
# => [
|
130
|
+
# 'Invalid configuration',
|
131
|
+
# 'is_admin must be true or false',
|
132
|
+
# 'user.title cannot be blank',
|
133
|
+
# 'user.username must be unique',
|
134
|
+
# 'user.username must not be blank'
|
135
|
+
# ]
|
136
|
+
|
137
|
+
result.errors.full_messages_for(:user)
|
138
|
+
# => [
|
139
|
+
# 'title cannot be blank',
|
140
|
+
# 'username must be unique',
|
141
|
+
# 'username must not be blank'
|
142
|
+
# ]
|
143
|
+
|
144
|
+
# The arguments to `slice` are a list of paths.
|
145
|
+
# In this case we're asking for the errors under `base` and also
|
146
|
+
# the errors found under user _and_ title.
|
147
|
+
result.errors.slice(:base, [:user, :title])
|
148
|
+
# => {
|
149
|
+
# base: 'Invalid configuration',
|
150
|
+
# user: { title: 'cannot be blank' }
|
151
|
+
# }
|
152
|
+
|
153
|
+
result.errors.to_h
|
154
|
+
# => {
|
155
|
+
# base: 'Invalid configuration',
|
156
|
+
# is_admin: 'must be true or false',
|
157
|
+
# user: {
|
158
|
+
# title: 'cannot be blank',
|
159
|
+
# username: ['must be unique', 'must not be blank']
|
160
|
+
# }
|
161
|
+
# }
|
162
|
+
```
|
163
|
+
|
164
|
+
### Spec Helpers
|
165
|
+
Enable the helpers and/or matchers:
|
166
|
+
```ruby
|
167
|
+
RSpec.configure do |config|
|
168
|
+
config.include Metaractor::Spec::Helpers
|
169
|
+
config.include Metaractor::Spec::Matchers
|
170
|
+
end
|
171
|
+
```
|
172
|
+
|
173
|
+
#### Helpers
|
174
|
+
- `context_creator`
|
175
|
+
```ruby
|
176
|
+
# context_creator(error_message: nil, error_messages: [], errors: [], valid: nil, invalid: nil, success: nil, failure: nil, **attributes)
|
177
|
+
|
178
|
+
# Create a blank context:
|
179
|
+
context_creator
|
180
|
+
|
181
|
+
# Create a context with some data:
|
182
|
+
context_creator(message: message, user: user)
|
183
|
+
|
184
|
+
# Create an invalid context:
|
185
|
+
context_creator(error_message: "invalid context", invalid: true)
|
186
|
+
|
187
|
+
# Create a context with string errors:
|
188
|
+
context_creator(error_messages: ["That didn't work", "Neither did this"])
|
189
|
+
|
190
|
+
# Create a context with structured errors:
|
191
|
+
context_creator(
|
192
|
+
user: user,
|
193
|
+
errors: {
|
194
|
+
user: {
|
195
|
+
email: 'must be unique'
|
196
|
+
},
|
197
|
+
profile: {
|
198
|
+
first_name: 'cannot be blank'
|
199
|
+
}
|
200
|
+
}
|
201
|
+
)
|
202
|
+
```
|
203
|
+
|
204
|
+
#### Matchers
|
205
|
+
- `include_errors`
|
206
|
+
```ruby
|
207
|
+
result = context_creator(
|
208
|
+
errors: {
|
209
|
+
user: [
|
210
|
+
title: 'cannot be blank',
|
211
|
+
username: ['must be unique', 'must not be blank']
|
212
|
+
]
|
213
|
+
}
|
214
|
+
)
|
215
|
+
|
216
|
+
expect(result).to include_errors(
|
217
|
+
'username must be unique',
|
218
|
+
'username must not be blank'
|
219
|
+
).at_path(:user, :username)
|
220
|
+
|
221
|
+
expect(result).to include_errors('user.title cannot be blank')
|
222
|
+
```
|
223
|
+
|
224
|
+
### Error Output
|
225
|
+
Metaractor customizes the exception message for `Interactor::Failure`:
|
226
|
+
```
|
227
|
+
Interactor::Failure:
|
228
|
+
Errors:
|
229
|
+
{:base=>"NOPE"}
|
230
|
+
|
231
|
+
Previously Called:
|
232
|
+
Chained
|
233
|
+
|
234
|
+
Context:
|
235
|
+
{:parent=>true, :chained=>true}
|
236
|
+
```
|
237
|
+
|
238
|
+
You can further customize the exception message:
|
239
|
+
```ruby
|
240
|
+
# Configure FailureOutput to use awesome_print
|
241
|
+
Metaractor::FailureOutput.hash_formatter = ->(hash) { hash.ai }
|
242
|
+
```
|
243
|
+
|
107
244
|
### Further Reading
|
108
245
|
For more examples of all of the above approaches, please see the specs.
|
109
246
|
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Metaractor
|
2
|
+
module FailureOutput
|
3
|
+
def self.format_hash(hash)
|
4
|
+
if @hash_formatter.nil?
|
5
|
+
@hash_formatter = ->(hash){ hash.inspect }
|
6
|
+
end
|
7
|
+
|
8
|
+
@hash_formatter.call(hash)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.hash_formatter=(callable)
|
12
|
+
@hash_formatter = callable
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
str = ''
|
17
|
+
|
18
|
+
if !context.errors.empty?
|
19
|
+
str << "Errors:\n"
|
20
|
+
str << Metaractor::FailureOutput.format_hash(context.errors.to_h)
|
21
|
+
str << "\n\n"
|
22
|
+
end
|
23
|
+
|
24
|
+
if !context._called.empty?
|
25
|
+
str << "Previously Called:\n"
|
26
|
+
context._called.each do |interactor|
|
27
|
+
str << interactor.class.name.to_s
|
28
|
+
end
|
29
|
+
str << "\n\n"
|
30
|
+
end
|
31
|
+
|
32
|
+
str << "Context:\n"
|
33
|
+
str << Metaractor::FailureOutput.format_hash(context.to_h.reject{|k,_| k == :errors})
|
34
|
+
str
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
Interactor::Failure.send(:include, Metaractor::FailureOutput)
|
data/lib/metaractor/version.rb
CHANGED
data/lib/metaractor.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: metaractor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Schlesinger
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-04-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: interactor
|
@@ -103,6 +103,7 @@ files:
|
|
103
103
|
- lib/metaractor/context_validity.rb
|
104
104
|
- lib/metaractor/errors.rb
|
105
105
|
- lib/metaractor/fail_from_context.rb
|
106
|
+
- lib/metaractor/failure_output.rb
|
106
107
|
- lib/metaractor/handle_errors.rb
|
107
108
|
- lib/metaractor/parameters.rb
|
108
109
|
- lib/metaractor/run_with_context.rb
|