mime_actor 0.6.0 → 0.6.1

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: 031455cd4203f02b1760129516e1a8722af2f84d7580cf1799f886d98262cdea
4
- data.tar.gz: 78b2841148310600b408fd3d2932741ab61280f24afb28f0b251e62bcba91419
3
+ metadata.gz: f5a67bb80dd83c069ea2f06a4afea5e241987d8b9a2a30f0a3eb0d01748b3759
4
+ data.tar.gz: acb0cd8b89e39ea3962c0949bff4666c96c36f6c15eae5a3709775daa5ef2516
5
5
  SHA512:
6
- metadata.gz: 2852a58bb4dc628d293e6d5974b452144496be454a2a594aec90baaffcf5fbbcdd096745778853f36cc5e8ef4eb577340175bd76533ba2be1852799ddf5cc2a6
7
- data.tar.gz: f548c1d8fe2c32a2aba34c4b9189e3e02272fdcfdc850d8b88e6cb6eea54514a1c95cc8ede181656f5ba0e92111f2566db1cbc98b647dd77f0922cd2ff1357be
6
+ metadata.gz: e64c6a62feb248b76672d75ef4cf9bc0f822b0f2fd57311f879874e910377b80549b133c85b148fd61d44d91259c780299770d7fae4792dbab094c01676df201
7
+ data.tar.gz: 2577dc3d03d3fa233ba136613e63d0c18a3e59f51bac690b582b18f424cc4ee7e5fee736eafc76393a94af20e3fcf930cd953b4eec07f21282fa9b5dd7be552d
data/COMPARE.md CHANGED
@@ -27,7 +27,7 @@ class EventsController < ActionController::Base
27
27
  before_action only: :index { @events = Event.all }
28
28
 
29
29
  # dynamically defines the action method according to on: argument
30
- act_on_format :html, :json, on: :index
30
+ respond_act_to :html, :json, on: :index
31
31
 
32
32
  def index_html
33
33
  @event_categories = EventCategory.all
@@ -92,7 +92,7 @@ class EventsController < ActionController::Base
92
92
  # AbstractController::Callbacks here to load model with params
93
93
  before_action only: [:show, :update] { @event = Event.find(params.require(:event_id)) }
94
94
 
95
- act_on_format :html, :json, on: [:show, :update]
95
+ respond_act_to :html, :json, on: [:show, :update]
96
96
 
97
97
  rescue_act_from ActiveRecord::RecordNotFound, format: :json do |ex|
98
98
  render status: :bad_request, json: { error: ex.message }
data/README.md CHANGED
@@ -16,8 +16,8 @@ class EventsController < ActionController::Base
16
16
  before_action only: :index { @events = Event.all }
17
17
  before_action only: [:show, :update] { @event = Event.find(params.require(:event_id)) }
18
18
 
19
- act_on_format :html, :json, on: :index
20
- act_on_format :html, :json, on: [:show, :update]
19
+ respond_act_to :html, :json, on: :index
20
+ respond_act_to :html, :json, on: [:show, :update]
21
21
 
22
22
  rescue_act_from ActiveRecord::RecordNotFound, format: :json do |ex|
23
23
  render status: :bad_request, json: { error: "Resouce not found" }
@@ -99,7 +99,7 @@ Please see [LICENSE](https://github.com/ryancyq/mime_actor/blob/main/LICENSE) fo
99
99
 
100
100
  ## Contributing
101
101
 
102
- Bug reports and pull requests are welcome on GitHub at https://github.com/ryancyq/mime_actor.
102
+ Bug reports and pull requests are welcome on GitHub at [https://github.com/ryancyq/mime_actor](https://github.com/ryancyq/mime_actor).
103
103
 
104
104
  [rubygems_badge]: https://img.shields.io/gem/v/mime_actor.svg
105
105
  [rubygems]: https://rubygems.org/gems/mime_actor
data/codecov.yml ADDED
@@ -0,0 +1,18 @@
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
@@ -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/core_ext/object/blank"
8
9
  require "active_support/lazy_load_hooks"
9
10
  require "abstract_controller/rendering"
10
11
  require "action_controller/metal/mime_responds"
@@ -44,17 +45,17 @@ module MimeActor
44
45
  #
45
46
  def start_scene(action)
46
47
  action = action&.to_sym
47
- formats = acting_scenes.fetch(action, Set.new)
48
+ formats = acting_scenes.fetch(action, {})
48
49
 
49
50
  if formats.empty?
50
- logger.warn { "format is empty for action :#{action}" }
51
+ logger.warn { "format is empty for action: #{action.inspect}" }
51
52
  return
52
53
  end
53
54
 
54
55
  respond_to do |collector|
55
- formats.each do |format|
56
+ formats.each do |format, actor|
56
57
  dispatch = self.class.dispatch_cue(action: action, format: format, context: self) do
57
- cue_actor("#{action}_#{format}")
58
+ cue_actor(actor.presence || "#{action}_#{format}")
58
59
  end
59
60
  collector.public_send(format, &dispatch)
60
61
  end
@@ -24,7 +24,7 @@ module MimeActor
24
24
 
25
25
  class ActorNotFound < ActorError
26
26
  def generate_message
27
- ":#{actor} not found"
27
+ "#{actor.inspect} not found"
28
28
  end
29
29
  end
30
30
 
@@ -39,7 +39,7 @@ module MimeActor
39
39
 
40
40
  class ActionExisted < ActionError
41
41
  def generate_message
42
- "action :#{action} already existed"
42
+ "action #{action.inspect} already existed"
43
43
  end
44
44
  end
45
45
  end
@@ -8,6 +8,7 @@ require "mime_actor/validator"
8
8
  require "active_support/concern"
9
9
  require "active_support/core_ext/array/wrap"
10
10
  require "active_support/core_ext/module/attribute_accessors"
11
+ require "active_support/core_ext/object/blank"
11
12
  require "active_support/core_ext/string/inflections"
12
13
 
13
14
  module MimeActor
@@ -28,13 +29,13 @@ module MimeActor
28
29
  mattr_accessor :actor_rescuers, instance_writer: false, default: []
29
30
  end
30
31
 
31
- class_methods do
32
+ module ClassMethods
32
33
  # Registers a rescue handler for the given error classes with `action`/`format` filter
33
34
  #
34
35
  # @param klazzes the error classes to rescue
35
36
  # @param action the `action` filter
36
37
  # @param format the `format` filter
37
- # @param with the rescue hanlder when `block` is not provided
38
+ # @param with the rescue handler when `block` is not provided
38
39
  # @param block the `block` to evaluate when `with` is not provided
39
40
  #
40
41
  # @example Rescue StandardError when raised for any action with `html` format
@@ -47,9 +48,13 @@ module MimeActor
47
48
  #
48
49
  def rescue_act_from(*klazzes, action: nil, format: nil, with: nil, &block)
49
50
  raise ArgumentError, "error filter is required" if klazzes.empty?
51
+ raise ArgumentError, "provide either the with: argument or a block" unless with.present? ^ block_given?
50
52
 
51
- validate!(:with, with, block)
52
- with = block if block_given?
53
+ if block_given?
54
+ with = block
55
+ else
56
+ validate!(:with, with)
57
+ end
53
58
 
54
59
  if action.present?
55
60
  action.is_a?(Enumerable) ? validate!(:actions, action) : validate!(:action, action)
@@ -96,26 +101,14 @@ module MimeActor
96
101
  case rescuer = find_rescuer(error, format:, action:)
97
102
  when Symbol
98
103
  rescuer_method = context.method(rescuer)
99
- case rescuer_method.arity
100
- when 0
101
- ->(_e, _f, _a) { rescuer_method.call }
102
- when 1
103
- ->(e, _f, _a) { rescuer_method.call(e) }
104
- when 2
105
- ->(e, f, _a) { rescuer_method.call(e, f) }
106
- else
107
- ->(e, f, a) { rescuer_method.call(e, f, a) }
104
+ lambda do |*args|
105
+ passable_args = rescuer_method.arity.negative? ? args : args.take(rescuer_method.arity)
106
+ rescuer_method.call(*passable_args)
108
107
  end
109
108
  when Proc
110
- case rescuer.arity
111
- when 0
112
- ->(_e, _f, _a) { context.instance_exec(&rescuer) }
113
- when 1
114
- ->(e, _f, _a) { context.instance_exec(e, &rescuer) }
115
- when 2
116
- ->(e, f, _a) { context.instance_exec(e, f, &rescuer) }
117
- else
118
- ->(e, f, a) { context.instance_exec(e, f, a, &rescuer) }
109
+ lambda do |*args|
110
+ passable_args = rescuer.arity.negative? ? args : args.take(rescuer.arity)
111
+ context.instance_exec(*passable_args, &rescuer)
119
112
  end
120
113
  end
121
114
  end
@@ -9,6 +9,7 @@ require "active_support/concern"
9
9
  require "active_support/core_ext/array/extract_options"
10
10
  require "active_support/core_ext/array/wrap"
11
11
  require "active_support/core_ext/module/attribute_accessors"
12
+ require "active_support/core_ext/object/blank"
12
13
 
13
14
  module MimeActor
14
15
  # # MimeActor Scene
@@ -16,9 +17,27 @@ module MimeActor
16
17
  # Scene provides configuration for `action` + `format` definitions
17
18
  #
18
19
  # @example register a `html` format on action `index`
19
- # act_on_format :html, on: :index
20
+ # respond_act_to :html, on: :index
21
+ #
22
+ # # this method should be defined in the class
23
+ # def index_html; end
20
24
  # @example register `html`, `json` formats on actions `index`, `show`
21
- # act_on_format :html, :json , on: [:index, :show]
25
+ # respond_act_to :html, :json , on: [:index, :show]
26
+ #
27
+ # # these methods should be defined in the class
28
+ # def index_html; end
29
+ # def index_json; end
30
+ # def show_html; end
31
+ # def show_json; end
32
+ # @example register a `html` format on action `index` with respond handler method
33
+ # respond_act_to :html, on: :index, with: :render_html
34
+ #
35
+ # # this method should be defined in the class
36
+ # def render_html; end
37
+ # @example register a `html` format on action `index` with respond handler proc
38
+ # respond_act_to :html, on: :index do
39
+ # render :index
40
+ # end
22
41
  #
23
42
  # NOTE: Calling the same `action`/`format` multiple times will overwrite previous `action` + `format` definitions.
24
43
  #
@@ -31,24 +50,50 @@ module MimeActor
31
50
  mattr_accessor :acting_scenes, instance_writer: false, default: {}
32
51
  end
33
52
 
34
- class_methods do
53
+ module ClassMethods
35
54
  # Register `action` + `format` definitions.
36
55
  #
37
- # @param options [Array]
38
- # @option options [Array] klazzes the collection of `format`
39
- # @option options [Hash] on the collection of `action`
56
+ # @param formats the collection of `format`
57
+ # @param on the collection of `action`
58
+ # @param with the respond handler when `block` is not provided
59
+ # @param block the `block` to evaluate when `with` is not provided
40
60
  #
41
61
  # @example register a `html` format on action `index`
42
- # act_on_format :html, on: :index
62
+ # respond_act_to :html, on: :index
63
+ #
64
+ # # this method should be defined in the class
65
+ # def index_html; end
43
66
  # @example register `html`, `json` formats on actions `index`, `show`
44
- # act_on_format :html, :json , on: [:index, :show]
67
+ # respond_act_to :html, :json , on: [:index, :show]
68
+ #
69
+ # # these methods should be defined in the class
70
+ # def index_html; end
71
+ # def index_json; end
72
+ # def show_html; end
73
+ # def show_json; end
74
+ # @example register a `html` format on action `index` with respond handler method
75
+ # respond_act_to :html, on: :index, with: :render_html
76
+ #
77
+ # # this method should be defined in the class
78
+ # def render_html; end
79
+ # @example register a `html` format on action `index` with respond handler proc
80
+ # respond_act_to :html, on: :index do
81
+ # render :index
82
+ # end
45
83
  #
46
84
  # For each unique `action` being registered, it will have a corresponding `action` method being defined.
47
- def act_on_format(*options)
48
- config = options.extract_options!
49
- validate!(:formats, options)
85
+ def respond_act_to(*formats, on: nil, with: nil, &block)
86
+ validate!(:formats, formats)
87
+
88
+ raise ArgumentError, "provide either the with: argument or a block" if with.present? && block_given?
50
89
 
51
- case actions = config[:on]
90
+ if block_given?
91
+ with = block
92
+ elsif with.present?
93
+ validate!(:with, with)
94
+ end
95
+
96
+ case actions = on
52
97
  when Enumerable
53
98
  validate!(:actions, actions)
54
99
  when Symbol, String
@@ -58,18 +103,20 @@ module MimeActor
58
103
  end
59
104
 
60
105
  Array.wrap(actions).each do |action|
61
- options.each { |format| compose_scene(action, format) }
106
+ formats.each { |format| compose_scene(action, format, with) }
62
107
  end
63
108
  end
64
109
 
110
+ alias act_on_format respond_act_to
111
+
65
112
  private
66
113
 
67
- def compose_scene(action, format)
114
+ def compose_scene(action, format, actor)
68
115
  action_defined = (instance_methods + private_instance_methods).include?(action.to_sym)
69
116
  raise MimeActor::ActionExisted, action if !acting_scenes.key?(action) && action_defined
70
117
 
71
- acting_scenes[action] ||= Set.new
72
- acting_scenes[action] |= [format]
118
+ acting_scenes[action] ||= {}
119
+ acting_scenes[action][format] = actor
73
120
 
74
121
  define_scene(action) unless action_defined
75
122
  end
@@ -83,7 +130,7 @@ module MimeActor
83
130
  def #{action}
84
131
  self.respond_to?(:start_scene) && self.start_scene(:#{action})
85
132
  end
86
- RUBY
133
+ RUBY
87
134
  )
88
135
  end
89
136
  end
@@ -22,7 +22,7 @@ module MimeActor
22
22
  mattr_accessor :raise_on_missing_actor, instance_writer: false, default: false
23
23
  end
24
24
 
25
- class_methods do
25
+ module ClassMethods
26
26
  # Determine if the `actor_name` belongs to a public instance method excluding methods inherited from ancestors
27
27
  #
28
28
  # @param actor_name
@@ -63,25 +63,45 @@ module MimeActor
63
63
  end
64
64
  end
65
65
 
66
- # Calls the `actor` method if defined, supports passing arguments to the `actor` method.
67
- #
66
+ # Calls the `actor` and passing arguments to it.
68
67
  # If a block is given, the result from the `actor` method will be yieled to the block.
69
68
  #
70
- # @param actor_name
71
- def cue_actor(actor_name, *args)
72
- unless self.class.actor?(actor_name)
73
- raise MimeActor::ActorNotFound, actor_name if raise_on_missing_actor
74
-
75
- logger.warn { "actor not found, expected :#{actor_name}" }
76
- return
77
- end
69
+ # NOTE: method call on actor if it is String or Symbol. Proc#call if actor is Proc
70
+ #
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
78
81
 
79
- result = public_send(actor_name, *args)
80
82
  if block_given?
81
83
  yield result
82
84
  else
83
85
  result
84
86
  end
85
87
  end
88
+
89
+ private
90
+
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
97
+ end
98
+
99
+ public_send(actor_method, *args)
100
+ end
101
+
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
+ end
86
106
  end
87
107
  end
@@ -3,6 +3,7 @@
3
3
  # :markup: markdown
4
4
 
5
5
  require "active_support/concern"
6
+ require "active_support/core_ext/object/blank"
6
7
  require "set" # required by mime_type with ruby <= 3.1
7
8
  require "action_dispatch/http/mime_type"
8
9
 
@@ -25,13 +26,13 @@ module MimeActor
25
26
  mattr_accessor :scene_formats, instance_writer: false, default: Mime::SET.symbols.to_set
26
27
  end
27
28
 
28
- class_methods do
29
+ module ClassMethods
29
30
  # Raise the error returned by validator if any.
30
31
  #
31
32
  # @param rule the name of validator
32
33
  def validate!(rule, *args)
33
34
  validator = "validate_#{rule}"
34
- raise NameError, "Validator not found, got: #{validator}" unless respond_to?(validator, true)
35
+ raise NameError, "Validator not found, got: #{validator.inspect}" unless respond_to?(validator, true)
35
36
 
36
37
  error = send(validator, *args)
37
38
  raise error if error
@@ -41,7 +42,7 @@ module MimeActor
41
42
  #
42
43
  # @param unchecked the `action` to be validated
43
44
  def validate_action(unchecked)
44
- ArgumentError.new("action must be a Symbol") unless unchecked.is_a?(Symbol)
45
+ TypeError.new("action must be a Symbol") unless unchecked.is_a?(Symbol)
45
46
  end
46
47
 
47
48
  # Validate `actions` must be a collection of Symbol
@@ -49,16 +50,16 @@ module MimeActor
49
50
  # @param unchecked the `actions` to be validated
50
51
  def validate_actions(unchecked)
51
52
  rejected = unchecked.reject { |action| action.is_a?(Symbol) }
52
- NameError.new("invalid actions, got: #{rejected.join(", ")}") if rejected.size.positive?
53
+ NameError.new("invalid actions, got: #{rejected.map(&:inspect).join(", ")}") if rejected.size.positive?
53
54
  end
54
55
 
55
56
  # Validate `format` must be a Symbol and a valid MIME type
56
57
  #
57
58
  # @param unchecked the `format` to be validated
58
59
  def validate_format(unchecked)
59
- return ArgumentError.new("format must be a Symbol") unless unchecked.is_a?(Symbol)
60
+ return TypeError.new("format must be a Symbol") unless unchecked.is_a?(Symbol)
60
61
 
61
- NameError.new("invalid format, got: #{unchecked}") unless scene_formats.include?(unchecked)
62
+ NameError.new("invalid format, got: #{unchecked.inspect}") unless scene_formats.include?(unchecked)
62
63
  end
63
64
 
64
65
  # Validate `formats` must be an collection of Symbol which each of them is a valid MIME type
@@ -69,7 +70,7 @@ module MimeActor
69
70
  filtered = unfiltered & scene_formats
70
71
  rejected = unfiltered - filtered
71
72
 
72
- NameError.new("invalid formats, got: #{rejected.join(", ")}") if rejected.size.positive?
73
+ NameError.new("invalid formats, got: #{rejected.map(&:inspect).join(", ")}") if rejected.size.positive?
73
74
  end
74
75
 
75
76
  # Validate `klazz` must be a Class/Module or a String referencing a Class/Module
@@ -78,23 +79,16 @@ module MimeActor
78
79
  def validate_klazz(unchecked)
79
80
  return if unchecked.is_a?(Module) || unchecked.is_a?(String)
80
81
 
81
- ArgumentError.new("#{unchecked.inspect} must be a Class/Module or a String referencing a Class/Module")
82
+ TypeError.new("#{unchecked.inspect} must be a Class/Module or a String referencing a Class/Module")
82
83
  end
83
84
 
84
- # Validate `with` or `block` must be provided and if `with` is provided, it must be a Symbol or Proc
85
+ # Validate `with` must be a Symbol or Proc
85
86
  #
86
87
  # @param unchecked the `with` to be validated
87
- # @param block the `block` to be valiated
88
- def validate_with(unchecked, block)
89
- if unchecked.present? && block.present?
90
- return ArgumentError.new("provide either the with: keyword argument or a block")
91
- end
92
- unless unchecked.present? || block.present?
93
- return ArgumentError.new("provide the with: keyword argument or a block")
94
- end
95
- return if block.present? || unchecked.is_a?(Proc) || unchecked.is_a?(Symbol)
96
-
97
- ArgumentError.new("with handler must be a Symbol or Proc, got: #{unchecked.inspect}")
88
+ def validate_with(unchecked)
89
+ return if unchecked.is_a?(Proc) || unchecked.is_a?(Symbol)
90
+
91
+ TypeError.new("with handler must be a Symbol or Proc, got: #{unchecked.inspect}")
98
92
  end
99
93
  end
100
94
  end
@@ -12,7 +12,7 @@ module MimeActor
12
12
  module VERSION
13
13
  MAJOR = 0
14
14
  MINOR = 6
15
- BUILD = 0
15
+ BUILD = 1
16
16
  PRE = nil
17
17
 
18
18
  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.0
4
+ version: 0.6.1
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-01 00:00:00.000000000 Z
11
+ date: 2024-07-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -68,6 +68,7 @@ files:
68
68
  - LICENSE
69
69
  - README.md
70
70
  - Rakefile
71
+ - codecov.yml
71
72
  - lib/mime_actor.rb
72
73
  - lib/mime_actor/action.rb
73
74
  - lib/mime_actor/errors.rb