the_help 3.0.0 → 3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 58c4ca451c960bbd6f54ee05d9a786db32365e8630cd57d1730d21b1e23b4b28
4
- data.tar.gz: d6b16972071beed84aebb226bf77be94e8e04bdc38ea8eb452170da903287e05
3
+ metadata.gz: b1529f0d2832e0d69096c3a00b7bf5a909b75f8b14b59a1a49aed87248d4935a
4
+ data.tar.gz: 80f2d717ef93107427856d2057672381067ef52939083f79dae38932df8c4b23
5
5
  SHA512:
6
- metadata.gz: 31854f6f5c438280a532d0f9674f10409873164fa240b06716939972d72dd28de48244dc9ab0b160d5714d9c351d5f37da2323cbf33780bcf4c62d23aeadbf2b
7
- data.tar.gz: 59f1e173753355dbbaec54c1d4411c49184ff769e3a84061c5f81413e634761a9b959b86d8ffe9ff86bc54c3b2b316671bd75f477ee3fe693e7fbf7883ba6671
6
+ metadata.gz: 376ecebb8cd352e0217f8d27fe3f7784ab2bf258454da67f9abdf1b68ba67bf99214f683e8041ef68e016ccb55cfe2492910eae0521652469ffe0b77b86d5e4a
7
+ data.tar.gz: b476d0491c4cb3a2f1c9a0149b1ac385d0f4ac6d033d4f0de8a061be6e1c47bbcda58a01fab928d0b93855aaeb14ffcc59d7030913923182479c4ecff54829ca
@@ -0,0 +1,11 @@
1
+ # TheHelp Changelog #
2
+
3
+ ## 3.3.0 ##
4
+
5
+ * Calling `#stop!` with no arguments in a service definition will now check that a result was set
6
+ with either `#result.success` or `#result.error` and raise `TheHelp::NoResultError` if no result
7
+ was set.
8
+
9
+ * You can now call `#stop!` with both a `type:` and `value:` argument. `type:` can be either
10
+ `:error` (the default) or `:success`, and `value:` can be any object. Calling in this manner
11
+ will set the service result to the specified type and value.
@@ -1,50 +1,55 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- the_help (3.0.0)
4
+ the_help (3.3.1)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
- ast (2.4.0)
10
- byebug (11.0.1)
11
- diff-lcs (1.3)
12
- jaro_winkler (1.5.3)
13
- parallel (1.18.0)
14
- parser (2.6.5.0)
15
- ast (~> 2.4.0)
9
+ ast (2.4.1)
10
+ byebug (11.1.3)
11
+ diff-lcs (1.4.4)
12
+ parallel (1.19.2)
13
+ parser (2.7.2.0)
14
+ ast (~> 2.4.1)
16
15
  rainbow (3.0.0)
17
- rake (10.5.0)
16
+ rake (13.0.1)
17
+ regexp_parser (1.8.2)
18
+ rexml (3.2.4)
18
19
  rspec (3.9.0)
19
20
  rspec-core (~> 3.9.0)
20
21
  rspec-expectations (~> 3.9.0)
21
22
  rspec-mocks (~> 3.9.0)
22
- rspec-core (3.9.0)
23
- rspec-support (~> 3.9.0)
24
- rspec-expectations (3.9.0)
23
+ rspec-core (3.9.3)
24
+ rspec-support (~> 3.9.3)
25
+ rspec-expectations (3.9.3)
25
26
  diff-lcs (>= 1.2.0, < 2.0)
26
27
  rspec-support (~> 3.9.0)
27
- rspec-mocks (3.9.0)
28
+ rspec-mocks (3.9.1)
28
29
  diff-lcs (>= 1.2.0, < 2.0)
29
30
  rspec-support (~> 3.9.0)
30
- rspec-support (3.9.0)
31
- rubocop (0.75.1)
32
- jaro_winkler (~> 1.5.1)
31
+ rspec-support (3.9.4)
32
+ rubocop (0.93.1)
33
33
  parallel (~> 1.10)
34
- parser (>= 2.6)
34
+ parser (>= 2.7.1.5)
35
35
  rainbow (>= 2.2.2, < 4.0)
36
+ regexp_parser (>= 1.8)
37
+ rexml
38
+ rubocop-ast (>= 0.6.0)
36
39
  ruby-progressbar (~> 1.7)
37
- unicode-display_width (>= 1.4.0, < 1.7)
40
+ unicode-display_width (>= 1.4.0, < 2.0)
41
+ rubocop-ast (1.1.0)
42
+ parser (>= 2.7.1.5)
38
43
  ruby-progressbar (1.10.1)
39
- unicode-display_width (1.6.0)
40
- yard (0.9.20)
44
+ unicode-display_width (1.7.0)
45
+ yard (0.9.25)
41
46
 
42
47
  PLATFORMS
43
48
  ruby
44
49
 
45
50
  DEPENDENCIES
46
51
  byebug
47
- rake (~> 10.0)
52
+ rake (~> 13.0)
48
53
  rspec (~> 3.0)
49
54
  rubocop (~> 0.50)
50
55
  the_help!
data/README.md CHANGED
@@ -118,6 +118,33 @@ call_service(MyService, foo: false)
118
118
  # raises the exception ArgumentError with the message 'foo must be true'
119
119
  ```
120
120
 
121
+ If you want to make sure the exception's backtrace points to the correct line of code, raise the
122
+ exception in a block provided to the `#error` method:
123
+
124
+ ```ruby
125
+ class MyService < TheHelp::Service
126
+ authorization_policy allow_all: true
127
+
128
+ input :foo
129
+
130
+ main do
131
+ if foo
132
+ result.success 'bar'
133
+ else
134
+ result.error { raise ArgumentError.new('foo must be true') }
135
+ end
136
+ end
137
+ end
138
+
139
+ call_service(MyService, foo: false)
140
+ # raises the exception ArgumentError with the message 'foo must be true'
141
+ ```
142
+
143
+ With the block form, the backtrace will point to the line where the exception was first raised
144
+ rather than to the `#value!` method, however all other code execution will continue until the
145
+ point where the `#value!` method is called (as long as the exception is a subtype of
146
+ `StandardError`.)
147
+
121
148
  ### Running Callbacks
122
149
 
123
150
  In some cases a simple success or error result is not sufficient to describe the various results
@@ -150,18 +150,42 @@ module TheHelp
150
150
  self
151
151
  end
152
152
 
153
- def input(name, **options)
154
- attr_accessor name, make_private: true
155
- if options.key?(:default)
156
- required_inputs.delete(name)
157
- define_method(name) do
158
- instance_variable_get("@#{name}") || options[:default]
159
- end
153
+ # Defines a service input
154
+ #
155
+ # The specified input becomes a named parameter for the service's `#call` method.
156
+ #
157
+ # @param name [Symbol] This becomes the name of the input parameter
158
+ #
159
+ # @param block [Proc] If a block is provided, the contents of the block will be executed in
160
+ # the scope of the service instance in order to provide the default
161
+ # value of the input. This is different than providing a Proc to the
162
+ # `:default` option, which would simply return the Proc itself as the
163
+ # default value rather than calling it.
164
+ #
165
+ # @option options [Object] :default If specified (and no block is given), this becomes the
166
+ # literal default value for the input.
167
+ def input(name, **options, &block)
168
+ if options.key?(:default) || block
169
+ make_optional_input(name, options[:default], &block)
160
170
  else
171
+ attr_accessor name, make_private: true
161
172
  required_inputs << name
162
173
  end
163
174
  self
164
175
  end
176
+
177
+ private
178
+
179
+ def make_optional_input(name, default, &block)
180
+ attr_writer name
181
+ private "#{name}="
182
+ default_routine = block || -> { default }
183
+ define_method("_#{name}", &default_routine)
184
+ define_method(name) do
185
+ instance_variable_get("@#{name}") || send("_#{name}")
186
+ end
187
+ required_inputs.delete(name)
188
+ end
165
189
  end
166
190
 
167
191
  # Holds the result of running a service as well as the execution status
@@ -194,8 +218,16 @@ module TheHelp
194
218
  freeze
195
219
  end
196
220
 
197
- def error(value)
198
- self.value = value
221
+ def error(value = nil, &block)
222
+ self.value = if block_given?
223
+ begin
224
+ self.value = block.call
225
+ rescue StandardError => e
226
+ e
227
+ end
228
+ else
229
+ value
230
+ end
199
231
  self.status = :error
200
232
  freeze
201
233
  end
@@ -231,16 +263,21 @@ module TheHelp
231
263
  # @return [TheHelp::Service::Result]
232
264
  def call
233
265
  validate_service_definition
266
+
234
267
  catch(:stop) do
235
268
  authorize
236
269
  log_service_call
237
270
  main
238
271
  check_result!
239
- self.block_result = yield result if block_given?
240
272
  end
273
+
274
+ self.block_result = yield result if block_given?
275
+
241
276
  throw :stop if stop_caller
277
+
242
278
  return block_result if block_given?
243
- return result
279
+
280
+ result
244
281
  end
245
282
 
246
283
  private
@@ -283,11 +320,20 @@ module TheHelp
283
320
  return if authorized?
284
321
  logger.warn("Unauthorized attempt to access #{self.class.name}/#{__id__} " \
285
322
  "as #{context.inspect}")
286
- run_callback(not_authorized, service: self.class, context: context)
323
+ result.error run_callback(not_authorized, service: self.class, context: context)
287
324
  stop!
288
325
  end
289
326
 
290
- def stop!
327
+ def stop!(type: :error, **opts)
328
+ if opts.has_key?(:value)
329
+ if type == :success
330
+ result.success value
331
+ else
332
+ result.error value
333
+ end
334
+ else
335
+ check_result!
336
+ end
291
337
  throw :stop
292
338
  end
293
339
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TheHelp
4
- VERSION = '3.0.0'
4
+ VERSION = '3.3.1'
5
5
  end
@@ -23,7 +23,7 @@ Gem::Specification.new do |spec|
23
23
  spec.require_paths = ['lib']
24
24
 
25
25
  spec.add_development_dependency 'byebug'
26
- spec.add_development_dependency 'rake', '~> 10.0'
26
+ spec.add_development_dependency 'rake', '~> 13.0'
27
27
  spec.add_development_dependency 'rspec', '~> 3.0'
28
28
  spec.add_development_dependency 'rubocop', '~> 0.50'
29
29
  spec.add_development_dependency 'yard'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: the_help
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Wilger
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-11-01 00:00:00.000000000 Z
11
+ date: 2020-10-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: byebug
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '13.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: '13.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -93,6 +93,7 @@ files:
93
93
  - ".rubocop.yml"
94
94
  - ".tool-versions"
95
95
  - ".travis.yml"
96
+ - CHANGELOG.md
96
97
  - CODE_OF_CONDUCT.md
97
98
  - Gemfile
98
99
  - Gemfile.lock