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,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "much-rails/action"
|
4
|
+
require "much-rails/change_action_result"
|
5
|
+
require "much-rails/config"
|
6
|
+
require "much-rails/mixin"
|
7
|
+
|
8
|
+
module MuchRails; end
|
9
|
+
|
10
|
+
module MuchRails::ChangeAction
|
11
|
+
Error = Class.new(StandardError)
|
12
|
+
|
13
|
+
include MuchRails::Mixin
|
14
|
+
|
15
|
+
mixin_included do
|
16
|
+
include MuchRails::Config
|
17
|
+
include MuchRails::Action
|
18
|
+
|
19
|
+
add_config :much_rails_change_action
|
20
|
+
|
21
|
+
on_after_call do
|
22
|
+
if any_unextracted_change_result_validation_errors?
|
23
|
+
raise(
|
24
|
+
MuchRails::Action::ActionError,
|
25
|
+
unhandled_change_result_action_error_message,
|
26
|
+
unhandled_change_result_action_error_backtrace,
|
27
|
+
)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
mixin_class_methods do
|
33
|
+
def change_result(&block)
|
34
|
+
much_rails_change_action_config.change_result_block = block
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
mixin_instance_methods do
|
39
|
+
def change_result
|
40
|
+
@change_result ||=
|
41
|
+
begin
|
42
|
+
unless (
|
43
|
+
self.class.much_rails_change_action_config.change_result_block
|
44
|
+
)
|
45
|
+
raise(Error, undefined_change_result_block_error_message)
|
46
|
+
end
|
47
|
+
|
48
|
+
MuchRails::ChangeActionResult.new(
|
49
|
+
instance_exec(
|
50
|
+
&self.class.much_rails_change_action_config.change_result_block
|
51
|
+
),
|
52
|
+
)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Check the instance variable directly to make sure the main `on_call`
|
57
|
+
# block actually called the `change_result` method and memoized a Result.
|
58
|
+
# If no Result memoized, there are implicitly no unhandled errors.
|
59
|
+
def any_unextracted_change_result_validation_errors?
|
60
|
+
!!@change_result&.any_unextracted_validation_errors?
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def unhandled_change_result_action_error_message
|
66
|
+
change_result.exception&.message ||
|
67
|
+
"#{change_result.inspect} has validation errors that were not handled "\
|
68
|
+
"by the Action: #{change_result.validation_errors.inspect}."
|
69
|
+
end
|
70
|
+
|
71
|
+
def unhandled_change_result_action_error_backtrace
|
72
|
+
change_result.exception&.backtrace || caller
|
73
|
+
end
|
74
|
+
|
75
|
+
def undefined_change_result_block_error_message
|
76
|
+
raise NotImplementedError
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class MuchRailsChangeActionConfig
|
81
|
+
attr_accessor :change_result_block
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "much-rails/result"
|
4
|
+
|
5
|
+
module MuchRails; end
|
6
|
+
|
7
|
+
# MuchRails::ChangeActionResult is a Result object intended to wrap and
|
8
|
+
# compose a MuchRails::Result.
|
9
|
+
class MuchRails::ChangeActionResult
|
10
|
+
def self.success(**kargs)
|
11
|
+
new(MuchRails::Result.success(**kargs))
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.failure(**kargs)
|
15
|
+
new(MuchRails::Result.failure(**kargs))
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_reader :service_result
|
19
|
+
|
20
|
+
def initialize(save_service_result)
|
21
|
+
unless save_service_result.is_a?(MuchRails::Result)
|
22
|
+
raise(
|
23
|
+
TypeError,
|
24
|
+
"MuchRails::Result expected, got #{save_service_result.class}",
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
@service_result = save_service_result
|
29
|
+
|
30
|
+
@service_result.validation_errors ||= {}
|
31
|
+
end
|
32
|
+
|
33
|
+
def validation_errors
|
34
|
+
@validation_errors ||=
|
35
|
+
service_result.get_for_all_results(:validation_errors).to_h
|
36
|
+
end
|
37
|
+
|
38
|
+
def validation_error_messages
|
39
|
+
validation_errors.values.flatten.compact
|
40
|
+
end
|
41
|
+
|
42
|
+
def extract_validation_error(field_name)
|
43
|
+
validation_errors.delete(field_name)
|
44
|
+
end
|
45
|
+
|
46
|
+
def any_unextracted_validation_errors?
|
47
|
+
!!(failure? && validation_errors.any?)
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def method_missing(name, *args, &block)
|
53
|
+
service_result&.__send__(name, *args, &block)
|
54
|
+
end
|
55
|
+
|
56
|
+
def respond_to_missing?(*args)
|
57
|
+
service_result.respond_to?(*args) || super
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "much-rails/mixin"
|
4
|
+
|
5
|
+
module MuchRails; end
|
6
|
+
|
7
|
+
# MuchRails::Config is a mix-in to implement object DSL configuration.
|
8
|
+
module MuchRails::Config
|
9
|
+
include MuchRails::Mixin
|
10
|
+
|
11
|
+
mixin_class_methods do
|
12
|
+
def add_config(name = nil, method_name: nil)
|
13
|
+
config_method_name, config_class_name, configure_method_name =
|
14
|
+
much_rails_config_names(name, method_name)
|
15
|
+
|
16
|
+
instance_eval(<<~RUBY, __FILE__, __LINE__ + 1)
|
17
|
+
def #{config_method_name}
|
18
|
+
@#{config_method_name} ||= self::#{config_class_name}.new
|
19
|
+
end
|
20
|
+
|
21
|
+
def #{configure_method_name}
|
22
|
+
yield(#{config_method_name}) if block_given?
|
23
|
+
end
|
24
|
+
RUBY
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_instance_config(name = nil, method_name: nil)
|
28
|
+
config_method_name, config_class_name, configure_method_name =
|
29
|
+
much_rails_config_names(name, method_name)
|
30
|
+
|
31
|
+
instance_eval(<<~RUBY, __FILE__, __LINE__ + 1)
|
32
|
+
define_method(:#{config_method_name}) do
|
33
|
+
@#{config_method_name} ||= self.class::#{config_class_name}.new
|
34
|
+
end
|
35
|
+
|
36
|
+
define_method(:#{configure_method_name}) do |&block|
|
37
|
+
block.call(#{config_method_name}) if block
|
38
|
+
end
|
39
|
+
RUBY
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def much_rails_config_names(name, method_name)
|
45
|
+
name_prefix = name.nil? ? "" : "#{name.to_s.underscore}_"
|
46
|
+
config_method_name = (method_name || "#{name_prefix}config").to_s
|
47
|
+
config_class_name = "#{name_prefix.classify}Config"
|
48
|
+
|
49
|
+
name_suffix = name.nil? ? "" : "_#{name.to_s.underscore}"
|
50
|
+
configure_method_name = "configure#{name_suffix}"
|
51
|
+
|
52
|
+
[config_method_name, config_class_name, configure_method_name]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MuchRails; end
|
4
|
+
|
5
|
+
module MuchRails::Date
|
6
|
+
InvalidError = Class.new(TypeError)
|
7
|
+
|
8
|
+
# @example
|
9
|
+
# MuchRails::Date.for(nil) # => nil
|
10
|
+
# MuchRails::Date.for(" ") # => nil
|
11
|
+
# MuchRails::Date.for(Time.zone.today) # => Date
|
12
|
+
# MuchRails::Date.for(Time.current) # => Date
|
13
|
+
# MuchRails::Date.for(DateTime.current) # => Date
|
14
|
+
# MuchRails::Date.for("07/04/2020") # => Date
|
15
|
+
# MuchRails::Date.for("2020.07.04") # => Date
|
16
|
+
# MuchRails::Date.for("2020-07-04T08:15:00Z") # => Date
|
17
|
+
def self.for(value)
|
18
|
+
return if value.blank?
|
19
|
+
|
20
|
+
if value.respond_to?(:to_date) && !value.is_a?(::String)
|
21
|
+
value.to_date
|
22
|
+
else
|
23
|
+
parse(value)
|
24
|
+
end
|
25
|
+
rescue
|
26
|
+
raise MuchRails::Date::InvalidError, "Invalid Date: #{value.inspect}."
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.parse(value)
|
30
|
+
parse_united_states(value)
|
31
|
+
rescue ArgumentError
|
32
|
+
parse8601(value)
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.parse_united_states(value)
|
36
|
+
formatted_value = value.to_s.gsub(/[^\w\s:]/, "-")
|
37
|
+
|
38
|
+
::Date.strptime(formatted_value, "%m-%d-%Y")
|
39
|
+
rescue ArgumentError
|
40
|
+
::Date.strptime(formatted_value, "%Y-%m-%d")
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.parse8601(value)
|
44
|
+
formatted_value = value.to_s.gsub(/[^\w\s:]/, "-")
|
45
|
+
|
46
|
+
::Date.iso8601(formatted_value)
|
47
|
+
rescue ArgumentError
|
48
|
+
::Time.iso8601(formatted_value).utc.to_date
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "much-rails/mixin"
|
4
|
+
require "much-rails/change_action"
|
5
|
+
|
6
|
+
module MuchRails; end
|
7
|
+
|
8
|
+
module MuchRails::DestroyAction
|
9
|
+
include MuchRails::Mixin
|
10
|
+
|
11
|
+
mixin_included do
|
12
|
+
include MuchRails::ChangeAction
|
13
|
+
end
|
14
|
+
|
15
|
+
mixin_class_methods do
|
16
|
+
def destroy_result(&block)
|
17
|
+
change_result(&block)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
mixin_instance_methods do
|
22
|
+
def destroy_result
|
23
|
+
change_result
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def undefined_change_result_block_error_message
|
29
|
+
"A `destroy_result` block must be defined."
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "much-rails/mixin"
|
4
|
+
require "much-rails/records"
|
5
|
+
require "much-rails/records/validate_destroy"
|
6
|
+
require "much-rails/result"
|
7
|
+
require "much-rails/service"
|
8
|
+
|
9
|
+
module MuchRails; end
|
10
|
+
|
11
|
+
# MuchRails::DestroyService is a common mix-in for all service objects that
|
12
|
+
# destroy records.
|
13
|
+
module MuchRails::DestroyService
|
14
|
+
include MuchRails::Mixin
|
15
|
+
|
16
|
+
mixin_included do
|
17
|
+
include MuchRails::Service
|
18
|
+
|
19
|
+
around_call do |receiver|
|
20
|
+
receiver.call
|
21
|
+
rescue *MuchRails::DestroyService::ValidationErrors.exception_classes => ex
|
22
|
+
set_the_return_value_for_the_call_method(
|
23
|
+
MuchRails::DestroyService::ValidationErrors.result_for(ex),
|
24
|
+
)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module ValidationErrors
|
29
|
+
def self.add(exception_class, &block)
|
30
|
+
service_validation_errors.add(exception_class, &block)
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.exception_classes
|
34
|
+
service_validation_errors.exception_classes
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.result_for(ex)
|
38
|
+
service_validation_errors.result_for(ex)
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.service_validation_errors
|
42
|
+
@service_validation_errors ||=
|
43
|
+
MuchRails::ServiceValidationErrors
|
44
|
+
.new
|
45
|
+
.tap do |e|
|
46
|
+
e.add(MuchRails::Records::DestructionInvalid) do |ex|
|
47
|
+
MuchRails::DestroyService::FailureResult.new(
|
48
|
+
record: ex.record,
|
49
|
+
exception: ex,
|
50
|
+
validation_errors: ex.errors.to_h,
|
51
|
+
validation_error_messages: ex.error_full_messages.to_a,
|
52
|
+
)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
module FailureResult
|
59
|
+
def self.new(exception:, validation_errors:, **kargs)
|
60
|
+
MuchResult.failure(
|
61
|
+
exception: exception,
|
62
|
+
validation_errors: validation_errors,
|
63
|
+
**kargs,
|
64
|
+
)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MuchRails; end
|
4
|
+
|
5
|
+
# MuchRails::InputValue is a utility module for dealing with input field values.
|
6
|
+
module MuchRails::InputValue
|
7
|
+
def self.strip(value)
|
8
|
+
return if value.blank?
|
9
|
+
|
10
|
+
value.to_s.strip
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.strip_all(values)
|
14
|
+
Array
|
15
|
+
.wrap(values)
|
16
|
+
.map{ |value| strip(value) }
|
17
|
+
.compact
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "oj"
|
4
|
+
|
5
|
+
module MuchRails; end
|
6
|
+
|
7
|
+
# MuchRails::JSON is an adapter for encoding and decoding JSON values.
|
8
|
+
# It uses Oj to do the work: https://github.com/ohler55/oj#-gem
|
9
|
+
module MuchRails::JSON
|
10
|
+
InvalidError = Class.new(TypeError)
|
11
|
+
|
12
|
+
def self.default_mode
|
13
|
+
:strict
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.encode(obj, **options)
|
17
|
+
options[:mode] ||= default_mode
|
18
|
+
::Oj.dump(obj, options)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.decode(json, **options)
|
22
|
+
options[:mode] ||= default_mode
|
23
|
+
::Oj.load(json, options)
|
24
|
+
rescue ::Oj::ParseError => ex
|
25
|
+
error = InvalidError.new("Oj::ParseError: #{ex.message}")
|
26
|
+
error.set_backtrace(ex.backtrace)
|
27
|
+
raise error
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "much-rails/layout/helper"
|
4
|
+
require "much-rails/mixin"
|
5
|
+
require "much-rails/view_models/breadcrumb"
|
6
|
+
|
7
|
+
module MuchRails; end
|
8
|
+
|
9
|
+
# MuchRails::Layout is a mix-in for view models that represent HTML rendered
|
10
|
+
# in a layout. It adds a DSL for accumulating page titles, stylesheets and
|
11
|
+
# javascripts.
|
12
|
+
module MuchRails::Layout
|
13
|
+
include MuchRails::Mixin
|
14
|
+
|
15
|
+
mixin_class_methods do
|
16
|
+
def page_title(&block)
|
17
|
+
page_titles << block
|
18
|
+
end
|
19
|
+
|
20
|
+
def page_titles
|
21
|
+
@page_titles ||= []
|
22
|
+
end
|
23
|
+
|
24
|
+
def application_page_title(&block)
|
25
|
+
@application_page_title = block if block
|
26
|
+
@application_page_title
|
27
|
+
end
|
28
|
+
|
29
|
+
def breadcrumb(&block)
|
30
|
+
breadcrumbs << block
|
31
|
+
end
|
32
|
+
|
33
|
+
def breadcrumbs
|
34
|
+
@breadcrumbs ||= []
|
35
|
+
end
|
36
|
+
|
37
|
+
def stylesheet(value = nil, &block)
|
38
|
+
stylesheets << (block || ->{ value })
|
39
|
+
end
|
40
|
+
|
41
|
+
def stylesheets
|
42
|
+
@stylesheets ||= []
|
43
|
+
end
|
44
|
+
|
45
|
+
def javascript(value = nil, &block)
|
46
|
+
javascripts << (block || ->{ value })
|
47
|
+
end
|
48
|
+
|
49
|
+
def javascripts
|
50
|
+
@javascripts ||= []
|
51
|
+
end
|
52
|
+
|
53
|
+
def head_link(url, **attributes)
|
54
|
+
head_links << HeadLink.new(url, **attributes)
|
55
|
+
end
|
56
|
+
|
57
|
+
def head_links
|
58
|
+
@head_links ||= []
|
59
|
+
end
|
60
|
+
|
61
|
+
def layout(value)
|
62
|
+
layouts << value
|
63
|
+
end
|
64
|
+
|
65
|
+
def layouts
|
66
|
+
@layouts ||= []
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
mixin_instance_methods do
|
71
|
+
def page_title
|
72
|
+
@page_title ||= instance_eval(&(self.class.page_titles.last || ->(_){}))
|
73
|
+
end
|
74
|
+
|
75
|
+
def application_page_title
|
76
|
+
@application_page_title ||=
|
77
|
+
instance_eval(&(self.class.application_page_title || ->(_){}))
|
78
|
+
end
|
79
|
+
|
80
|
+
def full_page_title
|
81
|
+
@full_page_title ||=
|
82
|
+
[
|
83
|
+
self
|
84
|
+
.class
|
85
|
+
.page_titles
|
86
|
+
.reverse
|
87
|
+
.map!{ |segment| instance_eval(&segment) }
|
88
|
+
.join(MuchRails.config.layout.full_page_title_segment_separator),
|
89
|
+
application_page_title,
|
90
|
+
]
|
91
|
+
.map(&:presence)
|
92
|
+
.compact
|
93
|
+
.join(MuchRails.config.layout.full_page_title_application_separator)
|
94
|
+
.presence
|
95
|
+
end
|
96
|
+
|
97
|
+
def breadcrumbs
|
98
|
+
@breadcrumbs ||=
|
99
|
+
self
|
100
|
+
.class
|
101
|
+
.breadcrumbs
|
102
|
+
.map do |block|
|
103
|
+
MuchRails::ViewModels::Breadcrumb.new(*instance_eval(&block))
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def stylesheets
|
108
|
+
@stylesheets ||= self.class.stylesheets.map(&:call)
|
109
|
+
end
|
110
|
+
|
111
|
+
def javascripts
|
112
|
+
@javascripts ||= self.class.javascripts.map(&:call)
|
113
|
+
end
|
114
|
+
|
115
|
+
def head_links
|
116
|
+
@head_links ||= self.class.head_links
|
117
|
+
end
|
118
|
+
|
119
|
+
def layouts
|
120
|
+
self.class.layouts
|
121
|
+
end
|
122
|
+
|
123
|
+
def any_breadcrumbs?
|
124
|
+
breadcrumbs.any?
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
class HeadLink
|
129
|
+
attr_reader :href, :attributes
|
130
|
+
|
131
|
+
def initialize(href, **attributes)
|
132
|
+
@href = href
|
133
|
+
@attributes = attributes
|
134
|
+
end
|
135
|
+
|
136
|
+
def ==(other)
|
137
|
+
super unless other.is_a?(self.class)
|
138
|
+
|
139
|
+
href == other.href && attributes == other.attributes
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|