actionview 6.1.7.2 → 7.1.3
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/CHANGELOG.md +299 -277
- data/MIT-LICENSE +2 -1
- data/README.rdoc +3 -3
- data/app/assets/javascripts/rails-ujs.esm.js +686 -0
- data/app/assets/javascripts/rails-ujs.js +630 -0
- data/lib/action_view/base.rb +37 -19
- data/lib/action_view/buffers.rb +107 -9
- data/lib/action_view/cache_expiry.rb +48 -37
- data/lib/action_view/context.rb +1 -1
- data/lib/action_view/dependency_tracker/erb_tracker.rb +154 -0
- data/lib/action_view/dependency_tracker/ripper_tracker.rb +59 -0
- data/lib/action_view/dependency_tracker.rb +6 -147
- data/lib/action_view/deprecator.rb +7 -0
- data/lib/action_view/digestor.rb +8 -5
- data/lib/action_view/flows.rb +4 -4
- data/lib/action_view/gem_version.rb +4 -4
- data/lib/action_view/helpers/active_model_helper.rb +3 -3
- data/lib/action_view/helpers/asset_tag_helper.rb +200 -60
- data/lib/action_view/helpers/asset_url_helper.rb +22 -21
- data/lib/action_view/helpers/atom_feed_helper.rb +8 -9
- data/lib/action_view/helpers/cache_helper.rb +55 -12
- data/lib/action_view/helpers/capture_helper.rb +34 -14
- data/lib/action_view/helpers/content_exfiltration_prevention_helper.rb +70 -0
- data/lib/action_view/helpers/controller_helper.rb +8 -2
- data/lib/action_view/helpers/csp_helper.rb +3 -3
- data/lib/action_view/helpers/csrf_helper.rb +4 -4
- data/lib/action_view/helpers/date_helper.rb +123 -57
- data/lib/action_view/helpers/debug_helper.rb +6 -4
- data/lib/action_view/helpers/form_helper.rb +253 -97
- data/lib/action_view/helpers/form_options_helper.rb +72 -34
- data/lib/action_view/helpers/form_tag_helper.rb +189 -58
- data/lib/action_view/helpers/javascript_helper.rb +4 -5
- data/lib/action_view/helpers/number_helper.rb +43 -335
- data/lib/action_view/helpers/output_safety_helper.rb +6 -6
- data/lib/action_view/helpers/rendering_helper.rb +6 -7
- data/lib/action_view/helpers/sanitize_helper.rb +54 -24
- data/lib/action_view/helpers/tag_helper.rb +42 -35
- data/lib/action_view/helpers/tags/base.rb +16 -77
- data/lib/action_view/helpers/tags/check_box.rb +1 -1
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +1 -0
- data/lib/action_view/helpers/tags/collection_radio_buttons.rb +1 -0
- data/lib/action_view/helpers/tags/collection_select.rb +4 -1
- data/lib/action_view/helpers/tags/date_field.rb +1 -1
- data/lib/action_view/helpers/tags/date_select.rb +2 -0
- data/lib/action_view/helpers/tags/datetime_field.rb +14 -6
- data/lib/action_view/helpers/tags/datetime_local_field.rb +11 -2
- data/lib/action_view/helpers/tags/file_field.rb +16 -0
- data/lib/action_view/helpers/tags/grouped_collection_select.rb +3 -0
- data/lib/action_view/helpers/tags/month_field.rb +1 -1
- data/lib/action_view/helpers/tags/select.rb +4 -1
- data/lib/action_view/helpers/tags/select_renderer.rb +56 -0
- data/lib/action_view/helpers/tags/time_field.rb +11 -2
- data/lib/action_view/helpers/tags/time_zone_select.rb +3 -0
- data/lib/action_view/helpers/tags/week_field.rb +1 -1
- data/lib/action_view/helpers/tags/weekday_select.rb +31 -0
- data/lib/action_view/helpers/tags.rb +5 -2
- data/lib/action_view/helpers/text_helper.rb +180 -97
- data/lib/action_view/helpers/translation_helper.rb +14 -45
- data/lib/action_view/helpers/url_helper.rb +230 -132
- data/lib/action_view/helpers.rb +27 -25
- data/lib/action_view/layouts.rb +15 -10
- data/lib/action_view/log_subscriber.rb +49 -32
- data/lib/action_view/lookup_context.rb +58 -61
- data/lib/action_view/model_naming.rb +2 -2
- data/lib/action_view/path_registry.rb +57 -0
- data/lib/action_view/path_set.rb +28 -35
- data/lib/action_view/railtie.rb +44 -9
- data/lib/action_view/record_identifier.rb +16 -9
- data/lib/action_view/render_parser.rb +188 -0
- data/lib/action_view/renderer/abstract_renderer.rb +3 -3
- data/lib/action_view/renderer/collection_renderer.rb +10 -2
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +21 -3
- data/lib/action_view/renderer/partial_renderer.rb +3 -36
- data/lib/action_view/renderer/renderer.rb +6 -4
- data/lib/action_view/renderer/streaming_template_renderer.rb +6 -5
- data/lib/action_view/renderer/template_renderer.rb +9 -4
- data/lib/action_view/rendering.rb +25 -7
- data/lib/action_view/ripper_ast_parser.rb +198 -0
- data/lib/action_view/routing_url_for.rb +8 -5
- data/lib/action_view/template/error.rb +122 -14
- data/lib/action_view/template/handlers/builder.rb +4 -4
- data/lib/action_view/template/handlers/erb/erubi.rb +23 -27
- data/lib/action_view/template/handlers/erb.rb +79 -1
- data/lib/action_view/template/handlers.rb +4 -4
- data/lib/action_view/template/html.rb +4 -4
- data/lib/action_view/template/inline.rb +3 -3
- data/lib/action_view/template/raw_file.rb +4 -4
- data/lib/action_view/template/renderable.rb +1 -1
- data/lib/action_view/template/resolver.rb +96 -313
- data/lib/action_view/template/text.rb +4 -4
- data/lib/action_view/template/types.rb +25 -32
- data/lib/action_view/template.rb +245 -41
- data/lib/action_view/template_details.rb +66 -0
- data/lib/action_view/template_path.rb +66 -0
- data/lib/action_view/test_case.rb +182 -23
- data/lib/action_view/testing/resolvers.rb +11 -12
- data/lib/action_view/unbound_template.rb +43 -7
- data/lib/action_view/version.rb +1 -1
- data/lib/action_view/view_paths.rb +19 -28
- data/lib/action_view.rb +6 -4
- data/lib/assets/compiled/rails-ujs.js +36 -5
- metadata +32 -25
data/lib/action_view/helpers.rb
CHANGED
|
@@ -1,34 +1,35 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "active_support/benchmarkable"
|
|
4
|
+
require "action_view/helpers/capture_helper"
|
|
5
|
+
require "action_view/helpers/output_safety_helper"
|
|
6
|
+
require "action_view/helpers/tag_helper"
|
|
7
|
+
require "action_view/helpers/url_helper"
|
|
8
|
+
require "action_view/helpers/sanitize_helper"
|
|
9
|
+
require "action_view/helpers/text_helper"
|
|
10
|
+
require "action_view/helpers/active_model_helper"
|
|
11
|
+
require "action_view/helpers/asset_tag_helper"
|
|
12
|
+
require "action_view/helpers/asset_url_helper"
|
|
13
|
+
require "action_view/helpers/atom_feed_helper"
|
|
14
|
+
require "action_view/helpers/cache_helper"
|
|
15
|
+
require "action_view/helpers/content_exfiltration_prevention_helper"
|
|
16
|
+
require "action_view/helpers/controller_helper"
|
|
17
|
+
require "action_view/helpers/csp_helper"
|
|
18
|
+
require "action_view/helpers/csrf_helper"
|
|
19
|
+
require "action_view/helpers/date_helper"
|
|
20
|
+
require "action_view/helpers/debug_helper"
|
|
21
|
+
require "action_view/helpers/form_tag_helper"
|
|
22
|
+
require "action_view/helpers/form_helper"
|
|
23
|
+
require "action_view/helpers/form_options_helper"
|
|
24
|
+
require "action_view/helpers/javascript_helper"
|
|
25
|
+
require "action_view/helpers/number_helper"
|
|
26
|
+
require "action_view/helpers/rendering_helper"
|
|
27
|
+
require "action_view/helpers/translation_helper"
|
|
4
28
|
|
|
5
|
-
module ActionView
|
|
6
|
-
module Helpers
|
|
29
|
+
module ActionView # :nodoc:
|
|
30
|
+
module Helpers # :nodoc:
|
|
7
31
|
extend ActiveSupport::Autoload
|
|
8
32
|
|
|
9
|
-
autoload :ActiveModelHelper
|
|
10
|
-
autoload :AssetTagHelper
|
|
11
|
-
autoload :AssetUrlHelper
|
|
12
|
-
autoload :AtomFeedHelper
|
|
13
|
-
autoload :CacheHelper
|
|
14
|
-
autoload :CaptureHelper
|
|
15
|
-
autoload :ControllerHelper
|
|
16
|
-
autoload :CspHelper
|
|
17
|
-
autoload :CsrfHelper
|
|
18
|
-
autoload :DateHelper
|
|
19
|
-
autoload :DebugHelper
|
|
20
|
-
autoload :FormHelper
|
|
21
|
-
autoload :FormOptionsHelper
|
|
22
|
-
autoload :FormTagHelper
|
|
23
|
-
autoload :JavaScriptHelper, "action_view/helpers/javascript_helper"
|
|
24
|
-
autoload :NumberHelper
|
|
25
|
-
autoload :OutputSafetyHelper
|
|
26
|
-
autoload :RenderingHelper
|
|
27
|
-
autoload :SanitizeHelper
|
|
28
|
-
autoload :TagHelper
|
|
29
|
-
autoload :TextHelper
|
|
30
|
-
autoload :TranslationHelper
|
|
31
|
-
autoload :UrlHelper
|
|
32
33
|
autoload :Tags
|
|
33
34
|
|
|
34
35
|
def self.eager_load!
|
|
@@ -45,6 +46,7 @@ module ActionView #:nodoc:
|
|
|
45
46
|
include AtomFeedHelper
|
|
46
47
|
include CacheHelper
|
|
47
48
|
include CaptureHelper
|
|
49
|
+
include ContentExfiltrationPreventionHelper
|
|
48
50
|
include ControllerHelper
|
|
49
51
|
include CspHelper
|
|
50
52
|
include CsrfHelper
|
data/lib/action_view/layouts.rb
CHANGED
|
@@ -4,12 +4,14 @@ require "action_view/rendering"
|
|
|
4
4
|
require "active_support/core_ext/module/redefine_method"
|
|
5
5
|
|
|
6
6
|
module ActionView
|
|
7
|
+
# = Action View \Layouts
|
|
8
|
+
#
|
|
7
9
|
# Layouts reverse the common pattern of including shared headers and footers in many templates to isolate changes in
|
|
8
10
|
# repeated setups. The inclusion pattern has pages that look like this:
|
|
9
11
|
#
|
|
10
|
-
# <%= render "
|
|
12
|
+
# <%= render "application/header" %>
|
|
11
13
|
# Hello World
|
|
12
|
-
# <%= render "
|
|
14
|
+
# <%= render "application/footer" %>
|
|
13
15
|
#
|
|
14
16
|
# This approach is a decent way of keeping common structures isolated from the changing content, but it's verbose
|
|
15
17
|
# and if you ever want to change the structure of these two includes, you'll have to change all the templates.
|
|
@@ -150,7 +152,7 @@ module ActionView
|
|
|
150
152
|
# The template will be looked always in <tt>app/views/layouts/</tt> folder. But you can point
|
|
151
153
|
# <tt>layouts</tt> folder direct also. <tt>layout "layouts/demo"</tt> is the same as <tt>layout "demo"</tt>.
|
|
152
154
|
#
|
|
153
|
-
# Setting the layout to +nil+ forces it to be looked up in the filesystem and
|
|
155
|
+
# Setting the layout to +nil+ forces it to be looked up in the filesystem and falls back to the parent behavior if none exists.
|
|
154
156
|
# Setting it to +nil+ is useful to re-enable template lookup overriding a previous configuration set in the parent:
|
|
155
157
|
#
|
|
156
158
|
# class ApplicationController < ActionController::Base
|
|
@@ -162,7 +164,7 @@ module ActionView
|
|
|
162
164
|
# end
|
|
163
165
|
#
|
|
164
166
|
# class CommentsController < ApplicationController
|
|
165
|
-
# # Will search for "comments" layout and
|
|
167
|
+
# # Will search for "comments" layout and fall back to "application" layout
|
|
166
168
|
# layout nil
|
|
167
169
|
# end
|
|
168
170
|
#
|
|
@@ -183,7 +185,7 @@ module ActionView
|
|
|
183
185
|
# be rendered directly, without wrapping a layout around the rendered view.
|
|
184
186
|
#
|
|
185
187
|
# Both the <tt>:only</tt> and <tt>:except</tt> condition can accept an arbitrary number of method references, so
|
|
186
|
-
#
|
|
188
|
+
# <tt>except: [ :rss, :text_only ]</tt> is valid, as is <tt>except: :rss</tt>.
|
|
187
189
|
#
|
|
188
190
|
# == Using a different layout in the action render call
|
|
189
191
|
#
|
|
@@ -210,9 +212,9 @@ module ActionView
|
|
|
210
212
|
class_attribute :_layout_conditions, instance_accessor: false, default: {}
|
|
211
213
|
|
|
212
214
|
_write_layout_method
|
|
213
|
-
end
|
|
214
215
|
|
|
215
|
-
|
|
216
|
+
delegate :_layout_conditions, to: :class
|
|
217
|
+
end
|
|
216
218
|
|
|
217
219
|
module ClassMethods
|
|
218
220
|
def inherited(klass) # :nodoc:
|
|
@@ -255,14 +257,17 @@ module ActionView
|
|
|
255
257
|
# true:: raise an ArgumentError
|
|
256
258
|
# nil:: Force default layout behavior with inheritance
|
|
257
259
|
#
|
|
258
|
-
# Return value of +Proc+ and +Symbol+ arguments should be +String+, +false+, +true
|
|
260
|
+
# Return value of +Proc+ and +Symbol+ arguments should be +String+, +false+, +true+, or +nil+
|
|
259
261
|
# with the same meaning as described above.
|
|
262
|
+
#
|
|
260
263
|
# ==== Parameters
|
|
264
|
+
#
|
|
261
265
|
# * <tt>layout</tt> - The layout to use.
|
|
262
266
|
#
|
|
263
267
|
# ==== Options (conditions)
|
|
264
|
-
#
|
|
265
|
-
# *
|
|
268
|
+
#
|
|
269
|
+
# * +:only+ - A list of actions to apply this layout to.
|
|
270
|
+
# * +:except+ - Apply this layout to all actions but this one.
|
|
266
271
|
def layout(layout, conditions = {})
|
|
267
272
|
include LayoutConditions unless conditions.empty?
|
|
268
273
|
|
|
@@ -5,7 +5,7 @@ require "active_support/log_subscriber"
|
|
|
5
5
|
module ActionView
|
|
6
6
|
# = Action View Log Subscriber
|
|
7
7
|
#
|
|
8
|
-
# Provides functionality so that Rails can output logs from Action View.
|
|
8
|
+
# Provides functionality so that \Rails can output logs from Action View.
|
|
9
9
|
class LogSubscriber < ActiveSupport::LogSubscriber
|
|
10
10
|
VIEWS_PATTERN = /^app\/views\//
|
|
11
11
|
|
|
@@ -21,6 +21,7 @@ module ActionView
|
|
|
21
21
|
message << " (Duration: #{event.duration.round(1)}ms | Allocations: #{event.allocations})"
|
|
22
22
|
end
|
|
23
23
|
end
|
|
24
|
+
subscribe_log_level :render_template, :debug
|
|
24
25
|
|
|
25
26
|
def render_partial(event)
|
|
26
27
|
debug do
|
|
@@ -31,6 +32,7 @@ module ActionView
|
|
|
31
32
|
message
|
|
32
33
|
end
|
|
33
34
|
end
|
|
35
|
+
subscribe_log_level :render_partial, :debug
|
|
34
36
|
|
|
35
37
|
def render_layout(event)
|
|
36
38
|
info do
|
|
@@ -38,6 +40,7 @@ module ActionView
|
|
|
38
40
|
message << " (Duration: #{event.duration.round(1)}ms | Allocations: #{event.allocations})"
|
|
39
41
|
end
|
|
40
42
|
end
|
|
43
|
+
subscribe_log_level :render_layout, :info
|
|
41
44
|
|
|
42
45
|
def render_collection(event)
|
|
43
46
|
identifier = event.payload[:identifier] || "templates"
|
|
@@ -49,29 +52,60 @@ module ActionView
|
|
|
49
52
|
message
|
|
50
53
|
end
|
|
51
54
|
end
|
|
55
|
+
subscribe_log_level :render_collection, :debug
|
|
52
56
|
|
|
53
|
-
|
|
54
|
-
|
|
57
|
+
module Utils # :nodoc:
|
|
58
|
+
def logger
|
|
59
|
+
ActionView::Base.logger
|
|
60
|
+
end
|
|
55
61
|
|
|
56
|
-
|
|
57
|
-
|
|
62
|
+
private
|
|
63
|
+
def from_rails_root(string)
|
|
64
|
+
string = string.sub(rails_root, "")
|
|
65
|
+
string.sub!(VIEWS_PATTERN, "")
|
|
66
|
+
string
|
|
67
|
+
end
|
|
58
68
|
|
|
59
|
-
|
|
60
|
-
|
|
69
|
+
def rails_root # :doc:
|
|
70
|
+
@root ||= "#{Rails.root}/"
|
|
71
|
+
end
|
|
61
72
|
end
|
|
62
73
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
74
|
+
include Utils
|
|
75
|
+
|
|
76
|
+
class Start # :nodoc:
|
|
77
|
+
include Utils
|
|
78
|
+
|
|
79
|
+
def start(name, id, payload)
|
|
80
|
+
return unless logger
|
|
81
|
+
logger.debug do
|
|
82
|
+
qualifier =
|
|
83
|
+
if name == "render_template.action_view"
|
|
84
|
+
""
|
|
85
|
+
elsif name == "render_layout.action_view"
|
|
86
|
+
"layout "
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
return unless qualifier
|
|
90
|
+
|
|
91
|
+
message = +" Rendering #{qualifier}#{from_rails_root(payload[:identifier])}"
|
|
92
|
+
message << " within #{from_rails_root(payload[:layout])}" if payload[:layout]
|
|
93
|
+
message
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def finish(name, id, payload)
|
|
98
|
+
end
|
|
69
99
|
end
|
|
70
100
|
|
|
71
|
-
def
|
|
72
|
-
|
|
101
|
+
def self.attach_to(*)
|
|
102
|
+
ActiveSupport::Notifications.subscribe("render_template.action_view", ActionView::LogSubscriber::Start.new)
|
|
103
|
+
ActiveSupport::Notifications.subscribe("render_layout.action_view", ActionView::LogSubscriber::Start.new)
|
|
104
|
+
|
|
105
|
+
super
|
|
73
106
|
end
|
|
74
107
|
|
|
108
|
+
private
|
|
75
109
|
def render_count(payload) # :doc:
|
|
76
110
|
if payload[:cache_hits]
|
|
77
111
|
"[#{payload[:cache_hits]} / #{payload[:count]} cache hits]"
|
|
@@ -88,23 +122,6 @@ module ActionView
|
|
|
88
122
|
"[cache miss]"
|
|
89
123
|
end
|
|
90
124
|
end
|
|
91
|
-
|
|
92
|
-
def log_rendering_start(payload, name)
|
|
93
|
-
debug do
|
|
94
|
-
qualifier =
|
|
95
|
-
if name == "render_template.action_view"
|
|
96
|
-
""
|
|
97
|
-
elsif name == "render_layout.action_view"
|
|
98
|
-
"layout "
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
return unless qualifier
|
|
102
|
-
|
|
103
|
-
message = +" Rendering #{qualifier}#{from_rails_root(payload[:identifier])}"
|
|
104
|
-
message << " within #{from_rails_root(payload[:layout])}" if payload[:layout]
|
|
105
|
-
message
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
125
|
end
|
|
109
126
|
end
|
|
110
127
|
|
|
@@ -12,12 +12,11 @@ module ActionView
|
|
|
12
12
|
# <tt>LookupContext</tt> is also responsible for generating a key, given to
|
|
13
13
|
# view paths, used in the resolver cache lookup. Since this key is generated
|
|
14
14
|
# only once during the request, it speeds up all cache accesses.
|
|
15
|
-
class LookupContext
|
|
16
|
-
attr_accessor :prefixes
|
|
15
|
+
class LookupContext # :nodoc:
|
|
16
|
+
attr_accessor :prefixes
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
mattr_accessor :registered_details, default: []
|
|
18
|
+
singleton_class.attr_accessor :registered_details
|
|
19
|
+
self.registered_details = []
|
|
21
20
|
|
|
22
21
|
def self.register_detail(name, &block)
|
|
23
22
|
registered_details << name
|
|
@@ -37,7 +36,7 @@ module ActionView
|
|
|
37
36
|
end
|
|
38
37
|
|
|
39
38
|
# Holds accessors for the registered details.
|
|
40
|
-
module Accessors
|
|
39
|
+
module Accessors # :nodoc:
|
|
41
40
|
DEFAULT_PROCS = {}
|
|
42
41
|
end
|
|
43
42
|
|
|
@@ -52,7 +51,7 @@ module ActionView
|
|
|
52
51
|
register_detail(:variants) { [] }
|
|
53
52
|
register_detail(:handlers) { Template::Handlers.extensions }
|
|
54
53
|
|
|
55
|
-
class DetailsKey
|
|
54
|
+
class DetailsKey # :nodoc:
|
|
56
55
|
alias :eql? :equal?
|
|
57
56
|
|
|
58
57
|
@details_keys = Concurrent::Map.new
|
|
@@ -64,18 +63,21 @@ module ActionView
|
|
|
64
63
|
end
|
|
65
64
|
|
|
66
65
|
def self.details_cache_key(details)
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
66
|
+
@details_keys.fetch(details) do
|
|
67
|
+
if formats = details[:formats]
|
|
68
|
+
unless Template::Types.valid_symbols?(formats)
|
|
69
|
+
details = details.dup
|
|
70
|
+
details[:formats] &= Template::Types.symbols
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
@details_keys[details] ||= TemplateDetails::Requested.new(**details)
|
|
70
74
|
end
|
|
71
|
-
@details_keys[details] ||= Object.new
|
|
72
75
|
end
|
|
73
76
|
|
|
74
77
|
def self.clear
|
|
75
|
-
ActionView::
|
|
76
|
-
|
|
78
|
+
ActionView::PathRegistry.all_resolvers.each do |resolver|
|
|
79
|
+
resolver.clear_cache
|
|
77
80
|
end
|
|
78
|
-
ActionView::LookupContext.fallbacks.each(&:clear_cache)
|
|
79
81
|
@view_context_class = nil
|
|
80
82
|
@details_keys.clear
|
|
81
83
|
@digest_cache.clear
|
|
@@ -85,9 +87,9 @@ module ActionView
|
|
|
85
87
|
@digest_cache.values
|
|
86
88
|
end
|
|
87
89
|
|
|
88
|
-
def self.view_context_class
|
|
90
|
+
def self.view_context_class
|
|
89
91
|
@view_context_mutex.synchronize do
|
|
90
|
-
@view_context_class ||=
|
|
92
|
+
@view_context_class ||= ActionView::Base.with_empty_template_cache
|
|
91
93
|
end
|
|
92
94
|
end
|
|
93
95
|
end
|
|
@@ -98,7 +100,7 @@ module ActionView
|
|
|
98
100
|
|
|
99
101
|
# Calculate the details key. Remove the handlers from calculation to improve performance
|
|
100
102
|
# since the user cannot modify it explicitly.
|
|
101
|
-
def details_key
|
|
103
|
+
def details_key # :nodoc:
|
|
102
104
|
@details_key ||= DetailsKey.details_cache_key(@details) if @cache
|
|
103
105
|
end
|
|
104
106
|
|
|
@@ -124,50 +126,49 @@ module ActionView
|
|
|
124
126
|
attr_reader :view_paths, :html_fallback_for_js
|
|
125
127
|
|
|
126
128
|
def find(name, prefixes = [], partial = false, keys = [], options = {})
|
|
127
|
-
|
|
129
|
+
name, prefixes = normalize_name(name, prefixes)
|
|
130
|
+
details, details_key = detail_args_for(options)
|
|
131
|
+
@view_paths.find(name, prefixes, partial, details, details_key, keys)
|
|
128
132
|
end
|
|
129
133
|
alias :find_template :find
|
|
130
134
|
|
|
131
135
|
def find_all(name, prefixes = [], partial = false, keys = [], options = {})
|
|
132
|
-
|
|
136
|
+
name, prefixes = normalize_name(name, prefixes)
|
|
137
|
+
details, details_key = detail_args_for(options)
|
|
138
|
+
@view_paths.find_all(name, prefixes, partial, details, details_key, keys)
|
|
133
139
|
end
|
|
134
140
|
|
|
135
141
|
def exists?(name, prefixes = [], partial = false, keys = [], **options)
|
|
136
|
-
|
|
142
|
+
name, prefixes = normalize_name(name, prefixes)
|
|
143
|
+
details, details_key = detail_args_for(options)
|
|
144
|
+
@view_paths.exists?(name, prefixes, partial, details, details_key, keys)
|
|
137
145
|
end
|
|
138
146
|
alias :template_exists? :exists?
|
|
139
147
|
|
|
140
148
|
def any?(name, prefixes = [], partial = false)
|
|
141
|
-
|
|
149
|
+
name, prefixes = normalize_name(name, prefixes)
|
|
150
|
+
details, details_key = detail_args_for_any
|
|
151
|
+
@view_paths.exists?(name, prefixes, partial, details, details_key, [])
|
|
142
152
|
end
|
|
143
153
|
alias :any_templates? :any?
|
|
144
154
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
view_paths = build_view_paths((@view_paths.paths + self.class.fallbacks).uniq)
|
|
155
|
+
def append_view_paths(paths)
|
|
156
|
+
@view_paths = build_view_paths(@view_paths.to_a + paths)
|
|
157
|
+
end
|
|
149
158
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
Calling `with_fallbacks` with a block is not supported. Call methods on
|
|
153
|
-
the lookup context returned by `with_fallbacks` instead.
|
|
154
|
-
eowarn
|
|
155
|
-
else
|
|
156
|
-
ActionView::LookupContext.new(view_paths, @details, @prefixes)
|
|
157
|
-
end
|
|
159
|
+
def prepend_view_paths(paths)
|
|
160
|
+
@view_paths = build_view_paths(paths + @view_paths.to_a)
|
|
158
161
|
end
|
|
159
162
|
|
|
160
163
|
private
|
|
161
164
|
# Whenever setting view paths, makes a copy so that we can manipulate them in
|
|
162
165
|
# instance objects as we wish.
|
|
163
166
|
def build_view_paths(paths)
|
|
164
|
-
ActionView::PathSet
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
details, details_key = detail_args_for(details_options)
|
|
170
|
-
[name, prefixes, partial || false, details, details_key, keys]
|
|
167
|
+
if ActionView::PathSet === paths
|
|
168
|
+
paths
|
|
169
|
+
else
|
|
170
|
+
ActionView::PathSet.new(Array(paths))
|
|
171
|
+
end
|
|
171
172
|
end
|
|
172
173
|
|
|
173
174
|
# Compute details hash and key according to user options (e.g. passed from #render).
|
|
@@ -184,17 +185,11 @@ module ActionView
|
|
|
184
185
|
[user_details, details_key]
|
|
185
186
|
end
|
|
186
187
|
|
|
187
|
-
def args_for_any(name, prefixes, partial)
|
|
188
|
-
name, prefixes = normalize_name(name, prefixes)
|
|
189
|
-
details, details_key = detail_args_for_any
|
|
190
|
-
[name, prefixes, partial || false, details, details_key]
|
|
191
|
-
end
|
|
192
|
-
|
|
193
188
|
def detail_args_for_any
|
|
194
189
|
@detail_args_for_any ||= begin
|
|
195
190
|
details = {}
|
|
196
191
|
|
|
197
|
-
registered_details.each do |k|
|
|
192
|
+
LookupContext.registered_details.each do |k|
|
|
198
193
|
if k == :variants
|
|
199
194
|
details[k] = :any
|
|
200
195
|
else
|
|
@@ -210,19 +205,21 @@ module ActionView
|
|
|
210
205
|
end
|
|
211
206
|
end
|
|
212
207
|
|
|
213
|
-
#
|
|
214
|
-
# as well as incorrectly putting part of the path in the template
|
|
215
|
-
# name instead of the prefix.
|
|
208
|
+
# Fix when prefix is specified as part of the template name
|
|
216
209
|
def normalize_name(name, prefixes)
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
name = parts.pop
|
|
210
|
+
name = name.to_s
|
|
211
|
+
idx = name.rindex("/")
|
|
212
|
+
return name, prefixes.presence || [""] unless idx
|
|
221
213
|
|
|
222
|
-
|
|
214
|
+
path_prefix = name[0, idx]
|
|
215
|
+
path_prefix = path_prefix.from(1) if path_prefix.start_with?("/")
|
|
216
|
+
name = name.from(idx + 1)
|
|
223
217
|
|
|
224
|
-
|
|
225
|
-
|
|
218
|
+
if !prefixes || prefixes.empty?
|
|
219
|
+
prefixes = [path_prefix]
|
|
220
|
+
else
|
|
221
|
+
prefixes = prefixes.map { |p| "#{p}/#{path_prefix}" }
|
|
222
|
+
end
|
|
226
223
|
|
|
227
224
|
return name, prefixes
|
|
228
225
|
end
|
|
@@ -254,7 +251,7 @@ module ActionView
|
|
|
254
251
|
end
|
|
255
252
|
|
|
256
253
|
def initialize_details(target, details)
|
|
257
|
-
registered_details.each do |k|
|
|
254
|
+
LookupContext.registered_details.each do |k|
|
|
258
255
|
target[k] = details[k] || Accessors::DEFAULT_PROCS[k].call
|
|
259
256
|
end
|
|
260
257
|
target
|
|
@@ -269,12 +266,12 @@ module ActionView
|
|
|
269
266
|
values.concat(default_formats) if values.delete "*/*"
|
|
270
267
|
values.uniq!
|
|
271
268
|
|
|
272
|
-
|
|
273
|
-
|
|
269
|
+
unless Template::Types.valid_symbols?(values)
|
|
270
|
+
invalid_values = values - Template::Types.symbols
|
|
274
271
|
raise ArgumentError, "Invalid formats: #{invalid_values.map(&:inspect).join(", ")}"
|
|
275
272
|
end
|
|
276
273
|
|
|
277
|
-
if values == [:js
|
|
274
|
+
if (values.length == 1) && (values[0] == :js)
|
|
278
275
|
values << :html
|
|
279
276
|
@html_fallback_for_js = true
|
|
280
277
|
end
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module ActionView
|
|
4
|
-
module ModelNaming
|
|
5
|
-
# Converts the given object to an
|
|
4
|
+
module ModelNaming # :nodoc:
|
|
5
|
+
# Converts the given object to an Active Model compliant one.
|
|
6
6
|
def convert_to_model(object)
|
|
7
7
|
object.respond_to?(:to_model) ? object.to_model : object
|
|
8
8
|
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActionView # :nodoc:
|
|
4
|
+
module PathRegistry # :nodoc:
|
|
5
|
+
@view_paths_by_class = {}
|
|
6
|
+
@file_system_resolvers = {}
|
|
7
|
+
@file_system_resolver_mutex = Mutex.new
|
|
8
|
+
@file_system_resolver_hooks = []
|
|
9
|
+
|
|
10
|
+
class << self
|
|
11
|
+
attr_reader :file_system_resolver_hooks
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.get_view_paths(klass)
|
|
15
|
+
@view_paths_by_class[klass] || get_view_paths(klass.superclass)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.set_view_paths(klass, paths)
|
|
19
|
+
@view_paths_by_class[klass] = paths
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.cast_file_system_resolvers(paths)
|
|
23
|
+
paths = Array(paths)
|
|
24
|
+
|
|
25
|
+
@file_system_resolver_mutex.synchronize do
|
|
26
|
+
built_resolver = false
|
|
27
|
+
paths = paths.map do |path|
|
|
28
|
+
case path
|
|
29
|
+
when String, Pathname
|
|
30
|
+
path = File.expand_path(path)
|
|
31
|
+
@file_system_resolvers[path] ||=
|
|
32
|
+
begin
|
|
33
|
+
built_resolver = true
|
|
34
|
+
FileSystemResolver.new(path)
|
|
35
|
+
end
|
|
36
|
+
else
|
|
37
|
+
path
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
file_system_resolver_hooks.each(&:call) if built_resolver
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
paths
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def self.all_resolvers
|
|
48
|
+
resolvers = [all_file_system_resolvers]
|
|
49
|
+
resolvers.concat @view_paths_by_class.values.map(&:to_a)
|
|
50
|
+
resolvers.flatten.uniq
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def self.all_file_system_resolvers
|
|
54
|
+
@file_system_resolvers.values
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|