servactory 2.4.3 → 2.5.0.rc2

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