mime_actor 0.6.2 → 0.6.3.alpha

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: a448d97c462d23aa41abbbad40c1e2ba0a6336c0069e12dd905b18c7cfeee435
4
- data.tar.gz: 3e7ee33e33138d37ef29ac4fa30d6b8284ca3fcb69dfd187b599be6a556aa963
3
+ metadata.gz: 5221de8b1d1149a88de730ab8e6c6c764a22e7067b9e57b6265ce801c671ce3f
4
+ data.tar.gz: e98f9d6f3e5a8aa04f16cf77921edad0b4a61893ddb3c019157885079462fcde
5
5
  SHA512:
6
- metadata.gz: d1284b778dc593f3a674a8c8de22d9b10d15eb46fa1e47025c091a0103701eb38426e2fdc0951960cfcac02de8587e9d63b9fde5267a44cebf3606cd4d58bb44
7
- data.tar.gz: 65f832e20fc1eeb9a2b6da8e37eb49041697afd66695a91998c65fd16942c915e2c2d4adb870d094858cc7fcb7dbd7849f25d229686849c57e8c98ef0904abcd
6
+ metadata.gz: 9f6ce7e70ab30a4be726f346beb517c8036c95a1d516c3012d9ed62723a14c130d4af05cdf3695244f5fcb56d33f83cf719369ead9d05eabeba89e5335de1f3a
7
+ data.tar.gz: 90e8ca69ac9ff99e9813c1dac19bc0826893f106968bb6c6684201a84523b13ab9df225fd597daf96379825080f9164ecfb19a6f7b48c8eabf217e5411654530
@@ -2,9 +2,10 @@
2
2
 
3
3
  # :markup: markdown
4
4
 
5
+ require "mime_actor/callbacks"
6
+ require "mime_actor/logging"
5
7
  require "mime_actor/scene"
6
8
  require "mime_actor/stage"
7
- require "mime_actor/rescue"
8
9
 
9
10
  require "active_support/concern"
10
11
  require "active_support/core_ext/object/blank"
@@ -25,9 +26,9 @@ module MimeActor
25
26
  include AbstractController::Rendering # required by MimeResponds
26
27
  include ActionController::MimeResponds
27
28
 
29
+ include Callbacks
28
30
  include Scene
29
31
  include Stage
30
- include Rescue
31
32
  include Logging
32
33
 
33
34
  # The core logic where rendering logics are collected as `Proc` and passed over to `ActionController::MimeResponds`
@@ -55,7 +56,11 @@ module MimeActor
55
56
 
56
57
  respond_to do |collector|
57
58
  formats.each do |format, actor|
58
- dispatch = -> { cue_actor(actor.presence || "#{action}_#{format}", action:, format:) }
59
+ dispatch = lambda do
60
+ run_act_callbacks(format) do
61
+ cue_actor(actor.presence || "#{action}_#{format}", action:, format:)
62
+ end
63
+ end
59
64
  collector.public_send(format, &dispatch)
60
65
  end
61
66
  end
@@ -0,0 +1,201 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
5
+ require "mime_actor/validator"
6
+
7
+ require "active_support/callbacks"
8
+ require "active_support/concern"
9
+ require "active_support/core_ext/array/wrap"
10
+ require "active_support/core_ext/object/blank"
11
+
12
+ module MimeActor
13
+ # # MimeActor Callbacks
14
+ #
15
+ # MimeActor provides hooks during the life cycle of an act. Available callbacks are:
16
+ #
17
+ # - before_act
18
+ # - around_act
19
+ # - after_act
20
+ #
21
+ # NOTE: Calling the same callback multiple times will overwrite previous callback definitions.
22
+ #
23
+ module Callbacks
24
+ extend ActiveSupport::Concern
25
+
26
+ include ActiveSupport::Callbacks
27
+ include MimeActor::Validator
28
+
29
+ included do
30
+ define_callbacks :act, skip_after_callbacks_if_terminated: true
31
+
32
+ %i[before after around].each { |kind| define_act_callbacks(kind) }
33
+ end
34
+
35
+ module ClassMethods
36
+ class ActionMatcher
37
+ def initialize(actions)
38
+ @actions = Array.wrap(actions).to_set(&:to_s)
39
+ end
40
+
41
+ def match?(controller)
42
+ @actions.include?(controller.action_name)
43
+ end
44
+
45
+ alias after match?
46
+ alias before match?
47
+ alias around match?
48
+ end
49
+
50
+ def callback_chain_name(format = nil)
51
+ if format.present?
52
+ validate!(:format, format)
53
+ :"act_#{format}"
54
+ else
55
+ :act
56
+ end
57
+ end
58
+
59
+ def callback_chain_defined?(name)
60
+ !!get_callbacks(name)
61
+ end
62
+
63
+ private
64
+
65
+ def define_callback_chain(name)
66
+ return if callback_chain_defined?(name)
67
+
68
+ define_callbacks name, skip_after_callbacks_if_terminated: true
69
+ end
70
+
71
+ def configure_callbacks(callbacks, actions, formats, block)
72
+ options = {}
73
+ options[:if] = ActionMatcher.new(actions) if actions.present?
74
+ callbacks.push(block) if block
75
+
76
+ formats = Array.wrap(formats)
77
+ formats << nil if formats.empty?
78
+
79
+ callbacks.each do |callback|
80
+ formats.each do |format|
81
+ chain = callback_chain_name(format)
82
+ define_callback_chain(chain)
83
+ yield chain, callback, options
84
+ end
85
+ end
86
+ end
87
+
88
+ def validate_callback_options!(action, format)
89
+ validate!(:action_or_actions, action) if action.present?
90
+ validate!(:format_or_formats, format) if format.present?
91
+ end
92
+
93
+ def define_act_callbacks(kind)
94
+ module_eval(
95
+ # def self.before_act(*callbacks, action: nil, format: nil, &block)
96
+ # validate_callback_options!(action, format)
97
+ # configure_callbacks(callbacks, action, format, block) do |chain, callback, options|
98
+ # set_callback(chain, :before, callback, options)
99
+ # end
100
+ # end
101
+ #
102
+ # def self.prepend_before_act(*callbacks, action: nil, format: nil, &block)
103
+ # validate_callback_options!(action, format)
104
+ # configure_callbacks(callbacks, action, format, block) do |chain, callback, options|
105
+ # set_callback(chain, :before, callback, options.merge!(prepend: true))
106
+ # end
107
+ # end
108
+ <<-RUBY, __FILE__, __LINE__ + 1
109
+ def self.#{kind}_act(*callbacks, action: nil, format: nil, &block)
110
+ validate_callback_options!(action, format)
111
+ configure_callbacks(callbacks, action, format, block) do |chain, callback, options|
112
+ set_callback(chain, :#{kind}, callback, options)
113
+ end
114
+ end
115
+
116
+ def self.prepend_#{kind}_act(*callbacks, action: nil, format: nil, &block)
117
+ validate_callback_options!(action, format)
118
+ configure_callbacks(callbacks, action, format, block) do |chain, callback, options|
119
+ set_callback(chain, :#{kind}, callback, options.merge!(prepend: true))
120
+ end
121
+ end
122
+ RUBY
123
+ )
124
+ end
125
+ end
126
+
127
+ # Callbacks invocation sequence depends on the order of callback definition.
128
+ # (except for callbacks with `format` filter).
129
+ #
130
+ # @example callbacks with/without action filter
131
+ # before_act :my_before_act_one
132
+ # before_act :my_before_act_two, action: :create
133
+ # before_act :my_before_act_three
134
+ #
135
+ # around_act :my_around_act_one
136
+ # around_act :my_around_act_two, action: :create
137
+ # around_act :my_around_act_three
138
+ #
139
+ # after_act :my_after_act_one
140
+ # after_act :my_after_act_two, action: :create
141
+ # after_act :my_after_act_three
142
+ #
143
+ # # actual sequence:
144
+ # # - my_before_act_one
145
+ # # - my_before_act_two
146
+ # # - my_before_act_three
147
+ # # - my_around_act_one
148
+ # # - my_around_act_two
149
+ # # - my_around_act_three
150
+ # # - my_after_act_three
151
+ # # - my_after_act_two
152
+ # # - my_after_act_one
153
+ #
154
+ # @example callbacks with format filter
155
+ # before_act :my_before_act_one
156
+ # before_act :my_before_act_two, action: :create
157
+ # before_act :my_before_act_three, action: :create, format: :html
158
+ # before_act :my_before_act_four
159
+ #
160
+ # around_act :my_around_act_one
161
+ # around_act :my_around_act_two, action: :create, format: :html
162
+ # around_act :my_around_act_three, action: :create
163
+ # around_act :my_around_act_four
164
+ #
165
+ # after_act :my_after_act_one, format: :html
166
+ # after_act :my_after_act_two
167
+ # after_act :my_after_act_three, action: :create
168
+ # after_act :my_after_act_four
169
+ #
170
+ # # actual sequence:
171
+ # # - my_before_act_one
172
+ # # - my_before_act_two
173
+ # # - my_before_act_four
174
+ # # - my_around_act_one
175
+ # # - my_around_act_three
176
+ # # - my_around_act_four
177
+ # # - my_before_act_three
178
+ # # - my_around_act_two
179
+ # # - my_after_act_one
180
+ # # - my_after_act_four
181
+ # # - my_after_act_three
182
+ # # - my_after_act_two
183
+ #
184
+ def run_act_callbacks(format)
185
+ action_chain = self.class.callback_chain_name
186
+ format_chain = self.class.callback_chain_name(format)
187
+
188
+ if self.class.callback_chain_defined?(format_chain)
189
+ run_callbacks action_chain do
190
+ run_callbacks format_chain do
191
+ yield if block_given?
192
+ end
193
+ end
194
+ else
195
+ run_callbacks action_chain do
196
+ yield if block_given?
197
+ end
198
+ end
199
+ end
200
+ end
201
+ end
@@ -2,6 +2,8 @@
2
2
 
3
3
  # :markup: markdown
4
4
 
5
+ require "mime_actor/errors"
6
+
5
7
  module MimeActor
6
8
  module Dispatcher
7
9
  class MethodCall
@@ -13,13 +15,12 @@ module MimeActor
13
15
  validate!
14
16
  end
15
17
 
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
18
+ def call(target)
19
+ raise MimeActor::ActorNotFound, method_name unless target.respond_to?(method_name)
20
+
21
+ method_call = target.method(method_name)
22
+ filtered_args = method_call.arity.negative? ? args : args.take(method_call.arity)
23
+ method_call.call(*filtered_args)
23
24
  end
24
25
 
25
26
  private
@@ -38,11 +39,9 @@ module MimeActor
38
39
  validate!
39
40
  end
40
41
 
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
42
+ def call(target)
43
+ filtered_args = block.arity.negative? ? args : args.take(block.arity)
44
+ target.instance_exec(*filtered_args, &block)
46
45
  end
47
46
 
48
47
  private
@@ -4,7 +4,6 @@
4
4
 
5
5
  require "mime_actor/dispatcher"
6
6
  require "mime_actor/validator"
7
- require "mime_actor/stage"
8
7
 
9
8
  require "active_support/concern"
10
9
  require "active_support/core_ext/array/wrap"
@@ -23,7 +22,6 @@ module MimeActor
23
22
  module Rescue
24
23
  extend ActiveSupport::Concern
25
24
 
26
- include Stage
27
25
  include Validator
28
26
 
29
27
  included do
@@ -51,19 +49,11 @@ module MimeActor
51
49
  raise ArgumentError, "error filter is required" if klazzes.empty?
52
50
  raise ArgumentError, "provide either the with: argument or a block" unless with.present? ^ block_given?
53
51
 
54
- if block_given?
55
- with = block
56
- else
57
- validate!(:with, with)
58
- end
59
-
60
- if action.present?
61
- action.is_a?(Enumerable) ? validate!(:actions, action) : validate!(:action, action)
62
- end
52
+ validate!(:with, with) if with.present?
53
+ with = block if block_given?
63
54
 
64
- if format.present?
65
- format.is_a?(Enumerable) ? validate!(:formats, format) : validate!(:format, format)
66
- end
55
+ validate!(:action_or_actions, action) if action.present?
56
+ validate!(:format_or_formats, format) if format.present?
67
57
 
68
58
  klazzes.each do |klazz|
69
59
  validate!(:klazz, klazz)
@@ -156,11 +146,7 @@ module MimeActor
156
146
  visited << error
157
147
  rescuer = find_rescuer(error, format:, action:)
158
148
  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
149
+ dispatch.call(self)
164
150
  error
165
151
  elsif error&.cause
166
152
  rescue_actor(error.cause, format:, action:, visited:)
@@ -86,20 +86,12 @@ module MimeActor
86
86
 
87
87
  raise ArgumentError, "provide either the with: argument or a block" if with.present? && block_given?
88
88
 
89
- if block_given?
90
- with = block
91
- elsif with.present?
92
- validate!(:with, with)
93
- end
89
+ validate!(:with, with) if with.present?
90
+ with = block if block_given?
94
91
 
95
- case actions = on
96
- when Enumerable
97
- validate!(:actions, actions)
98
- when Symbol, String
99
- validate!(:action, actions)
100
- else
101
- raise ArgumentError, "action is required"
102
- end
92
+ raise ArgumentError, "action is required" unless (actions = on).present?
93
+
94
+ validate!(:action_or_actions, actions)
103
95
 
104
96
  Array.wrap(actions).each do |action|
105
97
  formats.each { |format| compose_scene(action, format, with) }
@@ -2,9 +2,9 @@
2
2
 
3
3
  # :markup: markdown
4
4
 
5
- require "mime_actor/errors"
6
5
  require "mime_actor/dispatcher"
7
6
  require "mime_actor/logging"
7
+ require "mime_actor/rescue"
8
8
 
9
9
  require "active_support/concern"
10
10
  require "active_support/core_ext/module/attribute_accessors"
@@ -17,6 +17,7 @@ module MimeActor
17
17
  module Stage
18
18
  extend ActiveSupport::Concern
19
19
 
20
+ include Rescue
20
21
  include Logging
21
22
 
22
23
  included do
@@ -76,37 +77,21 @@ module MimeActor
76
77
  # @param args arguments to be passed when calling the actor
77
78
  #
78
79
  def cue_actor(actor, *args, action:, format:)
79
- dispatch = MimeActor::Dispatcher.build(actor, *args)
80
- raise TypeError, "invalid actor, got: #{actor.inspect}" unless dispatch
80
+ dispatcher = MimeActor::Dispatcher.build(actor, *args)
81
+ raise TypeError, "invalid actor, got: #{actor.inspect}" unless dispatcher
81
82
 
82
- result = dispatch_actor(dispatch, action:, format:)
83
+ result = dispatcher.call(self)
83
84
  if block_given?
84
85
  yield result
85
86
  else
86
87
  result
87
88
  end
88
- end
89
-
90
- private
91
-
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
100
- end
101
- handle_actor_error(result) unless dispatched || rescued
102
- result if dispatched
103
- end
104
-
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}" }
89
+ rescue MimeActor::ActorNotFound => e
90
+ logger.error { "actor error, cause: #{e.inspect}" } unless raise_on_actor_error
91
+ raise e if raise_on_actor_error
92
+ rescue StandardError => e
93
+ rescued = rescue_actor(e, action:, format:)
94
+ rescued || raise
110
95
  end
111
96
  end
112
97
  end
@@ -32,7 +32,7 @@ module MimeActor
32
32
  # @param rule the name of validator
33
33
  def validate!(rule, *args)
34
34
  validator = "validate_#{rule}"
35
- raise NameError, "Validator not found, got: #{validator.inspect}" unless respond_to?(validator, true)
35
+ raise NameError, "Validator not found, got: #{validator.inspect}" unless respond_to?(validator)
36
36
 
37
37
  error = send(validator, *args)
38
38
  raise error if error
@@ -53,6 +53,13 @@ module MimeActor
53
53
  NameError.new("invalid actions, got: #{rejected.map(&:inspect).join(", ")}") if rejected.size.positive?
54
54
  end
55
55
 
56
+ # Validate against `actions` rule if argument is a Enumerable. otherwise, validate against `action` rule.
57
+ #
58
+ # @param unchecked the `actions` or `action` to be validated
59
+ def validate_action_or_actions(unchecked)
60
+ unchecked.is_a?(Enumerable) ? validate_actions(unchecked) : validate_action(unchecked)
61
+ end
62
+
56
63
  # Validate `format` must be a Symbol and a valid MIME type
57
64
  #
58
65
  # @param unchecked the `format` to be validated
@@ -73,6 +80,13 @@ module MimeActor
73
80
  NameError.new("invalid formats, got: #{rejected.map(&:inspect).join(", ")}") if rejected.size.positive?
74
81
  end
75
82
 
83
+ # Validate against `formats` rule if argument is a Enumerable. otherwise, validate against `format` rule.
84
+ #
85
+ # @param unchecked the `formats` or `format` to be validated
86
+ def validate_format_or_formats(unchecked)
87
+ unchecked.is_a?(Enumerable) ? validate_formats(unchecked) : validate_format(unchecked)
88
+ end
89
+
76
90
  # Validate `klazz` must be a Class/Module or a String referencing a Class/Module
77
91
  #
78
92
  # @param unchecked the `klazz` to be validated
@@ -14,8 +14,8 @@ module MimeActor
14
14
  module VERSION
15
15
  MAJOR = 0
16
16
  MINOR = 6
17
- BUILD = 2
18
- PRE = nil
17
+ BUILD = 3
18
+ PRE = "alpha"
19
19
 
20
20
  STRING = [MAJOR, MINOR, BUILD, PRE].compact.join(".")
21
21
  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.2
4
+ version: 0.6.3.alpha
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-21 00:00:00.000000000 Z
11
+ date: 2024-07-23 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/callbacks.rb
74
75
  - lib/mime_actor/dispatcher.rb
75
76
  - lib/mime_actor/errors.rb
76
77
  - lib/mime_actor/logging.rb