light-service-ext 0.1.9 → 0.1.11

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: 587a60d79dffd34dfbdbdbfc28e024c3a2983310209a8169e555e9ae88c8592b
4
- data.tar.gz: 817889b86ce56ae818070d9bf938a34c8efca969729a51a8c4d37d738d20e821
3
+ metadata.gz: ce41945d8919b3cef73709b2a43f77621fb19019d35f22b6719de3d4c4af7948
4
+ data.tar.gz: 1f899858676cc260d26d381a4d2c8dbb19688b3aedd666d5e3380c164bf6f495
5
5
  SHA512:
6
- metadata.gz: 538351e6b9c9050dcc81f91487c4fcd81e48e822589b5b3a77fa39909b733964d383241bd236c9ac199a32b018b8f9c6edf11efa5ef37d4051f1d0d0212810bd
7
- data.tar.gz: 8ebd87e41ceb3bb2db3982289ded3281fd0c0234a33f255c95f9ff926b0a1a62231ade022b9c251246b1f1af6ee4ff4e0e5afe9b7e452ad8c8f41a3489022dbd
6
+ metadata.gz: 7a60af56510f4c620b78d97f2609c668b69fd595e6ed6f1acd50056a963ffd9a499e8843ff0147c533f184901f3e636d2e397bfc536b7eeb68af0ec19f970dee
7
+ data.tar.gz: e0c0bcb40521c6ea56cec36a555f1ffc6ebb11b7942b4709d616e7ce75ddb34aa79132f4396602cdacb534338e72d7f37a8e62b51f0609ad636fbae5564a18fb
data/README.md CHANGED
@@ -173,12 +173,14 @@ end
173
173
  - `LightServiceExt::Status::INCOMPLETE`
174
174
  - `:last_failed_context` ~ copy of context that failed e.g. with `errors` field present
175
175
  - `internal_only` ~ includes the likes of raised error summary and should never be passed to endpoint responses
176
+ - `meta` ~ used to store any additional information that could be helpful especially for debugging purposes.
176
177
  Example
177
178
 
178
179
  ````ruby
179
180
  input = { order: order }
180
181
  overrides = {} # optionally override `params`, `errors` and `allow_raise_on_failure`
181
- LightServiceExt::ApplicationContext.make_with_defaults(input, overrides)
182
+ meta = { current_user_id: 12345, request_id: some-unique-request-id, impersonator_id: 54321 }
183
+ LightServiceExt::ApplicationContext.make_with_defaults(input, overrides, meta: meta)
182
184
 
183
185
  # => { input: { order: order },
184
186
  # errors: { email: ['not found'] },
@@ -190,7 +192,8 @@ LightServiceExt::ApplicationContext.make_with_defaults(input, overrides)
190
192
  # api_responses: [ { user_id: 1, status: 'ACTIVE' } ],
191
193
  # last_failed_context: {input: { order: order }, params: {}, ...},
192
194
  # allow_raise_on_failure: true,
193
- # internal_only: { error_info: ErrorInfoInstance }
195
+ # internal_only: { error_info: ErrorInfoInstance },
196
+ # meta: { current_user_id: 12345, request_id: some-unique-request-id, impersonator_id: 54321 }
194
197
  # }
195
198
  ````
196
199
 
@@ -4,9 +4,31 @@ module LightServiceExt
4
4
  class ApplicationAction
5
5
  extend LightService::Action
6
6
 
7
+
7
8
  def self.inherited(base)
9
+ base.extend LifecycleMethods
8
10
  base.singleton_class.prepend AroundActionExecuteExtension
9
11
  super
10
12
  end
13
+
14
+ module LifecycleMethods
15
+ attr_writer :before_execute_block, :after_execute_block, :after_success_block, :after_failure_block
16
+
17
+ def before_execute_block
18
+ @before_execute_block ||= ->(_context) {}
19
+ end
20
+
21
+ def after_execute_block
22
+ @after_execute_block ||= ->(_context) {}
23
+ end
24
+
25
+ def after_success_block
26
+ @after_success_block ||= ->(_context) {}
27
+ end
28
+
29
+ def after_failure_block
30
+ @after_failure_block ||= ->(_context) {}
31
+ end
32
+ end
11
33
  end
12
34
  end
@@ -25,7 +25,8 @@ module LightServiceExt
25
25
  api_responses: [],
26
26
  last_failed_context: nil,
27
27
  allow_raise_on_failure: LightServiceExt.config.allow_raise_on_failure?,
28
- internal_only: {}
28
+ internal_only: {},
29
+ meta: {}
29
30
  }.freeze
30
31
  end
31
32
  end
@@ -63,6 +64,11 @@ module LightServiceExt
63
64
  add_attrs_to_ctx(:internal_only, **attrs)
64
65
  end
65
66
 
67
+ def add_meta(**attrs)
68
+ add_attrs_to_ctx(:meta, **attrs)
69
+ end
70
+
71
+
66
72
  def record_raised_error(error)
67
73
  @error_info = ErrorInfo.new(error)
68
74
  error_type = @error_info.type
@@ -3,10 +3,17 @@
3
3
  module LightServiceExt
4
4
  module AroundActionExecuteExtension
5
5
  def execute(context)
6
+ return context if context.status == Status::COMPLETE
7
+ self.before_execute_block.call(context)
8
+
6
9
  result = super(context.merge(invoked_action: self))
7
10
 
8
11
  context.merge!(result)
9
12
  context.fail! if result.errors.present?
13
+
14
+ self.after_execute_block.call(context)
15
+ self.after_success_block.call(context) if result.success?
16
+ self.after_failure_block.call(context) if result.failure?
10
17
  result
11
18
  end
12
19
  end
@@ -6,21 +6,26 @@ module LightServiceExt
6
6
 
7
7
  def self.call(context)
8
8
  with_error_handler(ctx: context) do
9
- result = yield
9
+ result = yield || context
10
10
  return context if outcomes_complete?(ctx: context, result: result)
11
11
 
12
+ invoked_action = result.invoked_action
13
+ return context if invoked_action.nil?
14
+
15
+ context.add_to_successful_actions(invoked_action.name)
16
+
12
17
  merge_api_responses!(ctx: context, result: result)
18
+ context
13
19
  end
14
20
  end
15
21
 
16
22
  class << self
17
23
  def merge_api_responses!(ctx:, result:)
18
- invoked_action = result.invoked_action
19
- return if invoked_action.nil?
24
+ api_response = result.current_api_response
25
+ return if api_response.blank?
20
26
 
21
- ctx.add_to_successful_actions(invoked_action.name)
22
- ctx.add_to_api_responses(result.current_api_response)
23
- ctx
27
+ ctx.add_to_api_responses(api_response)
28
+ nil
24
29
  end
25
30
 
26
31
  def outcomes_complete?(ctx:, result:)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LightServiceExt
4
- VERSION = "0.1.9"
4
+ VERSION = "0.1.11"
5
5
  end
@@ -4,7 +4,7 @@
4
4
  module LightServiceExt
5
5
  module WithErrorHandler
6
6
  def with_error_handler(ctx:)
7
- @result = yield || ApplicationContext.make_with_defaults
7
+ @result = yield || ctx
8
8
  rescue StandardError => e
9
9
  ctx.record_raised_error(e)
10
10
  ctx.add_status(Status::COMPLETE)
@@ -16,7 +16,7 @@ Gem::Specification.new do |gem|
16
16
  gem.name = "light-service-ext"
17
17
  gem.require_paths = ["lib"]
18
18
  gem.version = LightServiceExt::VERSION
19
- gem.required_ruby_version = ">= 3"
19
+ gem.required_ruby_version = ">= 2.7"
20
20
 
21
21
  gem.metadata["homepage_uri"] = gem.homepage
22
22
  gem.metadata["source_code_uri"] = gem.homepage
@@ -1,19 +1,17 @@
1
1
  module LightServiceExt
2
2
  RSpec.describe ApplicationAction do
3
- FakeApplicationAction = Class.new(described_class) do
4
- executed do |context|
5
- value = context.dig(:input, :callback).call
6
- context.add_params(value: value)
7
- context.add_errors!(value: value)
3
+ let(:fake_action) do
4
+ Class.new(described_class) do
5
+ executed do |context|
6
+ value = context.dig(:input, :callback).call
7
+ context.add_params(value: value)
8
+ context.add_errors!(value: value)
9
+ end
8
10
  end
9
11
  end
10
12
 
11
13
  let(:organizer_class) do
12
- Class.new(ApplicationOrganizer) do
13
- def self.steps
14
- [FakeApplicationAction]
15
- end
16
- end
14
+ Class.new(ApplicationOrganizer) do end
17
15
  end
18
16
 
19
17
  let(:value) { 'some-value' }
@@ -22,18 +20,54 @@ module LightServiceExt
22
20
  let(:ctx) do
23
21
  LightService::Testing::ContextFactory
24
22
  .make_from(organizer_class)
25
- .for(FakeApplicationAction)
23
+ .for(fake_action)
26
24
  .with(callback: callback)
27
25
  end
28
26
 
29
- subject(:context) do
30
- FakeApplicationAction.execute(ctx)
27
+ subject(:executed_ctx) { fake_action.execute(ctx) }
28
+
29
+ before do
30
+ allow(organizer_class).to receive(:steps) { [fake_action] }
31
31
  end
32
32
 
33
33
  it 'adds value returned by callback to params' do
34
- expect(context.keys).to include(:input, :errors, :params)
34
+ expect(executed_ctx.keys).to include(:input, :errors, :params)
35
+
36
+ expect(executed_ctx[:params]).to eql({ value: value })
37
+ end
38
+
39
+ describe 'lifecycle callbacks' do
40
+ before do
41
+ allow(fake_action.before_execute_block).to receive(:call)
42
+ allow(fake_action.after_execute_block).to receive(:call)
43
+ allow(fake_action.after_success_block).to receive(:call)
44
+ allow(fake_action.after_failure_block).to receive(:call)
45
+ end
35
46
 
36
- expect(context[:params]).to eql({ value: value })
47
+ it 'calls appropriate lifecycle callbacks' do
48
+ executed_ctx
49
+
50
+ expect(fake_action.before_execute_block).to have_received(:call).with(kind_of(ApplicationContext)).at_least(:once)
51
+ expect(fake_action.after_execute_block).to have_received(:call).with(kind_of(ApplicationContext))
52
+ expect(fake_action.after_success_block).not_to have_received(:call).with(kind_of(ApplicationContext))
53
+ expect(fake_action.after_failure_block).to have_received(:call).at_least(:once)
54
+ end
55
+
56
+ context 'with failure' do
57
+ before do
58
+ allow_any_instance_of(ApplicationContext).to receive(:errors) { {} }
59
+ allow_any_instance_of(ApplicationContext).to receive(:success?) { true }
60
+ end
61
+
62
+ it 'calls appropriate lifecycle callbacks' do
63
+ executed_ctx
64
+
65
+ expect(fake_action.before_execute_block).to have_received(:call).with(kind_of(ApplicationContext)).at_least(:once)
66
+ expect(fake_action.after_execute_block).to have_received(:call).with(kind_of(ApplicationContext)).at_least(:once)
67
+ expect(fake_action.after_success_block).to have_received(:call).with(kind_of(ApplicationContext))
68
+ expect(fake_action.after_failure_block).to_not have_received(:call)
69
+ end
70
+ end
37
71
  end
38
72
  end
39
73
  end
@@ -325,6 +325,21 @@ module LightServiceExt
325
325
 
326
326
  subject(:ctx_with_defaults) { described_class.make_with_defaults(input, overrides) }
327
327
 
328
+ describe '#add_meta' do
329
+ it 'adds meta to context' do
330
+ ctx_with_defaults.add_meta(key => value)
331
+ expect(ctx_with_defaults.meta).to eql(key => value)
332
+ end
333
+ end
334
+
335
+ context 'with meta as an override' do
336
+ let(:overrides) { { meta: { key: 'some-value' } } }
337
+
338
+ it 'adds meta to context' do
339
+ expect(ctx_with_defaults.meta).to eql(key => value)
340
+ end
341
+ end
342
+
328
343
  context 'with non symbolized input keys' do
329
344
  let(:input) { { "key" => 'some-value' } }
330
345
 
@@ -346,6 +361,7 @@ module LightServiceExt
346
361
  invoked_action
347
362
  current_api_response
348
363
  last_failed_context
364
+ meta
349
365
  ])
350
366
 
351
367
  expect(ctx_with_defaults[:input]).to eql(input)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: light-service-ext
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 0.1.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Desmond O'Leary
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-09-24 00:00:00.000000000 Z
11
+ date: 2023-09-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: light-service
@@ -205,7 +205,6 @@ files:
205
205
  - spec/light-service-ext/application_orchestrator_spec.rb
206
206
  - spec/light-service-ext/application_organizer_spec.rb
207
207
  - spec/light-service-ext/application_validator_action_spec.rb
208
- - spec/light-service-ext/around_action_execute_extension_spec.rb
209
208
  - spec/light-service-ext/configuration_spec.rb
210
209
  - spec/light-service-ext/context_error_spec.rb
211
210
  - spec/light-service-ext/error_info_spec.rb
@@ -229,7 +228,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
229
228
  requirements:
230
229
  - - ">="
231
230
  - !ruby/object:Gem::Version
232
- version: '3'
231
+ version: '2.7'
233
232
  required_rubygems_version: !ruby/object:Gem::Requirement
234
233
  requirements:
235
234
  - - ">="
@@ -249,7 +248,6 @@ test_files:
249
248
  - spec/light-service-ext/application_orchestrator_spec.rb
250
249
  - spec/light-service-ext/application_organizer_spec.rb
251
250
  - spec/light-service-ext/application_validator_action_spec.rb
252
- - spec/light-service-ext/around_action_execute_extension_spec.rb
253
251
  - spec/light-service-ext/configuration_spec.rb
254
252
  - spec/light-service-ext/context_error_spec.rb
255
253
  - spec/light-service-ext/error_info_spec.rb
@@ -1,56 +0,0 @@
1
- module LightServiceExt
2
- RSpec.describe AroundActionExecuteExtension do
3
- let(:fake_action) do
4
- Class.new do
5
- prepend AroundActionExecuteExtension
6
-
7
- def execute(_ctx)
8
- fake_resultant_ctx # HACK: to allow us to control returned value from prepended execute method
9
- end
10
-
11
- def fake_resultant_ctx; end
12
- end.new
13
- end
14
-
15
- describe '#execute' do
16
- let(:input) { { key: 'some-value' } }
17
- let(:orig_ctx) { ApplicationContext.make_with_defaults }
18
- let(:errors) { {} }
19
- let(:frozen_resultant_ctx) do
20
- ApplicationContext.make_with_defaults.merge({ key: 'some-value', errors: errors }).freeze
21
- end
22
-
23
- subject(:executed_ctx) { fake_action.execute(orig_ctx) }
24
-
25
- before do
26
- allow(fake_action).to receive(:fake_resultant_ctx) { frozen_resultant_ctx }
27
- end
28
-
29
- it 'returns unmodified resultant context' do
30
- expect(executed_ctx).to eql(frozen_resultant_ctx)
31
- end
32
-
33
- it 'calls underlying prepended execute method' do
34
- executed_ctx
35
-
36
- expect(fake_action).to have_received(:fake_resultant_ctx)
37
- end
38
-
39
- it 'merges key value pairs from underlying execute to original context' do
40
- executed_ctx
41
-
42
- expect(orig_ctx.keys).to include(:key)
43
- end
44
-
45
- context 'with resultant ctx with errors' do
46
- let(:errors) { { key: 'must be filled' } }
47
-
48
- it 'fails original context' do
49
- executed_ctx
50
-
51
- expect(orig_ctx.failure?).to be_truthy
52
- end
53
- end
54
- end
55
- end
56
- end