light-service-ext 0.1.9 → 0.1.11

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: 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