servactory 2.4.3 → 2.5.0.rc2

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: 326823cbdccc9f0f3dfca48c5b2ddbf518d50a713c45280b19da21ddf4483907
4
- data.tar.gz: ebf05e0ebdd4b9941809137d3f1e092ac72560fc199689d91713c253edcb3cd1
3
+ metadata.gz: ce8eb77c5347f231539b115081d7706f6546830ccda8269e414ba05d097d3d85
4
+ data.tar.gz: 3393084486439b10177a5a13eb4826f4b2ab19c21aefbe92a23aaa7c5ce0096c
5
5
  SHA512:
6
- metadata.gz: b99933c23fd601a8e5164a425695799b94648da7ba02232a676938f00466ce8bc60ecc59db4257f3d9e1b60ba98dbabb3f021bfbff263c085fe7c800c0b47976
7
- data.tar.gz: db16a9b4bbdfcfa4fdd11c6eabf8ae45468c8989d34ddc6a268df17e29e68878c5be9db72fda4a5e07529d2a6ccd3a9e2a1a2eb73b60389e9bd9fd637b894a56
6
+ metadata.gz: 4ae8873bb459d8bedac4d64cee6ca8f4049e57fd87f62e3842b47e5f20415196cc6470704e3d9fd1d2c380e75ae2ffdcd5f93ad5dfc87e677b259ef215d8974b
7
+ data.tar.gz: c0a37302c68b09fa238656f88bcdd536bb81d1a5f47db60ac8de52d7455d534b3622cbcd5568474e7d303b86bb7a6f5219f1f7e5fa0c7a5a0833d955194406d9
data/README.md CHANGED
@@ -38,13 +38,15 @@ class UserService::Authenticate < Servactory::Base
38
38
 
39
39
  output :user, type: User
40
40
 
41
+ make :authenticate!
42
+
41
43
  private
42
44
 
43
- def call
45
+ def authenticate!
44
46
  if (user = User.authenticate_by(email: inputs.email, password: inputs.password)).present?
45
47
  outputs.user = user
46
48
  else
47
- fail!(message: "Authentication failed")
49
+ fail!(message: "Authentication failed", meta: { email: inputs.email })
48
50
  end
49
51
  end
50
52
  end
@@ -55,14 +57,14 @@ end
55
57
  ```ruby
56
58
  class SessionsController < ApplicationController
57
59
  def create
58
- service_result = UserService::Authenticate.call(**session_params)
60
+ service = UserService::Authenticate.call(**session_params)
59
61
 
60
- if service_result.success?
61
- session[:current_user_id] = service_result.user.id
62
- redirect_to service_result.user
62
+ if service.success?
63
+ session[:current_user_id] = service.user.id
64
+ redirect_to service.user
63
65
  else
64
- flash.now[:message] = service_result.error.message
65
- render :new
66
+ flash.now[:alert] = service.error.message
67
+ render :new, status: :unprocessable_entity
66
68
  end
67
69
  end
68
70
 
@@ -17,6 +17,25 @@ module Servactory
17
17
 
18
18
  private
19
19
 
20
+ # NOTE: Based on https://github.com/rails/rails/blob/main/activesupport/lib/active_support/rescuable.rb
21
+ def fail_on!(*class_names, with: nil, &block) # rubocop:disable Metrics/MethodLength
22
+ with ||= block || ->(exception:) { exception.message }
23
+
24
+ class_names.each do |class_name|
25
+ key = if class_name.is_a?(Module) && class_name.respond_to?(:===)
26
+ class_name.name
27
+ elsif class_name.is_a?(String)
28
+ class_name
29
+ else
30
+ raise ArgumentError,
31
+ "#{class_name.inspect} must be an Exception class or a String referencing an Exception class"
32
+ end
33
+
34
+ # Put the new handler at the end because the list is read in reverse.
35
+ config.action_rescue_handlers += [[key, with]]
36
+ end
37
+ end
38
+
20
39
  def stage(&block)
21
40
  @current_stage = Stages::Stage.new(position: next_position)
22
41
 
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Servactory
4
+ module Actions
5
+ module RescueHandlers
6
+ class Collection
7
+ extend Forwardable
8
+ def_delegators :@collection, :+, :detect, :reverse_each
9
+
10
+ def initialize(*)
11
+ @collection = Set.new
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -57,6 +57,8 @@ module Servactory
57
57
 
58
58
  def call_method(method)
59
59
  @context.send(method.name)
60
+ rescue StandardError => e
61
+ rescue_with_handler(e) || raise
60
62
  end
61
63
 
62
64
  def unnecessary_for_stage?(stage)
@@ -83,6 +85,23 @@ module Servactory
83
85
 
84
86
  !condition.call(context: @context)
85
87
  end
88
+
89
+ def rescue_with_handler(exception) # rubocop:disable Metrics/MethodLength
90
+ _, handler = @context.class.config.action_rescue_handlers.reverse_each.detect do |class_or_name, _|
91
+ if (detected_exception = Servactory::Utils.constantize_class(class_or_name))
92
+ detected_exception === exception # rubocop:disable Style/CaseEquality
93
+ end
94
+ end
95
+
96
+ return if handler.nil?
97
+
98
+ @context.fail!(
99
+ message: handler.call(exception: exception),
100
+ meta: {
101
+ original_exception: exception
102
+ }
103
+ )
104
+ end
86
105
  end
87
106
  end
88
107
  end
@@ -18,6 +18,8 @@ module Servactory
18
18
  child.config.success_class = config.success_class
19
19
  child.config.failure_class = config.failure_class
20
20
 
21
+ child.config.result_class = config.result_class
22
+
21
23
  child.config.collection_mode_class_names = config.collection_mode_class_names
22
24
 
23
25
  child.config.input_option_helpers = config.input_option_helpers
@@ -26,6 +28,7 @@ module Servactory
26
28
 
27
29
  child.config.action_aliases = config.action_aliases
28
30
  child.config.action_shortcuts = config.action_shortcuts
31
+ child.config.action_rescue_handlers = config.action_rescue_handlers
29
32
  end
30
33
 
31
34
  def config
@@ -63,6 +63,12 @@ module Servactory
63
63
  raise_error_about_wrong_exception_class_with(:failure_class, failure_class)
64
64
  end
65
65
 
66
+ def result_class(result_class)
67
+ return @config.result_class = result_class if subclass_of_result?(result_class)
68
+
69
+ raise_error_about_wrong_result_class_with(:result_class, result_class)
70
+ end
71
+
66
72
  def collection_mode_class_names(collection_mode_class_names)
67
73
  @config.collection_mode_class_names.merge(collection_mode_class_names)
68
74
  end
@@ -91,19 +97,34 @@ module Servactory
91
97
  @config.action_shortcuts.merge(action_shortcuts)
92
98
  end
93
99
 
94
- ##########################################################################
100
+ private
101
+
102
+ # def action_rescue_handlers(action_rescue_handlers)
103
+ # @config.action_rescue_handlers.merge(action_rescue_handlers)
104
+ # end
95
105
 
96
106
  def subclass_of_exception?(value)
97
107
  value.is_a?(Class) && value <= Exception
98
108
  end
99
109
 
110
+ def subclass_of_result?(value)
111
+ value.is_a?(Class) && value <= Servactory::Result
112
+ end
113
+
100
114
  ##########################################################################
101
115
 
102
116
  def raise_error_about_wrong_exception_class_with(config_name, value)
103
117
  raise ArgumentError,
104
118
  "Error in `#{config_name}` configuration. " \
105
119
  "The `#{value}` value must be a subclass of `Exception`. " \
106
- "See example configuration here: https://servactory.com/guide/configuration"
120
+ "See configuration example here: https://servactory.com/guide/configuration"
121
+ end
122
+
123
+ def raise_error_about_wrong_result_class_with(config_name, value)
124
+ raise ArgumentError,
125
+ "Error in `#{config_name}` configuration. " \
126
+ "The `#{value}` value must be a subclass of `Servactory::Result`. " \
127
+ "See configuration example here: https://servactory.com/guide/configuration"
107
128
  end
108
129
  end
109
130
  end
@@ -8,15 +8,17 @@ module Servactory
8
8
  :output_exception_class,
9
9
  :success_class,
10
10
  :failure_class,
11
+ :result_class,
11
12
  :collection_mode_class_names,
12
13
  :hash_mode_class_names,
13
14
  :input_option_helpers,
14
15
  :internal_option_helpers,
15
16
  :output_option_helpers,
16
17
  :action_aliases,
17
- :action_shortcuts
18
+ :action_shortcuts,
19
+ :action_rescue_handlers
18
20
 
19
- def initialize # rubocop:disable Metrics/MethodLength
21
+ def initialize # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
20
22
  @input_exception_class = Servactory::Exceptions::Input
21
23
  @internal_exception_class = Servactory::Exceptions::Internal
22
24
  @output_exception_class = Servactory::Exceptions::Output
@@ -24,6 +26,8 @@ module Servactory
24
26
  @success_class = Servactory::Exceptions::Success
25
27
  @failure_class = Servactory::Exceptions::Failure
26
28
 
29
+ @result_class = Servactory::Result
30
+
27
31
  @collection_mode_class_names =
28
32
  Servactory::Maintenance::CollectionMode::ClassNamesCollection.new(default_collection_mode_class_names)
29
33
 
@@ -41,6 +45,7 @@ module Servactory
41
45
 
42
46
  @action_aliases = Servactory::Actions::Aliases::Collection.new
43
47
  @action_shortcuts = Servactory::Actions::Shortcuts::Collection.new
48
+ @action_rescue_handlers = Servactory::Actions::RescueHandlers::Collection.new
44
49
  end
45
50
 
46
51
  private
@@ -8,9 +8,9 @@ module Servactory
8
8
 
9
9
  _call!(context, **arguments)
10
10
 
11
- Servactory::Result.success_for(context: context)
11
+ config.result_class.success_for(context: context)
12
12
  rescue config.success_class => e
13
- Servactory::Result.success_for(context: e.context)
13
+ config.result_class.success_for(context: e.context)
14
14
  end
15
15
 
16
16
  def call(arguments = {})
@@ -18,11 +18,11 @@ module Servactory
18
18
 
19
19
  _call!(context, **arguments)
20
20
 
21
- Servactory::Result.success_for(context: context)
21
+ config.result_class.success_for(context: context)
22
22
  rescue config.success_class => e
23
- Servactory::Result.success_for(context: e.context)
23
+ config.result_class.success_for(context: e.context)
24
24
  rescue config.failure_class => e
25
- Servactory::Result.failure_for(context: context, exception: e)
25
+ config.result_class.failure_for(context: context, exception: e)
26
26
  end
27
27
 
28
28
  private
@@ -225,9 +225,6 @@ module Servactory
225
225
  )
226
226
  ],
227
227
  define_conflicts: [
228
- Servactory::Maintenance::Attributes::DefineConflict.new(
229
- content: -> { :prepare_vs_collection if @attribute.prepare_present? && @attribute.collection_mode? }
230
- ),
231
228
  Servactory::Maintenance::Attributes::DefineConflict.new(
232
229
  content: -> { :prepare_vs_inclusion if @attribute.prepare_present? && @attribute.inclusion_present? }
233
230
  ),
@@ -5,7 +5,7 @@ module Servactory
5
5
  module CollectionMode
6
6
  class ClassNamesCollection
7
7
  extend Forwardable
8
- def_delegators :@collection, :include?
8
+ def_delegators :@collection, :merge, :include?
9
9
 
10
10
  def initialize(collection)
11
11
  @collection = collection
@@ -68,11 +68,7 @@ module Servactory
68
68
 
69
69
  def prepared_types_from(types)
70
70
  types.map do |type|
71
- if type.is_a?(String)
72
- Object.const_get(type)
73
- else
74
- type
75
- end
71
+ Servactory::Utils.constantize_class(type)
76
72
  end
77
73
  end
78
74
 
@@ -89,11 +89,7 @@ module Servactory
89
89
 
90
90
  def prepared_types_from(types)
91
91
  types.map do |type|
92
- if type.is_a?(String)
93
- Object.const_get(type)
94
- else
95
- type
96
- end
92
+ Servactory::Utils.constantize_class(type)
97
93
  end
98
94
  end
99
95
  end
@@ -4,11 +4,15 @@ module Servactory
4
4
  module TestKit
5
5
  class Result
6
6
  def self.as_success(attributes = {})
7
- Servactory::Result.success_for(context: new(attributes))
7
+ context = new(attributes)
8
+
9
+ Servactory::Result.success_for(context: context)
8
10
  end
9
11
 
10
12
  def self.as_failure(attributes = {}, exception: nil)
11
- Servactory::Result.failure_for(context: new(attributes), exception: exception)
13
+ context = new(attributes)
14
+
15
+ Servactory::Result.failure_for(context: context, exception: exception)
12
16
  end
13
17
 
14
18
  def initialize(attributes = {})
@@ -84,5 +84,18 @@ module Servactory
84
84
  end
85
85
  end
86
86
  end
87
+
88
+ def constantize_class(class_or_name)
89
+ case class_or_name
90
+ when String, Symbol
91
+ begin
92
+ Object.const_get(class_or_name)
93
+ rescue NameError
94
+ class_or_name.safe_constantize
95
+ end
96
+ else
97
+ class_or_name
98
+ end
99
+ end
87
100
  end
88
101
  end
@@ -3,9 +3,9 @@
3
3
  module Servactory
4
4
  module VERSION
5
5
  MAJOR = 2
6
- MINOR = 4
7
- PATCH = 3
8
- PRE = nil
6
+ MINOR = 5
7
+ PATCH = 0
8
+ PRE = "rc2"
9
9
 
10
10
  STRING = [MAJOR, MINOR, PATCH, PRE].compact.join(".")
11
11
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: servactory
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.3
4
+ version: 2.5.0.rc2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anton Sokolov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-03-29 00:00:00.000000000 Z
11
+ date: 2024-04-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -242,6 +242,7 @@ files:
242
242
  - lib/servactory/actions/aliases/collection.rb
243
243
  - lib/servactory/actions/collection.rb
244
244
  - lib/servactory/actions/dsl.rb
245
+ - lib/servactory/actions/rescue_handlers/collection.rb
245
246
  - lib/servactory/actions/shortcuts/collection.rb
246
247
  - lib/servactory/actions/stages/collection.rb
247
248
  - lib/servactory/actions/stages/stage.rb
@@ -339,7 +340,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
339
340
  requirements:
340
341
  - - ">="
341
342
  - !ruby/object:Gem::Version
342
- version: 2.7.0
343
+ version: 3.0.0
343
344
  required_rubygems_version: !ruby/object:Gem::Requirement
344
345
  requirements:
345
346
  - - ">="