omg-actionview 8.0.0.alpha1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +25 -0
- data/MIT-LICENSE +21 -0
- data/README.rdoc +40 -0
- 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 +316 -0
- data/lib/action_view/buffers.rb +165 -0
- data/lib/action_view/cache_expiry.rb +69 -0
- data/lib/action_view/context.rb +32 -0
- data/lib/action_view/dependency_tracker/erb_tracker.rb +159 -0
- data/lib/action_view/dependency_tracker/ruby_tracker.rb +43 -0
- data/lib/action_view/dependency_tracker/wildcard_resolver.rb +32 -0
- data/lib/action_view/dependency_tracker.rb +41 -0
- data/lib/action_view/deprecator.rb +7 -0
- data/lib/action_view/digestor.rb +130 -0
- data/lib/action_view/flows.rb +75 -0
- data/lib/action_view/gem_version.rb +17 -0
- data/lib/action_view/helpers/active_model_helper.rb +54 -0
- data/lib/action_view/helpers/asset_tag_helper.rb +680 -0
- data/lib/action_view/helpers/asset_url_helper.rb +473 -0
- data/lib/action_view/helpers/atom_feed_helper.rb +205 -0
- data/lib/action_view/helpers/cache_helper.rb +315 -0
- data/lib/action_view/helpers/capture_helper.rb +236 -0
- data/lib/action_view/helpers/content_exfiltration_prevention_helper.rb +70 -0
- data/lib/action_view/helpers/controller_helper.rb +42 -0
- data/lib/action_view/helpers/csp_helper.rb +26 -0
- data/lib/action_view/helpers/csrf_helper.rb +35 -0
- data/lib/action_view/helpers/date_helper.rb +1266 -0
- data/lib/action_view/helpers/debug_helper.rb +38 -0
- data/lib/action_view/helpers/form_helper.rb +2765 -0
- data/lib/action_view/helpers/form_options_helper.rb +927 -0
- data/lib/action_view/helpers/form_tag_helper.rb +1088 -0
- data/lib/action_view/helpers/javascript_helper.rb +96 -0
- data/lib/action_view/helpers/number_helper.rb +165 -0
- data/lib/action_view/helpers/output_safety_helper.rb +70 -0
- data/lib/action_view/helpers/rendering_helper.rb +218 -0
- data/lib/action_view/helpers/sanitize_helper.rb +201 -0
- data/lib/action_view/helpers/tag_helper.rb +621 -0
- data/lib/action_view/helpers/tags/base.rb +138 -0
- data/lib/action_view/helpers/tags/check_box.rb +65 -0
- data/lib/action_view/helpers/tags/checkable.rb +18 -0
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +37 -0
- data/lib/action_view/helpers/tags/collection_helpers.rb +118 -0
- data/lib/action_view/helpers/tags/collection_radio_buttons.rb +31 -0
- data/lib/action_view/helpers/tags/collection_select.rb +33 -0
- data/lib/action_view/helpers/tags/color_field.rb +26 -0
- data/lib/action_view/helpers/tags/date_field.rb +14 -0
- data/lib/action_view/helpers/tags/date_select.rb +75 -0
- data/lib/action_view/helpers/tags/datetime_field.rb +39 -0
- data/lib/action_view/helpers/tags/datetime_local_field.rb +29 -0
- data/lib/action_view/helpers/tags/datetime_select.rb +10 -0
- data/lib/action_view/helpers/tags/email_field.rb +10 -0
- data/lib/action_view/helpers/tags/file_field.rb +26 -0
- data/lib/action_view/helpers/tags/grouped_collection_select.rb +34 -0
- data/lib/action_view/helpers/tags/hidden_field.rb +14 -0
- data/lib/action_view/helpers/tags/label.rb +84 -0
- data/lib/action_view/helpers/tags/month_field.rb +14 -0
- data/lib/action_view/helpers/tags/number_field.rb +20 -0
- data/lib/action_view/helpers/tags/password_field.rb +14 -0
- data/lib/action_view/helpers/tags/placeholderable.rb +24 -0
- data/lib/action_view/helpers/tags/radio_button.rb +32 -0
- data/lib/action_view/helpers/tags/range_field.rb +10 -0
- data/lib/action_view/helpers/tags/search_field.rb +27 -0
- data/lib/action_view/helpers/tags/select.rb +45 -0
- data/lib/action_view/helpers/tags/select_renderer.rb +56 -0
- data/lib/action_view/helpers/tags/tel_field.rb +10 -0
- data/lib/action_view/helpers/tags/text_area.rb +24 -0
- data/lib/action_view/helpers/tags/text_field.rb +33 -0
- data/lib/action_view/helpers/tags/time_field.rb +23 -0
- data/lib/action_view/helpers/tags/time_select.rb +10 -0
- data/lib/action_view/helpers/tags/time_zone_select.rb +25 -0
- data/lib/action_view/helpers/tags/translator.rb +39 -0
- data/lib/action_view/helpers/tags/url_field.rb +10 -0
- data/lib/action_view/helpers/tags/week_field.rb +14 -0
- data/lib/action_view/helpers/tags/weekday_select.rb +31 -0
- data/lib/action_view/helpers/tags.rb +47 -0
- data/lib/action_view/helpers/text_helper.rb +568 -0
- data/lib/action_view/helpers/translation_helper.rb +161 -0
- data/lib/action_view/helpers/url_helper.rb +812 -0
- data/lib/action_view/helpers.rb +68 -0
- data/lib/action_view/layouts.rb +434 -0
- data/lib/action_view/locale/en.yml +56 -0
- data/lib/action_view/log_subscriber.rb +132 -0
- data/lib/action_view/lookup_context.rb +299 -0
- data/lib/action_view/model_naming.rb +14 -0
- data/lib/action_view/path_registry.rb +57 -0
- data/lib/action_view/path_set.rb +84 -0
- data/lib/action_view/railtie.rb +132 -0
- data/lib/action_view/record_identifier.rb +118 -0
- data/lib/action_view/render_parser/prism_render_parser.rb +139 -0
- data/lib/action_view/render_parser/ripper_render_parser.rb +350 -0
- data/lib/action_view/render_parser.rb +40 -0
- data/lib/action_view/renderer/abstract_renderer.rb +186 -0
- data/lib/action_view/renderer/collection_renderer.rb +204 -0
- data/lib/action_view/renderer/object_renderer.rb +34 -0
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +120 -0
- data/lib/action_view/renderer/partial_renderer.rb +267 -0
- data/lib/action_view/renderer/renderer.rb +107 -0
- data/lib/action_view/renderer/streaming_template_renderer.rb +107 -0
- data/lib/action_view/renderer/template_renderer.rb +115 -0
- data/lib/action_view/rendering.rb +190 -0
- data/lib/action_view/routing_url_for.rb +149 -0
- data/lib/action_view/tasks/cache_digests.rake +25 -0
- data/lib/action_view/template/error.rb +264 -0
- data/lib/action_view/template/handlers/builder.rb +25 -0
- data/lib/action_view/template/handlers/erb/erubi.rb +85 -0
- data/lib/action_view/template/handlers/erb.rb +157 -0
- data/lib/action_view/template/handlers/html.rb +11 -0
- data/lib/action_view/template/handlers/raw.rb +11 -0
- data/lib/action_view/template/handlers.rb +66 -0
- data/lib/action_view/template/html.rb +33 -0
- data/lib/action_view/template/inline.rb +22 -0
- data/lib/action_view/template/raw_file.rb +25 -0
- data/lib/action_view/template/renderable.rb +30 -0
- data/lib/action_view/template/resolver.rb +212 -0
- data/lib/action_view/template/sources/file.rb +17 -0
- data/lib/action_view/template/sources.rb +13 -0
- data/lib/action_view/template/text.rb +32 -0
- data/lib/action_view/template/types.rb +50 -0
- data/lib/action_view/template.rb +580 -0
- 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 +449 -0
- data/lib/action_view/testing/resolvers.rb +44 -0
- data/lib/action_view/unbound_template.rb +67 -0
- data/lib/action_view/version.rb +10 -0
- data/lib/action_view/view_paths.rb +117 -0
- data/lib/action_view.rb +104 -0
- metadata +275 -0
@@ -0,0 +1,159 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActionView
|
4
|
+
class DependencyTracker # :nodoc:
|
5
|
+
class ERBTracker # :nodoc:
|
6
|
+
EXPLICIT_DEPENDENCY = /# Template Dependency: (\S+)/
|
7
|
+
|
8
|
+
# A valid ruby identifier - suitable for class, method and specially variable names
|
9
|
+
IDENTIFIER = /
|
10
|
+
[[:alpha:]_] # at least one uppercase letter, lowercase letter or underscore
|
11
|
+
[[:word:]]* # followed by optional letters, numbers or underscores
|
12
|
+
/x
|
13
|
+
|
14
|
+
# Any kind of variable name. e.g. @instance, @@class, $global or local.
|
15
|
+
# Possibly following a method call chain
|
16
|
+
VARIABLE_OR_METHOD_CHAIN = /
|
17
|
+
(?:\$|@{1,2})? # optional global, instance or class variable indicator
|
18
|
+
(?:#{IDENTIFIER}\.)* # followed by an optional chain of zero-argument method calls
|
19
|
+
(?<dynamic>#{IDENTIFIER}) # and a final valid identifier, captured as DYNAMIC
|
20
|
+
/x
|
21
|
+
|
22
|
+
# A simple string literal. e.g. "School's out!"
|
23
|
+
STRING = /
|
24
|
+
(?<quote>['"]) # an opening quote
|
25
|
+
(?<static>.*?) # with anything inside, captured as STATIC
|
26
|
+
\k<quote> # and a matching closing quote
|
27
|
+
/x
|
28
|
+
|
29
|
+
# Part of any hash containing the :partial key
|
30
|
+
PARTIAL_HASH_KEY = /
|
31
|
+
(?:\bpartial:|:partial\s*=>) # partial key in either old or new style hash syntax
|
32
|
+
\s* # followed by optional spaces
|
33
|
+
/x
|
34
|
+
|
35
|
+
# Part of any hash containing the :layout key
|
36
|
+
LAYOUT_HASH_KEY = /
|
37
|
+
(?:\blayout:|:layout\s*=>) # layout key in either old or new style hash syntax
|
38
|
+
\s* # followed by optional spaces
|
39
|
+
/x
|
40
|
+
|
41
|
+
# Matches:
|
42
|
+
# partial: "comments/comment", collection: @all_comments => "comments/comment"
|
43
|
+
# (object: @single_comment, partial: "comments/comment") => "comments/comment"
|
44
|
+
#
|
45
|
+
# "comments/comments"
|
46
|
+
# 'comments/comments'
|
47
|
+
# ('comments/comments')
|
48
|
+
#
|
49
|
+
# (@topic) => "topics/topic"
|
50
|
+
# topics => "topics/topic"
|
51
|
+
# (message.topics) => "topics/topic"
|
52
|
+
RENDER_ARGUMENTS = /\A
|
53
|
+
(?:\s*\(?\s*) # optional opening paren surrounded by spaces
|
54
|
+
(?:.*?#{PARTIAL_HASH_KEY}|#{LAYOUT_HASH_KEY})? # optional hash, up to the partial or layout key declaration
|
55
|
+
(?:#{STRING}|#{VARIABLE_OR_METHOD_CHAIN}) # finally, the dependency name of interest
|
56
|
+
/xm
|
57
|
+
|
58
|
+
LAYOUT_DEPENDENCY = /\A
|
59
|
+
(?:\s*\(?\s*) # optional opening paren surrounded by spaces
|
60
|
+
(?:.*?#{LAYOUT_HASH_KEY}) # check if the line has layout key declaration
|
61
|
+
(?:#{STRING}|#{VARIABLE_OR_METHOD_CHAIN}) # finally, the dependency name of interest
|
62
|
+
/xm
|
63
|
+
|
64
|
+
def self.supports_view_paths? # :nodoc:
|
65
|
+
true
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.call(name, template, view_paths = nil)
|
69
|
+
new(name, template, view_paths).dependencies
|
70
|
+
end
|
71
|
+
|
72
|
+
def initialize(name, template, view_paths = nil)
|
73
|
+
@name, @template, @view_paths = name, template, view_paths
|
74
|
+
end
|
75
|
+
|
76
|
+
def dependencies
|
77
|
+
WildcardResolver.new(@view_paths, render_dependencies + explicit_dependencies).resolve
|
78
|
+
end
|
79
|
+
|
80
|
+
attr_reader :name, :template
|
81
|
+
private :name, :template
|
82
|
+
|
83
|
+
private
|
84
|
+
def source
|
85
|
+
template.source
|
86
|
+
end
|
87
|
+
|
88
|
+
def directory
|
89
|
+
name.split("/")[0..-2].join("/")
|
90
|
+
end
|
91
|
+
|
92
|
+
def render_dependencies
|
93
|
+
dependencies = []
|
94
|
+
render_calls = source.split(/\brender\b/).drop(1)
|
95
|
+
|
96
|
+
render_calls.each do |arguments|
|
97
|
+
add_dependencies(dependencies, arguments, LAYOUT_DEPENDENCY)
|
98
|
+
add_dependencies(dependencies, arguments, RENDER_ARGUMENTS)
|
99
|
+
end
|
100
|
+
|
101
|
+
dependencies
|
102
|
+
end
|
103
|
+
|
104
|
+
def add_dependencies(render_dependencies, arguments, pattern)
|
105
|
+
arguments.scan(pattern) do
|
106
|
+
match = Regexp.last_match
|
107
|
+
add_dynamic_dependency(render_dependencies, match[:dynamic])
|
108
|
+
add_static_dependency(render_dependencies, match[:static], match[:quote])
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def add_dynamic_dependency(dependencies, dependency)
|
113
|
+
if dependency
|
114
|
+
dependencies << "#{dependency.pluralize}/#{dependency.singularize}"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def add_static_dependency(dependencies, dependency, quote_type)
|
119
|
+
if quote_type == '"' && dependency.include?('#{')
|
120
|
+
scanner = StringScanner.new(dependency)
|
121
|
+
|
122
|
+
wildcard_dependency = +""
|
123
|
+
|
124
|
+
while !scanner.eos?
|
125
|
+
next unless scanner.scan_until(/\#{/)
|
126
|
+
|
127
|
+
unmatched_brackets = 1
|
128
|
+
wildcard_dependency << scanner.pre_match
|
129
|
+
|
130
|
+
while unmatched_brackets > 0 && !scanner.eos?
|
131
|
+
scanner.scan_until(/[{}]/)
|
132
|
+
|
133
|
+
case scanner.matched
|
134
|
+
when "{"
|
135
|
+
unmatched_brackets += 1
|
136
|
+
when "}"
|
137
|
+
unmatched_brackets -= 1
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
wildcard_dependency << "*"
|
142
|
+
end
|
143
|
+
|
144
|
+
dependencies << wildcard_dependency
|
145
|
+
elsif dependency
|
146
|
+
if dependency.include?("/")
|
147
|
+
dependencies << dependency
|
148
|
+
else
|
149
|
+
dependencies << "#{directory}/#{dependency}"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def explicit_dependencies
|
155
|
+
source.scan(EXPLICIT_DEPENDENCY).flatten.uniq
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActionView
|
4
|
+
class DependencyTracker # :nodoc:
|
5
|
+
class RubyTracker # :nodoc:
|
6
|
+
EXPLICIT_DEPENDENCY = /# Template Dependency: (\S+)/
|
7
|
+
|
8
|
+
def self.call(name, template, view_paths = nil)
|
9
|
+
new(name, template, view_paths).dependencies
|
10
|
+
end
|
11
|
+
|
12
|
+
def dependencies
|
13
|
+
WildcardResolver.new(view_paths, render_dependencies + explicit_dependencies).resolve
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.supports_view_paths? # :nodoc:
|
17
|
+
true
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(name, template, view_paths = nil, parser_class: RenderParser::Default)
|
21
|
+
@name, @template, @view_paths = name, template, view_paths
|
22
|
+
@parser_class = parser_class
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
attr_reader :template, :name, :view_paths
|
27
|
+
|
28
|
+
def render_dependencies
|
29
|
+
return [] unless template.source.include?("render")
|
30
|
+
|
31
|
+
compiled_source = template.handler.call(template, template.source)
|
32
|
+
|
33
|
+
@parser_class.new(@name, compiled_source).render_calls.filter_map do |render_call|
|
34
|
+
render_call.gsub(%r|/_|, "/")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def explicit_dependencies
|
39
|
+
template.source.scan(EXPLICIT_DEPENDENCY).flatten.uniq
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActionView
|
4
|
+
class DependencyTracker # :nodoc:
|
5
|
+
class WildcardResolver # :nodoc:
|
6
|
+
def initialize(view_paths, dependencies)
|
7
|
+
@view_paths = view_paths
|
8
|
+
|
9
|
+
@wildcard_dependencies, @explicit_dependencies =
|
10
|
+
dependencies.partition { |dependency| dependency.end_with?("/*") }
|
11
|
+
end
|
12
|
+
|
13
|
+
def resolve
|
14
|
+
return explicit_dependencies.uniq if !view_paths || wildcard_dependencies.empty?
|
15
|
+
|
16
|
+
(explicit_dependencies + resolved_wildcard_dependencies).uniq
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
attr_reader :explicit_dependencies, :wildcard_dependencies, :view_paths
|
21
|
+
|
22
|
+
def resolved_wildcard_dependencies
|
23
|
+
# Remove trailing "/*"
|
24
|
+
prefixes = wildcard_dependencies.map { |query| query[0..-3] }
|
25
|
+
|
26
|
+
view_paths.flat_map(&:all_template_paths).uniq.filter_map { |path|
|
27
|
+
path.to_s if prefixes.include?(path.prefix)
|
28
|
+
}.sort
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "concurrent/map"
|
4
|
+
require "action_view/path_set"
|
5
|
+
require "action_view/render_parser"
|
6
|
+
|
7
|
+
module ActionView
|
8
|
+
class DependencyTracker # :nodoc:
|
9
|
+
extend ActiveSupport::Autoload
|
10
|
+
|
11
|
+
autoload :ERBTracker
|
12
|
+
autoload :RubyTracker
|
13
|
+
autoload :WildcardResolver
|
14
|
+
|
15
|
+
@trackers = Concurrent::Map.new
|
16
|
+
|
17
|
+
def self.find_dependencies(name, template, view_paths = nil)
|
18
|
+
tracker = @trackers[template.handler]
|
19
|
+
return [] unless tracker
|
20
|
+
|
21
|
+
tracker.call(name, template, view_paths)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.register_tracker(extension, tracker)
|
25
|
+
handler = Template.handler_for_extension(extension)
|
26
|
+
if tracker.respond_to?(:supports_view_paths?)
|
27
|
+
@trackers[handler] = tracker
|
28
|
+
else
|
29
|
+
@trackers[handler] = lambda { |name, template, _|
|
30
|
+
tracker.call(name, template)
|
31
|
+
}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.remove_tracker(handler)
|
36
|
+
@trackers.delete(handler)
|
37
|
+
end
|
38
|
+
|
39
|
+
register_tracker :erb, ERBTracker
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "action_view/dependency_tracker"
|
4
|
+
|
5
|
+
module ActionView
|
6
|
+
class Digestor
|
7
|
+
@@digest_mutex = Mutex.new
|
8
|
+
|
9
|
+
class << self
|
10
|
+
# Supported options:
|
11
|
+
#
|
12
|
+
# * <tt>name</tt> - Template name
|
13
|
+
# * <tt>format</tt> - Template format
|
14
|
+
# * +finder+ - An instance of ActionView::LookupContext
|
15
|
+
# * <tt>dependencies</tt> - An array of dependent views
|
16
|
+
def digest(name:, format: nil, finder:, dependencies: nil)
|
17
|
+
if dependencies.nil? || dependencies.empty?
|
18
|
+
cache_key = "#{name}.#{format}"
|
19
|
+
else
|
20
|
+
dependencies_suffix = dependencies.flatten.tap(&:compact!).join(".")
|
21
|
+
cache_key = "#{name}.#{format}.#{dependencies_suffix}"
|
22
|
+
end
|
23
|
+
|
24
|
+
# this is a correctly done double-checked locking idiom
|
25
|
+
# (Concurrent::Map's lookups have volatile semantics)
|
26
|
+
finder.digest_cache[cache_key] || @@digest_mutex.synchronize do
|
27
|
+
finder.digest_cache.fetch(cache_key) do # re-check under lock
|
28
|
+
path = TemplatePath.parse(name)
|
29
|
+
root = tree(path.to_s, finder, path.partial?)
|
30
|
+
dependencies.each do |injected_dep|
|
31
|
+
root.children << Injected.new(injected_dep, nil, nil)
|
32
|
+
end if dependencies
|
33
|
+
finder.digest_cache[cache_key] = root.digest(finder)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def logger
|
39
|
+
ActionView::Base.logger || NullLogger
|
40
|
+
end
|
41
|
+
|
42
|
+
# Create a dependency tree for template named +name+.
|
43
|
+
def tree(name, finder, partial = false, seen = {})
|
44
|
+
logical_name = name.gsub(%r|/_|, "/")
|
45
|
+
interpolated = name.include?("#")
|
46
|
+
|
47
|
+
path = TemplatePath.parse(name)
|
48
|
+
|
49
|
+
if !interpolated && (template = find_template(finder, path.name, [path.prefix], partial, []))
|
50
|
+
if node = seen[template.identifier] # handle cycles in the tree
|
51
|
+
node
|
52
|
+
else
|
53
|
+
node = seen[template.identifier] = Node.create(name, logical_name, template, partial)
|
54
|
+
|
55
|
+
deps = DependencyTracker.find_dependencies(name, template, finder.view_paths)
|
56
|
+
deps.uniq { |n| n.gsub(%r|/_|, "/") }.each do |dep_file|
|
57
|
+
node.children << tree(dep_file, finder, true, seen)
|
58
|
+
end
|
59
|
+
node
|
60
|
+
end
|
61
|
+
else
|
62
|
+
unless interpolated # Dynamic template partial names can never be tracked
|
63
|
+
logger.error " Couldn't find template for digesting: #{name}"
|
64
|
+
end
|
65
|
+
|
66
|
+
seen[name] ||= Missing.new(name, logical_name, nil)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
def find_template(finder, name, prefixes, partial, keys)
|
72
|
+
finder.disable_cache do
|
73
|
+
finder.find_all(name, prefixes, partial, keys).first
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class Node
|
79
|
+
attr_reader :name, :logical_name, :template, :children
|
80
|
+
|
81
|
+
def self.create(name, logical_name, template, partial)
|
82
|
+
klass = partial ? Partial : Node
|
83
|
+
klass.new(name, logical_name, template, [])
|
84
|
+
end
|
85
|
+
|
86
|
+
def initialize(name, logical_name, template, children = [])
|
87
|
+
@name = name
|
88
|
+
@logical_name = logical_name
|
89
|
+
@template = template
|
90
|
+
@children = children
|
91
|
+
end
|
92
|
+
|
93
|
+
def digest(finder, stack = [])
|
94
|
+
ActiveSupport::Digest.hexdigest("#{template.source}-#{dependency_digest(finder, stack)}")
|
95
|
+
end
|
96
|
+
|
97
|
+
def dependency_digest(finder, stack)
|
98
|
+
children.map do |node|
|
99
|
+
if stack.include?(node)
|
100
|
+
false
|
101
|
+
else
|
102
|
+
finder.digest_cache[node.name] ||= begin
|
103
|
+
stack.push node
|
104
|
+
node.digest(finder, stack).tap { stack.pop }
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end.join("-")
|
108
|
+
end
|
109
|
+
|
110
|
+
def to_dep_map
|
111
|
+
children.any? ? { name => children.map(&:to_dep_map) } : name
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
class Partial < Node; end
|
116
|
+
|
117
|
+
class Missing < Node
|
118
|
+
def digest(finder, _ = []) "" end
|
119
|
+
end
|
120
|
+
|
121
|
+
class Injected < Node
|
122
|
+
def digest(finder, _ = []) name end
|
123
|
+
end
|
124
|
+
|
125
|
+
class NullLogger
|
126
|
+
def self.debug(_); end
|
127
|
+
def self.error(_); end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/string/output_safety"
|
4
|
+
|
5
|
+
module ActionView
|
6
|
+
class OutputFlow # :nodoc:
|
7
|
+
attr_reader :content
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@content = Hash.new { |h, k| h[k] = ActiveSupport::SafeBuffer.new }
|
11
|
+
end
|
12
|
+
|
13
|
+
# Called by _layout_for to read stored values.
|
14
|
+
def get(key)
|
15
|
+
@content[key]
|
16
|
+
end
|
17
|
+
|
18
|
+
# Called by each renderer object to set the layout contents.
|
19
|
+
def set(key, value)
|
20
|
+
@content[key] = ActiveSupport::SafeBuffer.new(value.to_s)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Called by content_for
|
24
|
+
def append(key, value)
|
25
|
+
@content[key] << value.to_s
|
26
|
+
end
|
27
|
+
alias_method :append!, :append
|
28
|
+
end
|
29
|
+
|
30
|
+
class StreamingFlow < OutputFlow # :nodoc:
|
31
|
+
def initialize(view, fiber)
|
32
|
+
@view = view
|
33
|
+
@parent = nil
|
34
|
+
@child = view.output_buffer
|
35
|
+
@content = view.view_flow.content
|
36
|
+
@fiber = fiber
|
37
|
+
@root = Fiber.current.object_id
|
38
|
+
end
|
39
|
+
|
40
|
+
# Try to get stored content. If the content
|
41
|
+
# is not available and we're inside the layout fiber,
|
42
|
+
# then it will begin waiting for the given key and yield.
|
43
|
+
def get(key)
|
44
|
+
return super if @content.key?(key)
|
45
|
+
|
46
|
+
if inside_fiber?
|
47
|
+
view = @view
|
48
|
+
|
49
|
+
begin
|
50
|
+
@waiting_for = key
|
51
|
+
view.output_buffer, @parent = @child, view.output_buffer
|
52
|
+
Fiber.yield
|
53
|
+
ensure
|
54
|
+
@waiting_for = nil
|
55
|
+
view.output_buffer, @child = @parent, view.output_buffer
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
super
|
60
|
+
end
|
61
|
+
|
62
|
+
# Appends the contents for the given key. This is called
|
63
|
+
# by providing and resuming back to the fiber,
|
64
|
+
# if that's the key it's waiting for.
|
65
|
+
def append!(key, value)
|
66
|
+
super
|
67
|
+
@fiber.resume if @waiting_for == key
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
def inside_fiber?
|
72
|
+
Fiber.current.object_id != @root
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActionView
|
4
|
+
# Returns the currently loaded version of Action View as a +Gem::Version+.
|
5
|
+
def self.gem_version
|
6
|
+
Gem::Version.new VERSION::STRING
|
7
|
+
end
|
8
|
+
|
9
|
+
module VERSION
|
10
|
+
MAJOR = 8
|
11
|
+
MINOR = 0
|
12
|
+
TINY = 0
|
13
|
+
PRE = "alpha1"
|
14
|
+
|
15
|
+
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/module/attribute_accessors"
|
4
|
+
require "active_support/core_ext/enumerable"
|
5
|
+
|
6
|
+
module ActionView
|
7
|
+
module Helpers # :nodoc:
|
8
|
+
module ActiveModelHelper
|
9
|
+
end
|
10
|
+
|
11
|
+
# = Active \Model Instance Tag \Helpers
|
12
|
+
module ActiveModelInstanceTag
|
13
|
+
def object
|
14
|
+
@active_model_object ||= begin
|
15
|
+
object = super
|
16
|
+
object.respond_to?(:to_model) ? object.to_model : object
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def content_tag(type, options, *)
|
21
|
+
select_markup_helper?(type) ? super : error_wrapping(super)
|
22
|
+
end
|
23
|
+
|
24
|
+
def tag(type, options, *)
|
25
|
+
tag_generate_errors?(options) ? error_wrapping(super) : super
|
26
|
+
end
|
27
|
+
|
28
|
+
def error_wrapping(html_tag)
|
29
|
+
if object_has_errors?
|
30
|
+
@template_object.instance_exec(html_tag, self, &Base.field_error_proc)
|
31
|
+
else
|
32
|
+
html_tag
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def error_message
|
37
|
+
object.errors[@method_name]
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
def object_has_errors?
|
42
|
+
object.respond_to?(:errors) && object.errors.respond_to?(:[]) && error_message.present?
|
43
|
+
end
|
44
|
+
|
45
|
+
def select_markup_helper?(type)
|
46
|
+
["optgroup", "option"].include?(type)
|
47
|
+
end
|
48
|
+
|
49
|
+
def tag_generate_errors?(options)
|
50
|
+
options["type"] != "hidden"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|