mime_actor 0.6.1 → 0.6.2

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: f5a67bb80dd83c069ea2f06a4afea5e241987d8b9a2a30f0a3eb0d01748b3759
4
- data.tar.gz: acb0cd8b89e39ea3962c0949bff4666c96c36f6c15eae5a3709775daa5ef2516
3
+ metadata.gz: a448d97c462d23aa41abbbad40c1e2ba0a6336c0069e12dd905b18c7cfeee435
4
+ data.tar.gz: 3e7ee33e33138d37ef29ac4fa30d6b8284ca3fcb69dfd187b599be6a556aa963
5
5
  SHA512:
6
- metadata.gz: e64c6a62feb248b76672d75ef4cf9bc0f822b0f2fd57311f879874e910377b80549b133c85b148fd61d44d91259c780299770d7fae4792dbab094c01676df201
7
- data.tar.gz: 2577dc3d03d3fa233ba136613e63d0c18a3e59f51bac690b582b18f424cc4ee7e5fee736eafc76393a94af20e3fcf930cd953b4eec07f21282fa9b5dd7be552d
6
+ metadata.gz: d1284b778dc593f3a674a8c8de22d9b10d15eb46fa1e47025c091a0103701eb38426e2fdc0951960cfcac02de8587e9d63b9fde5267a44cebf3606cd4d58bb44
7
+ data.tar.gz: 65f832e20fc1eeb9a2b6da8e37eb49041697afd66695a91998c65fd16942c915e2c2d4adb870d094858cc7fcb7dbd7849f25d229686849c57e8c98ef0904abcd
data/.rubocop.yml CHANGED
@@ -16,6 +16,9 @@ Style/BlockComments:
16
16
  Exclude:
17
17
  - spec/*_helper.rb
18
18
 
19
+ Style/RegexpLiteral:
20
+ EnforcedStyle: percent_r
21
+
19
22
  Metrics/AbcSize:
20
23
  Enabled: false
21
24
 
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "mime_actor/scene"
4
6
  require "mime_actor/stage"
5
7
  require "mime_actor/rescue"
@@ -44,7 +46,6 @@ module MimeActor
44
46
  # end
45
47
  #
46
48
  def start_scene(action)
47
- action = action&.to_sym
48
49
  formats = acting_scenes.fetch(action, {})
49
50
 
50
51
  if formats.empty?
@@ -54,9 +55,7 @@ module MimeActor
54
55
 
55
56
  respond_to do |collector|
56
57
  formats.each do |format, actor|
57
- dispatch = self.class.dispatch_cue(action: action, format: format, context: self) do
58
- cue_actor(actor.presence || "#{action}_#{format}")
59
- end
58
+ dispatch = -> { cue_actor(actor.presence || "#{action}_#{format}", action:, format:) }
60
59
  collector.public_send(format, &dispatch)
61
60
  end
62
61
  end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
5
+ module MimeActor
6
+ module Dispatcher
7
+ class MethodCall
8
+ attr_reader :method_name, :args
9
+
10
+ def initialize(method_name, *args)
11
+ @method_name = method_name
12
+ @args = args
13
+ validate!
14
+ end
15
+
16
+ def to_callable
17
+ lambda do |target|
18
+ throw :abort, method_name unless target.respond_to?(method_name)
19
+ method_call = target.method(method_name)
20
+ filtered_args = method_call.arity.negative? ? args : args.take(method_call.arity)
21
+ method_call.call(*filtered_args)
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def validate!
28
+ raise ArgumentError, "invalid method name: #{method_name.inspect}" unless method_name in String | Symbol
29
+ end
30
+ end
31
+
32
+ class InstanceExec
33
+ attr_reader :block, :args
34
+
35
+ def initialize(block, *args)
36
+ @block = block
37
+ @args = args
38
+ validate!
39
+ end
40
+
41
+ def to_callable
42
+ lambda do |target|
43
+ filtered_args = block.arity.negative? ? args : args.take(block.arity)
44
+ target.instance_exec(*filtered_args, &block)
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def validate!
51
+ raise ArgumentError, "invalid block: #{block.inspect}" unless block in Proc
52
+ end
53
+ end
54
+
55
+ def self.build(callable, *args)
56
+ case callable
57
+ when String, Symbol
58
+ MethodCall.new(callable, *args)
59
+ when Proc
60
+ InstanceExec.new(callable, *args)
61
+ end
62
+ end
63
+ end
64
+ end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "set"
4
6
 
5
7
  module MimeActor
@@ -2,8 +2,9 @@
2
2
 
3
3
  # :markup: markdown
4
4
 
5
- require "mime_actor/stage"
5
+ require "mime_actor/dispatcher"
6
6
  require "mime_actor/validator"
7
+ require "mime_actor/stage"
7
8
 
8
9
  require "active_support/concern"
9
10
  require "active_support/core_ext/array/wrap"
@@ -139,5 +140,59 @@ module MimeActor
139
140
  end
140
141
  end
141
142
  end
143
+
144
+ # Resolve the error provided with the registered handlers.
145
+ #
146
+ # The handled error will be returned to indicate successful handling.
147
+ #
148
+ # @param error the error instance to rescue
149
+ # @param action the `action` filter
150
+ # @param format the `format` filter
151
+ # @param visited the errors to skip after no rescue handler matched the filter
152
+ #
153
+ def rescue_actor(error, action:, format:, visited: [])
154
+ return if visited.include?(error)
155
+
156
+ visited << error
157
+ rescuer = find_rescuer(error, format:, action:)
158
+ if (dispatch = MimeActor::Dispatcher.build(rescuer, error, format, action))
159
+ dispatched = false
160
+ result = catch(:abort) do
161
+ dispatch.to_callable.call(self).tap { dispatched = true }
162
+ end
163
+ logger.error { "rescue error, cause: #{result.inspect}" } unless dispatched
164
+ error
165
+ elsif error&.cause
166
+ rescue_actor(error.cause, format:, action:, visited:)
167
+ end
168
+ end
169
+
170
+ private
171
+
172
+ def find_rescuer(error, format:, action:)
173
+ return unless error
174
+
175
+ *_, rescuer = actor_rescuers.reverse_each.detect do |rescuee, format_filter, action_filter|
176
+ next if action_filter.present? && !Array.wrap(action_filter).include?(action)
177
+ next if format_filter.present? && !Array.wrap(format_filter).include?(format)
178
+ next unless (klazz = constantize_rescuee(rescuee))
179
+
180
+ error.is_a?(klazz)
181
+ end
182
+ rescuer
183
+ end
184
+
185
+ def constantize_rescuee(class_or_name)
186
+ case class_or_name
187
+ when String, Symbol
188
+ begin
189
+ const_get(class_or_name)
190
+ rescue NameError
191
+ class_or_name.safe_constantize
192
+ end
193
+ else
194
+ class_or_name
195
+ end
196
+ end
142
197
  end
143
198
  end
@@ -6,7 +6,6 @@ require "mime_actor/errors"
6
6
  require "mime_actor/validator"
7
7
 
8
8
  require "active_support/concern"
9
- require "active_support/core_ext/array/extract_options"
10
9
  require "active_support/core_ext/array/wrap"
11
10
  require "active_support/core_ext/module/attribute_accessors"
12
11
  require "active_support/core_ext/object/blank"
@@ -107,6 +106,7 @@ module MimeActor
107
106
  end
108
107
  end
109
108
 
109
+ # TODO: remove on next breaking change release
110
110
  alias act_on_format respond_act_to
111
111
 
112
112
  private
@@ -122,7 +122,7 @@ module MimeActor
122
122
  end
123
123
 
124
124
  def define_scene(action)
125
- class_eval(
125
+ module_eval(
126
126
  # def index
127
127
  # self.respond_to?(:start_scene) && self.start_scene(:index)
128
128
  # end
@@ -3,6 +3,7 @@
3
3
  # :markup: markdown
4
4
 
5
5
  require "mime_actor/errors"
6
+ require "mime_actor/dispatcher"
6
7
  require "mime_actor/logging"
7
8
 
8
9
  require "active_support/concern"
@@ -19,7 +20,7 @@ module MimeActor
19
20
  include Logging
20
21
 
21
22
  included do
22
- mattr_accessor :raise_on_missing_actor, instance_writer: false, default: false
23
+ mattr_accessor :raise_on_actor_error, instance_writer: false, default: false
23
24
  end
24
25
 
25
26
  module ClassMethods
@@ -46,13 +47,13 @@ module MimeActor
46
47
  # @param block the `block` to be evaluated
47
48
  #
48
49
  # @example Dispatch a cue that prints out a text
49
- # dispatch = self.class.dispatch_cue(action: :create, format: :json, context: self) do
50
+ # dispatch = self.class.dispatch_act(action: :create, format: :json, context: self) do
50
51
  # puts "completed the dispatch"
51
52
  # end
52
53
  #
53
54
  # dispatch.call == "completed the dispatch" # true
54
55
  #
55
- def dispatch_cue(action: nil, format: nil, context: self, &block)
56
+ def dispatch_act(action: nil, format: nil, context: self, &block)
56
57
  raise ArgumentError, "block must be provided" unless block_given?
57
58
 
58
59
  lambda do
@@ -61,6 +62,9 @@ module MimeActor
61
62
  (respond_to?(:rescue_actor) && rescue_actor(e, action:, format:, context:)) || raise
62
63
  end
63
64
  end
65
+
66
+ # TODO: remove on next breaking change release
67
+ alias dispatch_cue dispatch_act
64
68
  end
65
69
 
66
70
  # Calls the `actor` and passing arguments to it.
@@ -68,17 +72,14 @@ module MimeActor
68
72
  #
69
73
  # NOTE: method call on actor if it is String or Symbol. Proc#call if actor is Proc
70
74
  #
71
- # @param actor either a method name or a block to evaluate
72
- def cue_actor(actor, *args)
73
- result = case actor
74
- when String, Symbol
75
- actor_method_call(actor, *args)
76
- when Proc
77
- actor_proc_call(actor, *args)
78
- else
79
- raise TypeError, "invalid actor, got: #{actor.inspect}"
80
- end
75
+ # @param actor either a method name or a Proc to evaluate
76
+ # @param args arguments to be passed when calling the actor
77
+ #
78
+ def cue_actor(actor, *args, action:, format:)
79
+ dispatch = MimeActor::Dispatcher.build(actor, *args)
80
+ raise TypeError, "invalid actor, got: #{actor.inspect}" unless dispatch
81
81
 
82
+ result = dispatch_actor(dispatch, action:, format:)
82
83
  if block_given?
83
84
  yield result
84
85
  else
@@ -88,20 +89,24 @@ module MimeActor
88
89
 
89
90
  private
90
91
 
91
- def actor_method_call(actor_method, *args)
92
- unless self.class.actor?(actor_method)
93
- raise MimeActor::ActorNotFound, actor_method if raise_on_missing_actor
94
-
95
- logger.warn { "actor #{actor_method.inspect} not found" }
96
- return
92
+ def dispatch_actor(dispatch, action:, format:)
93
+ dispatched = false
94
+ rescued = false
95
+ result = catch(:abort) do
96
+ dispatch.to_callable.call(self).tap { dispatched = true }
97
+ rescue StandardError => e
98
+ rescued = respond_to?(:rescue_actor) && rescue_actor(e, action:, format:)
99
+ raise unless rescued
97
100
  end
98
-
99
- public_send(actor_method, *args)
101
+ handle_actor_error(result) unless dispatched || rescued
102
+ result if dispatched
100
103
  end
101
104
 
102
- def actor_proc_call(actor_proc, *args)
103
- passable_args = actor_proc.arity.negative? ? args : args.take(actor_proc.arity)
104
- instance_exec(*passable_args, &actor_proc)
105
+ def handle_actor_error(actor)
106
+ error = MimeActor::ActorNotFound.new(actor)
107
+ raise error if raise_on_actor_error
108
+
109
+ logger.error { "actor error, cause: #{error.inspect}" }
105
110
  end
106
111
  end
107
112
  end
@@ -1,18 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module MimeActor
4
6
  def self.version
5
- gem_version
7
+ VERSION::STRING
6
8
  end
7
9
 
8
10
  def self.gem_version
9
- Gem::Version.new VERSION::STRING
11
+ Gem::Version.new(VERSION::STRING)
10
12
  end
11
13
 
12
14
  module VERSION
13
15
  MAJOR = 0
14
16
  MINOR = 6
15
- BUILD = 1
17
+ BUILD = 2
16
18
  PRE = nil
17
19
 
18
20
  STRING = [MAJOR, MINOR, BUILD, PRE].compact.join(".")
data/lib/mime_actor.rb CHANGED
@@ -7,6 +7,7 @@ require "mime_actor/version"
7
7
  require "mime_actor/errors"
8
8
 
9
9
  require "active_support/dependencies/autoload"
10
+ require "active_support/deprecation"
10
11
 
11
12
  module MimeActor
12
13
  extend ActiveSupport::Autoload
@@ -17,4 +18,18 @@ module MimeActor
17
18
  autoload :Rescue
18
19
  autoload :Validator
19
20
  autoload :Logging
21
+
22
+ def self.deprecator
23
+ @deprecator ||= ActiveSupport::Deprecation.new("0.7.0", "MimeActor")
24
+ end
25
+
26
+ [
27
+ [MimeActor::Rescue::ClassMethods, { rescue_actor: "use #rescue_actor instance method" }],
28
+ [MimeActor::Scene::ClassMethods, { act_on_format: :respond_act_to }],
29
+ [MimeActor::Stage::ClassMethods, { actor?: "no longer supported, use Object#respond_to?" }],
30
+ [MimeActor::Stage::ClassMethods, { dispatch_cue: "no longer support anonymous proc with rescue" }],
31
+ [MimeActor::Stage::ClassMethods, { dispatch_act: "no longer support anonymous proc with rescue" }]
32
+ ].each do |klazz, *args|
33
+ deprecator.deprecate_methods(klazz, *args)
34
+ end
20
35
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mime_actor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.6.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Chang
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-07-03 00:00:00.000000000 Z
11
+ date: 2024-07-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -71,6 +71,7 @@ files:
71
71
  - codecov.yml
72
72
  - lib/mime_actor.rb
73
73
  - lib/mime_actor/action.rb
74
+ - lib/mime_actor/dispatcher.rb
74
75
  - lib/mime_actor/errors.rb
75
76
  - lib/mime_actor/logging.rb
76
77
  - lib/mime_actor/rescue.rb