actionview 6.0.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 (113) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +271 -0
  3. data/MIT-LICENSE +21 -0
  4. data/README.rdoc +40 -0
  5. data/lib/action_view.rb +98 -0
  6. data/lib/action_view/base.rb +312 -0
  7. data/lib/action_view/buffers.rb +67 -0
  8. data/lib/action_view/cache_expiry.rb +54 -0
  9. data/lib/action_view/context.rb +32 -0
  10. data/lib/action_view/dependency_tracker.rb +175 -0
  11. data/lib/action_view/digestor.rb +126 -0
  12. data/lib/action_view/flows.rb +76 -0
  13. data/lib/action_view/gem_version.rb +17 -0
  14. data/lib/action_view/helpers.rb +66 -0
  15. data/lib/action_view/helpers/active_model_helper.rb +55 -0
  16. data/lib/action_view/helpers/asset_tag_helper.rb +488 -0
  17. data/lib/action_view/helpers/asset_url_helper.rb +470 -0
  18. data/lib/action_view/helpers/atom_feed_helper.rb +205 -0
  19. data/lib/action_view/helpers/cache_helper.rb +271 -0
  20. data/lib/action_view/helpers/capture_helper.rb +216 -0
  21. data/lib/action_view/helpers/controller_helper.rb +36 -0
  22. data/lib/action_view/helpers/csp_helper.rb +26 -0
  23. data/lib/action_view/helpers/csrf_helper.rb +35 -0
  24. data/lib/action_view/helpers/date_helper.rb +1200 -0
  25. data/lib/action_view/helpers/debug_helper.rb +36 -0
  26. data/lib/action_view/helpers/form_helper.rb +2569 -0
  27. data/lib/action_view/helpers/form_options_helper.rb +896 -0
  28. data/lib/action_view/helpers/form_tag_helper.rb +920 -0
  29. data/lib/action_view/helpers/javascript_helper.rb +95 -0
  30. data/lib/action_view/helpers/number_helper.rb +456 -0
  31. data/lib/action_view/helpers/output_safety_helper.rb +70 -0
  32. data/lib/action_view/helpers/rendering_helper.rb +101 -0
  33. data/lib/action_view/helpers/sanitize_helper.rb +171 -0
  34. data/lib/action_view/helpers/tag_helper.rb +314 -0
  35. data/lib/action_view/helpers/tags.rb +44 -0
  36. data/lib/action_view/helpers/tags/base.rb +196 -0
  37. data/lib/action_view/helpers/tags/check_box.rb +66 -0
  38. data/lib/action_view/helpers/tags/checkable.rb +18 -0
  39. data/lib/action_view/helpers/tags/collection_check_boxes.rb +36 -0
  40. data/lib/action_view/helpers/tags/collection_helpers.rb +119 -0
  41. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +31 -0
  42. data/lib/action_view/helpers/tags/collection_select.rb +30 -0
  43. data/lib/action_view/helpers/tags/color_field.rb +27 -0
  44. data/lib/action_view/helpers/tags/date_field.rb +15 -0
  45. data/lib/action_view/helpers/tags/date_select.rb +74 -0
  46. data/lib/action_view/helpers/tags/datetime_field.rb +32 -0
  47. data/lib/action_view/helpers/tags/datetime_local_field.rb +21 -0
  48. data/lib/action_view/helpers/tags/datetime_select.rb +10 -0
  49. data/lib/action_view/helpers/tags/email_field.rb +10 -0
  50. data/lib/action_view/helpers/tags/file_field.rb +10 -0
  51. data/lib/action_view/helpers/tags/grouped_collection_select.rb +31 -0
  52. data/lib/action_view/helpers/tags/hidden_field.rb +10 -0
  53. data/lib/action_view/helpers/tags/label.rb +81 -0
  54. data/lib/action_view/helpers/tags/month_field.rb +15 -0
  55. data/lib/action_view/helpers/tags/number_field.rb +20 -0
  56. data/lib/action_view/helpers/tags/password_field.rb +14 -0
  57. data/lib/action_view/helpers/tags/placeholderable.rb +24 -0
  58. data/lib/action_view/helpers/tags/radio_button.rb +33 -0
  59. data/lib/action_view/helpers/tags/range_field.rb +10 -0
  60. data/lib/action_view/helpers/tags/search_field.rb +27 -0
  61. data/lib/action_view/helpers/tags/select.rb +43 -0
  62. data/lib/action_view/helpers/tags/tel_field.rb +10 -0
  63. data/lib/action_view/helpers/tags/text_area.rb +24 -0
  64. data/lib/action_view/helpers/tags/text_field.rb +34 -0
  65. data/lib/action_view/helpers/tags/time_field.rb +15 -0
  66. data/lib/action_view/helpers/tags/time_select.rb +10 -0
  67. data/lib/action_view/helpers/tags/time_zone_select.rb +22 -0
  68. data/lib/action_view/helpers/tags/translator.rb +39 -0
  69. data/lib/action_view/helpers/tags/url_field.rb +10 -0
  70. data/lib/action_view/helpers/tags/week_field.rb +15 -0
  71. data/lib/action_view/helpers/text_helper.rb +486 -0
  72. data/lib/action_view/helpers/translation_helper.rb +145 -0
  73. data/lib/action_view/helpers/url_helper.rb +676 -0
  74. data/lib/action_view/layouts.rb +433 -0
  75. data/lib/action_view/locale/en.yml +56 -0
  76. data/lib/action_view/log_subscriber.rb +96 -0
  77. data/lib/action_view/lookup_context.rb +316 -0
  78. data/lib/action_view/model_naming.rb +14 -0
  79. data/lib/action_view/path_set.rb +95 -0
  80. data/lib/action_view/railtie.rb +105 -0
  81. data/lib/action_view/record_identifier.rb +112 -0
  82. data/lib/action_view/renderer/abstract_renderer.rb +108 -0
  83. data/lib/action_view/renderer/partial_renderer.rb +563 -0
  84. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +103 -0
  85. data/lib/action_view/renderer/renderer.rb +68 -0
  86. data/lib/action_view/renderer/streaming_template_renderer.rb +105 -0
  87. data/lib/action_view/renderer/template_renderer.rb +108 -0
  88. data/lib/action_view/rendering.rb +171 -0
  89. data/lib/action_view/routing_url_for.rb +146 -0
  90. data/lib/action_view/tasks/cache_digests.rake +25 -0
  91. data/lib/action_view/template.rb +393 -0
  92. data/lib/action_view/template/error.rb +161 -0
  93. data/lib/action_view/template/handlers.rb +92 -0
  94. data/lib/action_view/template/handlers/builder.rb +25 -0
  95. data/lib/action_view/template/handlers/erb.rb +84 -0
  96. data/lib/action_view/template/handlers/erb/erubi.rb +87 -0
  97. data/lib/action_view/template/handlers/html.rb +11 -0
  98. data/lib/action_view/template/handlers/raw.rb +11 -0
  99. data/lib/action_view/template/html.rb +43 -0
  100. data/lib/action_view/template/inline.rb +22 -0
  101. data/lib/action_view/template/raw_file.rb +28 -0
  102. data/lib/action_view/template/resolver.rb +394 -0
  103. data/lib/action_view/template/sources.rb +13 -0
  104. data/lib/action_view/template/sources/file.rb +17 -0
  105. data/lib/action_view/template/text.rb +35 -0
  106. data/lib/action_view/template/types.rb +57 -0
  107. data/lib/action_view/test_case.rb +300 -0
  108. data/lib/action_view/testing/resolvers.rb +67 -0
  109. data/lib/action_view/unbound_template.rb +32 -0
  110. data/lib/action_view/version.rb +10 -0
  111. data/lib/action_view/view_paths.rb +129 -0
  112. data/lib/assets/compiled/rails-ujs.js +746 -0
  113. metadata +260 -0
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/log_subscriber"
4
+
5
+ module ActionView
6
+ # = Action View Log Subscriber
7
+ #
8
+ # Provides functionality so that Rails can output logs from Action View.
9
+ class LogSubscriber < ActiveSupport::LogSubscriber
10
+ VIEWS_PATTERN = /^app\/views\//
11
+
12
+ def initialize
13
+ @root = nil
14
+ super
15
+ end
16
+
17
+ def render_template(event)
18
+ info do
19
+ message = +" Rendered #{from_rails_root(event.payload[:identifier])}"
20
+ message << " within #{from_rails_root(event.payload[:layout])}" if event.payload[:layout]
21
+ message << " (Duration: #{event.duration.round(1)}ms | Allocations: #{event.allocations})"
22
+ end
23
+ end
24
+
25
+ def render_partial(event)
26
+ info do
27
+ message = +" Rendered #{from_rails_root(event.payload[:identifier])}"
28
+ message << " within #{from_rails_root(event.payload[:layout])}" if event.payload[:layout]
29
+ message << " (Duration: #{event.duration.round(1)}ms | Allocations: #{event.allocations})"
30
+ message << " #{cache_message(event.payload)}" unless event.payload[:cache_hit].nil?
31
+ message
32
+ end
33
+ end
34
+
35
+ def render_collection(event)
36
+ identifier = event.payload[:identifier] || "templates"
37
+
38
+ info do
39
+ " Rendered collection of #{from_rails_root(identifier)}" \
40
+ " #{render_count(event.payload)} (Duration: #{event.duration.round(1)}ms | Allocations: #{event.allocations})"
41
+ end
42
+ end
43
+
44
+ def start(name, id, payload)
45
+ if name == "render_template.action_view"
46
+ log_rendering_start(payload)
47
+ end
48
+
49
+ super
50
+ end
51
+
52
+ def logger
53
+ ActionView::Base.logger
54
+ end
55
+
56
+ private
57
+
58
+ EMPTY = ""
59
+ def from_rails_root(string) # :doc:
60
+ string = string.sub(rails_root, EMPTY)
61
+ string.sub!(VIEWS_PATTERN, EMPTY)
62
+ string
63
+ end
64
+
65
+ def rails_root # :doc:
66
+ @root ||= "#{Rails.root}/"
67
+ end
68
+
69
+ def render_count(payload) # :doc:
70
+ if payload[:cache_hits]
71
+ "[#{payload[:cache_hits]} / #{payload[:count]} cache hits]"
72
+ else
73
+ "[#{payload[:count]} times]"
74
+ end
75
+ end
76
+
77
+ def cache_message(payload) # :doc:
78
+ case payload[:cache_hit]
79
+ when :hit
80
+ "[cache hit]"
81
+ when :miss
82
+ "[cache miss]"
83
+ end
84
+ end
85
+
86
+ def log_rendering_start(payload)
87
+ info do
88
+ message = +" Rendering #{from_rails_root(payload[:identifier])}"
89
+ message << " within #{from_rails_root(payload[:layout])}" if payload[:layout]
90
+ message
91
+ end
92
+ end
93
+ end
94
+ end
95
+
96
+ ActionView::LogSubscriber.attach_to :action_view
@@ -0,0 +1,316 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "concurrent/map"
4
+ require "active_support/core_ext/module/remove_method"
5
+ require "active_support/core_ext/module/attribute_accessors"
6
+ require "active_support/deprecation"
7
+ require "action_view/template/resolver"
8
+
9
+ module ActionView
10
+ # = Action View Lookup Context
11
+ #
12
+ # <tt>LookupContext</tt> is the object responsible for holding all information
13
+ # required for looking up templates, i.e. view paths and details.
14
+ # <tt>LookupContext</tt> is also responsible for generating a key, given to
15
+ # view paths, used in the resolver cache lookup. Since this key is generated
16
+ # only once during the request, it speeds up all cache accesses.
17
+ class LookupContext #:nodoc:
18
+ attr_accessor :prefixes, :rendered_format
19
+ deprecate :rendered_format
20
+ deprecate :rendered_format=
21
+
22
+ mattr_accessor :fallbacks, default: FallbackFileSystemResolver.instances
23
+
24
+ mattr_accessor :registered_details, default: []
25
+
26
+ def self.register_detail(name, &block)
27
+ registered_details << name
28
+ Accessors::DEFAULT_PROCS[name] = block
29
+
30
+ Accessors.define_method(:"default_#{name}", &block)
31
+ Accessors.module_eval <<-METHOD, __FILE__, __LINE__ + 1
32
+ def #{name}
33
+ @details.fetch(:#{name}, [])
34
+ end
35
+
36
+ def #{name}=(value)
37
+ value = value.present? ? Array(value) : default_#{name}
38
+ _set_detail(:#{name}, value) if value != @details[:#{name}]
39
+ end
40
+ METHOD
41
+ end
42
+
43
+ # Holds accessors for the registered details.
44
+ module Accessors #:nodoc:
45
+ DEFAULT_PROCS = {}
46
+ end
47
+
48
+ register_detail(:locale) do
49
+ locales = [I18n.locale]
50
+ locales.concat(I18n.fallbacks[I18n.locale]) if I18n.respond_to? :fallbacks
51
+ locales << I18n.default_locale
52
+ locales.uniq!
53
+ locales
54
+ end
55
+ register_detail(:formats) { ActionView::Base.default_formats || [:html, :text, :js, :css, :xml, :json] }
56
+ register_detail(:variants) { [] }
57
+ register_detail(:handlers) { Template::Handlers.extensions }
58
+
59
+ class DetailsKey #:nodoc:
60
+ alias :eql? :equal?
61
+
62
+ @details_keys = Concurrent::Map.new
63
+ @digest_cache = Concurrent::Map.new
64
+
65
+ def self.digest_cache(details)
66
+ @digest_cache[details_cache_key(details)] ||= Concurrent::Map.new
67
+ end
68
+
69
+ def self.details_cache_key(details)
70
+ if details[:formats]
71
+ details = details.dup
72
+ details[:formats] &= Template::Types.symbols
73
+ end
74
+ @details_keys[details] ||= Object.new
75
+ end
76
+
77
+ def self.clear
78
+ ActionView::ViewPaths.all_view_paths.each do |path_set|
79
+ path_set.each(&:clear_cache)
80
+ end
81
+ ActionView::LookupContext.fallbacks.each(&:clear_cache)
82
+ @view_context_class = nil
83
+ @details_keys.clear
84
+ @digest_cache.clear
85
+ end
86
+
87
+ def self.digest_caches
88
+ @digest_cache.values
89
+ end
90
+
91
+ def self.view_context_class(klass)
92
+ @view_context_class ||= klass.with_empty_template_cache
93
+ end
94
+ end
95
+
96
+ # Add caching behavior on top of Details.
97
+ module DetailsCache
98
+ attr_accessor :cache
99
+
100
+ # Calculate the details key. Remove the handlers from calculation to improve performance
101
+ # since the user cannot modify it explicitly.
102
+ def details_key #:nodoc:
103
+ @details_key ||= DetailsKey.details_cache_key(@details) if @cache
104
+ end
105
+
106
+ # Temporary skip passing the details_key forward.
107
+ def disable_cache
108
+ old_value, @cache = @cache, false
109
+ yield
110
+ ensure
111
+ @cache = old_value
112
+ end
113
+
114
+ private
115
+
116
+ def _set_detail(key, value) # :doc:
117
+ @details = @details.dup if @digest_cache || @details_key
118
+ @digest_cache = nil
119
+ @details_key = nil
120
+ @details[key] = value
121
+ end
122
+ end
123
+
124
+ # Helpers related to template lookup using the lookup context information.
125
+ module ViewPaths
126
+ attr_reader :view_paths, :html_fallback_for_js
127
+
128
+ def find(name, prefixes = [], partial = false, keys = [], options = {})
129
+ @view_paths.find(*args_for_lookup(name, prefixes, partial, keys, options))
130
+ end
131
+ alias :find_template :find
132
+
133
+ alias :find_file :find
134
+ deprecate :find_file
135
+
136
+ def find_all(name, prefixes = [], partial = false, keys = [], options = {})
137
+ @view_paths.find_all(*args_for_lookup(name, prefixes, partial, keys, options))
138
+ end
139
+
140
+ def exists?(name, prefixes = [], partial = false, keys = [], **options)
141
+ @view_paths.exists?(*args_for_lookup(name, prefixes, partial, keys, options))
142
+ end
143
+ alias :template_exists? :exists?
144
+
145
+ def any?(name, prefixes = [], partial = false)
146
+ @view_paths.exists?(*args_for_any(name, prefixes, partial))
147
+ end
148
+ alias :any_templates? :any?
149
+
150
+ # Adds fallbacks to the view paths. Useful in cases when you are rendering
151
+ # a :file.
152
+ def with_fallbacks
153
+ view_paths = build_view_paths((@view_paths.paths + self.class.fallbacks).uniq)
154
+
155
+ if block_given?
156
+ ActiveSupport::Deprecation.warn <<~eowarn.squish
157
+ Calling `with_fallbacks` with a block is deprecated. Call methods on
158
+ the lookup context returned by `with_fallbacks` instead.
159
+ eowarn
160
+
161
+ begin
162
+ _view_paths = @view_paths
163
+ @view_paths = view_paths
164
+ yield
165
+ ensure
166
+ @view_paths = _view_paths
167
+ end
168
+ else
169
+ ActionView::LookupContext.new(view_paths, @details, @prefixes)
170
+ end
171
+ end
172
+
173
+ private
174
+
175
+ # Whenever setting view paths, makes a copy so that we can manipulate them in
176
+ # instance objects as we wish.
177
+ def build_view_paths(paths)
178
+ ActionView::PathSet.new(Array(paths))
179
+ end
180
+
181
+ def args_for_lookup(name, prefixes, partial, keys, details_options)
182
+ name, prefixes = normalize_name(name, prefixes)
183
+ details, details_key = detail_args_for(details_options)
184
+ [name, prefixes, partial || false, details, details_key, keys]
185
+ end
186
+
187
+ # Compute details hash and key according to user options (e.g. passed from #render).
188
+ def detail_args_for(options) # :doc:
189
+ return @details, details_key if options.empty? # most common path.
190
+ user_details = @details.merge(options)
191
+
192
+ if @cache
193
+ details_key = DetailsKey.details_cache_key(user_details)
194
+ else
195
+ details_key = nil
196
+ end
197
+
198
+ [user_details, details_key]
199
+ end
200
+
201
+ def args_for_any(name, prefixes, partial)
202
+ name, prefixes = normalize_name(name, prefixes)
203
+ details, details_key = detail_args_for_any
204
+ [name, prefixes, partial || false, details, details_key]
205
+ end
206
+
207
+ def detail_args_for_any
208
+ @detail_args_for_any ||= begin
209
+ details = {}
210
+
211
+ registered_details.each do |k|
212
+ if k == :variants
213
+ details[k] = :any
214
+ else
215
+ details[k] = Accessors::DEFAULT_PROCS[k].call
216
+ end
217
+ end
218
+
219
+ if @cache
220
+ [details, DetailsKey.details_cache_key(details)]
221
+ else
222
+ [details, nil]
223
+ end
224
+ end
225
+ end
226
+
227
+ # Support legacy foo.erb names even though we now ignore .erb
228
+ # as well as incorrectly putting part of the path in the template
229
+ # name instead of the prefix.
230
+ def normalize_name(name, prefixes)
231
+ prefixes = prefixes.presence
232
+ parts = name.to_s.split("/")
233
+ parts.shift if parts.first.empty?
234
+ name = parts.pop
235
+
236
+ return name, prefixes || [""] if parts.empty?
237
+
238
+ parts = parts.join("/")
239
+ prefixes = prefixes ? prefixes.map { |p| "#{p}/#{parts}" } : [parts]
240
+
241
+ return name, prefixes
242
+ end
243
+ end
244
+
245
+ include Accessors
246
+ include DetailsCache
247
+ include ViewPaths
248
+
249
+ def initialize(view_paths, details = {}, prefixes = [])
250
+ @details_key = nil
251
+ @digest_cache = nil
252
+ @cache = true
253
+ @prefixes = prefixes
254
+
255
+ @details = initialize_details({}, details)
256
+ @view_paths = build_view_paths(view_paths)
257
+ end
258
+
259
+ def digest_cache
260
+ @digest_cache ||= DetailsKey.digest_cache(@details)
261
+ end
262
+
263
+ def with_prepended_formats(formats)
264
+ details = @details.dup
265
+ details[:formats] = formats
266
+
267
+ self.class.new(@view_paths, details, @prefixes)
268
+ end
269
+
270
+ def initialize_details(target, details)
271
+ registered_details.each do |k|
272
+ target[k] = details[k] || Accessors::DEFAULT_PROCS[k].call
273
+ end
274
+ target
275
+ end
276
+ private :initialize_details
277
+
278
+ # Override formats= to expand ["*/*"] values and automatically
279
+ # add :html as fallback to :js.
280
+ def formats=(values)
281
+ if values
282
+ values = values.dup
283
+ values.concat(default_formats) if values.delete "*/*"
284
+ values.uniq!
285
+
286
+ invalid_values = (values - Template::Types.symbols)
287
+ unless invalid_values.empty?
288
+ raise ArgumentError, "Invalid formats: #{invalid_values.map(&:inspect).join(", ")}"
289
+ end
290
+
291
+ if values == [:js]
292
+ values << :html
293
+ @html_fallback_for_js = true
294
+ end
295
+ end
296
+ super(values)
297
+ end
298
+
299
+ # Override locale to return a symbol instead of array.
300
+ def locale
301
+ @details[:locale].first
302
+ end
303
+
304
+ # Overload locale= to also set the I18n.locale. If the current I18n.config object responds
305
+ # to original_config, it means that it has a copy of the original I18n configuration and it's
306
+ # acting as proxy, which we need to skip.
307
+ def locale=(value)
308
+ if value
309
+ config = I18n.config.respond_to?(:original_config) ? I18n.config.original_config : I18n.config
310
+ config.locale = value
311
+ end
312
+
313
+ super(default_locale)
314
+ end
315
+ end
316
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionView
4
+ module ModelNaming #:nodoc:
5
+ # Converts the given object to an ActiveModel compliant one.
6
+ def convert_to_model(object)
7
+ object.respond_to?(:to_model) ? object.to_model : object
8
+ end
9
+
10
+ def model_name_from_record_or_class(record_or_class)
11
+ convert_to_model(record_or_class).model_name
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionView #:nodoc:
4
+ # = Action View PathSet
5
+ #
6
+ # This class is used to store and access paths in Action View. A number of
7
+ # operations are defined so that you can search among the paths in this
8
+ # set and also perform operations on other +PathSet+ objects.
9
+ #
10
+ # A +LookupContext+ will use a +PathSet+ to store the paths in its context.
11
+ class PathSet #:nodoc:
12
+ include Enumerable
13
+
14
+ attr_reader :paths
15
+
16
+ delegate :[], :include?, :pop, :size, :each, to: :paths
17
+
18
+ def initialize(paths = [])
19
+ @paths = typecast paths
20
+ end
21
+
22
+ def initialize_copy(other)
23
+ @paths = other.paths.dup
24
+ self
25
+ end
26
+
27
+ def to_ary
28
+ paths.dup
29
+ end
30
+
31
+ def compact
32
+ PathSet.new paths.compact
33
+ end
34
+
35
+ def +(array)
36
+ PathSet.new(paths + array)
37
+ end
38
+
39
+ %w(<< concat push insert unshift).each do |method|
40
+ class_eval <<-METHOD, __FILE__, __LINE__ + 1
41
+ def #{method}(*args)
42
+ paths.#{method}(*typecast(args))
43
+ end
44
+ METHOD
45
+ end
46
+
47
+ def find(*args)
48
+ find_all(*args).first || raise(MissingTemplate.new(self, *args))
49
+ end
50
+
51
+ alias :find_file :find
52
+ deprecate :find_file
53
+
54
+ def find_all(path, prefixes = [], *args)
55
+ _find_all path, prefixes, args
56
+ end
57
+
58
+ def exists?(path, prefixes, *args)
59
+ find_all(path, prefixes, *args).any?
60
+ end
61
+
62
+ def find_all_with_query(query) # :nodoc:
63
+ paths.each do |resolver|
64
+ templates = resolver.find_all_with_query(query)
65
+ return templates unless templates.empty?
66
+ end
67
+
68
+ []
69
+ end
70
+
71
+ private
72
+
73
+ def _find_all(path, prefixes, args)
74
+ prefixes = [prefixes] if String === prefixes
75
+ prefixes.each do |prefix|
76
+ paths.each do |resolver|
77
+ templates = resolver.find_all(path, prefix, *args)
78
+ return templates unless templates.empty?
79
+ end
80
+ end
81
+ []
82
+ end
83
+
84
+ def typecast(paths)
85
+ paths.map do |path|
86
+ case path
87
+ when Pathname, String
88
+ OptimizedFileSystemResolver.new path.to_s
89
+ else
90
+ path
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end