much-rails 0.0.1 → 0.2.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/Gemfile +3 -1
- data/lib/much-rails.rb +85 -0
- data/lib/much-rails/action.rb +415 -0
- data/lib/much-rails/action/base_command_result.rb +22 -0
- data/lib/much-rails/action/base_result.rb +14 -0
- data/lib/much-rails/action/base_router.rb +474 -0
- data/lib/much-rails/action/controller.rb +100 -0
- data/lib/much-rails/action/head_result.rb +18 -0
- data/lib/much-rails/action/redirect_to_result.rb +18 -0
- data/lib/much-rails/action/render_result.rb +25 -0
- data/lib/much-rails/action/router.rb +101 -0
- data/lib/much-rails/action/send_data_result.rb +18 -0
- data/lib/much-rails/action/send_file_result.rb +18 -0
- data/lib/much-rails/action/unprocessable_entity_result.rb +37 -0
- data/lib/much-rails/assets.rb +54 -0
- data/lib/much-rails/boolean.rb +7 -0
- data/lib/much-rails/call_method.rb +27 -0
- data/lib/much-rails/call_method_callbacks.rb +122 -0
- data/lib/much-rails/change_action.rb +83 -0
- data/lib/much-rails/change_action_result.rb +59 -0
- data/lib/much-rails/config.rb +55 -0
- data/lib/much-rails/date.rb +50 -0
- data/lib/much-rails/decimal.rb +7 -0
- data/lib/much-rails/destroy_action.rb +32 -0
- data/lib/much-rails/destroy_service.rb +67 -0
- data/lib/much-rails/has_slug.rb +7 -0
- data/lib/much-rails/input_value.rb +19 -0
- data/lib/much-rails/json.rb +29 -0
- data/lib/much-rails/layout.rb +142 -0
- data/lib/much-rails/layout/helper.rb +25 -0
- data/lib/much-rails/mixin.rb +7 -0
- data/lib/much-rails/not_given.rb +7 -0
- data/lib/much-rails/rails_routes.rb +29 -0
- data/lib/much-rails/railtie.rb +39 -0
- data/lib/much-rails/records.rb +5 -0
- data/lib/much-rails/records/always_destroyable.rb +30 -0
- data/lib/much-rails/records/not_destroyable.rb +30 -0
- data/lib/much-rails/records/validate_destroy.rb +92 -0
- data/lib/much-rails/result.rb +7 -0
- data/lib/much-rails/save_action.rb +32 -0
- data/lib/much-rails/save_service.rb +68 -0
- data/lib/much-rails/service.rb +18 -0
- data/lib/much-rails/service_validation_errors.rb +41 -0
- data/lib/much-rails/time.rb +28 -0
- data/lib/much-rails/version.rb +3 -1
- data/lib/much-rails/view_models.rb +3 -0
- data/lib/much-rails/view_models/breadcrumb.rb +11 -0
- data/lib/much-rails/wrap_and_call_method.rb +41 -0
- data/lib/much-rails/wrap_method.rb +45 -0
- data/much-rails.gemspec +20 -4
- data/test/helper.rb +20 -2
- data/test/support/actions/show.rb +11 -0
- data/test/support/config/routes/test.rb +3 -0
- data/test/support/factory.rb +2 -0
- data/test/support/fake_action_controller.rb +63 -0
- data/test/unit/action/base_command_result_tests.rb +43 -0
- data/test/unit/action/base_result_tests.rb +22 -0
- data/test/unit/action/base_router_tests.rb +530 -0
- data/test/unit/action/controller_tests.rb +110 -0
- data/test/unit/action/head_result_tests.rb +24 -0
- data/test/unit/action/redirect_to_result_tests.rb +24 -0
- data/test/unit/action/render_result_tests.rb +43 -0
- data/test/unit/action/router_tests.rb +252 -0
- data/test/unit/action/send_data_result_tests.rb +24 -0
- data/test/unit/action/send_file_result_tests.rb +24 -0
- data/test/unit/action/unprocessable_entity_result_tests.rb +51 -0
- data/test/unit/action_tests.rb +400 -0
- data/test/unit/assets_tests.rb +127 -0
- data/test/unit/boolean_tests.rb +17 -0
- data/test/unit/call_method_callbacks_tests.rb +176 -0
- data/test/unit/call_method_tests.rb +62 -0
- data/test/unit/change_action_result_tests.rb +113 -0
- data/test/unit/change_action_tests.rb +260 -0
- data/test/unit/config_tests.rb +68 -0
- data/test/unit/date_tests.rb +55 -0
- data/test/unit/decimal_tests.rb +17 -0
- data/test/unit/destroy_action_tests.rb +83 -0
- data/test/unit/destroy_service_tests.rb +238 -0
- data/test/unit/has_slug_tests.rb +17 -0
- data/test/unit/input_value_tests.rb +34 -0
- data/test/unit/json_tests.rb +55 -0
- data/test/unit/layout_tests.rb +155 -0
- data/test/unit/mixin_tests.rb +17 -0
- data/test/unit/much-rails_tests.rb +82 -4
- data/test/unit/not_given_tests.rb +17 -0
- data/test/unit/rails_routes_tests.rb +28 -0
- data/test/unit/records/always_destroyable_tests.rb +43 -0
- data/test/unit/records/not_destroyable_tests.rb +40 -0
- data/test/unit/records/validate_destroy_tests.rb +252 -0
- data/test/unit/result_tests.rb +17 -0
- data/test/unit/save_action_tests.rb +83 -0
- data/test/unit/save_service_tests.rb +264 -0
- data/test/unit/service_tests.rb +33 -0
- data/test/unit/service_validation_errors_tests.rb +107 -0
- data/test/unit/time_tests.rb +58 -0
- data/test/unit/view_models/breadcrumb_tests.rb +53 -0
- data/test/unit/wrap_and_call_method_tests.rb +163 -0
- data/test/unit/wrap_method_tests.rb +112 -0
- metadata +356 -7
- data/test/unit/.keep +0 -0
@@ -0,0 +1,100 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "much-rails/action/router"
|
4
|
+
require "much-rails/mixin"
|
5
|
+
|
6
|
+
module MuchRails; end
|
7
|
+
module MuchRails::Action; end
|
8
|
+
|
9
|
+
# MuchRails::Action::Controller defines the behaviors for controllers processing
|
10
|
+
# MuchRails::Actions.
|
11
|
+
module MuchRails::Action::Controller
|
12
|
+
DEFAULT_ACTION_CLASS_FORMAT = :any
|
13
|
+
|
14
|
+
include MuchRails::Mixin
|
15
|
+
|
16
|
+
mixin_included do
|
17
|
+
attr_reader :much_rails_action_class
|
18
|
+
|
19
|
+
before_action(
|
20
|
+
:require_much_rails_action_class,
|
21
|
+
only: MuchRails::Action::Router::CONTROLLER_CALL_ACTION_METHOD_NAME,
|
22
|
+
)
|
23
|
+
before_action :permit_all_much_rails_action_params
|
24
|
+
end
|
25
|
+
|
26
|
+
mixin_instance_methods do
|
27
|
+
define_method(
|
28
|
+
MuchRails::Action::Router::CONTROLLER_CALL_ACTION_METHOD_NAME,
|
29
|
+
) do
|
30
|
+
respond_to do |format|
|
31
|
+
format.public_send(much_rails_action_class_format) do
|
32
|
+
result =
|
33
|
+
much_rails_action_class.call(
|
34
|
+
params: much_rails_action_params,
|
35
|
+
current_user: current_user,
|
36
|
+
request: request,
|
37
|
+
)
|
38
|
+
instance_exec(result, &result.execute_block)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
define_method(
|
44
|
+
MuchRails::Action::Router::CONTROLLER_NOT_FOUND_METHOD_NAME,
|
45
|
+
) do
|
46
|
+
respond_to do |format|
|
47
|
+
format.html do
|
48
|
+
head :not_found
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def much_rails_action_class_name
|
54
|
+
"::#{params[MuchRails::Action::Router::ACTION_CLASS_PARAM_NAME]}"
|
55
|
+
end
|
56
|
+
|
57
|
+
def much_rails_action_class_format
|
58
|
+
much_rails_action_class.format || DEFAULT_ACTION_CLASS_FORMAT
|
59
|
+
end
|
60
|
+
|
61
|
+
def much_rails_action_params
|
62
|
+
# If a `params_root` value is specified, pull the params from that key and
|
63
|
+
# merge them into the base params.
|
64
|
+
Array
|
65
|
+
.wrap(much_rails_action_class&.params_root)
|
66
|
+
.reduce(
|
67
|
+
params
|
68
|
+
.to_h
|
69
|
+
.except(
|
70
|
+
MuchRails::Action::Router::ACTION_CLASS_PARAM_NAME,
|
71
|
+
:controller,
|
72
|
+
:action,
|
73
|
+
),
|
74
|
+
) do |acc, root|
|
75
|
+
acc.merge(acc[root].to_h)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def require_much_rails_action_class
|
80
|
+
begin
|
81
|
+
@much_rails_action_class = much_rails_action_class_name.constantize
|
82
|
+
rescue NameError => ex
|
83
|
+
if MuchRails.config.action.raise_response_exceptions?
|
84
|
+
raise(
|
85
|
+
MuchRails::Action::ActionError,
|
86
|
+
"No Action class defined for "\
|
87
|
+
"#{much_rails_action_class_name.inspect}.",
|
88
|
+
cause: ex,
|
89
|
+
)
|
90
|
+
else
|
91
|
+
head(:not_found)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def permit_all_much_rails_action_params
|
97
|
+
params.permit!
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "much-rails/action/base_command_result"
|
4
|
+
|
5
|
+
module MuchRails; end
|
6
|
+
module MuchRails::Action; end
|
7
|
+
|
8
|
+
# MuchRails::Views::HeadResult is a command result for the `head` controller
|
9
|
+
# response command.
|
10
|
+
class MuchRails::Action::HeadResult < MuchRails::Action::BaseCommandResult
|
11
|
+
def initialize(*head_args)
|
12
|
+
super(:head, *head_args)
|
13
|
+
end
|
14
|
+
|
15
|
+
def head_args
|
16
|
+
command_args
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "much-rails/action/base_command_result"
|
4
|
+
|
5
|
+
module MuchRails; end
|
6
|
+
module MuchRails::Action; end
|
7
|
+
|
8
|
+
# MuchRails::Action::RedirectToResult is a command result for the
|
9
|
+
# `redirect_to` controller response command.
|
10
|
+
class MuchRails::Action::RedirectToResult < MuchRails::Action::BaseCommandResult
|
11
|
+
def initialize(*redirect_to_args)
|
12
|
+
super(:redirect_to, *redirect_to_args)
|
13
|
+
end
|
14
|
+
|
15
|
+
def redirect_to_args
|
16
|
+
command_args
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "much-rails/action/base_result"
|
4
|
+
|
5
|
+
module MuchRails; end
|
6
|
+
module MuchRails::Action; end
|
7
|
+
|
8
|
+
# MuchRails::Action::RenderResult is a result returned by calling a view
|
9
|
+
# action that directs the controller to render a response.
|
10
|
+
class MuchRails::Action::RenderResult < MuchRails::Action::BaseResult
|
11
|
+
attr_reader :render_view_model, :render_kargs
|
12
|
+
|
13
|
+
def initialize(render_view_model, **render_kargs)
|
14
|
+
@render_view_model = render_view_model
|
15
|
+
@render_kargs = render_kargs
|
16
|
+
end
|
17
|
+
|
18
|
+
# This block is called using `instance_exec` in the scope of the controller
|
19
|
+
def execute_block
|
20
|
+
->(result){
|
21
|
+
@view = result.render_view_model
|
22
|
+
render(**result.render_kargs)
|
23
|
+
}
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "much-rails/action/base_router"
|
4
|
+
|
5
|
+
module MuchRails; end
|
6
|
+
module MuchRails::Action; end
|
7
|
+
|
8
|
+
class MuchRails::Action::Router < MuchRails::Action::BaseRouter
|
9
|
+
DEFAULT_CONTROLLER_NAME = "application"
|
10
|
+
CONTROLLER_CALL_ACTION_METHOD_NAME = :much_rails_call_action
|
11
|
+
CONTROLLER_NOT_FOUND_METHOD_NAME = :much_rails_not_found
|
12
|
+
ACTION_CLASS_PARAM_NAME = :much_rails_action_class_name
|
13
|
+
|
14
|
+
def self.url_class
|
15
|
+
MuchRails::Action::Router::URL
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.load(routes_file_name, controller_name: nil)
|
19
|
+
if routes_file_name.to_s.strip.empty?
|
20
|
+
raise(
|
21
|
+
ArgumentError,
|
22
|
+
"expected a routes file name, given `#{routes_file_name.inspect}`.",
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
file_path = ::Rails.root.join("config/routes/#{routes_file_name}.rb")
|
27
|
+
unless file_path.exist?
|
28
|
+
raise ArgumentError, "routes file `#{file_path.inspect}` does not exist."
|
29
|
+
end
|
30
|
+
|
31
|
+
new(routes_file_name, controller_name: controller_name) do
|
32
|
+
instance_eval(File.read(file_path), file_path.to_s, 1)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
attr_reader :controller_name
|
37
|
+
|
38
|
+
def initialize(name = nil, controller_name: nil, &block)
|
39
|
+
super(name, &block)
|
40
|
+
|
41
|
+
@controller_name = controller_name || DEFAULT_CONTROLLER_NAME
|
42
|
+
end
|
43
|
+
|
44
|
+
# Example:
|
45
|
+
# MyRouter = MuchRails::Action::Router.new { ... }
|
46
|
+
# Rails.application.routes.draw do
|
47
|
+
# root "/"
|
48
|
+
# MyRouter.draw(self)
|
49
|
+
# end
|
50
|
+
def apply_to(application_routes_draw_scope)
|
51
|
+
validate!
|
52
|
+
draw_url_to = "#{controller_name}##{CONTROLLER_NOT_FOUND_METHOD_NAME}"
|
53
|
+
draw_route_to = "#{controller_name}##{CONTROLLER_CALL_ACTION_METHOD_NAME}"
|
54
|
+
|
55
|
+
definitions.each do |definition|
|
56
|
+
definition.request_type_actions.each do |request_type_action|
|
57
|
+
application_routes_draw_scope.public_send(
|
58
|
+
definition.http_method,
|
59
|
+
definition.path,
|
60
|
+
to: draw_route_to,
|
61
|
+
as: definition.name,
|
62
|
+
defaults:
|
63
|
+
definition.default_params.merge({
|
64
|
+
ACTION_CLASS_PARAM_NAME => request_type_action.class_name,
|
65
|
+
}),
|
66
|
+
constraints: request_type_action.constraints_lambda,
|
67
|
+
)
|
68
|
+
end
|
69
|
+
|
70
|
+
next unless definition.has_default_action_class_name?
|
71
|
+
|
72
|
+
application_routes_draw_scope.public_send(
|
73
|
+
definition.http_method,
|
74
|
+
definition.path,
|
75
|
+
to: draw_route_to,
|
76
|
+
as: definition.name,
|
77
|
+
defaults:
|
78
|
+
definition.default_params.merge({
|
79
|
+
ACTION_CLASS_PARAM_NAME => definition.default_action_class_name,
|
80
|
+
}),
|
81
|
+
)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Draw each URL that doesn't have a route definition so that we can generate
|
85
|
+
# them using MuchRails::RailsRoutes.
|
86
|
+
unrouted_urls.each do |url|
|
87
|
+
application_routes_draw_scope.get(url.path, to: draw_url_to, as: url.name)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
alias_method :draw, :apply_to
|
91
|
+
|
92
|
+
class URL < MuchRails::Action::BaseRouter::BaseURL
|
93
|
+
def path_for(*args)
|
94
|
+
MuchRails::RailsRoutes.instance.public_send("#{name}_path", *args)
|
95
|
+
end
|
96
|
+
|
97
|
+
def url_for(*args)
|
98
|
+
MuchRails::RailsRoutes.instance.public_send("#{name}_url", *args)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "much-rails/action/base_command_result"
|
4
|
+
|
5
|
+
module MuchRails; end
|
6
|
+
module MuchRails::Action; end
|
7
|
+
|
8
|
+
# MuchRails::Action::SendDataResult is a command result for the `send_data`
|
9
|
+
# controller response command.
|
10
|
+
class MuchRails::Action::SendDataResult < MuchRails::Action::BaseCommandResult
|
11
|
+
def initialize(*send_data_args)
|
12
|
+
super(:send_data, *send_data_args)
|
13
|
+
end
|
14
|
+
|
15
|
+
def send_data_args
|
16
|
+
command_args
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "much-rails/action/base_command_result"
|
4
|
+
|
5
|
+
module MuchRails; end
|
6
|
+
module MuchRails::Action; end
|
7
|
+
|
8
|
+
# MuchRails::Action::SendFileResult is a command result for the `send_file`
|
9
|
+
# controller response command.
|
10
|
+
class MuchRails::Action::SendFileResult < MuchRails::Action::BaseCommandResult
|
11
|
+
def initialize(*send_file_args)
|
12
|
+
super(:send_file, *send_file_args)
|
13
|
+
end
|
14
|
+
|
15
|
+
def send_file_args
|
16
|
+
command_args
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "much-rails/action/base_result"
|
4
|
+
|
5
|
+
module MuchRails; end
|
6
|
+
module MuchRails::Action; end
|
7
|
+
|
8
|
+
# MuchRails::Action::UnprocessableEntityResult is a result returned by
|
9
|
+
# calling a view action that is not valid. It returns JSON with the validation
|
10
|
+
# details.
|
11
|
+
#
|
12
|
+
# This result is only returned if, after validating the action, there are
|
13
|
+
# errors. Most commonly this occurs when validating form submission params.
|
14
|
+
class MuchRails::Action::UnprocessableEntityResult <
|
15
|
+
MuchRails::Action::BaseResult
|
16
|
+
attr_reader :errors
|
17
|
+
|
18
|
+
def initialize(errors)
|
19
|
+
@errors = errors
|
20
|
+
end
|
21
|
+
|
22
|
+
# This block is called using `instance_exec` in the scope of the controller
|
23
|
+
def execute_block
|
24
|
+
->(result){
|
25
|
+
errors =
|
26
|
+
Array
|
27
|
+
.wrap(much_rails_action_class&.params_root)
|
28
|
+
.reduce(result.errors) do |acc, root|
|
29
|
+
acc.merge(
|
30
|
+
acc.transform_keys{ |error_key| "#{root}[#{error_key}]" },
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
render(json: errors, status: :unprocessable_entity)
|
35
|
+
}
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dassets"
|
4
|
+
require "dassets/server"
|
5
|
+
require "dassets-erubi"
|
6
|
+
require "dassets-sass"
|
7
|
+
|
8
|
+
module MuchRails
|
9
|
+
Assets = Dassets
|
10
|
+
end
|
11
|
+
|
12
|
+
module MuchRails::Assets
|
13
|
+
def self.configure_for_rails(rails)
|
14
|
+
MuchRails::Assets.configure do |config|
|
15
|
+
# Cache fingerprints in memory for performance gains.
|
16
|
+
config.fingerprint_cache MuchRails::Assets::MemCache.new
|
17
|
+
|
18
|
+
# Cache compiled content in memory in development/test for performance
|
19
|
+
# gains since we aren't caching to the file system. Otherwise, don't
|
20
|
+
# cache in memory as we are caching to the file system and won't benefit
|
21
|
+
# from the in memory cache.
|
22
|
+
much_rails_content_cache =
|
23
|
+
if rails.env.development? || rails.env.test?
|
24
|
+
MuchRails::Assets::MemCache.new
|
25
|
+
else
|
26
|
+
MuchRails::Assets::NoCache.new
|
27
|
+
end
|
28
|
+
config.content_cache much_rails_content_cache
|
29
|
+
|
30
|
+
# Cache out compiled file content to the public folder in non
|
31
|
+
# development/test environments.
|
32
|
+
if !rails.env.development? && !rails.env.test?
|
33
|
+
config.file_store rails.root.join("public")
|
34
|
+
end
|
35
|
+
|
36
|
+
# Look for asset files in the app/assets folder. Support ERB processing
|
37
|
+
# on all .js and .scss files. Support compilation of .scss files.
|
38
|
+
config.source rails.root.join("app", "assets") do |s|
|
39
|
+
# Reject SCSS partials
|
40
|
+
s.filter do |paths|
|
41
|
+
paths.reject{ |p| File.basename(p) =~ /^_.*\.scss$/ }
|
42
|
+
end
|
43
|
+
|
44
|
+
s.engine "js", MuchRails::Assets::Erubi::Engine
|
45
|
+
s.engine "scss", MuchRails::Assets::Erubi::Engine
|
46
|
+
s.engine "scss", MuchRails::Assets::Sass::Engine, {
|
47
|
+
syntax: "scss",
|
48
|
+
output_style: "compressed",
|
49
|
+
}
|
50
|
+
end
|
51
|
+
end
|
52
|
+
MuchRails::Assets.init
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "much-rails/mixin"
|
4
|
+
|
5
|
+
module MuchRails; end
|
6
|
+
|
7
|
+
# MuchRails::CallMethod is a mix-in to implement the `call`
|
8
|
+
# class/instance method pattern.
|
9
|
+
module MuchRails::CallMethod
|
10
|
+
include MuchRails::Mixin
|
11
|
+
|
12
|
+
mixin_class_methods do
|
13
|
+
def call(*args, &block)
|
14
|
+
new(*args, &block).call
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
mixin_instance_methods do
|
19
|
+
def call
|
20
|
+
on_call
|
21
|
+
end
|
22
|
+
|
23
|
+
def on_call
|
24
|
+
raise NotImplementedError
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "much-rails/call_method"
|
4
|
+
require "much-rails/config"
|
5
|
+
require "much-rails/mixin"
|
6
|
+
|
7
|
+
module MuchRails; end
|
8
|
+
|
9
|
+
# MuchRails::CallMethodCallbacks is a common mix-in for adding before/after
|
10
|
+
# callback support to MuchRails::CallMethod. This is separate from the
|
11
|
+
# MuchRails::CallMethod mix-in as it adds a bit of overhead (e.g. the
|
12
|
+
# `much_rails_call_callbacks_config`) that may not be desired by things
|
13
|
+
# just wanting to use the basic `MuchRails::CallMethod`. This allows opting-in
|
14
|
+
# to callback support as needed.
|
15
|
+
module MuchRails::CallMethodCallbacks
|
16
|
+
include MuchRails::Mixin
|
17
|
+
|
18
|
+
mixin_included do
|
19
|
+
include MuchRails::CallMethod
|
20
|
+
include MuchRails::Config
|
21
|
+
|
22
|
+
add_config :much_rails_call_callbacks
|
23
|
+
end
|
24
|
+
|
25
|
+
mixin_class_methods do
|
26
|
+
def before_call(&block)
|
27
|
+
much_rails_call_callbacks_config.before_callbacks.append(block) if block
|
28
|
+
end
|
29
|
+
|
30
|
+
def prepend_before_call(&block)
|
31
|
+
much_rails_call_callbacks_config.before_callbacks.prepend(block) if block
|
32
|
+
end
|
33
|
+
|
34
|
+
def after_call(&block)
|
35
|
+
much_rails_call_callbacks_config.after_callbacks.append(block) if block
|
36
|
+
end
|
37
|
+
|
38
|
+
def prepend_after_call(&block)
|
39
|
+
much_rails_call_callbacks_config.after_callbacks.prepend(block) if block
|
40
|
+
end
|
41
|
+
|
42
|
+
def around_call(&block)
|
43
|
+
much_rails_call_callbacks_config.around_callbacks.append(block) if block
|
44
|
+
end
|
45
|
+
|
46
|
+
def prepend_around_call(&block)
|
47
|
+
much_rails_call_callbacks_config.around_callbacks.prepend(block) if block
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
mixin_instance_methods do
|
52
|
+
def call
|
53
|
+
set_the_return_value_for_the_call_method(nil)
|
54
|
+
|
55
|
+
execute_before_callbacks
|
56
|
+
execute_around_callbacks do
|
57
|
+
set_the_return_value_for_the_call_method(on_call)
|
58
|
+
end
|
59
|
+
execute_after_callbacks
|
60
|
+
|
61
|
+
the_return_value_for_the_call_method
|
62
|
+
end
|
63
|
+
|
64
|
+
# Do nothing by default - override as needed. Prefer this approach over
|
65
|
+
# e.g. `raise NotImplementedError` as it allows any callbacks that have been
|
66
|
+
# attached to run even if the actual `on_call` method was never overridden.
|
67
|
+
def on_call
|
68
|
+
end
|
69
|
+
|
70
|
+
def set_the_return_value_for_the_call_method(value)
|
71
|
+
@the_return_value_for_the_call_method = value
|
72
|
+
end
|
73
|
+
|
74
|
+
def the_return_value_for_the_call_method
|
75
|
+
@the_return_value_for_the_call_method
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def execute_before_callbacks
|
81
|
+
self
|
82
|
+
.class
|
83
|
+
.much_rails_call_callbacks_config
|
84
|
+
.before_callbacks
|
85
|
+
.each do |callback|
|
86
|
+
instance_exec(&callback)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def execute_around_callbacks(&on_call_block)
|
91
|
+
self
|
92
|
+
.class
|
93
|
+
.much_rails_call_callbacks_config
|
94
|
+
.around_callbacks
|
95
|
+
.reverse
|
96
|
+
.reduce(on_call_block){ |acc_proc, callback_proc|
|
97
|
+
->{ instance_exec(acc_proc, &callback_proc) }
|
98
|
+
}
|
99
|
+
.call
|
100
|
+
end
|
101
|
+
|
102
|
+
def execute_after_callbacks
|
103
|
+
self
|
104
|
+
.class
|
105
|
+
.much_rails_call_callbacks_config
|
106
|
+
.after_callbacks
|
107
|
+
.each do |callback|
|
108
|
+
instance_exec(&callback)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
class MuchRailsCallCallbacksConfig
|
114
|
+
attr_accessor :before_callbacks, :after_callbacks, :around_callbacks
|
115
|
+
|
116
|
+
def initialize
|
117
|
+
@before_callbacks = []
|
118
|
+
@after_callbacks = []
|
119
|
+
@around_callbacks = []
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|