actionview 6.1.3.2 → 7.0.0.alpha2
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +99 -262
- data/MIT-LICENSE +1 -1
- data/lib/action_view/base.rb +3 -3
- data/lib/action_view/buffers.rb +2 -2
- data/lib/action_view/cache_expiry.rb +46 -32
- data/lib/action_view/dependency_tracker/erb_tracker.rb +154 -0
- data/lib/action_view/dependency_tracker/ripper_tracker.rb +59 -0
- data/lib/action_view/dependency_tracker.rb +6 -147
- data/lib/action_view/digestor.rb +7 -4
- data/lib/action_view/flows.rb +4 -4
- data/lib/action_view/gem_version.rb +4 -4
- data/lib/action_view/helpers/active_model_helper.rb +1 -1
- data/lib/action_view/helpers/asset_tag_helper.rb +85 -30
- data/lib/action_view/helpers/asset_url_helper.rb +7 -7
- data/lib/action_view/helpers/atom_feed_helper.rb +3 -4
- data/lib/action_view/helpers/cache_helper.rb +51 -3
- data/lib/action_view/helpers/capture_helper.rb +2 -2
- data/lib/action_view/helpers/controller_helper.rb +2 -2
- data/lib/action_view/helpers/csp_helper.rb +1 -1
- data/lib/action_view/helpers/csrf_helper.rb +1 -1
- data/lib/action_view/helpers/date_helper.rb +5 -5
- data/lib/action_view/helpers/debug_helper.rb +3 -1
- data/lib/action_view/helpers/form_helper.rb +72 -12
- data/lib/action_view/helpers/form_options_helper.rb +65 -33
- data/lib/action_view/helpers/form_tag_helper.rb +73 -30
- data/lib/action_view/helpers/javascript_helper.rb +3 -5
- data/lib/action_view/helpers/number_helper.rb +3 -4
- data/lib/action_view/helpers/output_safety_helper.rb +2 -2
- data/lib/action_view/helpers/rendering_helper.rb +1 -1
- data/lib/action_view/helpers/sanitize_helper.rb +2 -2
- data/lib/action_view/helpers/tag_helper.rb +17 -4
- data/lib/action_view/helpers/tags/base.rb +2 -14
- data/lib/action_view/helpers/tags/check_box.rb +1 -1
- data/lib/action_view/helpers/tags/collection_select.rb +1 -1
- data/lib/action_view/helpers/tags/time_field.rb +10 -1
- data/lib/action_view/helpers/tags/weekday_select.rb +27 -0
- data/lib/action_view/helpers/tags.rb +3 -2
- data/lib/action_view/helpers/text_helper.rb +24 -13
- data/lib/action_view/helpers/translation_helper.rb +4 -3
- data/lib/action_view/helpers/url_helper.rb +122 -80
- data/lib/action_view/helpers.rb +25 -25
- data/lib/action_view/lookup_context.rb +33 -52
- data/lib/action_view/model_naming.rb +1 -1
- data/lib/action_view/path_set.rb +16 -22
- data/lib/action_view/railtie.rb +15 -2
- data/lib/action_view/render_parser.rb +188 -0
- data/lib/action_view/renderer/abstract_renderer.rb +2 -2
- data/lib/action_view/renderer/partial_renderer.rb +0 -34
- data/lib/action_view/renderer/renderer.rb +4 -4
- data/lib/action_view/renderer/streaming_template_renderer.rb +3 -3
- data/lib/action_view/renderer/template_renderer.rb +6 -2
- data/lib/action_view/rendering.rb +2 -2
- data/lib/action_view/ripper_ast_parser.rb +198 -0
- data/lib/action_view/routing_url_for.rb +1 -1
- data/lib/action_view/template/error.rb +108 -13
- data/lib/action_view/template/handlers/erb.rb +6 -0
- data/lib/action_view/template/handlers.rb +3 -3
- data/lib/action_view/template/html.rb +3 -3
- data/lib/action_view/template/inline.rb +3 -3
- data/lib/action_view/template/raw_file.rb +3 -3
- data/lib/action_view/template/resolver.rb +84 -311
- data/lib/action_view/template/text.rb +3 -3
- data/lib/action_view/template/types.rb +14 -12
- data/lib/action_view/template.rb +10 -1
- data/lib/action_view/template_details.rb +66 -0
- data/lib/action_view/template_path.rb +64 -0
- data/lib/action_view/test_case.rb +6 -2
- data/lib/action_view/testing/resolvers.rb +11 -12
- data/lib/action_view/unbound_template.rb +33 -7
- data/lib/action_view.rb +3 -4
- data/lib/assets/compiled/rails-ujs.js +2 -2
- metadata +25 -18
@@ -18,7 +18,7 @@ module ActionView
|
|
18
18
|
# renderer object of the correct type is created, and the +render+ method on
|
19
19
|
# that new object is called in turn. This abstracts the set up and rendering
|
20
20
|
# into a separate classes for partials and templates.
|
21
|
-
class AbstractRenderer
|
21
|
+
class AbstractRenderer # :nodoc:
|
22
22
|
delegate :template_exists?, :any_templates?, :formats, to: :@lookup_context
|
23
23
|
|
24
24
|
def initialize(lookup_context)
|
@@ -158,7 +158,7 @@ module ActionView
|
|
158
158
|
|
159
159
|
def extract_details(options) # :doc:
|
160
160
|
details = nil
|
161
|
-
|
161
|
+
LookupContext.registered_details.each do |key|
|
162
162
|
value = options[key]
|
163
163
|
|
164
164
|
if value
|
@@ -217,40 +217,6 @@ module ActionView
|
|
217
217
|
# </div>
|
218
218
|
#
|
219
219
|
# As you can see, the <tt>:locals</tt> hash is shared between both the partial and its layout.
|
220
|
-
#
|
221
|
-
# If you pass arguments to "yield" then this will be passed to the block. One way to use this is to pass
|
222
|
-
# an array to layout and treat it as an enumerable.
|
223
|
-
#
|
224
|
-
# <%# app/views/users/_user.html.erb %>
|
225
|
-
# <div class="user">
|
226
|
-
# Budget: $<%= user.budget %>
|
227
|
-
# <%= yield user %>
|
228
|
-
# </div>
|
229
|
-
#
|
230
|
-
# <%# app/views/users/index.html.erb %>
|
231
|
-
# <%= render layout: @users do |user| %>
|
232
|
-
# Title: <%= user.title %>
|
233
|
-
# <% end %>
|
234
|
-
#
|
235
|
-
# This will render the layout for each user and yield to the block, passing the user, each time.
|
236
|
-
#
|
237
|
-
# You can also yield multiple times in one layout and use block arguments to differentiate the sections.
|
238
|
-
#
|
239
|
-
# <%# app/views/users/_user.html.erb %>
|
240
|
-
# <div class="user">
|
241
|
-
# <%= yield user, :header %>
|
242
|
-
# Budget: $<%= user.budget %>
|
243
|
-
# <%= yield user, :footer %>
|
244
|
-
# </div>
|
245
|
-
#
|
246
|
-
# <%# app/views/users/index.html.erb %>
|
247
|
-
# <%= render layout: @users do |user, section| %>
|
248
|
-
# <%- case section when :header -%>
|
249
|
-
# Title: <%= user.title %>
|
250
|
-
# <%- when :footer -%>
|
251
|
-
# Deadline: <%= user.deadline %>
|
252
|
-
# <%- end -%>
|
253
|
-
# <% end %>
|
254
220
|
class PartialRenderer < AbstractRenderer
|
255
221
|
include CollectionCaching
|
256
222
|
|
@@ -44,12 +44,12 @@ module ActionView
|
|
44
44
|
end
|
45
45
|
|
46
46
|
# Direct access to template rendering.
|
47
|
-
def render_template(context, options)
|
47
|
+
def render_template(context, options) # :nodoc:
|
48
48
|
render_template_to_object(context, options).body
|
49
49
|
end
|
50
50
|
|
51
51
|
# Direct access to partial rendering.
|
52
|
-
def render_partial(context, options, &block)
|
52
|
+
def render_partial(context, options, &block) # :nodoc:
|
53
53
|
render_partial_to_object(context, options, &block).body
|
54
54
|
end
|
55
55
|
|
@@ -57,11 +57,11 @@ module ActionView
|
|
57
57
|
@cache_hits ||= {}
|
58
58
|
end
|
59
59
|
|
60
|
-
def render_template_to_object(context, options)
|
60
|
+
def render_template_to_object(context, options) # :nodoc:
|
61
61
|
TemplateRenderer.new(@lookup_context).render(context, options)
|
62
62
|
end
|
63
63
|
|
64
|
-
def render_partial_to_object(context, options, &block)
|
64
|
+
def render_partial_to_object(context, options, &block) # :nodoc:
|
65
65
|
partial = options[:partial]
|
66
66
|
if String === partial
|
67
67
|
collection = collection_from_options(options)
|
@@ -7,11 +7,11 @@ module ActionView
|
|
7
7
|
#
|
8
8
|
# * Support streaming from child templates, partials and so on.
|
9
9
|
# * Rack::Cache needs to support streaming bodies
|
10
|
-
class StreamingTemplateRenderer < TemplateRenderer
|
10
|
+
class StreamingTemplateRenderer < TemplateRenderer # :nodoc:
|
11
11
|
# A valid Rack::Body (i.e. it responds to each).
|
12
12
|
# It is initialized with a block that, when called, starts
|
13
13
|
# rendering the template.
|
14
|
-
class Body
|
14
|
+
class Body # :nodoc:
|
15
15
|
def initialize(&start)
|
16
16
|
@start = start
|
17
17
|
end
|
@@ -42,7 +42,7 @@ module ActionView
|
|
42
42
|
# For streaming, instead of rendering a given a template, we return a Body
|
43
43
|
# object that responds to each. This object is initialized with a block
|
44
44
|
# that knows how to render the template.
|
45
|
-
def render_template(view, template, layout_name = nil, locals = {})
|
45
|
+
def render_template(view, template, layout_name = nil, locals = {}) # :nodoc:
|
46
46
|
return [super.body] unless layout_name && template.supports_streaming?
|
47
47
|
|
48
48
|
locals ||= {}
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActionView
|
4
|
-
class TemplateRenderer < AbstractRenderer
|
4
|
+
class TemplateRenderer < AbstractRenderer # :nodoc:
|
5
5
|
def render(context, options)
|
6
6
|
@details = extract_details(options)
|
7
7
|
template = determine_template(options)
|
@@ -26,7 +26,11 @@ module ActionView
|
|
26
26
|
if File.exist?(options[:file])
|
27
27
|
Template::RawFile.new(options[:file])
|
28
28
|
else
|
29
|
-
|
29
|
+
if Pathname.new(options[:file]).absolute?
|
30
|
+
raise ArgumentError, "File #{options[:file]} does not exist"
|
31
|
+
else
|
32
|
+
raise ArgumentError, "`render file:` should be given the absolute path to a file. '#{options[:file]}' was given instead"
|
33
|
+
end
|
30
34
|
end
|
31
35
|
elsif options.key?(:inline)
|
32
36
|
handler = Template.handler_for_extension(options[:type] || "erb")
|
@@ -5,7 +5,7 @@ require "action_view/view_paths"
|
|
5
5
|
module ActionView
|
6
6
|
# This is a class to fix I18n global state. Whenever you provide I18n.locale during a request,
|
7
7
|
# it will trigger the lookup_context and consequently expire the cache.
|
8
|
-
class I18nProxy < ::I18n::Config
|
8
|
+
class I18nProxy < ::I18n::Config # :nodoc:
|
9
9
|
attr_reader :original_config, :lookup_context
|
10
10
|
|
11
11
|
def initialize(original_config, lookup_context)
|
@@ -34,7 +34,7 @@ module ActionView
|
|
34
34
|
end
|
35
35
|
|
36
36
|
# Overwrite process to set up I18n proxy.
|
37
|
-
def process(*)
|
37
|
+
def process(*) # :nodoc:
|
38
38
|
old_config, I18n.config = I18n.config, I18nProxy.new(I18n.config, lookup_context)
|
39
39
|
super
|
40
40
|
ensure
|
@@ -0,0 +1,198 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "ripper"
|
4
|
+
|
5
|
+
module ActionView
|
6
|
+
class RenderParser
|
7
|
+
module RipperASTParser # :nodoc:
|
8
|
+
class Node < ::Array # :nodoc:
|
9
|
+
attr_reader :type
|
10
|
+
|
11
|
+
def initialize(type, arr, opts = {})
|
12
|
+
@type = type
|
13
|
+
super(arr)
|
14
|
+
end
|
15
|
+
|
16
|
+
def children
|
17
|
+
to_a
|
18
|
+
end
|
19
|
+
|
20
|
+
def inspect
|
21
|
+
typeinfo = type && type != :list ? ":" + type.to_s + ", " : ""
|
22
|
+
"s(" + typeinfo + map(&:inspect).join(", ") + ")"
|
23
|
+
end
|
24
|
+
|
25
|
+
def fcall?
|
26
|
+
type == :command || type == :fcall
|
27
|
+
end
|
28
|
+
|
29
|
+
def fcall_named?(name)
|
30
|
+
fcall? &&
|
31
|
+
self[0].type == :@ident &&
|
32
|
+
self[0][0] == name
|
33
|
+
end
|
34
|
+
|
35
|
+
def argument_nodes
|
36
|
+
raise unless fcall?
|
37
|
+
return [] if self[1].nil?
|
38
|
+
if self[1].last == false || self[1].last.type == :vcall
|
39
|
+
self[1][0...-1]
|
40
|
+
else
|
41
|
+
self[1][0..-1]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def string?
|
46
|
+
type == :string_literal
|
47
|
+
end
|
48
|
+
|
49
|
+
def variable_reference?
|
50
|
+
type == :var_ref
|
51
|
+
end
|
52
|
+
|
53
|
+
def vcall?
|
54
|
+
type == :vcall
|
55
|
+
end
|
56
|
+
|
57
|
+
def call?
|
58
|
+
type == :call
|
59
|
+
end
|
60
|
+
|
61
|
+
def variable_name
|
62
|
+
self[0][0]
|
63
|
+
end
|
64
|
+
|
65
|
+
def call_method_name
|
66
|
+
self.last.first
|
67
|
+
end
|
68
|
+
|
69
|
+
def to_string
|
70
|
+
raise unless string?
|
71
|
+
self[0][0][0]
|
72
|
+
end
|
73
|
+
|
74
|
+
def hash?
|
75
|
+
type == :bare_assoc_hash || type == :hash
|
76
|
+
end
|
77
|
+
|
78
|
+
def to_hash
|
79
|
+
if type == :bare_assoc_hash
|
80
|
+
hash_from_body(self[0])
|
81
|
+
elsif type == :hash && self[0] == nil
|
82
|
+
{}
|
83
|
+
elsif type == :hash && self[0].type == :assoclist_from_args
|
84
|
+
hash_from_body(self[0][0])
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def hash_from_body(body)
|
89
|
+
body.map do |hash_node|
|
90
|
+
return nil if hash_node.type != :assoc_new
|
91
|
+
|
92
|
+
[hash_node[0], hash_node[1]]
|
93
|
+
end.to_h
|
94
|
+
end
|
95
|
+
|
96
|
+
def symbol?
|
97
|
+
type == :@label || type == :symbol_literal
|
98
|
+
end
|
99
|
+
|
100
|
+
def to_symbol
|
101
|
+
if type == :@label && self[0] =~ /\A(.+):\z/
|
102
|
+
$1.to_sym
|
103
|
+
elsif type == :symbol_literal && self[0].type == :symbol && self[0][0].type == :@ident
|
104
|
+
self[0][0][0].to_sym
|
105
|
+
else
|
106
|
+
raise "not a symbol?: #{self.inspect}"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
class NodeParser < ::Ripper # :nodoc:
|
112
|
+
PARSER_EVENTS.each do |event|
|
113
|
+
arity = PARSER_EVENT_TABLE[event]
|
114
|
+
if arity == 0 && event.to_s.end_with?("_new")
|
115
|
+
module_eval(<<-eof, __FILE__, __LINE__ + 1)
|
116
|
+
def on_#{event}(*args)
|
117
|
+
Node.new(:list, args, lineno: lineno(), column: column())
|
118
|
+
end
|
119
|
+
eof
|
120
|
+
elsif event.to_s.match?(/_add(_.+)?\z/)
|
121
|
+
module_eval(<<-eof, __FILE__, __LINE__ + 1)
|
122
|
+
begin; undef on_#{event}; rescue NameError; end
|
123
|
+
def on_#{event}(list, item)
|
124
|
+
list.push(item)
|
125
|
+
list
|
126
|
+
end
|
127
|
+
eof
|
128
|
+
else
|
129
|
+
module_eval(<<-eof, __FILE__, __LINE__ + 1)
|
130
|
+
begin; undef on_#{event}; rescue NameError; end
|
131
|
+
def on_#{event}(*args)
|
132
|
+
Node.new(:#{event}, args, lineno: lineno(), column: column())
|
133
|
+
end
|
134
|
+
eof
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
SCANNER_EVENTS.each do |event|
|
139
|
+
module_eval(<<-End, __FILE__, __LINE__ + 1)
|
140
|
+
def on_#{event}(tok)
|
141
|
+
Node.new(:@#{event}, [tok], lineno: lineno(), column: column())
|
142
|
+
end
|
143
|
+
End
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
class RenderCallExtractor < NodeParser # :nodoc:
|
148
|
+
attr_reader :render_calls
|
149
|
+
|
150
|
+
METHODS_TO_PARSE = %w(render render_to_string)
|
151
|
+
|
152
|
+
def initialize(*args)
|
153
|
+
super
|
154
|
+
|
155
|
+
@render_calls = []
|
156
|
+
end
|
157
|
+
|
158
|
+
private
|
159
|
+
def on_fcall(name, *args)
|
160
|
+
on_render_call(super)
|
161
|
+
end
|
162
|
+
|
163
|
+
def on_command(name, *args)
|
164
|
+
on_render_call(super)
|
165
|
+
end
|
166
|
+
|
167
|
+
def on_render_call(node)
|
168
|
+
METHODS_TO_PARSE.each do |method|
|
169
|
+
if node.fcall_named?(method)
|
170
|
+
@render_calls << [method, node]
|
171
|
+
return node
|
172
|
+
end
|
173
|
+
end
|
174
|
+
node
|
175
|
+
end
|
176
|
+
|
177
|
+
def on_arg_paren(content)
|
178
|
+
content
|
179
|
+
end
|
180
|
+
|
181
|
+
def on_paren(content)
|
182
|
+
content
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
extend self
|
187
|
+
|
188
|
+
def parse_render_nodes(code)
|
189
|
+
parser = RenderCallExtractor.new(code)
|
190
|
+
parser.parse
|
191
|
+
|
192
|
+
parser.render_calls.group_by(&:first).collect do |method, nodes|
|
193
|
+
[ method.to_sym, nodes.collect { |v| v[1] } ]
|
194
|
+
end.to_h
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
@@ -4,13 +4,13 @@ require "active_support/core_ext/enumerable"
|
|
4
4
|
|
5
5
|
module ActionView
|
6
6
|
# = Action View Errors
|
7
|
-
class ActionViewError < StandardError
|
7
|
+
class ActionViewError < StandardError # :nodoc:
|
8
8
|
end
|
9
9
|
|
10
|
-
class EncodingError < StandardError
|
10
|
+
class EncodingError < StandardError # :nodoc:
|
11
11
|
end
|
12
12
|
|
13
|
-
class WrongEncodingError < EncodingError
|
13
|
+
class WrongEncodingError < EncodingError # :nodoc:
|
14
14
|
def initialize(string, encoding)
|
15
15
|
@string, @encoding = string, encoding
|
16
16
|
end
|
@@ -26,12 +26,18 @@ module ActionView
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
-
class MissingTemplate < ActionViewError
|
30
|
-
attr_reader :path
|
29
|
+
class MissingTemplate < ActionViewError # :nodoc:
|
30
|
+
attr_reader :path, :paths, :prefixes, :partial
|
31
31
|
|
32
32
|
def initialize(paths, path, prefixes, partial, details, *)
|
33
|
+
if partial && path.present?
|
34
|
+
path = path.sub(%r{([^/]+)$}, "_\\1")
|
35
|
+
end
|
36
|
+
|
33
37
|
@path = path
|
34
|
-
|
38
|
+
@paths = paths
|
39
|
+
@prefixes = Array(prefixes)
|
40
|
+
@partial = partial
|
35
41
|
template_type = if partial
|
36
42
|
"partial"
|
37
43
|
elsif /layouts/i.match?(path)
|
@@ -40,22 +46,111 @@ module ActionView
|
|
40
46
|
"template"
|
41
47
|
end
|
42
48
|
|
43
|
-
|
44
|
-
path = path.sub(%r{([^/]+)$}, "_\\1")
|
45
|
-
end
|
46
|
-
searched_paths = prefixes.map { |prefix| [prefix, path].join("/") }
|
49
|
+
searched_paths = @prefixes.map { |prefix| [prefix, path].join("/") }
|
47
50
|
|
48
|
-
out = "Missing #{template_type} #{searched_paths.join(", ")} with #{details.inspect}
|
51
|
+
out = "Missing #{template_type} #{searched_paths.join(", ")} with #{details.inspect}.\n\nSearched in:\n"
|
49
52
|
out += paths.compact.map { |p| " * #{p.to_s.inspect}\n" }.join
|
50
53
|
super out
|
51
54
|
end
|
55
|
+
|
56
|
+
if defined?(DidYouMean::Correctable) && defined?(DidYouMean::Jaro)
|
57
|
+
include DidYouMean::Correctable
|
58
|
+
|
59
|
+
class Results # :nodoc:
|
60
|
+
Result = Struct.new(:path, :score)
|
61
|
+
|
62
|
+
def initialize(size)
|
63
|
+
@size = size
|
64
|
+
@results = []
|
65
|
+
end
|
66
|
+
|
67
|
+
def to_a
|
68
|
+
@results.map(&:path)
|
69
|
+
end
|
70
|
+
|
71
|
+
def should_record?(score)
|
72
|
+
if @results.size < @size
|
73
|
+
true
|
74
|
+
else
|
75
|
+
score < @results.last.score
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def add(path, score)
|
80
|
+
if should_record?(score)
|
81
|
+
@results << Result.new(path, score)
|
82
|
+
@results.sort_by!(&:score)
|
83
|
+
@results.pop if @results.size > @size
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Apps may have thousands of candidate templates so we attempt to
|
89
|
+
# generate the suggestions as efficiently as possible.
|
90
|
+
# First we split templates into prefixes and basenames, so that those can
|
91
|
+
# be matched separately.
|
92
|
+
def corrections
|
93
|
+
candidates = paths.flat_map(&:all_template_paths).uniq
|
94
|
+
|
95
|
+
if partial
|
96
|
+
candidates.select!(&:partial?)
|
97
|
+
else
|
98
|
+
candidates.reject!(&:partial?)
|
99
|
+
end
|
100
|
+
|
101
|
+
# Group by possible prefixes
|
102
|
+
files_by_dir = candidates.group_by(&:prefix)
|
103
|
+
files_by_dir.transform_values! do |files|
|
104
|
+
files.map do |file|
|
105
|
+
# Remove prefix
|
106
|
+
File.basename(file.to_s)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# No suggestions if there's an exact match, but wrong details
|
111
|
+
if prefixes.any? { |prefix| files_by_dir[prefix]&.include?(path) }
|
112
|
+
return []
|
113
|
+
end
|
114
|
+
|
115
|
+
cached_distance = Hash.new do |h, args|
|
116
|
+
h[args] = -DidYouMean::Jaro.distance(*args)
|
117
|
+
end
|
118
|
+
|
119
|
+
results = Results.new(6)
|
120
|
+
|
121
|
+
files_by_dir.keys.index_with do |dirname|
|
122
|
+
prefixes.map do |prefix|
|
123
|
+
cached_distance[[prefix, dirname]]
|
124
|
+
end.min
|
125
|
+
end.sort_by(&:last).each do |dirname, dirweight|
|
126
|
+
# If our directory's score makes it impossible to find a better match
|
127
|
+
# we can prune this search branch.
|
128
|
+
next unless results.should_record?(dirweight - 1.0)
|
129
|
+
|
130
|
+
files = files_by_dir[dirname]
|
131
|
+
|
132
|
+
files.each do |file|
|
133
|
+
fileweight = cached_distance[[path, file]]
|
134
|
+
score = dirweight + fileweight
|
135
|
+
|
136
|
+
results.add(File.join(dirname, file), score)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
if partial
|
141
|
+
results.to_a.map { |res| res.sub(%r{_([^/]+)\z}, "\\1") }
|
142
|
+
else
|
143
|
+
results.to_a
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
52
147
|
end
|
53
148
|
|
54
149
|
class Template
|
55
150
|
# The Template::Error exception is raised when the compilation or rendering of the template
|
56
151
|
# fails. This exception then gathers a bunch of intimate details and uses it to report a
|
57
152
|
# precise exception message.
|
58
|
-
class Error < ActionViewError
|
153
|
+
class Error < ActionViewError # :nodoc:
|
59
154
|
SOURCE_CODE_RADIUS = 3
|
60
155
|
|
61
156
|
# Override to prevent #cause resetting during re-raise.
|
@@ -134,7 +229,7 @@ module ActionView
|
|
134
229
|
|
135
230
|
TemplateError = Template::Error
|
136
231
|
|
137
|
-
class SyntaxErrorInTemplate < TemplateError
|
232
|
+
class SyntaxErrorInTemplate < TemplateError # :nodoc:
|
138
233
|
def initialize(template, offending_code_string)
|
139
234
|
@offending_code_string = offending_code_string
|
140
235
|
super(template)
|