actionview 4.2.10 → 5.1.0

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 (91) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +141 -272
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +2 -3
  5. data/lib/action_view/base.rb +33 -21
  6. data/lib/action_view/buffers.rb +1 -1
  7. data/lib/action_view/context.rb +1 -1
  8. data/lib/action_view/dependency_tracker.rb +52 -20
  9. data/lib/action_view/digestor.rb +86 -83
  10. data/lib/action_view/flows.rb +9 -11
  11. data/lib/action_view/gem_version.rb +3 -3
  12. data/lib/action_view/helpers/active_model_helper.rb +8 -8
  13. data/lib/action_view/helpers/asset_tag_helper.rb +74 -38
  14. data/lib/action_view/helpers/asset_url_helper.rb +160 -59
  15. data/lib/action_view/helpers/atom_feed_helper.rb +16 -16
  16. data/lib/action_view/helpers/cache_helper.rb +90 -35
  17. data/lib/action_view/helpers/capture_helper.rb +7 -6
  18. data/lib/action_view/helpers/controller_helper.rb +3 -2
  19. data/lib/action_view/helpers/csrf_helper.rb +3 -3
  20. data/lib/action_view/helpers/date_helper.rb +156 -108
  21. data/lib/action_view/helpers/debug_helper.rb +3 -4
  22. data/lib/action_view/helpers/form_helper.rb +475 -94
  23. data/lib/action_view/helpers/form_options_helper.rb +87 -47
  24. data/lib/action_view/helpers/form_tag_helper.rb +88 -57
  25. data/lib/action_view/helpers/javascript_helper.rb +10 -10
  26. data/lib/action_view/helpers/number_helper.rb +76 -59
  27. data/lib/action_view/helpers/output_safety_helper.rb +34 -4
  28. data/lib/action_view/helpers/record_tag_helper.rb +12 -99
  29. data/lib/action_view/helpers/rendering_helper.rb +3 -3
  30. data/lib/action_view/helpers/sanitize_helper.rb +17 -14
  31. data/lib/action_view/helpers/tag_helper.rb +198 -73
  32. data/lib/action_view/helpers/tags/base.rb +132 -97
  33. data/lib/action_view/helpers/tags/check_box.rb +17 -17
  34. data/lib/action_view/helpers/tags/collection_check_boxes.rb +9 -33
  35. data/lib/action_view/helpers/tags/collection_helpers.rb +68 -36
  36. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +3 -11
  37. data/lib/action_view/helpers/tags/collection_select.rb +2 -2
  38. data/lib/action_view/helpers/tags/date_select.rb +36 -36
  39. data/lib/action_view/helpers/tags/datetime_field.rb +1 -1
  40. data/lib/action_view/helpers/tags/grouped_collection_select.rb +2 -2
  41. data/lib/action_view/helpers/tags/label.rb +5 -1
  42. data/lib/action_view/helpers/tags/password_field.rb +1 -1
  43. data/lib/action_view/helpers/tags/placeholderable.rb +1 -1
  44. data/lib/action_view/helpers/tags/radio_button.rb +4 -4
  45. data/lib/action_view/helpers/tags/search_field.rb +12 -9
  46. data/lib/action_view/helpers/tags/select.rb +9 -9
  47. data/lib/action_view/helpers/tags/text_area.rb +1 -1
  48. data/lib/action_view/helpers/tags/text_field.rb +5 -6
  49. data/lib/action_view/helpers/tags/translator.rb +15 -13
  50. data/lib/action_view/helpers/text_helper.rb +47 -30
  51. data/lib/action_view/helpers/translation_helper.rb +60 -30
  52. data/lib/action_view/helpers/url_helper.rb +132 -104
  53. data/lib/action_view/helpers.rb +1 -1
  54. data/lib/action_view/layouts.rb +59 -54
  55. data/lib/action_view/log_subscriber.rb +56 -7
  56. data/lib/action_view/lookup_context.rb +76 -61
  57. data/lib/action_view/model_naming.rb +1 -1
  58. data/lib/action_view/path_set.rb +28 -19
  59. data/lib/action_view/railtie.rb +30 -6
  60. data/lib/action_view/record_identifier.rb +51 -25
  61. data/lib/action_view/renderer/abstract_renderer.rb +19 -15
  62. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +55 -0
  63. data/lib/action_view/renderer/partial_renderer.rb +208 -206
  64. data/lib/action_view/renderer/renderer.rb +2 -6
  65. data/lib/action_view/renderer/streaming_template_renderer.rb +46 -48
  66. data/lib/action_view/renderer/template_renderer.rb +65 -66
  67. data/lib/action_view/rendering.rb +16 -9
  68. data/lib/action_view/routing_url_for.rb +25 -17
  69. data/lib/action_view/tasks/cache_digests.rake +23 -0
  70. data/lib/action_view/template/error.rb +14 -13
  71. data/lib/action_view/template/handlers/builder.rb +7 -7
  72. data/lib/action_view/template/handlers/erb/deprecated_erubis.rb +9 -0
  73. data/lib/action_view/template/handlers/erb/erubi.rb +81 -0
  74. data/lib/action_view/template/handlers/erb/erubis.rb +81 -0
  75. data/lib/action_view/template/handlers/erb.rb +9 -76
  76. data/lib/action_view/template/handlers/html.rb +9 -0
  77. data/lib/action_view/template/handlers/raw.rb +1 -3
  78. data/lib/action_view/template/handlers.rb +8 -6
  79. data/lib/action_view/template/html.rb +2 -4
  80. data/lib/action_view/template/resolver.rb +133 -109
  81. data/lib/action_view/template/text.rb +5 -8
  82. data/lib/action_view/template/types.rb +15 -17
  83. data/lib/action_view/template.rb +51 -28
  84. data/lib/action_view/test_case.rb +32 -27
  85. data/lib/action_view/testing/resolvers.rb +29 -31
  86. data/lib/action_view/version.rb +1 -1
  87. data/lib/action_view/view_paths.rb +26 -32
  88. data/lib/action_view.rb +5 -5
  89. data/lib/assets/compiled/rails-ujs.js +685 -0
  90. metadata +23 -23
  91. data/lib/action_view/tasks/dependencies.rake +0 -23
@@ -1,10 +1,9 @@
1
- require 'fiber'
1
+ require "fiber"
2
2
 
3
3
  module ActionView
4
4
  # == TODO
5
5
  #
6
6
  # * Support streaming from child templates, partials and so on.
7
- # * Integrate exceptions with exceptron
8
7
  # * Rack::Cache needs to support streaming bodies
9
8
  class StreamingTemplateRenderer < TemplateRenderer #:nodoc:
10
9
  # A valid Rack::Body (i.e. it responds to each).
@@ -27,17 +26,16 @@ module ActionView
27
26
 
28
27
  private
29
28
 
30
- # This is the same logging logic as in ShowExceptions middleware.
31
- # TODO Once "exceptron" is in, refactor this piece to simply re-use exceptron.
32
- def log_error(exception) #:nodoc:
33
- logger = ActionView::Base.logger
34
- return unless logger
29
+ # This is the same logging logic as in ShowExceptions middleware.
30
+ def log_error(exception)
31
+ logger = ActionView::Base.logger
32
+ return unless logger
35
33
 
36
- message = "\n#{exception.class} (#{exception.message}):\n"
37
- message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code)
38
- message << " " << exception.backtrace.join("\n ")
39
- logger.fatal("#{message}\n\n")
40
- end
34
+ message = "\n#{exception.class} (#{exception.message}):\n"
35
+ message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code)
36
+ message << " " << exception.backtrace.join("\n ")
37
+ logger.fatal("#{message}\n\n")
38
+ end
41
39
  end
42
40
 
43
41
  # For streaming, instead of rendering a given a template, we return a Body
@@ -47,7 +45,7 @@ module ActionView
47
45
  return [super] unless layout_name && template.supports_streaming?
48
46
 
49
47
  locals ||= {}
50
- layout = layout_name && find_layout(layout_name, locals.keys)
48
+ layout = layout_name && find_layout(layout_name, locals.keys, [formats.first])
51
49
 
52
50
  Body.new do |buffer|
53
51
  delayed_render(buffer, template, layout, @view, locals)
@@ -56,48 +54,48 @@ module ActionView
56
54
 
57
55
  private
58
56
 
59
- def delayed_render(buffer, template, layout, view, locals)
60
- # Wrap the given buffer in the StreamingBuffer and pass it to the
61
- # underlying template handler. Now, every time something is concatenated
62
- # to the buffer, it is not appended to an array, but streamed straight
63
- # to the client.
64
- output = ActionView::StreamingBuffer.new(buffer)
65
- yielder = lambda { |*name| view._layout_for(*name) }
66
-
67
- instrument(:template, :identifier => template.identifier, :layout => layout.try(:virtual_path)) do
68
- fiber = Fiber.new do
69
- if layout
70
- layout.render(view, locals, output, &yielder)
71
- else
72
- # If you don't have a layout, just render the thing
73
- # and concatenate the final result. This is the same
74
- # as a layout with just <%= yield %>
75
- output.safe_concat view._layout_for
57
+ def delayed_render(buffer, template, layout, view, locals)
58
+ # Wrap the given buffer in the StreamingBuffer and pass it to the
59
+ # underlying template handler. Now, every time something is concatenated
60
+ # to the buffer, it is not appended to an array, but streamed straight
61
+ # to the client.
62
+ output = ActionView::StreamingBuffer.new(buffer)
63
+ yielder = lambda { |*name| view._layout_for(*name) }
64
+
65
+ instrument(:template, identifier: template.identifier, layout: layout.try(:virtual_path)) do
66
+ fiber = Fiber.new do
67
+ if layout
68
+ layout.render(view, locals, output, &yielder)
69
+ else
70
+ # If you don't have a layout, just render the thing
71
+ # and concatenate the final result. This is the same
72
+ # as a layout with just <%= yield %>
73
+ output.safe_concat view._layout_for
74
+ end
76
75
  end
77
- end
78
76
 
79
- # Set the view flow to support streaming. It will be aware
80
- # when to stop rendering the layout because it needs to search
81
- # something in the template and vice-versa.
82
- view.view_flow = StreamingFlow.new(view, fiber)
77
+ # Set the view flow to support streaming. It will be aware
78
+ # when to stop rendering the layout because it needs to search
79
+ # something in the template and vice-versa.
80
+ view.view_flow = StreamingFlow.new(view, fiber)
83
81
 
84
- # Yo! Start the fiber!
85
- fiber.resume
82
+ # Yo! Start the fiber!
83
+ fiber.resume
86
84
 
87
- # If the fiber is still alive, it means we need something
88
- # from the template, so start rendering it. If not, it means
89
- # the layout exited without requiring anything from the template.
90
- if fiber.alive?
91
- content = template.render(view, locals, &yielder)
85
+ # If the fiber is still alive, it means we need something
86
+ # from the template, so start rendering it. If not, it means
87
+ # the layout exited without requiring anything from the template.
88
+ if fiber.alive?
89
+ content = template.render(view, locals, &yielder)
92
90
 
93
- # Once rendering the template is done, sets its content in the :layout key.
94
- view.view_flow.set(:layout, content)
91
+ # Once rendering the template is done, sets its content in the :layout key.
92
+ view.view_flow.set(:layout, content)
95
93
 
96
- # In case the layout continues yielding, we need to resume
97
- # the fiber until all yields are handled.
98
- fiber.resume while fiber.alive?
94
+ # In case the layout continues yielding, we need to resume
95
+ # the fiber until all yields are handled.
96
+ fiber.resume while fiber.alive?
97
+ end
99
98
  end
100
99
  end
101
- end
102
100
  end
103
101
  end
@@ -1,4 +1,4 @@
1
- require 'active_support/core_ext/object/try'
1
+ require "active_support/core_ext/object/try"
2
2
 
3
3
  module ActionView
4
4
  class TemplateRenderer < AbstractRenderer #:nodoc:
@@ -16,86 +16,85 @@ module ActionView
16
16
 
17
17
  private
18
18
 
19
- # Determine the template to be rendered using the given options.
20
- def determine_template(options)
21
- keys = options.has_key?(:locals) ? options[:locals].keys : []
19
+ # Determine the template to be rendered using the given options.
20
+ def determine_template(options)
21
+ keys = options.has_key?(:locals) ? options[:locals].keys : []
22
22
 
23
- if options.key?(:body)
24
- Template::Text.new(options[:body])
25
- elsif options.key?(:text)
26
- Template::Text.new(options[:text], formats.first)
27
- elsif options.key?(:plain)
28
- Template::Text.new(options[:plain])
29
- elsif options.key?(:html)
30
- Template::HTML.new(options[:html], formats.first)
31
- elsif options.key?(:file)
32
- with_fallbacks { find_file(options[:file], nil, false, keys, @details) }
33
- elsif options.key?(:inline)
34
- handler = Template.handler_for_extension(options[:type] || "erb")
35
- Template.new(options[:inline], "inline template", handler, :locals => keys)
36
- elsif options.key?(:template)
37
- if options[:template].respond_to?(:render)
38
- options[:template]
23
+ if options.key?(:body)
24
+ Template::Text.new(options[:body])
25
+ elsif options.key?(:plain)
26
+ Template::Text.new(options[:plain])
27
+ elsif options.key?(:html)
28
+ Template::HTML.new(options[:html], formats.first)
29
+ elsif options.key?(:file)
30
+ with_fallbacks { find_file(options[:file], nil, false, keys, @details) }
31
+ elsif options.key?(:inline)
32
+ handler = Template.handler_for_extension(options[:type] || "erb")
33
+ Template.new(options[:inline], "inline template", handler, locals: keys)
34
+ elsif options.key?(:template)
35
+ if options[:template].respond_to?(:render)
36
+ options[:template]
37
+ else
38
+ find_template(options[:template], options[:prefixes], false, keys, @details)
39
+ end
39
40
  else
40
- find_template(options[:template], options[:prefixes], false, keys, @details)
41
+ raise ArgumentError, "You invoked render but did not give any of :partial, :template, :inline, :file, :plain, :html or :body option."
41
42
  end
42
- else
43
- raise ArgumentError, "You invoked render but did not give any of :partial, :template, :inline, :file, :plain, :text or :body option."
44
43
  end
45
- end
46
44
 
47
- # Renders the given template. A string representing the layout can be
48
- # supplied as well.
49
- def render_template(template, layout_name = nil, locals = nil) #:nodoc:
50
- view, locals = @view, locals || {}
45
+ # Renders the given template. A string representing the layout can be
46
+ # supplied as well.
47
+ def render_template(template, layout_name = nil, locals = nil)
48
+ view, locals = @view, locals || {}
51
49
 
52
- render_with_layout(layout_name, locals) do |layout|
53
- instrument(:template, :identifier => template.identifier, :layout => layout.try(:virtual_path)) do
54
- template.render(view, locals) { |*name| view._layout_for(*name) }
50
+ render_with_layout(layout_name, locals) do |layout|
51
+ instrument(:template, identifier: template.identifier, layout: layout.try(:virtual_path)) do
52
+ template.render(view, locals) { |*name| view._layout_for(*name) }
53
+ end
55
54
  end
56
55
  end
57
- end
58
56
 
59
- def render_with_layout(path, locals) #:nodoc:
60
- layout = path && find_layout(path, locals.keys)
61
- content = yield(layout)
57
+ def render_with_layout(path, locals)
58
+ layout = path && find_layout(path, locals.keys, [formats.first])
59
+ content = yield(layout)
60
+
61
+ if layout
62
+ view = @view
63
+ view.view_flow.set(:layout, content)
64
+ layout.render(view, locals) { |*name| view._layout_for(*name) }
65
+ else
66
+ content
67
+ end
68
+ end
62
69
 
63
- if layout
64
- view = @view
65
- view.view_flow.set(:layout, content)
66
- layout.render(view, locals){ |*name| view._layout_for(*name) }
67
- else
68
- content
70
+ # This is the method which actually finds the layout using details in the lookup
71
+ # context object. If no layout is found, it checks if at least a layout with
72
+ # the given name exists across all details before raising the error.
73
+ def find_layout(layout, keys, formats)
74
+ resolve_layout(layout, keys, formats)
69
75
  end
70
- end
71
76
 
72
- # This is the method which actually finds the layout using details in the lookup
73
- # context object. If no layout is found, it checks if at least a layout with
74
- # the given name exists across all details before raising the error.
75
- def find_layout(layout, keys)
76
- with_layout_format { resolve_layout(layout, keys) }
77
- end
77
+ def resolve_layout(layout, keys, formats)
78
+ details = @details.dup
79
+ details[:formats] = formats
78
80
 
79
- def resolve_layout(layout, keys)
80
- case layout
81
- when String
82
- begin
83
- if layout =~ /^\//
84
- with_fallbacks { find_template(layout, nil, false, keys, @details) }
85
- else
86
- find_template(layout, nil, false, keys, @details)
81
+ case layout
82
+ when String
83
+ begin
84
+ if layout.start_with?("/")
85
+ with_fallbacks { find_template(layout, nil, false, [], details) }
86
+ else
87
+ find_template(layout, nil, false, [], details)
88
+ end
89
+ rescue ActionView::MissingTemplate
90
+ all_details = @details.merge(formats: @lookup_context.default_formats)
91
+ raise unless template_exists?(layout, nil, false, [], all_details)
87
92
  end
88
- rescue ActionView::MissingTemplate
89
- all_details = @details.merge(:formats => @lookup_context.default_formats)
90
- raise unless template_exists?(layout, nil, false, keys, all_details)
93
+ when Proc
94
+ resolve_layout(layout.call(formats), keys, formats)
95
+ else
96
+ layout
91
97
  end
92
- when Proc
93
- resolve_layout(layout.call, keys)
94
- when FalseClass
95
- nil
96
- else
97
- layout
98
98
  end
99
- end
100
99
  end
101
100
  end
@@ -59,7 +59,7 @@ module ActionView
59
59
  @_view_context_class ||= self.class.view_context_class
60
60
  end
61
61
 
62
- # An instance of a view class. The default view class is ActionView::Base
62
+ # An instance of a view class. The default view class is ActionView::Base.
63
63
  #
64
64
  # The view class must have the following methods:
65
65
  # View.new[lookup_context, assigns, controller]
@@ -84,24 +84,27 @@ module ActionView
84
84
  end
85
85
 
86
86
  def rendered_format
87
- Mime[lookup_context.rendered_format]
87
+ Template::Types[lookup_context.rendered_format]
88
88
  end
89
89
 
90
90
  private
91
91
 
92
92
  # Find and render a template based on the options given.
93
93
  # :api: private
94
- def _render_template(options) #:nodoc:
95
- variant = options[:variant]
94
+ def _render_template(options)
95
+ variant = options.delete(:variant)
96
+ assigns = options.delete(:assigns)
97
+ context = view_context
96
98
 
99
+ context.assign assigns if assigns
97
100
  lookup_context.rendered_format = nil if options[:formats]
98
101
  lookup_context.variants = variant if variant
99
102
 
100
- view_renderer.render(view_context, options)
103
+ view_renderer.render(context, options)
101
104
  end
102
105
 
103
- # Assign the rendered format to lookup context.
104
- def _process_format(format, options = {}) #:nodoc:
106
+ # Assign the rendered format to look up context.
107
+ def _process_format(format)
105
108
  super
106
109
  lookup_context.formats = [format.to_sym]
107
110
  lookup_context.rendered_format = lookup_context.formats.first
@@ -110,7 +113,7 @@ module ActionView
110
113
  # Normalize args by converting render "foo" to render :action => "foo" and
111
114
  # render "foo/bar" to render :template => "foo/bar".
112
115
  # :api: private
113
- def _normalize_args(action=nil, options={})
116
+ def _normalize_args(action = nil, options = {})
114
117
  options = super(action, options)
115
118
  case action
116
119
  when NilClass
@@ -121,7 +124,11 @@ module ActionView
121
124
  key = action.include?(?/) ? :template : :action
122
125
  options[key] = action
123
126
  else
124
- options[:partial] = action
127
+ if action.respond_to?(:permitted?) && action.permitted?
128
+ options = action
129
+ else
130
+ options[:partial] = action
131
+ end
125
132
  end
126
133
 
127
134
  options
@@ -1,8 +1,7 @@
1
- require 'action_dispatch/routing/polymorphic_routes'
1
+ require "action_dispatch/routing/polymorphic_routes"
2
2
 
3
3
  module ActionView
4
4
  module RoutingUrlFor
5
-
6
5
  # Returns the URL for the set of +options+ provided. This takes the
7
6
  # same options as +url_for+ in Action Controller (see the
8
7
  # documentation for <tt>ActionController::Base#url_for</tt>). Note that by default
@@ -32,7 +31,7 @@ module ActionView
32
31
  #
33
32
  # ==== Examples
34
33
  # <%= url_for(action: 'index') %>
35
- # # => /blog/
34
+ # # => /blogs/
36
35
  #
37
36
  # <%= url_for(action: 'find', controller: 'books') %>
38
37
  # # => /books/find
@@ -84,11 +83,13 @@ module ActionView
84
83
  when Hash
85
84
  options = options.symbolize_keys
86
85
  unless options.key?(:only_path)
87
- if options[:host].nil?
88
- options[:only_path] = _generate_paths_by_default
89
- else
90
- options[:only_path] = false
91
- end
86
+ options[:only_path] = only_path?(options[:host])
87
+ end
88
+
89
+ super(options)
90
+ when ActionController::Parameters
91
+ unless options.key?(:only_path)
92
+ options[:only_path] = only_path?(options[:host])
92
93
  end
93
94
 
94
95
  super(options)
@@ -121,15 +122,22 @@ module ActionView
121
122
  controller.url_options
122
123
  end
123
124
 
124
- def _routes_context #:nodoc:
125
- controller
126
- end
127
- protected :_routes_context
125
+ private
126
+ def _routes_context
127
+ controller
128
+ end
128
129
 
129
- def optimize_routes_generation? #:nodoc:
130
- controller.respond_to?(:optimize_routes_generation?, true) ?
131
- controller.optimize_routes_generation? : super
132
- end
133
- protected :optimize_routes_generation?
130
+ def optimize_routes_generation?
131
+ controller.respond_to?(:optimize_routes_generation?, true) ?
132
+ controller.optimize_routes_generation? : super
133
+ end
134
+
135
+ def _generate_paths_by_default
136
+ true
137
+ end
138
+
139
+ def only_path?(host)
140
+ _generate_paths_by_default unless host
141
+ end
134
142
  end
135
143
  end
@@ -0,0 +1,23 @@
1
+ namespace :cache_digests do
2
+ desc "Lookup nested dependencies for TEMPLATE (like messages/show or comments/_comment.html)"
3
+ task nested_dependencies: :environment do
4
+ abort "You must provide TEMPLATE for the task to run" unless ENV["TEMPLATE"].present?
5
+ puts JSON.pretty_generate ActionView::Digestor.tree(CacheDigests.template_name, CacheDigests.finder).children.map(&:to_dep_map)
6
+ end
7
+
8
+ desc "Lookup first-level dependencies for TEMPLATE (like messages/show or comments/_comment.html)"
9
+ task dependencies: :environment do
10
+ abort "You must provide TEMPLATE for the task to run" unless ENV["TEMPLATE"].present?
11
+ puts JSON.pretty_generate ActionView::Digestor.tree(CacheDigests.template_name, CacheDigests.finder).children.map(&:name)
12
+ end
13
+
14
+ class CacheDigests
15
+ def self.template_name
16
+ ENV["TEMPLATE"].split(".", 2).first
17
+ end
18
+
19
+ def self.finder
20
+ ApplicationController.new.lookup_context
21
+ end
22
+ end
23
+ end
@@ -35,10 +35,10 @@ module ActionView
35
35
  prefixes = Array(prefixes)
36
36
  template_type = if partial
37
37
  "partial"
38
- elsif path =~ /layouts/i
39
- 'layout'
38
+ elsif /layouts/i.match?(path)
39
+ "layout"
40
40
  else
41
- 'template'
41
+ "template"
42
42
  end
43
43
 
44
44
  if partial && path.present?
@@ -59,13 +59,14 @@ module ActionView
59
59
  class Error < ActionViewError #:nodoc:
60
60
  SOURCE_CODE_RADIUS = 3
61
61
 
62
- attr_reader :original_exception
62
+ # Override to prevent #cause resetting during re-raise.
63
+ attr_reader :cause
63
64
 
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)
65
+ def initialize(template)
66
+ super($!.message)
67
+ set_backtrace($!.backtrace)
68
+ @cause = $!
69
+ @template, @sub_templates = template, nil
69
70
  end
70
71
 
71
72
  def file_name
@@ -75,7 +76,7 @@ module ActionView
75
76
  def sub_template_message
76
77
  if @sub_templates
77
78
  "Trace of template inclusion: " +
78
- @sub_templates.collect { |template| template.inspect }.join(", ")
79
+ @sub_templates.collect(&:inspect).join(", ")
79
80
  else
80
81
  ""
81
82
  end
@@ -119,18 +120,18 @@ module ActionView
119
120
  if line_number
120
121
  "on line ##{line_number} of "
121
122
  else
122
- 'in '
123
+ "in "
123
124
  end + file_name
124
125
  end
125
126
 
126
127
  def formatted_code_for(source_code, line_counter, indent, output)
127
- start_value = (output == :html) ? {} : ""
128
+ start_value = (output == :html) ? {} : []
128
129
  source_code.inject(start_value) do |result, line|
129
130
  line_counter += 1
130
131
  if output == :html
131
132
  result.update(line_counter.to_s => "%#{indent}s %s\n" % ["", line])
132
133
  else
133
- result << "%#{indent}s: %s\n" % [line_counter, line]
134
+ result << "%#{indent}s: %s" % [line_counter, line]
134
135
  end
135
136
  end
136
137
  end
@@ -7,20 +7,20 @@ module ActionView
7
7
 
8
8
  def call(template)
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
12
  template.source +
13
13
  ";xml.target!;"
14
14
  end
15
15
 
16
- protected
16
+ private
17
17
 
18
- def require_engine
19
- @required ||= begin
20
- require "builder"
21
- true
18
+ def require_engine # :doc:
19
+ @required ||= begin
20
+ require "builder"
21
+ true
22
+ end
22
23
  end
23
- end
24
24
  end
25
25
  end
26
26
  end
@@ -0,0 +1,9 @@
1
+ ::ActiveSupport::Deprecation.warn("ActionView::Template::Handlers::Erubis is deprecated and will be removed from Rails 5.2. Switch to ActionView::Template::Handlers::ERB::Erubi instead.")
2
+
3
+ module ActionView
4
+ class Template
5
+ module Handlers
6
+ Erubis = ERB::Erubis
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,81 @@
1
+ require "erubi"
2
+
3
+ module ActionView
4
+ class Template
5
+ module Handlers
6
+ class ERB
7
+ class Erubi < ::Erubi::Engine
8
+ # :nodoc: all
9
+ def initialize(input, properties = {})
10
+ @newline_pending = 0
11
+
12
+ # Dup properties so that we don't modify argument
13
+ properties = Hash[properties]
14
+ properties[:preamble] = "@output_buffer = output_buffer || ActionView::OutputBuffer.new;"
15
+ properties[:postamble] = "@output_buffer.to_s"
16
+ properties[:bufvar] = "@output_buffer"
17
+ properties[:escapefunc] = ""
18
+
19
+ super
20
+ end
21
+
22
+ def evaluate(action_view_erb_handler_context)
23
+ pr = eval("proc { #{@src} }", binding, @filename || "(erubi)")
24
+ action_view_erb_handler_context.instance_eval(&pr)
25
+ end
26
+
27
+ private
28
+ def add_text(text)
29
+ return if text.empty?
30
+
31
+ if text == "\n"
32
+ @newline_pending += 1
33
+ else
34
+ src << "@output_buffer.safe_append='"
35
+ src << "\n" * @newline_pending if @newline_pending > 0
36
+ src << text.gsub(/['\\]/, '\\\\\&')
37
+ src << "'.freeze;"
38
+
39
+ @newline_pending = 0
40
+ end
41
+ end
42
+
43
+ BLOCK_EXPR = /\s*((\s+|\))do|\{)(\s*\|[^|]*\|)?\s*\Z/
44
+
45
+ def add_expression(indicator, code)
46
+ flush_newline_if_pending(src)
47
+
48
+ if (indicator == "==") || @escape
49
+ src << "@output_buffer.safe_expr_append="
50
+ else
51
+ src << "@output_buffer.append="
52
+ end
53
+
54
+ if BLOCK_EXPR.match?(code)
55
+ src << " " << code
56
+ else
57
+ src << "(" << code << ");"
58
+ end
59
+ end
60
+
61
+ def add_code(code)
62
+ flush_newline_if_pending(src)
63
+ super
64
+ end
65
+
66
+ def add_postamble(_)
67
+ flush_newline_if_pending(src)
68
+ super
69
+ end
70
+
71
+ def flush_newline_if_pending(src)
72
+ if @newline_pending > 0
73
+ src << "@output_buffer.safe_append='#{"\n" * @newline_pending}'.freeze;"
74
+ @newline_pending = 0
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end