mime_actor 0.6.2 → 0.6.3

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: c54b7a74eed15ac67b37d8df3879584634955ff4db0275cecc1dd4b7d531ec55
4
+ data.tar.gz: da797d40d7f90f5c6f8e23b61f2fe1441aef08860c6af5ff1763f49cee15ccaa
5
5
  SHA512:
6
- metadata.gz: d1284b778dc593f3a674a8c8de22d9b10d15eb46fa1e47025c091a0103701eb38426e2fdc0951960cfcac02de8587e9d63b9fde5267a44cebf3606cd4d58bb44
7
- data.tar.gz: 65f832e20fc1eeb9a2b6da8e37eb49041697afd66695a91998c65fd16942c915e2c2d4adb870d094858cc7fcb7dbd7849f25d229686849c57e8c98ef0904abcd
6
+ metadata.gz: 79eea272d7e8c3b625584eb8ae54790076035b511210302bb948076f54d847f34bb5c1f354d03b5fa319fbcc7c370f4c72a97b806593a732dd6207dfb8b6bbbe
7
+ data.tar.gz: 387780b44aafbcd60e79b7f9ebedd3c00edc40faa1acdce0c6946aad5787f053ae17ae62cab3ba84f8dd695874074e66ef867f6cfbb79e9ba947ddff837c7baa
data/COMPARE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ## Comparison in Rails
2
2
 
3
- ### MIME Rendering
3
+ ### MIME Action
4
4
 
5
5
  #### before
6
6
  ```rb
@@ -22,103 +22,104 @@ end
22
22
  #### after
23
23
  ```rb
24
24
  class EventsController < ActionController::Base
25
- include MimeActor::Action
25
+ include MimeActor::Action
26
26
 
27
- before_action only: :index { @events = Event.all }
27
+ before_act -> { @events = Event.all }, action: :index
28
28
 
29
- # dynamically defines the action method according to on: argument
30
- respond_act_to :html, :json, on: :index
29
+ # dynamically defines the action method according to on: argument
30
+ respond_act_to :html, :json, on: :index
31
31
 
32
- def index_html
33
- @event_categories = EventCategory.all
34
-
35
- # render html using @events and @event_categories
36
- render :index
37
- end
32
+ def index_html
33
+ @event_categories = EventCategory.all
34
+
35
+ # render html using @events and @event_categories
36
+ render :index
37
+ end
38
38
 
39
- def index_json
40
- # render json using #as_json
41
- render json: @events
42
- end
39
+ def index_json
40
+ # render json using #as_json
41
+ render json: @events
42
+ end
43
43
  end
44
44
  ```
45
45
 
46
- ### MIME Rescuing
46
+ ### MIME Rescue
47
47
 
48
48
  #### before
49
49
  ```rb
50
50
  class EventsController < ActionController::Base
51
- # AbstractController::Callbacks here to load model with params
52
- before_action only: [:show, :update] { @event = Event.find(params.require(:event_id)) }
53
-
54
- rescue_from ActiveRecord::RecordNotFound do |ex|
55
- case action_name.to_s
56
- when "show"
57
- respond_to do |format|
58
- format.html { redirect_to events_path } # redirect to index
59
- format.json { render status: :bad_request, json: { error: ex.message } }
60
- end
61
- when "update"
62
- respond_to do |format|
63
- format.html { render :edit }
64
- format.json { render status: :bad_request, json: { error: ex.message } }
65
- end
66
- else
67
- raise ex # re-raise since we are not handling it
68
- end
51
+ before_action only: %i[show update], with: :load_event
52
+
53
+ rescue_from ActiveRecord::RecordNotFound do |ex|
54
+ case action_name.to_s
55
+ when "show"
56
+ respond_to do |format|
57
+ format.html { redirect_to events_path } # redirect to index
58
+ format.json { render status: :bad_request, json: { error: ex.message } }
59
+ end
60
+ when "update"
61
+ respond_to do |format|
62
+ format.html { render :edit }
63
+ format.json { render status: :bad_request, json: { error: ex.message } }
64
+ end
65
+ else
66
+ raise ex # re-raise since we are not handling it
69
67
  end
68
+ end
70
69
 
71
- def show
72
- respond_to do |format|
73
- format.html { render :show } # render html using @event
74
- format.json { render json: @event } # render json using #as_json
75
- end
70
+ def show
71
+ respond_to do |format|
72
+ format.html { render :show } # render html using @event
73
+ format.json { render json: @event } # render json using #as_json
76
74
  end
75
+ end
77
76
 
78
- def update
79
- # ...
80
- respond_to do |format|
81
- format.html { redirect_to event_path(@event.id) } # redirect to show upon sucessful update
82
- format.json { render json: @event } # render json using #as_json
83
- end
77
+ def update
78
+ # ...
79
+ respond_to do |format|
80
+ format.html { redirect_to event_path(@event.id) } # redirect to show upon sucessful update
81
+ format.json { render json: @event } # render json using #as_json
84
82
  end
83
+ end
84
+
85
+ private
86
+
87
+ def load_event
88
+ @event = Event.find(params.require(:event_id))
89
+ end
85
90
  end
86
91
  ```
87
92
  #### after
88
93
  ```rb
89
94
  class EventsController < ActionController::Base
90
- include MimeActor::Action
95
+ include MimeActor::Action
91
96
 
92
- # AbstractController::Callbacks here to load model with params
93
- before_action only: [:show, :update] { @event = Event.find(params.require(:event_id)) }
97
+ before_action only: %i[show update], with: :load_event
94
98
 
95
- respond_act_to :html, :json, on: [:show, :update]
99
+ respond_act_to :html, on: %i[show update]
100
+ respond_act_to :json, on: %i[show update], with: -> { render json: @event } # render json using #as_json
96
101
 
97
- rescue_act_from ActiveRecord::RecordNotFound, format: :json do |ex|
98
- render status: :bad_request, json: { error: ex.message }
99
- end
102
+ rescue_act_from ActiveRecord::RecordNotFound, format: :json, with: :handle_json_error
100
103
 
101
- rescue_act_from ActiveRecord::RecordNotFound, format: :html, action: :show do |ex|
102
- redirect_to events_path
103
- end
104
+ rescue_act_from ActiveRecord::RecordNotFound, format: :html, action: :show do
105
+ redirect_to events_path
106
+ end
104
107
 
105
- def show_html
106
- render :show # render html using @event
107
- end
108
+ private
109
+
110
+ def show_html
111
+ render :show # render html using @event
112
+ end
108
113
 
109
- def update_html
110
- redirect_to event_path(@event.id) # redirect to show upon sucessful update
111
- rescue ActiveRecord::RecordNotFound
112
- render :edit
113
- end
114
-
115
- def show_json
116
- render json: @event # render json using #as_json
117
- end
114
+ def update_html
115
+ # ...
116
+ redirect_to event_path(@event.id) # redirect to show upon sucessful update
117
+ rescue ActiveRecord::RecordNotFound
118
+ render :edit
119
+ end
118
120
 
119
- def update_json
120
- # ...
121
- render json: @event # render json using #as_json
122
- end
121
+ def handle_json_error(error)
122
+ render status: :bad_request, json: { error: error.message }
123
+ end
123
124
  end
124
125
  ```
data/README.md CHANGED
@@ -5,55 +5,51 @@
5
5
  [![Coverage][coverage_badge]][coverage]
6
6
  [![Maintainability][maintainability_badge]][maintainability]
7
7
 
8
- Action Render + Rescue handlers for different MIME types in Rails
8
+ Action processing with Callback + Rescue handlers for different MIME types in Rails.
9
9
 
10
10
  ## Usage
11
11
 
12
12
  MimeActor allows you to do something like below:
13
13
  ```rb
14
14
  class EventsController < ActionController::Base
15
- # AbstractController::Callbacks here to load model with params
16
- before_action only: :index { @events = Event.all }
17
- before_action only: [:show, :update] { @event = Event.find(params.require(:event_id)) }
18
-
19
- respond_act_to :html, :json, on: :index
20
- respond_act_to :html, :json, on: [:show, :update]
21
-
22
- rescue_act_from ActiveRecord::RecordNotFound, format: :json do |ex|
23
- render status: :bad_request, json: { error: "Resouce not found" }
24
- end
25
-
26
- rescue_act_from ActiveRecord::RecordNotFound, format: :html, action: :show do |ex|
27
- redirect_to events_path
28
- end
29
-
30
- def index_html
31
- @event_categories = EventCategory.all
32
- render :index # render html using @events and @event_categories
33
- end
34
-
35
- def index_json
36
- render json: @events # render json using #as_json
37
- end
38
-
39
- def show_html
40
- render :show # render html using @event
41
- end
42
-
43
- def update_html
44
- redirect_to event_path(@event.id) # redirect to show upon sucessful update
45
- rescue ActiveRecord::RecordNotFound
46
- render :edit
47
- end
48
-
49
- def show_json
50
- render json: @event # render json using #as_json
51
- end
52
-
53
- def update_json
54
- # ...
55
- render json: @event # render json using #as_json
56
- end
15
+ include MimeActor::Action
16
+
17
+ before_act -> { @events = Event.all }, action: :index
18
+ before_act :load_event, action: %i[show update]
19
+
20
+ respond_act_to :html, :json, on: :update
21
+ respond_act_to :html, on: %i[index show], with: :render_html
22
+ respond_act_to :json, on: %i[index show], with: -> { render json: { action: action_name } }
23
+
24
+ rescue_act_from ActiveRecord::RecordNotFound, format: :json, with: :handle_json_error
25
+ rescue_act_from ActiveRecord::RecordNotFound, format: :html, action: :show, with: -> { redirect_to "/events" }
26
+
27
+ private
28
+
29
+ def update_html
30
+ # ...
31
+ redirect_to "/events/#{@event.id}" # redirect to show upon sucessful update
32
+ rescue ActiveRecord::RecordNotFound
33
+ render html: :edit
34
+ end
35
+
36
+ def update_json
37
+ # ...
38
+ render json: @event # render json using #as_json
39
+ end
40
+
41
+ def render_html
42
+ @event_categories = EventCategory.all if action_name == :index
43
+ render html: action_name
44
+ end
45
+
46
+ def load_event
47
+ @event = Event.find(params.require(:event_id))
48
+ end
49
+
50
+ def handle_json_error(error)
51
+ render status: :bad_request, json: { error: error.message }
52
+ end
57
53
  end
58
54
  ```
59
55
 
@@ -2,9 +2,9 @@
2
2
 
3
3
  # :markup: markdown
4
4
 
5
+ require "mime_actor/logging"
5
6
  require "mime_actor/scene"
6
7
  require "mime_actor/stage"
7
- require "mime_actor/rescue"
8
8
 
9
9
  require "active_support/concern"
10
10
  require "active_support/core_ext/object/blank"
@@ -17,7 +17,7 @@ module MimeActor
17
17
  #
18
18
  # `Action` is the recommended `Module` to be included in the `ActionController`.
19
19
  #
20
- # Provides intuitive way of `action` rendering for a specific MIME type with rescue handlers.
20
+ # Provides intuitive way of `action` processing for a specific MIME type with callback + rescue handlers.
21
21
  #
22
22
  module Action
23
23
  extend ActiveSupport::Concern
@@ -27,15 +27,13 @@ module MimeActor
27
27
 
28
28
  include Scene
29
29
  include Stage
30
- include Rescue
31
30
  include Logging
32
31
 
33
32
  # The core logic where rendering logics are collected as `Proc` and passed over to `ActionController::MimeResponds`
34
33
  #
35
- # @param action the `action` of the controller
36
- #
37
34
  # @example process `create` action
38
- # start_scene(:create)
35
+ # # it uses AbstractController#action_name to process
36
+ # start_scene
39
37
  #
40
38
  # # it is equivalent to the following if `create` action is configured with `html` and `json` formats
41
39
  # def create
@@ -45,17 +43,18 @@ module MimeActor
45
43
  # end
46
44
  # end
47
45
  #
48
- def start_scene(action)
46
+ def start_scene
47
+ action = action_name.to_sym
49
48
  formats = acting_scenes.fetch(action, {})
50
49
 
51
50
  if formats.empty?
52
- logger.warn { "format is empty for action: #{action.inspect}" }
51
+ logger.warn { "format is empty for action: #{action_name.inspect}" }
53
52
  return
54
53
  end
55
54
 
56
55
  respond_to do |collector|
57
56
  formats.each do |format, actor|
58
- dispatch = -> { cue_actor(actor.presence || "#{action}_#{format}", action:, format:) }
57
+ dispatch = -> { cue_actor(actor.presence || "#{action}_#{format}", format:) }
59
58
  collector.public_send(format, &dispatch)
60
59
  end
61
60
  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, true)
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) }
@@ -124,11 +116,11 @@ module MimeActor
124
116
  def define_scene(action)
125
117
  module_eval(
126
118
  # def index
127
- # self.respond_to?(:start_scene) && self.start_scene(:index)
119
+ # self.respond_to?(:start_scene) && self.start_scene
128
120
  # end
129
121
  <<-RUBY, __FILE__, __LINE__ + 1
130
122
  def #{action}
131
- self.respond_to?(:start_scene) && self.start_scene(:#{action})
123
+ self.respond_to?(:start_scene) && self.start_scene
132
124
  end
133
125
  RUBY
134
126
  )
@@ -2,9 +2,10 @@
2
2
 
3
3
  # :markup: markdown
4
4
 
5
- require "mime_actor/errors"
5
+ require "mime_actor/callbacks"
6
6
  require "mime_actor/dispatcher"
7
7
  require "mime_actor/logging"
8
+ require "mime_actor/rescue"
8
9
 
9
10
  require "active_support/concern"
10
11
  require "active_support/core_ext/module/attribute_accessors"
@@ -17,6 +18,8 @@ module MimeActor
17
18
  module Stage
18
19
  extend ActiveSupport::Concern
19
20
 
21
+ include Callbacks
22
+ include Rescue
20
23
  include Logging
21
24
 
22
25
  included do
@@ -75,38 +78,22 @@ module MimeActor
75
78
  # @param actor either a method name or a Proc to evaluate
76
79
  # @param args arguments to be passed when calling the actor
77
80
  #
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
+ def cue_actor(actor, *args, format:)
82
+ dispatcher = MimeActor::Dispatcher.build(actor, *args)
83
+ raise TypeError, "invalid actor, got: #{actor.inspect}" unless dispatcher
81
84
 
82
- result = dispatch_actor(dispatch, action:, format:)
83
- if block_given?
84
- yield result
85
- else
86
- result
87
- end
88
- end
89
-
90
- private
85
+ self.class.validate!(:format, format)
91
86
 
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
87
+ run_act_callbacks(format) do
88
+ result = dispatcher.call(self)
89
+ block_given? ? yield(result) : result
100
90
  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}" }
91
+ rescue MimeActor::ActorNotFound => e
92
+ logger.error { "actor error, cause: #{e.inspect}" } unless raise_on_actor_error
93
+ raise e if raise_on_actor_error
94
+ rescue StandardError => e
95
+ rescued = rescue_actor(e, action: action_name.to_sym, format: format)
96
+ rescued || raise
110
97
  end
111
98
  end
112
99
  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,7 +14,7 @@ module MimeActor
14
14
  module VERSION
15
15
  MAJOR = 0
16
16
  MINOR = 6
17
- BUILD = 2
17
+ BUILD = 3
18
18
  PRE = nil
19
19
 
20
20
  STRING = [MAJOR, MINOR, BUILD, PRE].compact.join(".")
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
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-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -59,18 +59,12 @@ executables: []
59
59
  extensions: []
60
60
  extra_rdoc_files: []
61
61
  files:
62
- - ".hound.yml"
63
- - ".rspec"
64
- - ".rubocop.yml"
65
- - ".ruby-version"
66
- - ".yardopts"
67
62
  - COMPARE.md
68
63
  - LICENSE
69
64
  - README.md
70
- - Rakefile
71
- - codecov.yml
72
65
  - lib/mime_actor.rb
73
66
  - lib/mime_actor/action.rb
67
+ - lib/mime_actor/callbacks.rb
74
68
  - lib/mime_actor/dispatcher.rb
75
69
  - lib/mime_actor/errors.rb
76
70
  - lib/mime_actor/logging.rb
@@ -107,5 +101,6 @@ requirements: []
107
101
  rubygems_version: 3.5.9
108
102
  signing_key:
109
103
  specification_version: 4
110
- summary: Action Render + Rescue handlers for different MIME types in Rails
104
+ summary: Action processing with Callback + Rescue handlers for different MIME types
105
+ in Rails
111
106
  test_files: []
data/.hound.yml DELETED
@@ -1,2 +0,0 @@
1
- rubocop:
2
- enabled: false
data/.rspec DELETED
@@ -1 +0,0 @@
1
- --require spec_helper
data/.rubocop.yml DELETED
@@ -1,66 +0,0 @@
1
- require:
2
- - rubocop-rake
3
- - rubocop-rspec
4
-
5
- AllCops:
6
- TargetRubyVersion: 3.1
7
- NewCops: enable
8
- Exclude:
9
- - bin/*
10
- - vendor/**/*
11
-
12
- Style/Documentation:
13
- Enabled: false
14
-
15
- Style/BlockComments:
16
- Exclude:
17
- - spec/*_helper.rb
18
-
19
- Style/RegexpLiteral:
20
- EnforcedStyle: percent_r
21
-
22
- Metrics/AbcSize:
23
- Enabled: false
24
-
25
- Metrics/BlockLength:
26
- AllowedMethods:
27
- - class_methods
28
-
29
- Metrics/CyclomaticComplexity:
30
- Enabled: false
31
-
32
- Metrics/PerceivedComplexity:
33
- Enabled: false
34
-
35
- Metrics/MethodLength:
36
- CountAsOne: ['array', 'heredoc', 'method_call']
37
- Max: 15
38
-
39
- Style/StringLiterals:
40
- EnforcedStyle: double_quotes
41
-
42
- Style/StringLiteralsInInterpolation:
43
- EnforcedStyle: double_quotes
44
-
45
- Style/HashSyntax:
46
- EnforcedShorthandSyntax: consistent
47
-
48
- Layout/FirstHashElementIndentation:
49
- EnforcedStyle: consistent
50
-
51
- Layout/HashAlignment:
52
- EnforcedHashRocketStyle: table
53
- EnforcedColonStyle: table
54
-
55
- RSpec/MultipleExpectations:
56
- Max: 6
57
-
58
- RSpec/ExampleLength:
59
- CountAsOne: ['array', 'heredoc', 'method_call']
60
- Max: 10
61
-
62
- RSpec/MultipleMemoizedHelpers:
63
- Max: 10
64
-
65
- RSpec/NestedGroups:
66
- Max: 5
data/.ruby-version DELETED
@@ -1 +0,0 @@
1
- 3.3.1
data/.yardopts DELETED
@@ -1,2 +0,0 @@
1
- --markup markdown
2
- lib/**/*.rb
data/Rakefile DELETED
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "bundler/gem_tasks"
4
-
5
- require "rubocop/rake_task"
6
- RuboCop::RakeTask.new
7
-
8
- require "rspec/core/rake_task"
9
- RSpec::Core::RakeTask.new(:spec)
data/codecov.yml DELETED
@@ -1,18 +0,0 @@
1
- codecov:
2
- notify:
3
- wait_for_ci: false
4
- require_ci_to_pass: false
5
-
6
- coverage:
7
- status:
8
- project:
9
- default:
10
- target: 99%
11
- threshold: 1%
12
- patch:
13
- default:
14
- target: 99%
15
- threshold: 1%
16
-
17
- comment:
18
- require_changes: true