mime_actor 0.3.3 → 0.4.0
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 +4 -4
- data/.rubocop.yml +22 -2
- data/README.md +1 -1
- data/lib/mime_actor/act.rb +17 -25
- data/lib/mime_actor/errors.rb +29 -4
- data/lib/mime_actor/logging.rb +29 -0
- data/lib/mime_actor/rescue.rb +26 -25
- data/lib/mime_actor/scene.rb +22 -20
- data/lib/mime_actor/stage.rb +22 -22
- data/lib/mime_actor/validator.rb +62 -0
- data/lib/mime_actor/version.rb +2 -2
- data/lib/mime_actor.rb +2 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7f099315434127b3b7044aad85eca2f69664521753dd339af0f8b6829e0ef8dc
|
4
|
+
data.tar.gz: f8d79ab0813b5f3d63a8a991c9a0f39f328cc67e991738a21030a7fcaee3eae6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ba11f403b7031051f9d56577a34dc7b2c63906aabe7b6e663fa9ef87225e0a9334d3a9f08eabbefc5f85a201c8ed73e231e4c616a2f0bac7d1a37e05607a4e81
|
7
|
+
data.tar.gz: 3f21642e23e14ef5a175740e7916618ed3fb99b8395197d7b5239abe0ead83d0ea498ed1b6f63fa4830e9803e2bc16c04f32c43b25544bcf57c9986f2999f528
|
data/.rubocop.yml
CHANGED
@@ -15,6 +15,19 @@ Style/BlockComments:
|
|
15
15
|
Exclude:
|
16
16
|
- spec/*_helper.rb
|
17
17
|
|
18
|
+
Metrics/AbcSize:
|
19
|
+
Enabled: false
|
20
|
+
|
21
|
+
Metrics/CyclomaticComplexity:
|
22
|
+
Enabled: false
|
23
|
+
|
24
|
+
Metrics/PerceivedComplexity:
|
25
|
+
Enabled: false
|
26
|
+
|
27
|
+
Metrics/MethodLength:
|
28
|
+
CountAsOne: ['array', 'heredoc', 'method_call']
|
29
|
+
Max: 15
|
30
|
+
|
18
31
|
Style/StringLiterals:
|
19
32
|
EnforcedStyle: double_quotes
|
20
33
|
|
@@ -32,7 +45,14 @@ Layout/HashAlignment:
|
|
32
45
|
EnforcedColonStyle: table
|
33
46
|
|
34
47
|
RSpec/MultipleExpectations:
|
35
|
-
|
48
|
+
Max: 6
|
36
49
|
|
37
50
|
RSpec/ExampleLength:
|
38
|
-
|
51
|
+
CountAsOne: ['array', 'heredoc', 'method_call']
|
52
|
+
Max: 10
|
53
|
+
|
54
|
+
RSpec/MultipleMemoizedHelpers:
|
55
|
+
Max: 10
|
56
|
+
|
57
|
+
RSpec/NestedGroups:
|
58
|
+
Max: 5
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# mime_actor
|
2
2
|
|
3
|
-
[](https://badge.fury.io/rb/mime_actor)
|
4
4
|
[](https://github.com/ryancyq/mime_actor/actions/workflows/build.yml)
|
5
5
|
|
6
6
|
Action rendering and rescue with mime type via configuration in actionpack
|
data/lib/mime_actor/act.rb
CHANGED
@@ -5,6 +5,7 @@ require "mime_actor/stage"
|
|
5
5
|
require "mime_actor/rescue"
|
6
6
|
|
7
7
|
require "active_support/concern"
|
8
|
+
require "active_support/lazy_load_hooks"
|
8
9
|
require "abstract_controller/rendering"
|
9
10
|
require "action_controller/metal/mime_responds"
|
10
11
|
|
@@ -14,40 +15,31 @@ module MimeActor
|
|
14
15
|
|
15
16
|
include AbstractController::Rendering # required by MimeResponds
|
16
17
|
include ActionController::MimeResponds
|
18
|
+
|
17
19
|
include Scene
|
18
20
|
include Stage
|
19
21
|
include Rescue
|
22
|
+
include Logging
|
20
23
|
|
21
|
-
|
22
|
-
def dispatch_act(action: nil, format: nil, context: self, &block)
|
23
|
-
lambda do
|
24
|
-
context.instance_exec(&block)
|
25
|
-
rescue StandardError => e
|
26
|
-
(respond_to?(:rescue_actor) && rescue_actor(e, action:, format:, context:)) || raise
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
private
|
32
|
-
|
33
|
-
def play_scene(action)
|
24
|
+
def start_scene(action)
|
34
25
|
action = action&.to_sym
|
35
|
-
|
26
|
+
formats = acting_scenes.fetch(action, Set.new)
|
27
|
+
|
28
|
+
if formats.empty?
|
29
|
+
logger.warn { "format is empty, action: #{action}" }
|
30
|
+
return
|
31
|
+
end
|
36
32
|
|
37
|
-
mime_types = acting_scenes.fetch(action, Set.new)
|
38
33
|
respond_to do |collector|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
format: mime_type,
|
45
|
-
context: self,
|
46
|
-
&actor
|
47
|
-
)
|
48
|
-
collector.public_send(mime_type, &dispatch)
|
34
|
+
formats.each do |format|
|
35
|
+
dispatch = self.class.dispatch_cue(action: action, format: format, context: self) do
|
36
|
+
cue_actor("#{action}_#{format}")
|
37
|
+
end
|
38
|
+
collector.public_send(format, &dispatch)
|
49
39
|
end
|
50
40
|
end
|
51
41
|
end
|
42
|
+
|
43
|
+
ActiveSupport.run_load_hooks(:mime_actor, self)
|
52
44
|
end
|
53
45
|
end
|
data/lib/mime_actor/errors.rb
CHANGED
@@ -1,20 +1,45 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "set"
|
4
|
+
|
3
5
|
module MimeActor
|
4
6
|
class Error < StandardError
|
7
|
+
def inspect
|
8
|
+
"<#{self.class.name}> #{message}"
|
9
|
+
end
|
10
|
+
|
11
|
+
def generate_message
|
12
|
+
self.class.name
|
13
|
+
end
|
5
14
|
end
|
6
15
|
|
7
|
-
class
|
16
|
+
class ActorError < Error
|
8
17
|
attr_reader :actor
|
9
18
|
|
10
19
|
def initialize(actor)
|
11
20
|
@actor = actor
|
21
|
+
super(generate_message)
|
22
|
+
end
|
23
|
+
end
|
12
24
|
|
13
|
-
|
25
|
+
class ActorNotFound < ActorError
|
26
|
+
def generate_message
|
27
|
+
":#{actor} not found"
|
14
28
|
end
|
29
|
+
end
|
15
30
|
|
16
|
-
|
17
|
-
|
31
|
+
class ActionError < Error
|
32
|
+
attr_reader :action
|
33
|
+
|
34
|
+
def initialize(action = nil)
|
35
|
+
@action = action
|
36
|
+
super(generate_message)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class ActionExisted < ActionError
|
41
|
+
def generate_message
|
42
|
+
"action :#{action} already existed"
|
18
43
|
end
|
19
44
|
end
|
20
45
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/concern"
|
4
|
+
require "active_support/configurable"
|
5
|
+
require "active_support/isolated_execution_state" # required by active_support/logger
|
6
|
+
require "active_support/logger"
|
7
|
+
require "active_support/tagged_logging"
|
8
|
+
|
9
|
+
module MimeActor
|
10
|
+
module Logging
|
11
|
+
extend ActiveSupport::Concern
|
12
|
+
|
13
|
+
include ActiveSupport::Configurable
|
14
|
+
|
15
|
+
included do
|
16
|
+
config_accessor :logger, default: ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new($stdout))
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def fill_run_sheet(*scenes, &)
|
22
|
+
return yield unless logger.respond_to?(:tagged)
|
23
|
+
|
24
|
+
scenes.unshift "MimeActor" unless logger.formatter.current_tags.include?("MimeActor")
|
25
|
+
|
26
|
+
logger.tagged(*scenes, &)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/mime_actor/rescue.rb
CHANGED
@@ -1,56 +1,56 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "mime_actor/stage"
|
4
|
+
require "mime_actor/validator"
|
5
|
+
|
3
6
|
require "active_support/concern"
|
4
7
|
require "active_support/core_ext/array/wrap"
|
5
8
|
require "active_support/core_ext/module/attribute_accessors"
|
6
|
-
require "active_support/core_ext/object/blank"
|
7
9
|
require "active_support/core_ext/string/inflections"
|
8
|
-
require "set" # remove when ruby > 3,1
|
9
|
-
require "action_dispatch/http/mime_type"
|
10
10
|
|
11
11
|
module MimeActor
|
12
12
|
module Rescue
|
13
13
|
extend ActiveSupport::Concern
|
14
14
|
|
15
|
+
include Stage
|
16
|
+
include Validator
|
17
|
+
|
15
18
|
included do
|
16
19
|
mattr_accessor :actor_rescuers, instance_writer: false, default: []
|
17
20
|
end
|
18
21
|
|
19
22
|
module ClassMethods
|
20
23
|
def rescue_actor_from(*klazzes, action: nil, format: nil, with: nil, &block)
|
21
|
-
raise ArgumentError, "
|
22
|
-
raise ArgumentError, "Provide only the with: keyword argument or a block" if with.present? && block_given?
|
23
|
-
raise ArgumentError, "Provide the with: keyword argument or a block" unless with.present? || block_given?
|
24
|
+
raise ArgumentError, "error filter is required" if klazzes.empty?
|
24
25
|
|
26
|
+
validate!(:with, with, block)
|
25
27
|
with = block if block_given?
|
26
|
-
raise ArgumentError, "Rescue handler can only be Symbol/Proc" unless with.is_a?(Proc) || with.is_a?(Symbol)
|
27
28
|
|
28
|
-
if
|
29
|
-
|
30
|
-
|
31
|
-
raise ArgumentError, "Unsupported format: #{format}" unless Mime::SET.symbols.include?(format.to_sym)
|
32
|
-
when Enumerable
|
33
|
-
unfiltered = format.to_set
|
34
|
-
filtered = unfiltered & Mime::SET.symbols.to_set
|
35
|
-
rejected = unfiltered - filtered
|
36
|
-
raise ArgumentError, "Unsupported formats: #{rejected.join(", ")}" if rejected.size.positive?
|
29
|
+
if action.present?
|
30
|
+
if action.is_a?(Enumerable)
|
31
|
+
validate!(:actions, action)
|
37
32
|
else
|
38
|
-
|
33
|
+
validate!(:action, action)
|
39
34
|
end
|
40
35
|
end
|
41
36
|
|
42
|
-
if
|
43
|
-
|
37
|
+
if format.present?
|
38
|
+
if format.is_a?(Enumerable)
|
39
|
+
validate!(:formats, format)
|
40
|
+
else
|
41
|
+
validate!(:format, format)
|
42
|
+
end
|
44
43
|
end
|
45
44
|
|
46
45
|
klazzes.each do |klazz|
|
47
|
-
error =
|
46
|
+
error = case klazz
|
47
|
+
when Module
|
48
48
|
klazz.name
|
49
|
-
|
49
|
+
when String
|
50
50
|
klazz
|
51
51
|
else
|
52
|
-
|
53
|
-
|
52
|
+
message = "#{klazz.inspect} must be a Class/Module or a String referencing a Class/Module"
|
53
|
+
raise ArgumentError, message
|
54
54
|
end
|
55
55
|
|
56
56
|
# append at the end because strategies are read in reverse.
|
@@ -59,12 +59,13 @@ module MimeActor
|
|
59
59
|
end
|
60
60
|
|
61
61
|
def rescue_actor(error, action: nil, format: nil, context: self, visited: [])
|
62
|
-
|
62
|
+
return if visited.include?(error)
|
63
63
|
|
64
|
+
visited << error
|
64
65
|
if (rescuer = dispatch_rescuer(error, format:, action:, context:))
|
65
66
|
rescuer.call(error, format, action)
|
66
67
|
error
|
67
|
-
elsif error&.cause
|
68
|
+
elsif error&.cause
|
68
69
|
rescue_actor(error.cause, format:, action:, context:, visited:)
|
69
70
|
end
|
70
71
|
end
|
data/lib/mime_actor/scene.rb
CHANGED
@@ -1,52 +1,54 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "mime_actor/
|
3
|
+
require "mime_actor/errors"
|
4
|
+
require "mime_actor/validator"
|
4
5
|
|
5
6
|
require "active_support/concern"
|
6
7
|
require "active_support/core_ext/array/extract_options"
|
7
8
|
require "active_support/core_ext/array/wrap"
|
8
|
-
require "active_support/core_ext/hash/indifferent_access"
|
9
9
|
require "active_support/core_ext/module/attribute_accessors"
|
10
|
-
require "set" # remove when ruby > 3,1
|
11
|
-
require "action_dispatch/http/mime_type"
|
12
10
|
|
13
11
|
module MimeActor
|
14
12
|
module Scene
|
15
13
|
extend ActiveSupport::Concern
|
16
14
|
|
17
|
-
include
|
15
|
+
include Validator
|
18
16
|
|
19
17
|
included do
|
20
|
-
mattr_accessor :acting_scenes, instance_writer: false, default:
|
18
|
+
mattr_accessor :acting_scenes, instance_writer: false, default: {}
|
21
19
|
end
|
22
20
|
|
23
21
|
module ClassMethods
|
24
22
|
def compose_scene(*options)
|
25
23
|
config = options.extract_options!
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
24
|
+
validate!(:formats, options)
|
25
|
+
|
26
|
+
actions = config[:on]
|
27
|
+
if !actions
|
28
|
+
raise ArgumentError, "action is required"
|
29
|
+
elsif actions.is_a?(Enumerable)
|
30
|
+
validate!(:actions, actions)
|
31
|
+
else
|
32
|
+
validate!(:action, actions)
|
33
|
+
end
|
32
34
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
35
|
+
options.each do |format|
|
36
|
+
Array.wrap(actions).each do |action|
|
37
|
+
action_defined = (instance_methods + private_instance_methods).include?(action.to_sym)
|
38
|
+
raise MimeActor::ActionExisted, action if !acting_scenes.key?(action) && action_defined
|
37
39
|
|
38
40
|
acting_scenes[action] ||= Set.new
|
39
|
-
acting_scenes[action] |= [
|
41
|
+
acting_scenes[action] |= [format]
|
40
42
|
|
41
|
-
next if
|
43
|
+
next if action_defined
|
42
44
|
|
43
45
|
class_eval(
|
44
46
|
# def index
|
45
|
-
# self.
|
47
|
+
# self.respond_to?(:start_scene) && self.start_scene(:index)
|
46
48
|
# end
|
47
49
|
<<-RUBY, __FILE__, __LINE__ + 1
|
48
50
|
def #{action}
|
49
|
-
self.
|
51
|
+
self.respond_to?(:start_scene) && self.start_scene(:#{action})
|
50
52
|
end
|
51
53
|
RUBY
|
52
54
|
)
|
data/lib/mime_actor/stage.rb
CHANGED
@@ -1,18 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "mime_actor/errors"
|
4
|
+
require "mime_actor/logging"
|
4
5
|
|
5
6
|
require "active_support/concern"
|
6
|
-
require "active_support/configurable"
|
7
7
|
require "active_support/core_ext/module/attribute_accessors"
|
8
|
-
require "abstract_controller/logger"
|
9
8
|
|
10
9
|
module MimeActor
|
11
10
|
module Stage
|
12
11
|
extend ActiveSupport::Concern
|
13
12
|
|
14
|
-
include
|
15
|
-
include AbstractController::Logger
|
13
|
+
include Logging
|
16
14
|
|
17
15
|
included do
|
18
16
|
mattr_accessor :raise_on_missing_actor, instance_writer: false, default: false
|
@@ -20,29 +18,31 @@ module MimeActor
|
|
20
18
|
|
21
19
|
module ClassMethods
|
22
20
|
def actor?(actor_name)
|
23
|
-
|
24
|
-
|
25
|
-
|
21
|
+
# exclude public methods from ancestors
|
22
|
+
found = public_instance_methods(false).include?(actor_name.to_sym)
|
23
|
+
# exclude private methods from ancestors
|
24
|
+
if !found && private_instance_methods(false).include?(actor_name.to_sym)
|
25
|
+
logger.debug { "actor must be public method, #{actor_name} is private method" }
|
26
|
+
end
|
27
|
+
found
|
26
28
|
end
|
27
|
-
end
|
28
|
-
|
29
|
-
def actor?(actor_name)
|
30
|
-
return action_methods.include?(actor_name.to_s) if respond_to?(:action_methods)
|
31
|
-
|
32
|
-
methods.include?(actor_name.to_sym)
|
33
|
-
end
|
34
29
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
30
|
+
def dispatch_cue(action: nil, format: nil, context: self, &block)
|
31
|
+
lambda do
|
32
|
+
context.instance_exec(&block)
|
33
|
+
rescue StandardError => e
|
34
|
+
(respond_to?(:rescue_actor) && rescue_actor(e, action:, format:, context:)) || raise
|
35
|
+
end
|
36
|
+
end
|
42
37
|
end
|
43
38
|
|
44
39
|
def cue_actor(actor_name, *args)
|
45
|
-
|
40
|
+
unless self.class.actor?(actor_name)
|
41
|
+
raise MimeActor::ActorNotFound, actor_name if raise_on_missing_actor
|
42
|
+
|
43
|
+
logger.warn { "actor not found, got: #{actor_name}" }
|
44
|
+
return
|
45
|
+
end
|
46
46
|
|
47
47
|
result = public_send(actor_name, *args)
|
48
48
|
if block_given?
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/concern"
|
4
|
+
require "set" # required by mime_type with ruby <= 3.1
|
5
|
+
require "action_dispatch/http/mime_type"
|
6
|
+
|
7
|
+
module MimeActor
|
8
|
+
module Validator
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
included do
|
12
|
+
mattr_accessor :scene_formats, instance_writer: false, default: Mime::SET.symbols.to_set
|
13
|
+
end
|
14
|
+
|
15
|
+
module ClassMethods
|
16
|
+
def validate!(rule, *args)
|
17
|
+
validator = "validate_#{rule}"
|
18
|
+
raise NameError, "Validator not found, got: #{validator}" unless respond_to?(validator, true)
|
19
|
+
|
20
|
+
error = send(validator, *args)
|
21
|
+
raise error if error
|
22
|
+
end
|
23
|
+
|
24
|
+
def validate_action(unchecked)
|
25
|
+
ArgumentError.new("action must be a Symbol") unless unchecked.is_a?(Symbol)
|
26
|
+
end
|
27
|
+
|
28
|
+
def validate_actions(unchecked)
|
29
|
+
rejected = unchecked.reject { |action| action.is_a?(Symbol) }
|
30
|
+
NameError.new("invalid actions, got: #{rejected.join(", ")}") if rejected.size.positive?
|
31
|
+
end
|
32
|
+
|
33
|
+
def validate_format(unchecked)
|
34
|
+
return ArgumentError.new("format must be a Symbol") unless unchecked.is_a?(Symbol)
|
35
|
+
|
36
|
+
NameError.new("invalid format, got: #{unchecked}") unless scene_formats.include?(unchecked)
|
37
|
+
end
|
38
|
+
|
39
|
+
def validate_formats(unchecked)
|
40
|
+
unfiltered = unchecked.to_set
|
41
|
+
filtered = unfiltered & scene_formats
|
42
|
+
rejected = unfiltered - filtered
|
43
|
+
|
44
|
+
NameError.new("invalid formats, got: #{rejected.join(", ")}") if rejected.size.positive?
|
45
|
+
end
|
46
|
+
|
47
|
+
def validate_with(unchecked, block)
|
48
|
+
if unchecked.present? && block.present?
|
49
|
+
return ArgumentError.new("provide either the with: keyword argument or a block")
|
50
|
+
end
|
51
|
+
unless unchecked.present? || block.present?
|
52
|
+
return ArgumentError.new("provide the with: keyword argument or a block")
|
53
|
+
end
|
54
|
+
|
55
|
+
return if block.present?
|
56
|
+
return if unchecked.is_a?(Proc) || unchecked.is_a?(Symbol)
|
57
|
+
|
58
|
+
ArgumentError.new("with handler must be a Symbol or Proc, got: #{unchecked.inspect}")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/mime_actor/version.rb
CHANGED
data/lib/mime_actor.rb
CHANGED
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.
|
4
|
+
version: 0.4.0
|
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-06-
|
11
|
+
date: 2024-06-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: actionpack
|
@@ -68,9 +68,11 @@ files:
|
|
68
68
|
- lib/mime_actor.rb
|
69
69
|
- lib/mime_actor/act.rb
|
70
70
|
- lib/mime_actor/errors.rb
|
71
|
+
- lib/mime_actor/logging.rb
|
71
72
|
- lib/mime_actor/rescue.rb
|
72
73
|
- lib/mime_actor/scene.rb
|
73
74
|
- lib/mime_actor/stage.rb
|
75
|
+
- lib/mime_actor/validator.rb
|
74
76
|
- lib/mime_actor/version.rb
|
75
77
|
- sig/mime_actor.rbs
|
76
78
|
homepage: https://github.com/ryancyq/mime_actor
|