actionview 5.2.4.4 → 6.1.1

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 (92) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +221 -93
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -3
  5. data/lib/action_view.rb +7 -2
  6. data/lib/action_view/base.rb +81 -15
  7. data/lib/action_view/buffers.rb +15 -0
  8. data/lib/action_view/cache_expiry.rb +52 -0
  9. data/lib/action_view/context.rb +5 -9
  10. data/lib/action_view/dependency_tracker.rb +10 -4
  11. data/lib/action_view/digestor.rb +15 -22
  12. data/lib/action_view/flows.rb +0 -1
  13. data/lib/action_view/gem_version.rb +4 -4
  14. data/lib/action_view/helpers.rb +0 -2
  15. data/lib/action_view/helpers/active_model_helper.rb +0 -1
  16. data/lib/action_view/helpers/asset_tag_helper.rb +63 -46
  17. data/lib/action_view/helpers/asset_url_helper.rb +9 -6
  18. data/lib/action_view/helpers/atom_feed_helper.rb +2 -1
  19. data/lib/action_view/helpers/cache_helper.rb +23 -22
  20. data/lib/action_view/helpers/capture_helper.rb +4 -0
  21. data/lib/action_view/helpers/csp_helper.rb +4 -2
  22. data/lib/action_view/helpers/csrf_helper.rb +1 -1
  23. data/lib/action_view/helpers/date_helper.rb +73 -30
  24. data/lib/action_view/helpers/form_helper.rb +305 -37
  25. data/lib/action_view/helpers/form_options_helper.rb +23 -23
  26. data/lib/action_view/helpers/form_tag_helper.rb +19 -16
  27. data/lib/action_view/helpers/javascript_helper.rb +12 -11
  28. data/lib/action_view/helpers/number_helper.rb +14 -8
  29. data/lib/action_view/helpers/output_safety_helper.rb +1 -1
  30. data/lib/action_view/helpers/rendering_helper.rb +17 -7
  31. data/lib/action_view/helpers/sanitize_helper.rb +12 -18
  32. data/lib/action_view/helpers/tag_helper.rb +98 -22
  33. data/lib/action_view/helpers/tags/base.rb +18 -11
  34. data/lib/action_view/helpers/tags/check_box.rb +0 -1
  35. data/lib/action_view/helpers/tags/collection_check_boxes.rb +0 -1
  36. data/lib/action_view/helpers/tags/collection_helpers.rb +0 -1
  37. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +0 -1
  38. data/lib/action_view/helpers/tags/color_field.rb +1 -2
  39. data/lib/action_view/helpers/tags/date_field.rb +1 -2
  40. data/lib/action_view/helpers/tags/date_select.rb +2 -3
  41. data/lib/action_view/helpers/tags/datetime_field.rb +0 -1
  42. data/lib/action_view/helpers/tags/datetime_local_field.rb +1 -2
  43. data/lib/action_view/helpers/tags/label.rb +4 -1
  44. data/lib/action_view/helpers/tags/month_field.rb +1 -2
  45. data/lib/action_view/helpers/tags/radio_button.rb +0 -1
  46. data/lib/action_view/helpers/tags/select.rb +1 -2
  47. data/lib/action_view/helpers/tags/text_field.rb +0 -1
  48. data/lib/action_view/helpers/tags/time_field.rb +1 -2
  49. data/lib/action_view/helpers/tags/translator.rb +1 -6
  50. data/lib/action_view/helpers/tags/week_field.rb +1 -2
  51. data/lib/action_view/helpers/text_helper.rb +3 -4
  52. data/lib/action_view/helpers/translation_helper.rb +93 -55
  53. data/lib/action_view/helpers/url_helper.rb +121 -27
  54. data/lib/action_view/layouts.rb +8 -10
  55. data/lib/action_view/log_subscriber.rb +30 -15
  56. data/lib/action_view/lookup_context.rb +63 -35
  57. data/lib/action_view/path_set.rb +3 -12
  58. data/lib/action_view/railtie.rb +42 -26
  59. data/lib/action_view/record_identifier.rb +2 -3
  60. data/lib/action_view/renderer/abstract_renderer.rb +142 -11
  61. data/lib/action_view/renderer/collection_renderer.rb +196 -0
  62. data/lib/action_view/renderer/object_renderer.rb +34 -0
  63. data/lib/action_view/renderer/partial_renderer.rb +21 -273
  64. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +61 -16
  65. data/lib/action_view/renderer/renderer.rb +59 -4
  66. data/lib/action_view/renderer/streaming_template_renderer.rb +10 -8
  67. data/lib/action_view/renderer/template_renderer.rb +35 -27
  68. data/lib/action_view/rendering.rb +54 -33
  69. data/lib/action_view/routing_url_for.rb +13 -12
  70. data/lib/action_view/template.rb +66 -75
  71. data/lib/action_view/template/error.rb +30 -15
  72. data/lib/action_view/template/handlers.rb +1 -1
  73. data/lib/action_view/template/handlers/builder.rb +2 -2
  74. data/lib/action_view/template/handlers/erb.rb +16 -11
  75. data/lib/action_view/template/handlers/erb/erubi.rb +15 -9
  76. data/lib/action_view/template/handlers/html.rb +1 -1
  77. data/lib/action_view/template/handlers/raw.rb +2 -2
  78. data/lib/action_view/template/html.rb +5 -6
  79. data/lib/action_view/template/inline.rb +22 -0
  80. data/lib/action_view/template/raw_file.rb +25 -0
  81. data/lib/action_view/template/renderable.rb +24 -0
  82. data/lib/action_view/template/resolver.rb +191 -150
  83. data/lib/action_view/template/sources.rb +13 -0
  84. data/lib/action_view/template/sources/file.rb +17 -0
  85. data/lib/action_view/template/text.rb +2 -3
  86. data/lib/action_view/test_case.rb +21 -29
  87. data/lib/action_view/testing/resolvers.rb +18 -27
  88. data/lib/action_view/unbound_template.rb +31 -0
  89. data/lib/action_view/view_paths.rb +59 -38
  90. data/lib/assets/compiled/rails-ujs.js +29 -3
  91. metadata +32 -21
  92. data/lib/action_view/helpers/record_tag_helper.rb +0 -23
@@ -84,29 +84,28 @@ module ActionView
84
84
  super(only_path: _generate_paths_by_default)
85
85
  when Hash
86
86
  options = options.symbolize_keys
87
- unless options.key?(:only_path)
88
- options[:only_path] = only_path?(options[:host])
89
- end
87
+ ensure_only_path_option(options)
90
88
 
91
89
  super(options)
92
90
  when ActionController::Parameters
93
- unless options.key?(:only_path)
94
- options[:only_path] = only_path?(options[:host])
95
- end
91
+ ensure_only_path_option(options)
96
92
 
97
93
  super(options)
98
94
  when :back
99
95
  _back_url
100
96
  when Array
101
97
  components = options.dup
102
- if _generate_paths_by_default
103
- polymorphic_path(components, components.extract_options!)
98
+ options = components.extract_options!
99
+ ensure_only_path_option(options)
100
+
101
+ if options[:only_path]
102
+ polymorphic_path(components, options)
104
103
  else
105
- polymorphic_url(components, components.extract_options!)
104
+ polymorphic_url(components, options)
106
105
  end
107
106
  else
108
107
  method = _generate_paths_by_default ? :path : :url
109
- builder = ActionDispatch::Routing::PolymorphicRoutes::HelperMethodBuilder.send(method)
108
+ builder = ActionDispatch::Routing::PolymorphicRoutes::HelperMethodBuilder.public_send(method)
110
109
 
111
110
  case options
112
111
  when Symbol
@@ -138,8 +137,10 @@ module ActionView
138
137
  true
139
138
  end
140
139
 
141
- def only_path?(host)
142
- _generate_paths_by_default unless host
140
+ def ensure_only_path_option(options)
141
+ unless options.key?(:only_path)
142
+ options[:only_path] = _generate_paths_by_default unless options[:host]
143
+ end
143
144
  end
144
145
  end
145
146
  end
@@ -1,8 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/object/try"
4
- require "active_support/core_ext/kernel/singleton_class"
5
3
  require "thread"
4
+ require "delegate"
6
5
 
7
6
  module ActionView
8
7
  # = Action View Template
@@ -103,41 +102,37 @@ module ActionView
103
102
 
104
103
  eager_autoload do
105
104
  autoload :Error
105
+ autoload :RawFile
106
+ autoload :Renderable
106
107
  autoload :Handlers
107
108
  autoload :HTML
109
+ autoload :Inline
110
+ autoload :Sources
108
111
  autoload :Text
109
112
  autoload :Types
110
113
  end
111
114
 
112
115
  extend Template::Handlers
113
116
 
114
- attr_accessor :locals, :formats, :variants, :virtual_path
115
-
116
- attr_reader :source, :identifier, :handler, :original_encoding, :updated_at
117
-
118
- # This finalizer is needed (and exactly with a proc inside another proc)
119
- # otherwise templates leak in development.
120
- Finalizer = proc do |method_name, mod| # :nodoc:
121
- proc do
122
- mod.module_eval do
123
- remove_possible_method method_name
124
- end
125
- end
126
- end
127
-
128
- def initialize(source, identifier, handler, details)
129
- format = details[:format] || (handler.default_format if handler.respond_to?(:default_format))
117
+ attr_reader :identifier, :handler
118
+ attr_reader :variable, :format, :variant, :locals, :virtual_path
130
119
 
120
+ def initialize(source, identifier, handler, locals:, format: nil, variant: nil, virtual_path: nil)
131
121
  @source = source
132
122
  @identifier = identifier
133
123
  @handler = handler
134
124
  @compiled = false
135
- @original_encoding = nil
136
- @locals = details[:locals] || []
137
- @virtual_path = details[:virtual_path]
138
- @updated_at = details[:updated_at] || Time.now
139
- @formats = Array(format).map { |f| f.respond_to?(:ref) ? f.ref : f }
140
- @variants = [details[:variant]]
125
+ @locals = locals
126
+ @virtual_path = virtual_path
127
+
128
+ @variable = if @virtual_path
129
+ base = @virtual_path.end_with?("/") ? "" : ::File.basename(@virtual_path)
130
+ base =~ /\A_?(.*?)(?:\.\w+)*\z/
131
+ $1.to_sym
132
+ end
133
+
134
+ @format = format
135
+ @variant = variant
141
136
  @compile_mutex = Mutex.new
142
137
  end
143
138
 
@@ -153,40 +148,29 @@ module ActionView
153
148
  # This method is instrumented as "!render_template.action_view". Notice that
154
149
  # we use a bang in this instrumentation because you don't want to
155
150
  # consume this in production. This is only slow if it's being listened to.
156
- def render(view, locals, buffer = nil, &block)
151
+ def render(view, locals, buffer = ActionView::OutputBuffer.new, add_to_stack: true, &block)
157
152
  instrument_render_template do
158
153
  compile!(view)
159
- view.send(method_name, locals, buffer, &block)
154
+ view._run(method_name, self, locals, buffer, add_to_stack: add_to_stack, &block)
160
155
  end
161
156
  rescue => e
162
157
  handle_render_error(view, e)
163
158
  end
164
159
 
165
160
  def type
166
- @type ||= Types[@formats.first] if @formats.first
161
+ @type ||= Types[format]
167
162
  end
168
163
 
169
- # Receives a view object and return a template similar to self by using @virtual_path.
170
- #
171
- # This method is useful if you have a template object but it does not contain its source
172
- # anymore since it was already compiled. In such cases, all you need to do is to call
173
- # refresh passing in the view object.
174
- #
175
- # Notice this method raises an error if the template to be refreshed does not have a
176
- # virtual path set (true just for inline templates).
177
- def refresh(view)
178
- raise "A template needs to have a virtual path in order to be refreshed" unless @virtual_path
179
- lookup = view.lookup_context
180
- pieces = @virtual_path.split("/")
181
- name = pieces.pop
182
- partial = !!name.sub!(/^_/, "")
183
- lookup.disable_cache do
184
- lookup.find_template(name, [ pieces.join("/") ], partial, @locals)
185
- end
164
+ def short_identifier
165
+ @short_identifier ||= defined?(Rails.root) ? identifier.delete_prefix("#{Rails.root}/") : identifier
186
166
  end
187
167
 
188
168
  def inspect
189
- @inspect ||= defined?(Rails.root) ? identifier.sub("#{Rails.root}/", "".freeze) : identifier
169
+ "#<#{self.class.name} #{short_identifier} locals=#{@locals.inspect}>"
170
+ end
171
+
172
+ def source
173
+ @source.to_s
190
174
  end
191
175
 
192
176
  # This method is responsible for properly setting the encoding of the
@@ -200,7 +184,9 @@ module ActionView
200
184
  # before passing the source on to the template engine, leaving a
201
185
  # blank line in its stead.
202
186
  def encode!
203
- return unless source.encoding == Encoding::BINARY
187
+ source = self.source
188
+
189
+ return source unless source.encoding == Encoding::BINARY
204
190
 
205
191
  # Look for # encoding: *. If we find one, we'll encode the
206
192
  # String in that encoding, otherwise, we'll use the
@@ -233,8 +219,20 @@ module ActionView
233
219
  end
234
220
  end
235
221
 
236
- private
237
222
 
223
+ # Exceptions are marshalled when using the parallel test runner with DRb, so we need
224
+ # to ensure that references to the template object can be marshalled as well. This means forgoing
225
+ # the marshalling of the compiler mutex and instantiating that again on unmarshalling.
226
+ def marshal_dump # :nodoc:
227
+ [ @source, @identifier, @handler, @compiled, @locals, @virtual_path, @format, @variant ]
228
+ end
229
+
230
+ def marshal_load(array) # :nodoc:
231
+ @source, @identifier, @handler, @compiled, @locals, @virtual_path, @format, @variant = *array
232
+ @compile_mutex = Mutex.new
233
+ end
234
+
235
+ private
238
236
  # Compile a template. This method ensures a template is compiled
239
237
  # just once and removes the source after it is compiled.
240
238
  def compile!(view)
@@ -249,19 +247,12 @@ module ActionView
249
247
  # re-compilation
250
248
  return if @compiled
251
249
 
252
- if view.is_a?(ActionView::CompiledTemplates)
253
- mod = ActionView::CompiledTemplates
254
- else
255
- mod = view.singleton_class
256
- end
250
+ mod = view.compiled_method_container
257
251
 
258
252
  instrument("!compile_template") do
259
253
  compile(mod)
260
254
  end
261
255
 
262
- # Just discard the source if we have a virtual path. This
263
- # means we can get the template back.
264
- @source = nil if @virtual_path
265
256
  @compiled = true
266
257
  end
267
258
  end
@@ -279,16 +270,15 @@ module ActionView
279
270
  # In general, this means that templates will be UTF-8 inside of Rails,
280
271
  # regardless of the original source encoding.
281
272
  def compile(mod)
282
- encode!
283
- code = @handler.call(self)
273
+ source = encode!
274
+ code = @handler.call(self, source)
284
275
 
285
276
  # Make sure that the resulting String to be eval'd is in the
286
277
  # encoding of the code
287
- source = <<-end_src.dup
278
+ original_source = source
279
+ source = +<<-end_src
288
280
  def #{method_name}(local_assigns, output_buffer)
289
- _old_virtual_path, @virtual_path = @virtual_path, #{@virtual_path.inspect};_old_output_buffer = @output_buffer;#{locals_code};#{code}
290
- ensure
291
- @virtual_path, @output_buffer = _old_virtual_path, _old_output_buffer
281
+ @virtual_path = #{@virtual_path.inspect};#{locals_code};#{code}
292
282
  end
293
283
  end_src
294
284
 
@@ -303,11 +293,17 @@ module ActionView
303
293
  # handler is valid in the default_internal. This is for handlers
304
294
  # that handle encoding but screw up
305
295
  unless source.valid_encoding?
306
- raise WrongEncodingError.new(@source, Encoding.default_internal)
296
+ raise WrongEncodingError.new(source, Encoding.default_internal)
307
297
  end
308
298
 
309
- mod.module_eval(source, identifier, 0)
310
- ObjectSpace.define_finalizer(self, Finalizer[method_name, mod])
299
+ begin
300
+ mod.module_eval(source, identifier, 0)
301
+ rescue SyntaxError
302
+ # Account for when code in the template is not syntactically valid; e.g. if we're using
303
+ # ERB and the user writes <%= foo( %>, attempting to call a helper `foo` and interpolate
304
+ # the result into the template, but missing an end parenthesis.
305
+ raise SyntaxErrorInTemplate.new(self, original_source)
306
+ end
311
307
  end
312
308
 
313
309
  def handle_render_error(view, e)
@@ -315,12 +311,7 @@ module ActionView
315
311
  e.sub_template_of(self)
316
312
  raise e
317
313
  else
318
- template = self
319
- unless template.source
320
- template = refresh(view)
321
- template.encode!
322
- end
323
- raise Template::Error.new(template)
314
+ raise Template::Error.new(self)
324
315
  end
325
316
  end
326
317
 
@@ -331,19 +322,19 @@ module ActionView
331
322
  locals = locals.grep(/\A@?(?![A-Z0-9])(?:[[:alnum:]_]|[^\0-\177])+\z/)
332
323
 
333
324
  # Assign for the same variable is to suppress unused variable warning
334
- locals.each_with_object("".dup) { |key, code| code << "#{key} = local_assigns[:#{key}]; #{key} = #{key};" }
325
+ locals.each_with_object(+"") { |key, code| code << "#{key} = local_assigns[:#{key}]; #{key} = #{key};" }
335
326
  end
336
327
 
337
328
  def method_name
338
329
  @method_name ||= begin
339
- m = "_#{identifier_method_name}__#{@identifier.hash}_#{__id__}".dup
340
- m.tr!("-".freeze, "_".freeze)
330
+ m = +"_#{identifier_method_name}__#{@identifier.hash}_#{__id__}"
331
+ m.tr!("-", "_")
341
332
  m
342
333
  end
343
334
  end
344
335
 
345
336
  def identifier_method_name
346
- inspect.tr("^a-z_".freeze, "_".freeze)
337
+ short_identifier.tr("^a-z_", "_")
347
338
  end
348
339
 
349
340
  def instrument(action, &block) # :doc:
@@ -351,7 +342,7 @@ module ActionView
351
342
  end
352
343
 
353
344
  def instrument_render_template(&block)
354
- ActiveSupport::Notifications.instrument("!render_template.action_view".freeze, instrument_payload, &block)
345
+ ActiveSupport::Notifications.instrument("!render_template.action_view", instrument_payload, &block)
355
346
  end
356
347
 
357
348
  def instrument_payload
@@ -81,19 +81,19 @@ module ActionView
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,12 +109,11 @@ 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 "
@@ -123,19 +122,35 @@ module ActionView
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" % [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
@@ -14,7 +14,7 @@ module ActionView #:nodoc:
14
14
  base.register_template_handler :erb, ERB.new
15
15
  base.register_template_handler :html, Html.new
16
16
  base.register_template_handler :builder, Builder.new
17
- base.register_template_handler :ruby, :source.to_proc
17
+ base.register_template_handler :ruby, lambda { |_, source| source }
18
18
  end
19
19
 
20
20
  @@template_handlers = {}
@@ -5,11 +5,11 @@ module ActionView
5
5
  class Builder
6
6
  class_attribute :default_format, default: :xml
7
7
 
8
- def call(template)
8
+ def call(template, source)
9
9
  require_engine
10
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
 
@@ -14,12 +14,12 @@ module ActionView
14
14
  class_attribute :erb_implementation, default: Erubi
15
15
 
16
16
  # Do not escape templates of these mime types.
17
- class_attribute :escape_whitelist, default: ["text/plain"]
17
+ class_attribute :escape_ignore_list, default: ["text/plain"]
18
18
 
19
19
  ENCODING_TAG = Regexp.new("\\A(<%#{ENCODING_FLAG}-?%>)[ \\t]*")
20
20
 
21
- def self.call(template)
22
- new.call(template)
21
+ def self.call(template, source)
22
+ new.call(template, source)
23
23
  end
24
24
 
25
25
  def supports_streaming?
@@ -30,30 +30,35 @@ module ActionView
30
30
  true
31
31
  end
32
32
 
33
- def call(template)
33
+ def call(template, source)
34
34
  # First, convert to BINARY, so in case the encoding is
35
35
  # wrong, we can still find an encoding tag
36
36
  # (<%# encoding %>) inside the String using a regular
37
37
  # expression
38
- template_source = template.source.dup.force_encoding(Encoding::ASCII_8BIT)
38
+ template_source = source.b
39
39
 
40
40
  erb = template_source.gsub(ENCODING_TAG, "")
41
41
  encoding = $2
42
42
 
43
- erb.force_encoding valid_encoding(template.source.dup, encoding)
43
+ erb.force_encoding valid_encoding(source.dup, encoding)
44
44
 
45
45
  # Always make sure we return a String in the default_internal
46
46
  erb.encode!
47
47
 
48
- self.class.erb_implementation.new(
49
- erb,
50
- escape: (self.class.escape_whitelist.include? template.type),
48
+ options = {
49
+ escape: (self.class.escape_ignore_list.include? template.type),
51
50
  trim: (self.class.erb_trim_mode == "-")
52
- ).src
51
+ }
52
+
53
+ if ActionView::Base.annotate_rendered_view_with_filenames && template.format == :html
54
+ options[:preamble] = "@output_buffer.safe_append='<!-- BEGIN #{template.short_identifier} -->';"
55
+ options[:postamble] = "@output_buffer.safe_append='<!-- END #{template.short_identifier} -->';@output_buffer.to_s"
56
+ end
57
+
58
+ self.class.erb_implementation.new(erb, options).src
53
59
  end
54
60
 
55
61
  private
56
-
57
62
  def valid_encoding(string, encoding)
58
63
  # If a magic encoding comment was found, tag the
59
64
  # String with this encoding. This is for a case