actionview 4.2.11.1 → 6.0.4.8

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionview might be problematic. Click here for more details.

Files changed (114) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +242 -186
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +9 -8
  5. data/lib/action_view/base.rb +144 -37
  6. data/lib/action_view/buffers.rb +18 -1
  7. data/lib/action_view/cache_expiry.rb +53 -0
  8. data/lib/action_view/context.rb +8 -12
  9. data/lib/action_view/dependency_tracker.rb +54 -20
  10. data/lib/action_view/digestor.rb +88 -85
  11. data/lib/action_view/flows.rb +11 -12
  12. data/lib/action_view/gem_version.rb +6 -4
  13. data/lib/action_view/helpers/active_model_helper.rb +16 -11
  14. data/lib/action_view/helpers/asset_tag_helper.rb +241 -82
  15. data/lib/action_view/helpers/asset_url_helper.rb +171 -67
  16. data/lib/action_view/helpers/atom_feed_helper.rb +19 -17
  17. data/lib/action_view/helpers/cache_helper.rb +112 -42
  18. data/lib/action_view/helpers/capture_helper.rb +20 -13
  19. data/lib/action_view/helpers/controller_helper.rb +15 -4
  20. data/lib/action_view/helpers/csp_helper.rb +26 -0
  21. data/lib/action_view/helpers/csrf_helper.rb +8 -6
  22. data/lib/action_view/helpers/date_helper.rb +230 -129
  23. data/lib/action_view/helpers/debug_helper.rb +7 -6
  24. data/lib/action_view/helpers/form_helper.rb +755 -129
  25. data/lib/action_view/helpers/form_options_helper.rb +130 -75
  26. data/lib/action_view/helpers/form_tag_helper.rb +116 -71
  27. data/lib/action_view/helpers/javascript_helper.rb +30 -14
  28. data/lib/action_view/helpers/number_helper.rb +84 -59
  29. data/lib/action_view/helpers/output_safety_helper.rb +36 -4
  30. data/lib/action_view/helpers/rendering_helper.rb +11 -8
  31. data/lib/action_view/helpers/sanitize_helper.rb +30 -31
  32. data/lib/action_view/helpers/tag_helper.rb +232 -75
  33. data/lib/action_view/helpers/tags/base.rb +138 -98
  34. data/lib/action_view/helpers/tags/check_box.rb +20 -19
  35. data/lib/action_view/helpers/tags/checkable.rb +4 -2
  36. data/lib/action_view/helpers/tags/collection_check_boxes.rb +12 -34
  37. data/lib/action_view/helpers/tags/collection_helpers.rb +69 -36
  38. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +6 -12
  39. data/lib/action_view/helpers/tags/collection_select.rb +4 -2
  40. data/lib/action_view/helpers/tags/color_field.rb +4 -3
  41. data/lib/action_view/helpers/tags/date_field.rb +2 -1
  42. data/lib/action_view/helpers/tags/date_select.rb +37 -36
  43. data/lib/action_view/helpers/tags/datetime_field.rb +4 -3
  44. data/lib/action_view/helpers/tags/datetime_local_field.rb +2 -1
  45. data/lib/action_view/helpers/tags/datetime_select.rb +2 -0
  46. data/lib/action_view/helpers/tags/email_field.rb +2 -0
  47. data/lib/action_view/helpers/tags/file_field.rb +2 -0
  48. data/lib/action_view/helpers/tags/grouped_collection_select.rb +4 -2
  49. data/lib/action_view/helpers/tags/hidden_field.rb +2 -0
  50. data/lib/action_view/helpers/tags/label.rb +3 -2
  51. data/lib/action_view/helpers/tags/month_field.rb +2 -1
  52. data/lib/action_view/helpers/tags/number_field.rb +2 -0
  53. data/lib/action_view/helpers/tags/password_field.rb +3 -1
  54. data/lib/action_view/helpers/tags/placeholderable.rb +3 -1
  55. data/lib/action_view/helpers/tags/radio_button.rb +7 -6
  56. data/lib/action_view/helpers/tags/range_field.rb +2 -0
  57. data/lib/action_view/helpers/tags/search_field.rb +14 -9
  58. data/lib/action_view/helpers/tags/select.rb +11 -10
  59. data/lib/action_view/helpers/tags/tel_field.rb +2 -0
  60. data/lib/action_view/helpers/tags/text_area.rb +4 -2
  61. data/lib/action_view/helpers/tags/text_field.rb +8 -8
  62. data/lib/action_view/helpers/tags/time_field.rb +2 -1
  63. data/lib/action_view/helpers/tags/time_select.rb +2 -0
  64. data/lib/action_view/helpers/tags/time_zone_select.rb +3 -1
  65. data/lib/action_view/helpers/tags/translator.rb +15 -16
  66. data/lib/action_view/helpers/tags/url_field.rb +2 -0
  67. data/lib/action_view/helpers/tags/week_field.rb +2 -1
  68. data/lib/action_view/helpers/tags.rb +3 -1
  69. data/lib/action_view/helpers/text_helper.rb +56 -38
  70. data/lib/action_view/helpers/translation_helper.rb +91 -47
  71. data/lib/action_view/helpers/url_helper.rb +160 -105
  72. data/lib/action_view/helpers.rb +5 -3
  73. data/lib/action_view/layouts.rb +65 -61
  74. data/lib/action_view/log_subscriber.rb +61 -10
  75. data/lib/action_view/lookup_context.rb +147 -89
  76. data/lib/action_view/model_naming.rb +3 -1
  77. data/lib/action_view/path_set.rb +28 -23
  78. data/lib/action_view/railtie.rb +62 -6
  79. data/lib/action_view/record_identifier.rb +53 -26
  80. data/lib/action_view/renderer/abstract_renderer.rb +71 -13
  81. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +103 -0
  82. data/lib/action_view/renderer/partial_renderer.rb +239 -225
  83. data/lib/action_view/renderer/renderer.rb +22 -8
  84. data/lib/action_view/renderer/streaming_template_renderer.rb +54 -54
  85. data/lib/action_view/renderer/template_renderer.rb +79 -73
  86. data/lib/action_view/rendering.rb +68 -44
  87. data/lib/action_view/routing_url_for.rb +33 -22
  88. data/lib/action_view/tasks/cache_digests.rake +25 -0
  89. data/lib/action_view/template/error.rb +44 -29
  90. data/lib/action_view/template/handlers/builder.rb +12 -13
  91. data/lib/action_view/template/handlers/erb/erubi.rb +87 -0
  92. data/lib/action_view/template/handlers/erb.rb +24 -86
  93. data/lib/action_view/template/handlers/html.rb +11 -0
  94. data/lib/action_view/template/handlers/raw.rb +4 -4
  95. data/lib/action_view/template/handlers.rb +38 -8
  96. data/lib/action_view/template/html.rb +19 -10
  97. data/lib/action_view/template/inline.rb +22 -0
  98. data/lib/action_view/template/raw_file.rb +28 -0
  99. data/lib/action_view/template/resolver.rb +217 -193
  100. data/lib/action_view/template/sources/file.rb +17 -0
  101. data/lib/action_view/template/sources.rb +13 -0
  102. data/lib/action_view/template/text.rb +11 -10
  103. data/lib/action_view/template/types.rb +18 -18
  104. data/lib/action_view/template.rb +146 -90
  105. data/lib/action_view/test_case.rb +52 -32
  106. data/lib/action_view/testing/resolvers.rb +46 -34
  107. data/lib/action_view/unbound_template.rb +31 -0
  108. data/lib/action_view/version.rb +3 -1
  109. data/lib/action_view/view_paths.rb +48 -31
  110. data/lib/action_view.rb +11 -8
  111. data/lib/assets/compiled/rails-ujs.js +746 -0
  112. metadata +41 -32
  113. data/lib/action_view/helpers/record_tag_helper.rb +0 -108
  114. data/lib/action_view/tasks/dependencies.rake +0 -23
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :cache_digests do
4
+ desc "Lookup nested dependencies for TEMPLATE (like messages/show or comments/_comment.html)"
5
+ task nested_dependencies: :environment do
6
+ abort "You must provide TEMPLATE for the task to run" unless ENV["TEMPLATE"].present?
7
+ puts JSON.pretty_generate ActionView::Digestor.tree(CacheDigests.template_name, CacheDigests.finder).children.map(&:to_dep_map)
8
+ end
9
+
10
+ desc "Lookup first-level dependencies for TEMPLATE (like messages/show or comments/_comment.html)"
11
+ task dependencies: :environment do
12
+ abort "You must provide TEMPLATE for the task to run" unless ENV["TEMPLATE"].present?
13
+ puts JSON.pretty_generate ActionView::Digestor.tree(CacheDigests.template_name, CacheDigests.finder).children.map(&:name)
14
+ end
15
+
16
+ class CacheDigests
17
+ def self.template_name
18
+ ENV["TEMPLATE"].split(".", 2).first
19
+ end
20
+
21
+ def self.finder
22
+ ApplicationController.new.lookup_context
23
+ end
24
+ end
25
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/enumerable"
2
4
 
3
5
  module ActionView
@@ -8,9 +10,6 @@ module ActionView
8
10
  class EncodingError < StandardError #:nodoc:
9
11
  end
10
12
 
11
- class MissingRequestError < StandardError #:nodoc:
12
- end
13
-
14
13
  class WrongEncodingError < EncodingError #:nodoc:
15
14
  def initialize(string, encoding)
16
15
  @string, @encoding = string, encoding
@@ -35,10 +34,10 @@ module ActionView
35
34
  prefixes = Array(prefixes)
36
35
  template_type = if partial
37
36
  "partial"
38
- elsif path =~ /layouts/i
39
- 'layout'
37
+ elsif /layouts/i.match?(path)
38
+ "layout"
40
39
  else
41
- 'template'
40
+ "template"
42
41
  end
43
42
 
44
43
  if partial && path.present?
@@ -59,13 +58,14 @@ module ActionView
59
58
  class Error < ActionViewError #:nodoc:
60
59
  SOURCE_CODE_RADIUS = 3
61
60
 
62
- attr_reader :original_exception
61
+ # Override to prevent #cause resetting during re-raise.
62
+ attr_reader :cause
63
63
 
64
- def initialize(template, original_exception)
65
- super(original_exception.message)
66
- @template, @original_exception = template, original_exception
67
- @sub_templates = nil
68
- set_backtrace(original_exception.backtrace)
64
+ def initialize(template)
65
+ super($!.message)
66
+ set_backtrace($!.backtrace)
67
+ @cause = $!
68
+ @template, @sub_templates = template, nil
69
69
  end
70
70
 
71
71
  def file_name
@@ -75,25 +75,25 @@ module ActionView
75
75
  def sub_template_message
76
76
  if @sub_templates
77
77
  "Trace of template inclusion: " +
78
- @sub_templates.collect { |template| template.inspect }.join(", ")
78
+ @sub_templates.collect(&:inspect).join(", ")
79
79
  else
80
80
  ""
81
81
  end
82
82
  end
83
83
 
84
- def source_extract(indentation = 0, output = :console)
85
- return unless num = line_number
84
+ def source_extract(indentation = 0)
85
+ return [] unless num = line_number
86
86
  num = num.to_i
87
87
 
88
- source_code = @template.source.split("\n")
88
+ source_code = @template.encode!.split("\n")
89
89
 
90
90
  start_on_line = [ num - SOURCE_CODE_RADIUS - 1, 0 ].max
91
91
  end_on_line = [ num + SOURCE_CODE_RADIUS - 1, source_code.length].min
92
92
 
93
93
  indent = end_on_line.to_s.size + indentation
94
- return unless source_code = source_code[start_on_line..end_on_line]
94
+ return [] unless source_code = source_code[start_on_line..end_on_line]
95
95
 
96
- formatted_code_for(source_code, start_on_line, indent, output)
96
+ formatted_code_for(source_code, start_on_line, indent)
97
97
  end
98
98
 
99
99
  def sub_template_of(template_path)
@@ -109,33 +109,48 @@ module ActionView
109
109
  end
110
110
  end
111
111
 
112
- def annoted_source_code
112
+ def annotated_source_code
113
113
  source_extract(4)
114
114
  end
115
115
 
116
116
  private
117
-
118
117
  def source_location
119
118
  if line_number
120
119
  "on line ##{line_number} of "
121
120
  else
122
- 'in '
121
+ "in "
123
122
  end + file_name
124
123
  end
125
124
 
126
- def formatted_code_for(source_code, line_counter, indent, output)
127
- start_value = (output == :html) ? {} : ""
128
- source_code.inject(start_value) do |result, line|
125
+ def formatted_code_for(source_code, line_counter, indent)
126
+ indent_template = "%#{indent}s: %s"
127
+ source_code.map do |line|
129
128
  line_counter += 1
130
- if output == :html
131
- result.update(line_counter.to_s => "%#{indent}s %s\n" % ["", line])
132
- else
133
- result << "%#{indent}s: %s\n" % [line_counter, line]
134
- end
129
+ indent_template % [line_counter, line]
135
130
  end
136
131
  end
137
132
  end
138
133
  end
139
134
 
140
135
  TemplateError = Template::Error
136
+
137
+ class SyntaxErrorInTemplate < TemplateError #:nodoc
138
+ def initialize(template, offending_code_string)
139
+ @offending_code_string = offending_code_string
140
+ super(template)
141
+ end
142
+
143
+ def message
144
+ <<~MESSAGE
145
+ Encountered a syntax error while rendering template: check #{@offending_code_string}
146
+ MESSAGE
147
+ end
148
+
149
+ def annotated_source_code
150
+ @offending_code_string.split("\n").map.with_index(1) { |line, index|
151
+ indentation = " " * 4
152
+ "#{index}:#{indentation}#{line}"
153
+ }
154
+ end
155
+ end
141
156
  end
@@ -1,26 +1,25 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActionView
2
4
  module Template::Handlers
3
5
  class Builder
4
- # Default format used by Builder.
5
- class_attribute :default_format
6
- self.default_format = :xml
6
+ class_attribute :default_format, default: :xml
7
7
 
8
- def call(template)
8
+ def call(template, source)
9
9
  require_engine
10
- "xml = ::Builder::XmlMarkup.new(:indent => 2);" +
10
+ "xml = ::Builder::XmlMarkup.new(:indent => 2);" \
11
11
  "self.output_buffer = xml.target!;" +
12
- template.source +
12
+ source +
13
13
  ";xml.target!;"
14
14
  end
15
15
 
16
- protected
17
-
18
- def require_engine
19
- @required ||= begin
20
- require "builder"
21
- true
16
+ private
17
+ def require_engine # :doc:
18
+ @required ||= begin
19
+ require "builder"
20
+ true
21
+ end
22
22
  end
23
- end
24
23
  end
25
24
  end
26
25
  end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erubi"
4
+
5
+ module ActionView
6
+ class Template
7
+ module Handlers
8
+ class ERB
9
+ class Erubi < ::Erubi::Engine
10
+ # :nodoc: all
11
+ def initialize(input, properties = {})
12
+ @newline_pending = 0
13
+
14
+ # Dup properties so that we don't modify argument
15
+ properties = Hash[properties]
16
+ properties[:preamble] = ""
17
+ properties[:postamble] = "@output_buffer.to_s"
18
+ properties[:bufvar] = "@output_buffer"
19
+ properties[:escapefunc] = ""
20
+
21
+ super
22
+ end
23
+
24
+ def evaluate(action_view_erb_handler_context)
25
+ src = @src
26
+ view = Class.new(ActionView::Base) {
27
+ include action_view_erb_handler_context._routes.url_helpers
28
+ class_eval("define_method(:_template) { |local_assigns, output_buffer| #{src} }", defined?(@filename) ? @filename : "(erubi)", 0)
29
+ }.empty
30
+ view._run(:_template, nil, {}, ActionView::OutputBuffer.new)
31
+ end
32
+
33
+ private
34
+ def add_text(text)
35
+ return if text.empty?
36
+
37
+ if text == "\n"
38
+ @newline_pending += 1
39
+ else
40
+ src << "@output_buffer.safe_append='"
41
+ src << "\n" * @newline_pending if @newline_pending > 0
42
+ src << text.gsub(/['\\]/, '\\\\\&')
43
+ src << "'.freeze;"
44
+
45
+ @newline_pending = 0
46
+ end
47
+ end
48
+
49
+ BLOCK_EXPR = /\s*((\s+|\))do|\{)(\s*\|[^|]*\|)?\s*\Z/
50
+
51
+ def add_expression(indicator, code)
52
+ flush_newline_if_pending(src)
53
+
54
+ if (indicator == "==") || @escape
55
+ src << "@output_buffer.safe_expr_append="
56
+ else
57
+ src << "@output_buffer.append="
58
+ end
59
+
60
+ if BLOCK_EXPR.match?(code)
61
+ src << " " << code
62
+ else
63
+ src << "(" << code << ");"
64
+ end
65
+ end
66
+
67
+ def add_code(code)
68
+ flush_newline_if_pending(src)
69
+ super
70
+ end
71
+
72
+ def add_postamble(_)
73
+ flush_newline_if_pending(src)
74
+ super
75
+ end
76
+
77
+ def flush_newline_if_pending(src)
78
+ if @newline_pending > 0
79
+ src << "@output_buffer.safe_append='#{"\n" * @newline_pending}'.freeze;"
80
+ @newline_pending = 0
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -1,96 +1,35 @@
1
- require 'erubis'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module ActionView
4
4
  class Template
5
5
  module Handlers
6
- class Erubis < ::Erubis::Eruby
7
- def add_preamble(src)
8
- @newline_pending = 0
9
- src << "@output_buffer = output_buffer || ActionView::OutputBuffer.new;"
10
- end
11
-
12
- def add_text(src, text)
13
- return if text.empty?
14
-
15
- if text == "\n"
16
- @newline_pending += 1
17
- else
18
- src << "@output_buffer.safe_append='"
19
- src << "\n" * @newline_pending if @newline_pending > 0
20
- src << escape_text(text)
21
- src << "'.freeze;"
22
-
23
- @newline_pending = 0
24
- end
25
- end
26
-
27
- # Erubis toggles <%= and <%== behavior when escaping is enabled.
28
- # We override to always treat <%== as escaped.
29
- def add_expr(src, code, indicator)
30
- case indicator
31
- when '=='
32
- add_expr_escaped(src, code)
33
- else
34
- super
35
- end
36
- end
37
-
38
- BLOCK_EXPR = /\s*((\s+|\))do|\{)(\s*\|[^|]*\|)?\s*\Z/
39
-
40
- def add_expr_literal(src, code)
41
- flush_newline_if_pending(src)
42
- if code =~ BLOCK_EXPR
43
- src << '@output_buffer.append= ' << code
44
- else
45
- src << '@output_buffer.append=(' << code << ');'
46
- end
47
- end
48
-
49
- def add_expr_escaped(src, code)
50
- flush_newline_if_pending(src)
51
- if code =~ BLOCK_EXPR
52
- src << "@output_buffer.safe_expr_append= " << code
53
- else
54
- src << "@output_buffer.safe_expr_append=(" << code << ");"
55
- end
56
- end
57
-
58
- def add_stmt(src, code)
59
- flush_newline_if_pending(src)
60
- super
61
- end
62
-
63
- def add_postamble(src)
64
- flush_newline_if_pending(src)
65
- src << '@output_buffer.to_s'
66
- end
67
-
68
- def flush_newline_if_pending(src)
69
- if @newline_pending > 0
70
- src << "@output_buffer.safe_append='#{"\n" * @newline_pending}'.freeze;"
71
- @newline_pending = 0
72
- end
73
- end
74
- end
75
-
76
6
  class ERB
7
+ autoload :Erubi, "action_view/template/handlers/erb/erubi"
8
+
77
9
  # Specify trim mode for the ERB compiler. Defaults to '-'.
78
10
  # See ERB documentation for suitable values.
79
- class_attribute :erb_trim_mode
80
- self.erb_trim_mode = '-'
11
+ class_attribute :erb_trim_mode, default: "-"
81
12
 
82
13
  # Default implementation used.
83
- class_attribute :erb_implementation
84
- self.erb_implementation = Erubis
14
+ class_attribute :erb_implementation, default: Erubi
85
15
 
86
16
  # Do not escape templates of these mime types.
87
- class_attribute :escape_whitelist
88
- self.escape_whitelist = ["text/plain"]
17
+ class_attribute :escape_ignore_list, default: ["text/plain"]
18
+
19
+ [self, singleton_class].each do |base|
20
+ base.alias_method :escape_whitelist, :escape_ignore_list
21
+ base.alias_method :escape_whitelist=, :escape_ignore_list=
22
+
23
+ base.deprecate(
24
+ escape_whitelist: "use #escape_ignore_list instead",
25
+ :escape_whitelist= => "use #escape_ignore_list= instead"
26
+ )
27
+ end
89
28
 
90
29
  ENCODING_TAG = Regexp.new("\\A(<%#{ENCODING_FLAG}-?%>)[ \\t]*")
91
30
 
92
- def self.call(template)
93
- new.call(template)
31
+ def self.call(template, source)
32
+ new.call(template, source)
94
33
  end
95
34
 
96
35
  def supports_streaming?
@@ -101,30 +40,29 @@ module ActionView
101
40
  true
102
41
  end
103
42
 
104
- def call(template)
43
+ def call(template, source)
105
44
  # First, convert to BINARY, so in case the encoding is
106
45
  # wrong, we can still find an encoding tag
107
46
  # (<%# encoding %>) inside the String using a regular
108
47
  # expression
109
- template_source = template.source.dup.force_encoding(Encoding::ASCII_8BIT)
48
+ template_source = source.dup.force_encoding(Encoding::ASCII_8BIT)
110
49
 
111
- erb = template_source.gsub(ENCODING_TAG, '')
50
+ erb = template_source.gsub(ENCODING_TAG, "")
112
51
  encoding = $2
113
52
 
114
- erb.force_encoding valid_encoding(template.source.dup, encoding)
53
+ erb.force_encoding valid_encoding(source.dup, encoding)
115
54
 
116
55
  # Always make sure we return a String in the default_internal
117
56
  erb.encode!
118
57
 
119
58
  self.class.erb_implementation.new(
120
59
  erb,
121
- :escape => (self.class.escape_whitelist.include? template.type),
122
- :trim => (self.class.erb_trim_mode == "-")
60
+ escape: (self.class.escape_ignore_list.include? template.type),
61
+ trim: (self.class.erb_trim_mode == "-")
123
62
  ).src
124
63
  end
125
64
 
126
65
  private
127
-
128
66
  def valid_encoding(string, encoding)
129
67
  # If a magic encoding comment was found, tag the
130
68
  # String with this encoding. This is for a case
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionView
4
+ module Template::Handlers
5
+ class Html < Raw
6
+ def call(template, source)
7
+ "ActionView::OutputBuffer.new #{super}"
8
+ end
9
+ end
10
+ end
11
+ end
@@ -1,10 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActionView
2
4
  module Template::Handlers
3
5
  class Raw
4
- def call(template)
5
- escaped = template.source.gsub(/:/, '\:')
6
-
7
- '%q:' + escaped + ':;'
6
+ def call(template, source)
7
+ "#{source.inspect}.html_safe;"
8
8
  end
9
9
  end
10
10
  end
@@ -1,16 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/deprecation"
4
+
1
5
  module ActionView #:nodoc:
2
6
  # = Action View Template Handlers
3
- class Template
7
+ class Template #:nodoc:
4
8
  module Handlers #:nodoc:
5
- autoload :ERB, 'action_view/template/handlers/erb'
6
- autoload :Builder, 'action_view/template/handlers/builder'
7
- autoload :Raw, 'action_view/template/handlers/raw'
9
+ autoload :Raw, "action_view/template/handlers/raw"
10
+ autoload :ERB, "action_view/template/handlers/erb"
11
+ autoload :Html, "action_view/template/handlers/html"
12
+ autoload :Builder, "action_view/template/handlers/builder"
8
13
 
9
14
  def self.extended(base)
10
- base.register_default_template_handler :erb, ERB.new
15
+ base.register_default_template_handler :raw, Raw.new
16
+ base.register_template_handler :erb, ERB.new
17
+ base.register_template_handler :html, Html.new
11
18
  base.register_template_handler :builder, Builder.new
12
- base.register_template_handler :raw, Raw.new
13
- base.register_template_handler :ruby, :source.to_proc
19
+ base.register_template_handler :ruby, lambda { |_, source| source }
14
20
  end
15
21
 
16
22
  @@template_handlers = {}
@@ -20,11 +26,35 @@ module ActionView #:nodoc:
20
26
  @@template_extensions ||= @@template_handlers.keys
21
27
  end
22
28
 
29
+ class LegacyHandlerWrapper < SimpleDelegator # :nodoc:
30
+ def call(view, source)
31
+ __getobj__.call(ActionView::Template::LegacyTemplate.new(view, source))
32
+ end
33
+ end
34
+
23
35
  # Register an object that knows how to handle template files with the given
24
36
  # extensions. This can be used to implement new template types.
25
37
  # The handler must respond to +:call+, which will be passed the template
26
38
  # and should return the rendered template as a String.
27
39
  def register_template_handler(*extensions, handler)
40
+ params = if handler.is_a?(Proc)
41
+ handler.parameters
42
+ else
43
+ handler.method(:call).parameters
44
+ end
45
+
46
+ unless params.find_all { |type, _| type == :req || type == :opt }.length >= 2
47
+ ActiveSupport::Deprecation.warn <<~eowarn
48
+ Single arity template handlers are deprecated. Template handlers must
49
+ now accept two parameters, the view object and the source for the view object.
50
+ Change:
51
+ >> #{handler}.call(#{params.map(&:last).join(", ")})
52
+ To:
53
+ >> #{handler}.call(#{params.map(&:last).join(", ")}, source)
54
+ eowarn
55
+ handler = LegacyHandlerWrapper.new(handler)
56
+ end
57
+
28
58
  raise(ArgumentError, "Extension is required") if extensions.empty?
29
59
  extensions.each do |extension|
30
60
  @@template_handlers[extension.to_sym] = handler
@@ -42,7 +72,7 @@ module ActionView #:nodoc:
42
72
  end
43
73
 
44
74
  def template_handler_extensions
45
- @@template_handlers.keys.map {|key| key.to_s }.sort
75
+ @@template_handlers.keys.map(&:to_s).sort
46
76
  end
47
77
 
48
78
  def registered_template_handler(extension)
@@ -1,22 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/deprecation"
4
+
1
5
  module ActionView #:nodoc:
2
6
  # = Action View HTML Template
3
- class Template
7
+ class Template #:nodoc:
4
8
  class HTML #:nodoc:
5
- attr_accessor :type
9
+ attr_reader :type
6
10
 
7
11
  def initialize(string, type = nil)
12
+ unless type
13
+ ActiveSupport::Deprecation.warn "ActionView::Template::HTML#initialize requires a type parameter"
14
+ type = :html
15
+ end
16
+
8
17
  @string = string.to_s
9
- @type = Types[type] || type if type
10
- @type ||= Types[:html]
18
+ @type = type
11
19
  end
12
20
 
13
21
  def identifier
14
- 'html template'
22
+ "html template"
15
23
  end
16
24
 
17
- def inspect
18
- 'html template'
19
- end
25
+ alias_method :inspect, :identifier
20
26
 
21
27
  def to_str
22
28
  ERB::Util.h(@string)
@@ -26,9 +32,12 @@ module ActionView #:nodoc:
26
32
  to_str
27
33
  end
28
34
 
29
- def formats
30
- [@type.respond_to?(:ref) ? @type.ref : @type.to_s]
35
+ def format
36
+ @type
31
37
  end
38
+
39
+ def formats; Array(format); end
40
+ deprecate :formats
32
41
  end
33
42
  end
34
43
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionView #:nodoc:
4
+ class Template #:nodoc:
5
+ class Inline < Template #:nodoc:
6
+ # This finalizer is needed (and exactly with a proc inside another proc)
7
+ # otherwise templates leak in development.
8
+ Finalizer = proc do |method_name, mod| # :nodoc:
9
+ proc do
10
+ mod.module_eval do
11
+ remove_possible_method method_name
12
+ end
13
+ end
14
+ end
15
+
16
+ def compile(mod)
17
+ super
18
+ ObjectSpace.define_finalizer(self, Finalizer[method_name, mod])
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionView #:nodoc:
4
+ # = Action View RawFile Template
5
+ class Template #:nodoc:
6
+ class RawFile #:nodoc:
7
+ attr_accessor :type, :format
8
+
9
+ def initialize(filename)
10
+ @filename = filename.to_s
11
+ extname = ::File.extname(filename).delete(".")
12
+ @type = Template::Types[extname] || Template::Types[:text]
13
+ @format = @type.symbol
14
+ end
15
+
16
+ def identifier
17
+ @filename
18
+ end
19
+
20
+ def render(*args)
21
+ ::File.read(@filename)
22
+ end
23
+
24
+ def formats; Array(format); end
25
+ deprecate :formats
26
+ end
27
+ end
28
+ end