Skip to content

Commit

Permalink
ActionPack action callbacks and respond_to sigs (#112)
Browse files Browse the repository at this point in the history
* Add *_action callbacks to actionpack.

* Add method signature for respond_to.
connorshea authored and elliottt committed Aug 12, 2019
1 parent b6a174d commit 4a922d8
Showing 2 changed files with 259 additions and 0 deletions.
161 changes: 161 additions & 0 deletions lib/actionpack/all/actionpack.rbi
Original file line number Diff line number Diff line change
@@ -461,3 +461,164 @@ module ActionDispatch::Routing::Mapper::Resources
sig { returns(T::Boolean) }
def shallow?; end
end

# https://api.rubyonrails.org/classes/AbstractController/Callbacks/ClassMethods.html
module AbstractController::Callbacks::ClassMethods
sig do
params(
names: Symbol,
except: T.nilable(T.any(Symbol, T::Array[Symbol])),
only: T.nilable(T.any(Symbol, T::Array[Symbol])),
if: T.nilable(T.any(Symbol, T::Array[Symbol], Proc)),
unless: T.nilable(T.any(Symbol, T::Array[Symbol], Proc)),
block: T.nilable(T.proc.returns(T.untyped))
).void
end
def after_action(*names, except: nil, only: nil, if: nil, unless: nil, &block); end

# append_after_action is an alias of after_action
sig do
params(
names: Symbol,
except: T.nilable(T.any(Symbol, T::Array[Symbol])),
only: T.nilable(T.any(Symbol, T::Array[Symbol])),
if: T.nilable(T.any(Symbol, T::Array[Symbol], Proc)),
unless: T.nilable(T.any(Symbol, T::Array[Symbol], Proc)),
block: T.nilable(T.proc.returns(T.untyped))
).void
end
def append_after_action(*names, except: nil, only: nil, if: nil, unless: nil, &block); end

# append_around_action is an alias of around_action
sig do
params(
names: Symbol,
except: T.nilable(T.any(Symbol, T::Array[Symbol])),
only: T.nilable(T.any(Symbol, T::Array[Symbol])),
if: T.nilable(T.any(Symbol, T::Array[Symbol], Proc)),
unless: T.nilable(T.any(Symbol, T::Array[Symbol], Proc)),
block: T.nilable(T.proc.returns(T.untyped))
).void
end
def append_around_action(*names, except: nil, only: nil, if: nil, unless: nil, &block); end

# append_before_action is an alias of before_action
sig do
params(
names: Symbol,
except: T.nilable(T.any(Symbol, T::Array[Symbol])),
only: T.nilable(T.any(Symbol, T::Array[Symbol])),
if: T.nilable(T.any(Symbol, T::Array[Symbol], Proc)),
unless: T.nilable(T.any(Symbol, T::Array[Symbol], Proc)),
block: T.nilable(T.proc.returns(T.untyped))
).void
end
def append_before_action(*names, except: nil, only: nil, if: nil, unless: nil, &block); end

sig do
params(
names: Symbol,
except: T.nilable(T.any(Symbol, T::Array[Symbol])),
only: T.nilable(T.any(Symbol, T::Array[Symbol])),
if: T.nilable(T.any(Symbol, T::Array[Symbol], Proc)),
unless: T.nilable(T.any(Symbol, T::Array[Symbol], Proc)),
block: T.nilable(T.proc.returns(T.untyped))
).void
end
def around_action(*names, except: nil, only: nil, if: nil, unless: nil, &block); end

sig do
params(
names: Symbol,
except: T.nilable(T.any(Symbol, T::Array[Symbol])),
only: T.nilable(T.any(Symbol, T::Array[Symbol])),
if: T.nilable(T.any(Symbol, T::Array[Symbol], Proc)),
unless: T.nilable(T.any(Symbol, T::Array[Symbol], Proc)),
block: T.nilable(T.proc.returns(T.untyped))
).void
end
def before_action(*names, except: nil, only: nil, if: nil, unless: nil, &block); end

sig do
params(
names: Symbol,
except: T.nilable(T.any(Symbol, T::Array[Symbol])),
only: T.nilable(T.any(Symbol, T::Array[Symbol])),
if: T.nilable(T.any(Symbol, T::Array[Symbol], Proc)),
unless: T.nilable(T.any(Symbol, T::Array[Symbol], Proc)),
block: T.nilable(T.proc.returns(T.untyped))
).void
end
def prepend_after_action(*names, except: nil, only: nil, if: nil, unless: nil, &block); end

sig do
params(
names: Symbol,
except: T.nilable(T.any(Symbol, T::Array[Symbol])),
only: T.nilable(T.any(Symbol, T::Array[Symbol])),
if: T.nilable(T.any(Symbol, T::Array[Symbol], Proc)),
unless: T.nilable(T.any(Symbol, T::Array[Symbol], Proc)),
block: T.nilable(T.proc.returns(T.untyped))
).void
end
def prepend_around_action(*names, except: nil, only: nil, if: nil, unless: nil, &block); end

sig do
params(
names: Symbol,
except: T.nilable(T.any(Symbol, T::Array[Symbol])),
only: T.nilable(T.any(Symbol, T::Array[Symbol])),
if: T.nilable(T.any(Symbol, T::Array[Symbol], Proc)),
unless: T.nilable(T.any(Symbol, T::Array[Symbol], Proc)),
block: T.nilable(T.proc.returns(T.untyped))
).void
end
def prepend_before_action(*names, except: nil, only: nil, if: nil, unless: nil, &block); end

sig do
params(
names: Symbol,
except: T.nilable(T.any(Symbol, T::Array[Symbol])),
only: T.nilable(T.any(Symbol, T::Array[Symbol])),
if: T.nilable(T.any(Symbol, T::Array[Symbol], Proc)),
unless: T.nilable(T.any(Symbol, T::Array[Symbol], Proc))
).void
end
def skip_after_action(*names, except: nil, only: nil, if: nil, unless: nil); end

sig do
params(
names: Symbol,
except: T.nilable(T.any(Symbol, T::Array[Symbol])),
only: T.nilable(T.any(Symbol, T::Array[Symbol])),
if: T.nilable(T.any(Symbol, T::Array[Symbol], Proc)),
unless: T.nilable(T.any(Symbol, T::Array[Symbol], Proc))
).void
end
def skip_around_action(*names, except: nil, only: nil, if: nil, unless: nil); end

sig do
params(
names: Symbol,
except: T.nilable(T.any(Symbol, T::Array[Symbol])),
only: T.nilable(T.any(Symbol, T::Array[Symbol])),
if: T.nilable(T.any(Symbol, T::Array[Symbol], Proc)),
unless: T.nilable(T.any(Symbol, T::Array[Symbol], Proc))
).void
end
def skip_before_action(*names, except: nil, only: nil, if: nil, unless: nil); end
end

# https://api.rubyonrails.org/classes/ActionController/MimeResponds.html
module ActionController::MimeResponds
sig do
params(
mimes: T.nilable(Symbol),
block: T.nilable(T.proc.params(arg0: ActionController::MimeResponds::Collector).void)
).void
end
def respond_to(*mimes, &block); end
end

class ActionController::MimeResponds::Collector
end
98 changes: 98 additions & 0 deletions lib/actionpack/test/actionpack_test.rb
Original file line number Diff line number Diff line change
@@ -102,3 +102,101 @@ def person_params
)
end
end

module ActionPackCallbacksTest
extend AbstractController::Callbacks::ClassMethods

# Test without any options.
prepend_before_action :action_name
before_action :action_name
append_before_action :action_name
skip_before_action :action_name

prepend_around_action :action_name
around_action :action_name
append_around_action :action_name
skip_around_action :action_name

prepend_after_action :action_name
after_action :action_name
append_after_action :action_name
skip_after_action :action_name


# Test with multiple actions.
prepend_before_action :action_name, :action_name_2
before_action :action_name, :action_name_2
append_before_action :action_name, :action_name_2
skip_before_action :action_name, :action_name_2

prepend_around_action :action_name, :action_name_2
around_action :action_name, :action_name_2
append_around_action :action_name, :action_name_2
skip_around_action :action_name, :action_name_2

prepend_after_action :action_name, :action_name_2
after_action :action_name, :action_name_2
append_after_action :action_name, :action_name_2
skip_after_action :action_name, :action_name_2


# Test using a block. (skip_* methods don't accept a block)
prepend_before_action :action_name, only: :show { |controller| puts controller }
before_action :action_name, only: :show { |controller| puts controller }
append_before_action :action_name, only: :show { |controller| puts controller }

prepend_around_action :action_name, only: :show { |controller| puts controller }
around_action :action_name, only: :show { |controller| puts controller }
append_around_action :action_name, only: :show { |controller| puts controller }

prepend_after_action :action_name, only: :show { |controller| puts controller }
after_action :action_name, only: :show { |controller| puts controller }
append_after_action :action_name, only: :show { |controller| puts controller }


# Test proc for `if`, symbol for `only`, symbol array for `except`.
prepend_before_action :action_name, if: -> { true }, only: :show, except: [:edit, :delete]
before_action :action_name, if: -> { true }, only: :show, except: [:edit, :delete]
append_before_action :action_name, if: -> { true }, only: :show, except: [:edit, :delete]
skip_before_action :action_name, if: -> { true }, only: :show, except: [:edit, :delete]

prepend_around_action :action_name, if: -> { true }, only: :show, except: [:edit, :delete]
around_action :action_name, if: -> { true }, only: :show, except: [:edit, :delete]
append_around_action :action_name, if: -> { true }, only: :show, except: [:edit, :delete]
skip_around_action :action_name, if: -> { true }, only: :show, except: [:edit, :delete]

prepend_after_action :action_name, if: -> { true }, only: :show, except: [:edit, :delete]
after_action :action_name, if: -> { true }, only: :show, except: [:edit, :delete]
append_after_action :action_name, if: -> { true }, only: :show, except: [:edit, :delete]
skip_after_action :action_name, if: -> { true }, only: :show, except: [:edit, :delete]


# Test symbol for `if`, symbol array for `only`, symbol for `except`.
prepend_before_action :action_name, if: :method_name?, only: [:show, :delete], except: :edit
before_action :action_name, if: :method_name?, only: [:show, :delete], except: :edit
append_before_action :action_name, if: :method_name?, only: [:show, :delete], except: :edit
skip_before_action :action_name, if: :method_name?, only: [:show, :delete], except: :edit

prepend_around_action :action_name, if: :method_name?, only: [:show, :delete], except: :edit
around_action :action_name, if: :method_name?, only: [:show, :delete], except: :edit
append_around_action :action_name, if: :method_name?, only: [:show, :delete], except: :edit
skip_around_action :action_name, if: :method_name?, only: [:show, :delete], except: :edit

prepend_after_action :action_name, if: :method_name?, only: [:show, :delete], except: :edit
after_action :action_name, if: :method_name?, only: [:show, :delete], except: :edit
append_after_action :action_name, if: :method_name?, only: [:show, :delete], except: :edit
skip_after_action :action_name, if: :method_name?, only: [:show, :delete], except: :edit
end

module ActionPackMimeRespondsTest
extend ActionController::MimeResponds

respond_to :html, :js

# Don't call any methods on format because the class it returns has methods
# generated dynamically based on what mime types have been registered,
# and we can't type those statically.
respond_to do |format|
format
end
end

0 comments on commit 4a922d8

Please sign in to comment.