aboutsummaryrefslogtreecommitdiffstats
path: root/actionview
diff options
context:
space:
mode:
Diffstat (limited to 'actionview')
-rw-r--r--actionview/CHANGELOG.md37
-rw-r--r--actionview/lib/action_view/base.rb4
-rw-r--r--actionview/lib/action_view/dependency_tracker.rb38
-rw-r--r--actionview/lib/action_view/digestor.rb14
-rw-r--r--actionview/lib/action_view/helpers/asset_tag_helper.rb4
-rw-r--r--actionview/lib/action_view/helpers/asset_url_helper.rb31
-rw-r--r--actionview/lib/action_view/helpers/cache_helper.rb19
-rw-r--r--actionview/lib/action_view/helpers/capture_helper.rb2
-rw-r--r--actionview/lib/action_view/helpers/date_helper.rb15
-rw-r--r--actionview/lib/action_view/helpers/form_options_helper.rb8
-rw-r--r--actionview/lib/action_view/helpers/form_tag_helper.rb40
-rw-r--r--actionview/lib/action_view/helpers/javascript_helper.rb6
-rw-r--r--actionview/lib/action_view/helpers/rendering_helper.rb2
-rw-r--r--actionview/lib/action_view/helpers/sanitize_helper.rb2
-rw-r--r--actionview/lib/action_view/helpers/tag_helper.rb27
-rw-r--r--actionview/lib/action_view/helpers/text_helper.rb13
-rw-r--r--actionview/lib/action_view/helpers/url_helper.rb11
-rw-r--r--actionview/lib/action_view/layouts.rb15
-rw-r--r--actionview/lib/action_view/lookup_context.rb31
-rw-r--r--actionview/lib/action_view/path_set.rb9
-rw-r--r--actionview/lib/action_view/railtie.rb8
-rw-r--r--actionview/lib/action_view/renderer/partial_renderer.rb2
-rw-r--r--actionview/lib/action_view/renderer/streaming_template_renderer.rb2
-rw-r--r--actionview/lib/action_view/renderer/template_renderer.rb19
-rw-r--r--actionview/lib/action_view/rendering.rb4
-rw-r--r--actionview/lib/action_view/routing_url_for.rb10
-rw-r--r--actionview/lib/action_view/template.rb19
-rw-r--r--actionview/lib/action_view/template/resolver.rb18
-rw-r--r--actionview/lib/action_view/test_case.rb12
-rw-r--r--actionview/lib/action_view/view_paths.rb6
-rw-r--r--actionview/test/abstract_unit.rb18
-rw-r--r--actionview/test/actionpack/abstract/layouts_test.rb4
-rw-r--r--actionview/test/actionpack/abstract/render_test.rb3
-rw-r--r--actionview/test/actionpack/controller/render_test.rb38
-rw-r--r--actionview/test/activerecord/relation_cache_test.rb18
-rw-r--r--actionview/test/fixtures/actionpack/layouts/standard.text.erb1
-rw-r--r--actionview/test/fixtures/digestor/events/_completed.html.erb0
-rw-r--r--actionview/test/fixtures/digestor/events/index.html.erb1
-rw-r--r--actionview/test/fixtures/project.rb4
-rw-r--r--actionview/test/template/asset_tag_helper_test.rb10
-rw-r--r--actionview/test/template/digestor_test.rb53
-rw-r--r--actionview/test/template/form_helper_test.rb71
-rw-r--r--actionview/test/template/form_options_helper_i18n_test.rb5
-rw-r--r--actionview/test/template/form_tag_helper_test.rb40
-rw-r--r--actionview/test/template/lookup_context_test.rb66
-rw-r--r--actionview/test/template/number_helper_test.rb2
-rw-r--r--actionview/test/template/template_test.rb10
-rw-r--r--actionview/test/template/test_case_test.rb25
-rw-r--r--actionview/test/template/text_helper_test.rb4
-rw-r--r--actionview/test/template/translation_helper_test.rb13
-rw-r--r--actionview/test/template/url_helper_test.rb8
51 files changed, 547 insertions, 275 deletions
diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md
index 1f6bb31cd4..f97ca88b87 100644
--- a/actionview/CHANGELOG.md
+++ b/actionview/CHANGELOG.md
@@ -1,3 +1,40 @@
+* `number_to_currency` and `number_with_delimiter` now accept custom `delimiter_pattern` option
+ to handle placement of delimiter, to support currency formats like INR
+
+ Example:
+
+ number_to_currency(1230000, delimiter_pattern: /(\d+?)(?=(\d\d)+(\d)(?!\d))/, unit: '₹', format: "%u %n")
+ # => '₹ 12,30,000.00'
+
+ *Vipul A M*
+
+* Make `disable_with` the default behavior for submit tags. Disables the
+ button on submit to prevent double submits.
+
+ *Justin Schiff*
+
+* Add a break_sequence option to word_wrap so you can specify a custom break.
+
+ * Mauricio Gomez *
+
+* Add wildcard matching to explicit dependencies.
+
+ Turns:
+
+ ```erb
+ <% # Template Dependency: recordings/threads/events/subscribers_changed %>
+ <% # Template Dependency: recordings/threads/events/completed %>
+ <% # Template Dependency: recordings/threads/events/uncompleted %>
+ ```
+
+ Into:
+
+ ```erb
+ <% # Template Dependency: recordings/threads/events/* %>
+ ```
+
+ *Kasper Timm Hansen*
+
* Allow defining explicit collection caching using a `# Template Collection: ...`
directive inside templates.
diff --git a/actionview/lib/action_view/base.rb b/actionview/lib/action_view/base.rb
index 43124bb904..72ca6f7ec6 100644
--- a/actionview/lib/action_view/base.rb
+++ b/actionview/lib/action_view/base.rb
@@ -161,6 +161,10 @@ module ActionView #:nodoc:
cattr_accessor :raise_on_missing_translations
@@raise_on_missing_translations = false
+ # Specify whether submit_tag should automatically disable on click
+ cattr_accessor :automatically_disable_submit_tag
+ @@automatically_disable_submit_tag = true
+
class_attribute :_routes
class_attribute :logger
diff --git a/actionview/lib/action_view/dependency_tracker.rb b/actionview/lib/action_view/dependency_tracker.rb
index 7a7e116dbb..6e8c7f8203 100644
--- a/actionview/lib/action_view/dependency_tracker.rb
+++ b/actionview/lib/action_view/dependency_tracker.rb
@@ -1,16 +1,18 @@
require 'thread_safe'
+require 'action_view/path_set'
module ActionView
class DependencyTracker # :nodoc:
@trackers = ThreadSafe::Cache.new
- def self.find_dependencies(name, template)
+ def self.find_dependencies(name, template, view_paths = nil)
tracker = @trackers[template.handler]
+ return [] unless tracker.present?
- if tracker.present?
- tracker.call(name, template)
+ if tracker.respond_to?(:supports_view_paths?) && tracker.supports_view_paths?
+ tracker.call(name, template, view_paths)
else
- []
+ tracker.call(name, template)
end
end
@@ -82,12 +84,16 @@ module ActionView
(?:#{STRING}|#{VARIABLE_OR_METHOD_CHAIN}) # finally, the dependency name of interest
/xm
- def self.call(name, template)
- new(name, template).dependencies
+ def self.supports_view_paths? # :nodoc:
+ true
+ end
+
+ def self.call(name, template, view_paths = nil)
+ new(name, template, view_paths).dependencies
end
- def initialize(name, template)
- @name, @template = name, template
+ def initialize(name, template, view_paths = nil)
+ @name, @template, @view_paths = name, template, view_paths
end
def dependencies
@@ -142,8 +148,22 @@ module ActionView
end
end
+ def resolve_directories(wildcard_dependencies)
+ return [] unless @view_paths
+
+ wildcard_dependencies.each_with_object([]) do |query, templates|
+ @view_paths.find_all_with_query(query).each do |template|
+ templates << "#{File.dirname(query)}/#{File.basename(template).split('.').first}"
+ end
+ end
+ end
+
def explicit_dependencies
- source.scan(EXPLICIT_DEPENDENCY).flatten.uniq
+ dependencies = source.scan(EXPLICIT_DEPENDENCY).flatten.uniq
+
+ wildcards, explicits = dependencies.partition { |dependency| dependency[-1] == '*' }
+
+ (explicits + resolve_directories(wildcards)).uniq
end
end
diff --git a/actionview/lib/action_view/digestor.rb b/actionview/lib/action_view/digestor.rb
index df8059d04e..9a8a4feb2e 100644
--- a/actionview/lib/action_view/digestor.rb
+++ b/actionview/lib/action_view/digestor.rb
@@ -8,6 +8,13 @@ module ActionView
@@cache = ThreadSafe::Cache.new
@@digest_monitor = Monitor.new
+ class PerRequestDigestCacheExpiry < Struct.new(:app) # :nodoc:
+ def call(env)
+ ActionView::Digestor.cache.clear
+ app.call(env)
+ end
+ end
+
class << self
# Supported options:
#
@@ -41,10 +48,7 @@ module ActionView
Digestor
end
- digest = klass.new(options).digest
- # Store the actual digest if config.cache_template_loading is true
- @@cache[cache_key] = stored_digest = digest if ActionView::Resolver.caching?
- digest
+ @@cache[cache_key] = stored_digest = klass.new(options).digest
ensure
# something went wrong or ActionView::Resolver.caching? is false, make sure not to corrupt the @@cache
@@cache.delete_pair(cache_key, false) if pre_stored && !stored_digest
@@ -68,7 +72,7 @@ module ActionView
end
def dependencies
- DependencyTracker.find_dependencies(name, template)
+ DependencyTracker.find_dependencies(name, template, finder.view_paths)
rescue ActionView::MissingTemplate
logger.try :error, " '#{name}' file doesn't exist, so no dependencies"
[]
diff --git a/actionview/lib/action_view/helpers/asset_tag_helper.rb b/actionview/lib/action_view/helpers/asset_tag_helper.rb
index e32f8e219e..e506c782d6 100644
--- a/actionview/lib/action_view/helpers/asset_tag_helper.rb
+++ b/actionview/lib/action_view/helpers/asset_tag_helper.rb
@@ -60,7 +60,7 @@ module ActionView
tag_options = {
"src" => path_to_javascript(source, path_options)
}.merge!(options)
- content_tag(:script, "", tag_options)
+ content_tag("script".freeze, "", tag_options)
}.join("\n").html_safe
end
@@ -237,7 +237,7 @@ module ActionView
# image_alt('underscored_file_name.png')
# # => Underscored file name
def image_alt(src)
- File.basename(src, '.*').sub(/-[[:xdigit:]]{32}\z/, '').tr('-_', ' ').capitalize
+ File.basename(src, '.*'.freeze).sub(/-[[:xdigit:]]{32}\z/, ''.freeze).tr('-_'.freeze, ' '.freeze).capitalize
end
# Returns an HTML video tag for the +sources+. If +sources+ is a string,
diff --git a/actionview/lib/action_view/helpers/asset_url_helper.rb b/actionview/lib/action_view/helpers/asset_url_helper.rb
index b19dc25025..717b326740 100644
--- a/actionview/lib/action_view/helpers/asset_url_helper.rb
+++ b/actionview/lib/action_view/helpers/asset_url_helper.rb
@@ -31,26 +31,33 @@ module ActionView
# stylesheet_link_tag("application")
# # => <link href="http://assets.example.com/assets/application.css" media="screen" rel="stylesheet" />
#
- # Browsers typically open at most two simultaneous connections to a single
- # host, which means your assets often have to wait for other assets to finish
- # downloading. You can alleviate this by using a <tt>%d</tt> wildcard in the
- # +asset_host+. For example, "assets%d.example.com". If that wildcard is
- # present Rails distributes asset requests among the corresponding four hosts
- # "assets0.example.com", ..., "assets3.example.com". With this trick browsers
- # will open eight simultaneous connections rather than two.
+ # Browsers open a limited number of simultaneous connections to a single
+ # host. The exact number varies by browser and version. This limit may cause
+ # some asset downloads to wait for previous assets to finish before they can
+ # begin. You can use the <tt>%d</tt> wildcard in the +asset_host+ to
+ # distribute the requests over four hosts. For example,
+ # <tt>assets%d.example.com<tt> will spread the asset requests over
+ # "assets0.example.com", ..., "assets3.example.com".
#
# image_tag("rails.png")
# # => <img alt="Rails" src="http://assets0.example.com/assets/rails.png" />
# stylesheet_link_tag("application")
# # => <link href="http://assets2.example.com/assets/application.css" media="screen" rel="stylesheet" />
#
- # To do this, you can either setup four actual hosts, or you can use wildcard
- # DNS to CNAME the wildcard to a single asset host. You can read more about
- # setting up your DNS CNAME records from your ISP.
+ # This may improve the asset loading performance of your application.
+ # It is also possible the combination of additional connection overhead
+ # (DNS, SSL) and the overall browser connection limits may result in this
+ # solution being slower. You should be sure to measure your actual
+ # performance across targeted browsers both before and after this change.
+ #
+ # To implement the corresponding hosts you can either setup four actual
+ # hosts or use wildcard DNS to CNAME the wildcard to a single asset host.
+ # You can read more about setting up your DNS CNAME records from your ISP.
#
# Note: This is purely a browser performance optimization and is not meant
# for server load balancing. See http://www.die.net/musings/page_load_time/
- # for background.
+ # for background and http://www.browserscope.org/?category=network for
+ # connection limit data.
#
# Alternatively, you can exert more control over the asset host by setting
# +asset_host+ to a proc like this:
@@ -127,7 +134,7 @@ module ActionView
return "" unless source.present?
return source if source =~ URI_REGEXP
- tail, source = source[/([\?#].+)$/], source.sub(/([\?#].+)$/, '')
+ tail, source = source[/([\?#].+)$/], source.sub(/([\?#].+)$/, ''.freeze)
if extname = compute_asset_extname(source, options)
source = "#{source}#{extname}"
diff --git a/actionview/lib/action_view/helpers/cache_helper.rb b/actionview/lib/action_view/helpers/cache_helper.rb
index 797d029317..e473aeaea9 100644
--- a/actionview/lib/action_view/helpers/cache_helper.rb
+++ b/actionview/lib/action_view/helpers/cache_helper.rb
@@ -98,7 +98,19 @@ module ActionView
# <%# Template Dependency: todolists/todolist %>
# <%= render_sortable_todolists @project.todolists %>
#
- # The pattern used to match these is <tt>/# Template Dependency: (\S+)/</tt>,
+ # In some cases, like a single table inheritance setup, you might have
+ # a bunch of explicit dependencies. Instead of writing every template out,
+ # you can use a wildcard to match any template in a directory:
+ #
+ # <%# Template Dependency: events/* %>
+ # <%= render_categorizable_events @person.events %>
+ #
+ # This marks every template in the directory as a dependency. To find those
+ # templates, the wildcard path must be absolutely defined from app/views or paths
+ # otherwise added with +prepend_view_path+ or +append_view_path+.
+ # This way the wildcard for `app/views/recordings/events` would be `recordings/events/*` etc.
+ #
+ # The pattern used to match explicit dependencies is <tt>/# Template Dependency: (\S+)/</tt>,
# so it's important that you type it out just so.
# You can only declare one template dependency per line.
#
@@ -217,10 +229,9 @@ module ActionView
def fragment_name_with_digest(name, virtual_path) #:nodoc:
virtual_path ||= @virtual_path
if virtual_path
- names = Array(name.is_a?(Hash) ? controller.url_for(name).split("://").last : name)
+ name = controller.url_for(name).split("://").last if name.is_a?(Hash)
digest = Digestor.digest name: virtual_path, finder: lookup_context, dependencies: view_cache_dependencies
-
- [ *names, digest ]
+ [ name, digest ]
else
name
end
diff --git a/actionview/lib/action_view/helpers/capture_helper.rb b/actionview/lib/action_view/helpers/capture_helper.rb
index a67ba580f1..93c7cba395 100644
--- a/actionview/lib/action_view/helpers/capture_helper.rb
+++ b/actionview/lib/action_view/helpers/capture_helper.rb
@@ -115,7 +115,7 @@ module ActionView
# <li><%= link_to 'Home', action: 'index' %></li>
# <% end %>
#
- # And in other place:
+ # And in another place:
#
# <% content_for :navigation do %>
# <li><%= link_to 'Login', action: 'login' %></li>
diff --git a/actionview/lib/action_view/helpers/date_helper.rb b/actionview/lib/action_view/helpers/date_helper.rb
index 9c8edc69a9..312e41ee48 100644
--- a/actionview/lib/action_view/helpers/date_helper.rb
+++ b/actionview/lib/action_view/helpers/date_helper.rb
@@ -70,7 +70,7 @@ module ActionView
# distance_of_time_in_words(Time.now, Time.now) # => less than a minute
#
# With the <tt>scope</tt> option, you can define a custom scope for Rails
- # to lookup the translation.
+ # to look up the translation.
#
# For example you can define the following in your locale (e.g. en.yml).
#
@@ -228,6 +228,7 @@ module ActionView
# or the given prompt string.
# * <tt>:with_css_classes</tt> - Set to true if you want assign different styles for 'select' tags. This option
# automatically set classes 'year', 'month', 'day', 'hour', 'minute' and 'second' for your 'select' tags.
+ # * <tt>:use_hidden</tt> - Set to true if you only want to generate hidden input tags.
#
# If anything is passed in the +html_options+ hash it will be applied to every select tag in the set.
#
@@ -681,7 +682,7 @@ module ActionView
content = args.first || I18n.l(date_or_time, :format => format)
datetime = date_or_time.acts_like?(:time) ? date_or_time.xmlschema : date_or_time.iso8601
- content_tag(:time, content, options.reverse_merge(:datetime => datetime), &block)
+ content_tag("time".freeze, content, options.reverse_merge(:datetime => datetime), &block)
end
end
@@ -809,7 +810,7 @@ module ActionView
1.upto(12) do |month_number|
options = { :value => month_number }
options[:selected] = "selected" if month == month_number
- month_options << content_tag(:option, month_name(month_number), options) + "\n"
+ month_options << content_tag("option".freeze, month_name(month_number), options) + "\n"
end
build_select(:month, month_options.join)
end
@@ -971,7 +972,7 @@ module ActionView
tag_options[:selected] = "selected" if selected == i
text = options[:use_two_digit_numbers] ? sprintf("%02d", i) : value
text = options[:ampm] ? AMPM_TRANSLATION[i] : text
- select_options << content_tag(:option, text, tag_options)
+ select_options << content_tag("option".freeze, text, tag_options)
end
(select_options.join("\n") + "\n").html_safe
@@ -991,11 +992,11 @@ module ActionView
select_options[:class] = [select_options[:class], type].compact.join(' ') if @options[:with_css_classes]
select_html = "\n"
- select_html << content_tag(:option, '', :value => '') + "\n" if @options[:include_blank]
+ select_html << content_tag("option".freeze, '', :value => '') + "\n" if @options[:include_blank]
select_html << prompt_option_tag(type, @options[:prompt]) + "\n" if @options[:prompt]
select_html << select_options_as_html
- (content_tag(:select, select_html.html_safe, select_options) + "\n").html_safe
+ (content_tag("select".freeze, select_html.html_safe, select_options) + "\n").html_safe
end
# Builds a prompt option tag with supplied options or from default options.
@@ -1012,7 +1013,7 @@ module ActionView
I18n.translate(:"datetime.prompts.#{type}", :locale => @options[:locale])
end
- prompt ? content_tag(:option, prompt, :value => '') : ''
+ prompt ? content_tag("option".freeze, prompt, :value => '') : ''
end
# Builds hidden input tag for date part and value.
diff --git a/actionview/lib/action_view/helpers/form_options_helper.rb b/actionview/lib/action_view/helpers/form_options_helper.rb
index 8e729b3c39..728e633bbf 100644
--- a/actionview/lib/action_view/helpers/form_options_helper.rb
+++ b/actionview/lib/action_view/helpers/form_options_helper.rb
@@ -456,7 +456,7 @@ module ActionView
option_tags = options_from_collection_for_select(
group.send(group_method), option_key_method, option_value_method, selected_key)
- content_tag(:optgroup, option_tags, label: group.send(group_label_method))
+ content_tag("optgroup".freeze, option_tags, label: group.send(group_label_method))
end.join.html_safe
end
@@ -528,7 +528,7 @@ module ActionView
body = "".html_safe
if prompt
- body.safe_concat content_tag(:option, prompt_text(prompt), value: "")
+ body.safe_concat content_tag("option".freeze, prompt_text(prompt), value: "")
end
grouped_options.each do |container|
@@ -541,7 +541,7 @@ module ActionView
end
html_attributes = { label: label }.merge!(html_attributes)
- body.safe_concat content_tag(:optgroup, options_for_select(container, selected_key), html_attributes)
+ body.safe_concat content_tag("optgroup".freeze, options_for_select(container, selected_key), html_attributes)
end
body
@@ -577,7 +577,7 @@ module ActionView
end
zone_options.safe_concat options_for_select(convert_zones[priority_zones], selected)
- zone_options.safe_concat content_tag(:option, '-------------', value: '', disabled: true)
+ zone_options.safe_concat content_tag("option".freeze, '-------------', value: '', disabled: true)
zone_options.safe_concat "\n"
zones = zones - priority_zones
diff --git a/actionview/lib/action_view/helpers/form_tag_helper.rb b/actionview/lib/action_view/helpers/form_tag_helper.rb
index 896020bc15..af684e05c6 100644
--- a/actionview/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionview/lib/action_view/helpers/form_tag_helper.rb
@@ -140,15 +140,15 @@ module ActionView
end
if include_blank
- option_tags = content_tag(:option, include_blank, value: '').safe_concat(option_tags)
+ option_tags = content_tag("option".freeze, include_blank, value: '').safe_concat(option_tags)
end
end
if prompt = options.delete(:prompt)
- option_tags = content_tag(:option, prompt, value: '').safe_concat(option_tags)
+ option_tags = content_tag("option".freeze, prompt, value: '').safe_concat(option_tags)
end
- content_tag :select, option_tags, { "name" => html_name, "id" => sanitize_to_id(name) }.update(options.stringify_keys)
+ content_tag "select".freeze, option_tags, { "name" => html_name, "id" => sanitize_to_id(name) }.update(options.stringify_keys)
end
# Creates a standard text field; use these text fields to input smaller chunks of text like a username
@@ -414,34 +414,48 @@ module ActionView
# the form is processed normally, otherwise no action is taken.
# * <tt>:disable_with</tt> - Value of this parameter will be used as the value for a
# disabled version of the submit button when the form is submitted. This feature is
- # provided by the unobtrusive JavaScript driver.
+ # provided by the unobtrusive JavaScript driver. To disable this feature for a single submit tag
+ # pass <tt>:data => { disable_with: false }</tt> Defaults to value attribute.
#
# ==== Examples
# submit_tag
- # # => <input name="commit" type="submit" value="Save changes" />
+ # # => <input name="commit" data-disable-with="Save changes" type="submit" value="Save changes" />
#
# submit_tag "Edit this article"
- # # => <input name="commit" type="submit" value="Edit this article" />
+ # # => <input name="commit" data-disable-with="Edit this article" type="submit" value="Edit this article" />
#
# submit_tag "Save edits", disabled: true
- # # => <input disabled="disabled" name="commit" type="submit" value="Save edits" />
+ # # => <input disabled="disabled" name="commit" data-disable-with="Save edits" type="submit" value="Save edits" />
#
- # submit_tag "Complete sale", data: { disable_with: "Please wait..." }
- # # => <input name="commit" data-disable-with="Please wait..." type="submit" value="Complete sale" />
+ # submit_tag "Complete sale", data: { disable_with: "Submitting..." }
+ # # => <input name="commit" data-disable-with="Submitting..." type="submit" value="Complete sale" />
#
# submit_tag nil, class: "form_submit"
# # => <input class="form_submit" name="commit" type="submit" />
#
# submit_tag "Edit", class: "edit_button"
- # # => <input class="edit_button" name="commit" type="submit" value="Edit" />
+ # # => <input class="edit_button" data-disable-with="Edit" name="commit" type="submit" value="Edit" />
#
# submit_tag "Save", data: { confirm: "Are you sure?" }
- # # => <input name='commit' type='submit' value='Save' data-confirm="Are you sure?" />
+ # # => <input name='commit' type='submit' value='Save' data-disable-with="Save" data-confirm="Are you sure?" />
#
def submit_tag(value = "Save changes", options = {})
options = options.stringify_keys
+ tag_options = { "type" => "submit", "name" => "commit", "value" => value }.update(options)
+
+ if ActionView::Base.automatically_disable_submit_tag
+ unless tag_options["data-disable-with"] == false || (tag_options["data"] && tag_options["data"][:disable_with] == false)
+ disable_with_text = tag_options["data-disable-with"]
+ disable_with_text ||= tag_options["data"][:disable_with] if tag_options["data"]
+ disable_with_text ||= value.clone
+ tag_options.deep_merge!("data" => { "disable_with" => disable_with_text })
+ else
+ tag_options.delete("data-disable-with")
+ tag_options["data"].delete(:disable_with) if tag_options["data"]
+ end
+ end
- tag :input, { "type" => "submit", "name" => "commit", "value" => value }.update(options)
+ tag :input, tag_options
end
# Creates a button element that defines a <tt>submit</tt> button,
@@ -568,7 +582,7 @@ module ActionView
# # => <fieldset class="format"><p><input id="name" name="name" type="text" /></p></fieldset>
def field_set_tag(legend = nil, options = nil, &block)
output = tag(:fieldset, options, true)
- output.safe_concat(content_tag(:legend, legend)) unless legend.blank?
+ output.safe_concat(content_tag("legend".freeze, legend)) unless legend.blank?
output.concat(capture(&block)) if block_given?
output.safe_concat("</fieldset>")
end
diff --git a/actionview/lib/action_view/helpers/javascript_helper.rb b/actionview/lib/action_view/helpers/javascript_helper.rb
index e237a32cb7..ed7e882c94 100644
--- a/actionview/lib/action_view/helpers/javascript_helper.rb
+++ b/actionview/lib/action_view/helpers/javascript_helper.rb
@@ -47,8 +47,8 @@ module ActionView
# tag.
#
# javascript_tag "alert('All is good')", defer: 'defer'
- #
- # Returns:
+ #
+ # Returns:
# <script defer="defer">
# //<![CDATA[
# alert('All is good')
@@ -70,7 +70,7 @@ module ActionView
content_or_options_with_block
end
- content_tag(:script, javascript_cdata_section(content), html_options)
+ content_tag("script".freeze, javascript_cdata_section(content), html_options)
end
def javascript_cdata_section(content) #:nodoc:
diff --git a/actionview/lib/action_view/helpers/rendering_helper.rb b/actionview/lib/action_view/helpers/rendering_helper.rb
index 827932d8e2..c98f2d74a8 100644
--- a/actionview/lib/action_view/helpers/rendering_helper.rb
+++ b/actionview/lib/action_view/helpers/rendering_helper.rb
@@ -18,7 +18,7 @@ module ActionView
# performs HTML escape on the string first. Setting the content type as
# <tt>text/html</tt>.
# * <tt>:body</tt> - Renders the text passed in, and inherits the content
- # type of <tt>text/html</tt> from <tt>ActionDispatch::Response</tt>
+ # type of <tt>text/plain</tt> from <tt>ActionDispatch::Response</tt>
# object.
#
# If no options hash is passed or :update specified, the default is to render a partial and use the second parameter
diff --git a/actionview/lib/action_view/helpers/sanitize_helper.rb b/actionview/lib/action_view/helpers/sanitize_helper.rb
index a2e9f37453..191a881de0 100644
--- a/actionview/lib/action_view/helpers/sanitize_helper.rb
+++ b/actionview/lib/action_view/helpers/sanitize_helper.rb
@@ -120,7 +120,7 @@ module ActionView
attr_writer :full_sanitizer, :link_sanitizer, :white_list_sanitizer
# Vendors the full, link and white list sanitizers.
- # Provided strictly for compabitility and can be removed in Rails 5.
+ # Provided strictly for compatibility and can be removed in Rails 5.
def sanitizer_vendor
Rails::Html::Sanitizer
end
diff --git a/actionview/lib/action_view/helpers/tag_helper.rb b/actionview/lib/action_view/helpers/tag_helper.rb
index a87c223a71..2562504896 100644
--- a/actionview/lib/action_view/helpers/tag_helper.rb
+++ b/actionview/lib/action_view/helpers/tag_helper.rb
@@ -22,9 +22,10 @@ module ActionView
TAG_PREFIXES = ['aria', 'data', :aria, :data].to_set
- PRE_CONTENT_STRINGS = {
- :textarea => "\n"
- }
+ PRE_CONTENT_STRINGS = Hash.new { "".freeze }
+ PRE_CONTENT_STRINGS[:textarea] = "\n"
+ PRE_CONTENT_STRINGS["textarea"] = "\n"
+
# Returns an empty HTML tag of type +name+ which by default is XHTML
# compliant. Set +open+ to true to create an open tag compatible
@@ -143,24 +144,30 @@ module ActionView
def content_tag_string(name, content, options, escape = true)
tag_options = tag_options(options, escape) if options
content = ERB::Util.unwrapped_html_escape(content) if escape
- "<#{name}#{tag_options}>#{PRE_CONTENT_STRINGS[name.to_sym]}#{content}</#{name}>".html_safe
+ "<#{name}#{tag_options}>#{PRE_CONTENT_STRINGS[name]}#{content}</#{name}>".html_safe
end
def tag_options(options, escape = true)
return if options.blank?
- attrs = []
+ output = ""
+ sep = " ".freeze
options.each_pair do |key, value|
if TAG_PREFIXES.include?(key) && value.is_a?(Hash)
value.each_pair do |k, v|
- attrs << prefix_tag_option(key, k, v, escape)
+ output << sep
+ output << prefix_tag_option(key, k, v, escape)
end
elsif BOOLEAN_ATTRIBUTES.include?(key)
- attrs << boolean_tag_option(key) if value
+ if value
+ output << sep
+ output << boolean_tag_option(key)
+ end
elsif !value.nil?
- attrs << tag_option(key, value, escape)
+ output << sep
+ output << tag_option(key, value, escape)
end
end
- " #{attrs * ' '}" unless attrs.empty?
+ output unless output.empty?
end
def prefix_tag_option(prefix, key, value, escape)
@@ -177,7 +184,7 @@ module ActionView
def tag_option(key, value, escape)
if value.is_a?(Array)
- value = escape ? safe_join(value, " ") : value.join(" ")
+ value = escape ? safe_join(value, " ".freeze) : value.join(" ".freeze)
else
value = escape ? ERB::Util.unwrapped_html_escape(value) : value
end
diff --git a/actionview/lib/action_view/helpers/text_helper.rb b/actionview/lib/action_view/helpers/text_helper.rb
index 6a3d01667d..432693bc23 100644
--- a/actionview/lib/action_view/helpers/text_helper.rb
+++ b/actionview/lib/action_view/helpers/text_helper.rb
@@ -250,12 +250,15 @@ module ActionView
#
# word_wrap('Once upon a time', line_width: 1)
# # => Once\nupon\na\ntime
- def word_wrap(text, options = {})
- line_width = options.fetch(:line_width, 80)
-
+ #
+ # You can also specify a custom +break_sequence+ ("\n" by default)
+ #
+ # word_wrap('Once upon a time', line_width: 1, break_sequence: "\r\n")
+ # # => Once\r\nupon\r\na\r\ntime
+ def word_wrap(text, line_width: 80, break_sequence: "\n")
text.split("\n").collect! do |line|
- line.length > line_width ? line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1\n").strip : line
- end * "\n"
+ line.length > line_width ? line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1#{break_sequence}").strip : line
+ end * break_sequence
end
# Returns +text+ transformed into HTML using simple formatting rules.
diff --git a/actionview/lib/action_view/helpers/url_helper.rb b/actionview/lib/action_view/helpers/url_helper.rb
index afb1265ad9..5684de35e8 100644
--- a/actionview/lib/action_view/helpers/url_helper.rb
+++ b/actionview/lib/action_view/helpers/url_helper.rb
@@ -184,9 +184,9 @@ module ActionView
html_options = convert_options_to_data_attributes(options, html_options)
url = url_for(options)
- html_options['href'] ||= url
+ html_options["href".freeze] ||= url
- content_tag(:a, name || url, html_options, &block)
+ content_tag("a".freeze, name || url, html_options, &block)
end
# Generates a form containing a single button that submits to the URL created
@@ -464,13 +464,14 @@ module ActionView
extras = %w{ cc bcc body subject reply_to }.map! { |item|
option = html_options.delete(item).presence || next
- "#{item.dasherize}=#{Rack::Utils.escape_path(option)}"
+ "#{item.dasherize}=#{ERB::Util.url_encode(option)}"
}.compact
extras = extras.empty? ? '' : '?' + extras.join('&')
- html_options["href"] = "mailto:#{email_address}#{extras}"
+ encoded_email_address = ERB::Util.url_encode(email_address).gsub("%40", "@")
+ html_options["href"] = "mailto:#{encoded_email_address}#{extras}"
- content_tag(:a, name || email_address, html_options, &block)
+ content_tag("a".freeze, name || email_address, html_options, &block)
end
# True if the current request URI was generated by the given +options+.
diff --git a/actionview/lib/action_view/layouts.rb b/actionview/lib/action_view/layouts.rb
index 9d636c8c9e..cabba967c9 100644
--- a/actionview/lib/action_view/layouts.rb
+++ b/actionview/lib/action_view/layouts.rb
@@ -277,7 +277,7 @@ module ActionView
remove_possible_method(:_layout)
prefixes = _implied_layout_name =~ /\blayouts/ ? [] : ["layouts"]
- default_behavior = "lookup_context.find_all('#{_implied_layout_name}', #{prefixes.inspect}).first || super"
+ default_behavior = "lookup_context.find_all('#{_implied_layout_name}', #{prefixes.inspect}, false, [], { formats: formats }).first || super"
name_clause = if name
default_behavior
else
@@ -316,7 +316,7 @@ module ActionView
end
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
- def _layout
+ def _layout(formats)
if _conditional_layout?
#{layout_definition}
else
@@ -372,7 +372,7 @@ module ActionView
end
# This will be overwritten by _write_layout_method
- def _layout; end
+ def _layout(*); end
# Determine the layout for a given name, taking into account the name type.
#
@@ -382,8 +382,8 @@ module ActionView
case name
when String then _normalize_layout(name)
when Proc then name
- when true then Proc.new { _default_layout(true) }
- when :default then Proc.new { _default_layout(false) }
+ when true then Proc.new { |formats| _default_layout(formats, true) }
+ when :default then Proc.new { |formats| _default_layout(formats, false) }
when false, nil then nil
else
raise ArgumentError,
@@ -399,14 +399,15 @@ module ActionView
# Optionally raises an exception if the layout could not be found.
#
# ==== Parameters
+ # * <tt>formats</tt> - The formats accepted to this layout
# * <tt>require_layout</tt> - If set to true and layout is not found,
# an ArgumentError exception is raised (defaults to false)
#
# ==== Returns
# * <tt>template</tt> - The template object for the default layout (or nil)
- def _default_layout(require_layout = false)
+ def _default_layout(formats, require_layout = false)
begin
- value = _layout if action_has_layout?
+ value = _layout(formats) if action_has_layout?
rescue NameError => e
raise e, "Could not render layout: #{e.message}"
end
diff --git a/actionview/lib/action_view/lookup_context.rb b/actionview/lib/action_view/lookup_context.rb
index 817b30dd2f..fba9a44cb1 100644
--- a/actionview/lib/action_view/lookup_context.rb
+++ b/actionview/lib/action_view/lookup_context.rb
@@ -6,10 +6,11 @@ require 'action_view/template/resolver'
module ActionView
# = Action View Lookup Context
#
- # <tt>LookupContext</tt> is the object responsible to hold all information required to lookup
- # templates, i.e. view paths and details. The LookupContext is also responsible to
- # generate a key, given to view paths, used in the resolver cache lookup. Since
- # this key is generated just once during the request, it speeds up all cache accesses.
+ # <tt>LookupContext</tt> is the object responsible for holding all information
+ # required for looking up templates, i.e. view paths and details.
+ # <tt>LookupContext</tt> is also responsible for generating a key, given to
+ # view paths, used in the resolver cache lookup. Since this key is generated
+ # only once during the request, it speeds up all cache accesses.
class LookupContext #:nodoc:
attr_accessor :prefixes, :rendered_format
@@ -172,13 +173,13 @@ module ActionView
# name instead of the prefix.
def normalize_name(name, prefixes) #:nodoc:
prefixes = prefixes.presence
- parts = name.to_s.split('/')
+ parts = name.to_s.split('/'.freeze)
parts.shift if parts.first.empty?
name = parts.pop
return name, prefixes || [""] if parts.empty?
- parts = parts.join('/')
+ parts = parts.join('/'.freeze)
prefixes = prefixes ? prefixes.map { |p| "#{p}/#{parts}" } : [parts]
return name, prefixes
@@ -203,7 +204,7 @@ module ActionView
# add :html as fallback to :js.
def formats=(values)
if values
- values.concat(default_formats) if values.delete "*/*"
+ values.concat(default_formats) if values.delete "*/*".freeze
if values == [:js]
values << :html
@html_fallback_for_js = true
@@ -228,21 +229,5 @@ module ActionView
super(default_locale)
end
-
- # Uses the first format in the formats array for layout lookup.
- def with_layout_format
- if formats.size == 1
- yield
- else
- old_formats = formats
- _set_detail(:formats, formats[0,1])
-
- begin
- yield
- ensure
- _set_detail(:formats, old_formats)
- end
- end
- end
end
end
diff --git a/actionview/lib/action_view/path_set.rb b/actionview/lib/action_view/path_set.rb
index 91ee2ea8f5..7a88f6bc50 100644
--- a/actionview/lib/action_view/path_set.rb
+++ b/actionview/lib/action_view/path_set.rb
@@ -61,6 +61,15 @@ module ActionView #:nodoc:
find_all(path, prefixes, *args).any?
end
+ def find_all_with_query(query) # :nodoc:
+ paths.each do |resolver|
+ templates = resolver.find_all_with_query(query)
+ return templates unless templates.empty?
+ end
+
+ []
+ end
+
private
def typecast(paths)
diff --git a/actionview/lib/action_view/railtie.rb b/actionview/lib/action_view/railtie.rb
index 5dc7950d6b..e829d86c99 100644
--- a/actionview/lib/action_view/railtie.rb
+++ b/actionview/lib/action_view/railtie.rb
@@ -42,6 +42,14 @@ module ActionView
end
end
+ initializer "action_view.per_request_digest_cache" do |app|
+ ActiveSupport.on_load(:action_view) do
+ if app.config.consider_all_requests_local
+ app.middleware.use ActionView::Digestor::PerRequestDigestCacheExpiry
+ end
+ end
+ end
+
initializer "action_view.setup_action_pack" do |app|
ActiveSupport.on_load(:action_controller) do
ActionView::RoutingUrlFor.include(ActionDispatch::Routing::UrlFor)
diff --git a/actionview/lib/action_view/renderer/partial_renderer.rb b/actionview/lib/action_view/renderer/partial_renderer.rb
index 780fdabbd1..1f9e960488 100644
--- a/actionview/lib/action_view/renderer/partial_renderer.rb
+++ b/actionview/lib/action_view/renderer/partial_renderer.rb
@@ -520,7 +520,7 @@ module ActionView
def retrieve_variable(path, as)
variable = as || begin
- base = path[-1] == "/" ? "" : File.basename(path)
+ base = path[-1] == "/".freeze ? "".freeze : File.basename(path)
raise_invalid_identifier(path) unless base =~ /\A_?(.*)(?:\.\w+)*\z/
$1.to_sym
end
diff --git a/actionview/lib/action_view/renderer/streaming_template_renderer.rb b/actionview/lib/action_view/renderer/streaming_template_renderer.rb
index 3ab2cd36fc..f38e2764d0 100644
--- a/actionview/lib/action_view/renderer/streaming_template_renderer.rb
+++ b/actionview/lib/action_view/renderer/streaming_template_renderer.rb
@@ -47,7 +47,7 @@ module ActionView
return [super] unless layout_name && template.supports_streaming?
locals ||= {}
- layout = layout_name && find_layout(layout_name, locals.keys)
+ layout = layout_name && find_layout(layout_name, locals.keys, [formats.first])
Body.new do |buffer|
delayed_render(buffer, template, layout, @view, locals)
diff --git a/actionview/lib/action_view/renderer/template_renderer.rb b/actionview/lib/action_view/renderer/template_renderer.rb
index dbb4855e39..75217e1630 100644
--- a/actionview/lib/action_view/renderer/template_renderer.rb
+++ b/actionview/lib/action_view/renderer/template_renderer.rb
@@ -57,7 +57,7 @@ module ActionView
end
def render_with_layout(path, locals) #:nodoc:
- layout = path && find_layout(path, locals.keys)
+ layout = path && find_layout(path, locals.keys, [formats.first])
content = yield(layout)
if layout
@@ -72,27 +72,28 @@ module ActionView
# This is the method which actually finds the layout using details in the lookup
# context object. If no layout is found, it checks if at least a layout with
# the given name exists across all details before raising the error.
- def find_layout(layout, keys)
- with_layout_format { resolve_layout(layout, keys) }
+ def find_layout(layout, keys, formats)
+ resolve_layout(layout, keys, formats)
end
- def resolve_layout(layout, keys)
+ def resolve_layout(layout, keys, formats)
+ details = @details.dup
+ details[:formats] = formats
+
case layout
when String
begin
if layout =~ /^\//
- with_fallbacks { find_template(layout, nil, false, keys, @details) }
+ with_fallbacks { find_template(layout, nil, false, keys, details) }
else
- find_template(layout, nil, false, keys, @details)
+ find_template(layout, nil, false, keys, details)
end
rescue ActionView::MissingTemplate
all_details = @details.merge(:formats => @lookup_context.default_formats)
raise unless template_exists?(layout, nil, false, keys, all_details)
end
when Proc
- resolve_layout(layout.call, keys)
- when FalseClass
- nil
+ resolve_layout(layout.call(formats), keys, formats)
else
layout
end
diff --git a/actionview/lib/action_view/rendering.rb b/actionview/lib/action_view/rendering.rb
index 91b7e845d6..8604637da2 100644
--- a/actionview/lib/action_view/rendering.rb
+++ b/actionview/lib/action_view/rendering.rb
@@ -103,8 +103,8 @@ module ActionView
view_renderer.render(context, options)
end
- # Assign the rendered format to lookup context.
- def _process_format(format, options = {}) #:nodoc:
+ # Assign the rendered format to look up context.
+ def _process_format(format) #:nodoc:
super
lookup_context.formats = [format.to_sym]
lookup_context.rendered_format = lookup_context.formats.first
diff --git a/actionview/lib/action_view/routing_url_for.rb b/actionview/lib/action_view/routing_url_for.rb
index 0371db07dc..20d6b9a64c 100644
--- a/actionview/lib/action_view/routing_url_for.rb
+++ b/actionview/lib/action_view/routing_url_for.rb
@@ -92,6 +92,16 @@ module ActionView
end
super(options)
+ when ActionController::Parameters
+ unless options.key?(:only_path)
+ if options[:host].nil?
+ options[:only_path] = _generate_paths_by_default
+ else
+ options[:only_path] = false
+ end
+ end
+
+ super(options)
when :back
_back_url
when Array
diff --git a/actionview/lib/action_view/template.rb b/actionview/lib/action_view/template.rb
index d8585514d5..0ed208f27e 100644
--- a/actionview/lib/action_view/template.rb
+++ b/actionview/lib/action_view/template.rb
@@ -141,7 +141,7 @@ module ActionView
@compile_mutex = Mutex.new
end
- # Returns if the underlying handler supports streaming. If so,
+ # Returns whether the underlying handler supports streaming. If so,
# a streaming buffer *may* be passed when it start rendering.
def supports_streaming?
handler.respond_to?(:supports_streaming?) && handler.supports_streaming?
@@ -154,7 +154,7 @@ module ActionView
# we use a bang in this instrumentation because you don't want to
# consume this in production. This is only slow if it's being listened to.
def render(view, locals, buffer=nil, &block)
- instrument("!render_template") do
+ instrument("!render_template".freeze) do
compile!(view)
view.send(method_name, locals, buffer, &block)
end
@@ -190,7 +190,7 @@ module ActionView
end
def inspect
- @inspect ||= defined?(Rails.root) ? identifier.sub("#{Rails.root}/", '') : identifier
+ @inspect ||= defined?(Rails.root) ? identifier.sub("#{Rails.root}/", ''.freeze) : identifier
end
# This method is responsible for properly setting the encoding of the
@@ -337,18 +337,23 @@ module ActionView
def method_name #:nodoc:
@method_name ||= begin
m = "_#{identifier_method_name}__#{@identifier.hash}_#{__id__}"
- m.tr!('-', '_')
+ m.tr!('-'.freeze, '_'.freeze)
m
end
end
def identifier_method_name #:nodoc:
- inspect.tr('^a-z_', '_')
+ inspect.tr('^a-z_'.freeze, '_'.freeze)
end
def instrument(action, &block)
payload = { virtual_path: @virtual_path, identifier: @identifier }
- ActiveSupport::Notifications.instrument("#{action}.action_view", payload, &block)
+ case action
+ when "!render_template".freeze
+ ActiveSupport::Notifications.instrument("!render_template.action_view".freeze, payload, &block)
+ else
+ ActiveSupport::Notifications.instrument("#{action}.action_view".freeze, payload, &block)
+ end
end
EXPLICIT_COLLECTION = /# Template Collection: (?<resource_name>\w+)/
@@ -366,7 +371,7 @@ module ActionView
end
def inferred_cache_name
- @inferred_cache_name ||= @virtual_path.split('/').last.sub('_', '')
+ @inferred_cache_name ||= @virtual_path.split('/'.freeze).last.sub('_'.freeze, ''.freeze)
end
end
end
diff --git a/actionview/lib/action_view/template/resolver.rb b/actionview/lib/action_view/template/resolver.rb
index 2b00b0303d..28967f40a6 100644
--- a/actionview/lib/action_view/template/resolver.rb
+++ b/actionview/lib/action_view/template/resolver.rb
@@ -52,6 +52,7 @@ module ActionView
def initialize
@data = SmallCache.new(&KEY_BLOCK)
+ @query_cache = SmallCache.new
end
# Cache the templates returned by the block
@@ -70,8 +71,17 @@ module ActionView
end
end
+ def cache_query(query) # :nodoc:
+ if Resolver.caching?
+ @query_cache[query] ||= canonical_no_templates(yield)
+ else
+ yield
+ end
+ end
+
def clear
@data.clear
+ @query_cache.clear
end
private
@@ -116,6 +126,10 @@ module ActionView
end
end
+ def find_all_with_query(query) # :nodoc:
+ @cache.cache_query(query) { find_template_paths(File.join(@path, query)) }
+ end
+
private
delegate :caching?, to: :class
@@ -222,7 +236,7 @@ module ActionView
end
def escape_entry(entry)
- entry.gsub(/[*?{}\[\]]/, '\\\\\\&')
+ entry.gsub(/[*?{}\[\]]/, '\\\\\\&'.freeze)
end
# Returns the file mtime from the filesystem.
@@ -234,7 +248,7 @@ module ActionView
# from the path, or the handler, we should return the array of formats given
# to the resolver.
def extract_handler_and_format_and_variant(path, default_formats)
- pieces = File.basename(path).split('.')
+ pieces = File.basename(path).split('.'.freeze)
pieces.shift
extension = pieces.pop
diff --git a/actionview/lib/action_view/test_case.rb b/actionview/lib/action_view/test_case.rb
index c4bc26ca8a..f6b5696a13 100644
--- a/actionview/lib/action_view/test_case.rb
+++ b/actionview/lib/action_view/test_case.rb
@@ -263,9 +263,15 @@ module ActionView
end
def method_missing(selector, *args)
- if @controller.respond_to?(:_routes) &&
- ( @controller._routes.named_routes.route_defined?(selector) ||
- @controller._routes.mounted_helpers.method_defined?(selector) )
+ begin
+ routes = @controller.respond_to?(:_routes) && @controller._routes
+ rescue
+ # Dont call routes, if there is an error on _routes call
+ end
+
+ if routes &&
+ ( routes.named_routes.route_defined?(selector) ||
+ routes.mounted_helpers.method_defined?(selector) )
@controller.__send__(selector, *args)
else
super
diff --git a/actionview/lib/action_view/view_paths.rb b/actionview/lib/action_view/view_paths.rb
index ebca598337..37722013ce 100644
--- a/actionview/lib/action_view/view_paths.rb
+++ b/actionview/lib/action_view/view_paths.rb
@@ -36,9 +36,9 @@ module ActionView
self.class._prefixes
end
- # <tt>LookupContext</tt> is the object responsible to hold all information required to lookup
- # templates, i.e. view paths and details. Check <tt>ActionView::LookupContext</tt> for more
- # information.
+ # <tt>LookupContext</tt> is the object responsible for holding all
+ # information required for looking up templates, i.e. view paths and
+ # details. Check <tt>ActionView::LookupContext</tt> for more information.
def lookup_context
@_lookup_context ||=
ActionView::LookupContext.new(self.class._view_paths, details_for_lookup, _prefixes)
diff --git a/actionview/test/abstract_unit.rb b/actionview/test/abstract_unit.rb
index 4635c645d0..12870acaa6 100644
--- a/actionview/test/abstract_unit.rb
+++ b/actionview/test/abstract_unit.rb
@@ -16,6 +16,7 @@ silence_warnings do
end
require 'active_support/testing/autorun'
+require 'active_support/testing/method_call_assertions'
require 'action_controller'
require 'action_view'
require 'action_view/testing/resolvers'
@@ -147,13 +148,13 @@ class ActionDispatch::IntegrationTest < ActiveSupport::TestCase
def self.build_app(routes = nil)
RoutedRackApp.new(routes || ActionDispatch::Routing::RouteSet.new) do |middleware|
- middleware.use "ActionDispatch::ShowExceptions", ActionDispatch::PublicExceptions.new("#{FIXTURE_LOAD_PATH}/public")
- middleware.use "ActionDispatch::DebugExceptions"
- middleware.use "ActionDispatch::Callbacks"
- middleware.use "ActionDispatch::ParamsParser"
- middleware.use "ActionDispatch::Cookies"
- middleware.use "ActionDispatch::Flash"
- middleware.use "Rack::Head"
+ middleware.use ActionDispatch::ShowExceptions, ActionDispatch::PublicExceptions.new("#{FIXTURE_LOAD_PATH}/public")
+ middleware.use ActionDispatch::DebugExceptions
+ middleware.use ActionDispatch::Callbacks
+ middleware.use ActionDispatch::ParamsParser
+ middleware.use ActionDispatch::Cookies
+ middleware.use ActionDispatch::Flash
+ middleware.use Rack::Head
yield(middleware) if block_given?
end
end
@@ -281,3 +282,6 @@ def jruby_skip(message = '')
end
require 'mocha/setup' # FIXME: stop using mocha
+class ActiveSupport::TestCase
+ include ActiveSupport::Testing::MethodCallAssertions
+end
diff --git a/actionview/test/actionpack/abstract/layouts_test.rb b/actionview/test/actionpack/abstract/layouts_test.rb
index a6786d9b6b..80bc665b0a 100644
--- a/actionview/test/actionpack/abstract/layouts_test.rb
+++ b/actionview/test/actionpack/abstract/layouts_test.rb
@@ -52,7 +52,7 @@ module AbstractControllerTests
end
def overwrite_skip
- render :text => "Hello text!"
+ render plain: "Hello text!"
end
end
@@ -371,7 +371,7 @@ module AbstractControllerTests
test "layout for anonymous controller" do
klass = Class.new(WithString) do
def index
- render :text => 'index', :layout => true
+ render plain: 'index', layout: true
end
end
diff --git a/actionview/test/actionpack/abstract/render_test.rb b/actionview/test/actionpack/abstract/render_test.rb
index d09f91c1e2..e5721d6416 100644
--- a/actionview/test/actionpack/abstract/render_test.rb
+++ b/actionview/test/actionpack/abstract/render_test.rb
@@ -1,4 +1,5 @@
require 'abstract_unit'
+require 'active_support/deprecation'
module AbstractController
module Testing
@@ -33,7 +34,7 @@ module AbstractController
end
def text
- render :text => "With Text"
+ render plain: "With Text"
end
def default
diff --git a/actionview/test/actionpack/controller/render_test.rb b/actionview/test/actionpack/controller/render_test.rb
index ebaf39a12d..8d048ddbcb 100644
--- a/actionview/test/actionpack/controller/render_test.rb
+++ b/actionview/test/actionpack/controller/render_test.rb
@@ -121,7 +121,7 @@ class TestController < ApplicationController
# :ported:
def render_hello_world_from_variable
@person = "david"
- render :text => "hello #{@person}"
+ render plain: "hello #{@person}"
end
# :ported:
@@ -143,13 +143,13 @@ class TestController < ApplicationController
# :ported:
def render_text_hello_world
- render :text => "hello world"
+ render plain: "hello world"
end
# :ported:
def render_text_hello_world_with_layout
@variable_for_layout = ", I am here!"
- render :text => "hello world", :layout => true
+ render plain: "hello world", :layout => true
end
def hello_world_with_layout_false
@@ -212,26 +212,26 @@ class TestController < ApplicationController
# :ported:
def render_custom_code
- render :text => "hello world", :status => 404
+ render plain: "hello world", :status => 404
end
# :ported:
def render_text_with_nil
- render :text => nil
+ render plain: nil
end
# :ported:
def render_text_with_false
- render :text => false
+ render plain: false
end
def render_text_with_resource
- render :text => Customer.new("David")
+ render plain: Customer.new("David")
end
# :ported:
def render_nothing_with_appendix
- render :text => "appended"
+ render plain: "appended"
end
# This test is testing 3 things:
@@ -262,7 +262,7 @@ class TestController < ApplicationController
# :ported:
def blank_response
- render :text => ' '
+ render plain: ' '
end
# :ported:
@@ -294,7 +294,7 @@ class TestController < ApplicationController
def hello_in_a_string
@customers = [ Customer.new("david"), Customer.new("mary") ]
- render :text => "How's there? " + render_to_string(:template => "test/list")
+ render plain: "How's there? " + render_to_string(:template => "test/list")
end
def accessing_params_in_template
@@ -362,7 +362,7 @@ class TestController < ApplicationController
def render_to_string_with_assigns
@before = "i'm before the render"
- render_to_string :text => "foo"
+ render_to_string plain: "foo"
@after = "i'm after the render"
render :template => "test/hello_world"
end
@@ -409,8 +409,8 @@ class TestController < ApplicationController
# :ported:
def double_render
- render :text => "hello"
- render :text => "world"
+ render plain: "hello"
+ render plain: "world"
end
def double_redirect
@@ -419,13 +419,13 @@ class TestController < ApplicationController
end
def render_and_redirect
- render :text => "hello"
+ render plain: "hello"
redirect_to :action => "double_render"
end
def render_to_string_and_render
- @stuff = render_to_string :text => "here is some cached stuff"
- render :text => "Hi web users! #{@stuff}"
+ @stuff = render_to_string plain: "here is some cached stuff"
+ render plain: "Hi web users! #{@stuff}"
end
def render_to_string_with_inline_and_render
@@ -454,7 +454,7 @@ class TestController < ApplicationController
# :addressed:
def render_text_with_assigns
@hello = "world"
- render :text => "foo"
+ render plain: "foo"
end
def render_with_assigns_option
@@ -467,7 +467,7 @@ class TestController < ApplicationController
def render_content_type_from_body
response.content_type = Mime::RSS
- render :text => "hello world!"
+ render body: "hello world!"
end
def render_using_layout_around_block
@@ -770,7 +770,7 @@ class RenderTest < ActionController::TestCase
# :ported:
def test_do_with_render_text_and_layout
get :render_text_hello_world_with_layout
- assert_equal "<html>hello world, I am here!</html>", @response.body
+ assert_equal "{{hello world, I am here!}}\n", @response.body
end
# :ported:
diff --git a/actionview/test/activerecord/relation_cache_test.rb b/actionview/test/activerecord/relation_cache_test.rb
new file mode 100644
index 0000000000..8e97417b94
--- /dev/null
+++ b/actionview/test/activerecord/relation_cache_test.rb
@@ -0,0 +1,18 @@
+require 'active_record_unit'
+
+class RelationCacheTest < ActionView::TestCase
+ tests ActionView::Helpers::CacheHelper
+
+ def setup
+ @virtual_path = "path"
+ controller.cache_store = ActiveSupport::Cache::MemoryStore.new
+ end
+
+ def test_cache_relation_other
+ cache(Project.all){ concat("Hello World") }
+ assert_equal "Hello World", controller.cache_store.read("views/projects-#{Project.count}/")
+ end
+
+ def view_cache_dependencies; end
+
+end
diff --git a/actionview/test/fixtures/actionpack/layouts/standard.text.erb b/actionview/test/fixtures/actionpack/layouts/standard.text.erb
new file mode 100644
index 0000000000..a58afb1aa2
--- /dev/null
+++ b/actionview/test/fixtures/actionpack/layouts/standard.text.erb
@@ -0,0 +1 @@
+{{<%= yield %><%= @variable_for_layout %>}}
diff --git a/actionview/test/fixtures/digestor/events/_completed.html.erb b/actionview/test/fixtures/digestor/events/_completed.html.erb
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/actionview/test/fixtures/digestor/events/_completed.html.erb
diff --git a/actionview/test/fixtures/digestor/events/index.html.erb b/actionview/test/fixtures/digestor/events/index.html.erb
new file mode 100644
index 0000000000..bc45e41bcb
--- /dev/null
+++ b/actionview/test/fixtures/digestor/events/index.html.erb
@@ -0,0 +1 @@
+<% # Template Dependency: events/* %> \ No newline at end of file
diff --git a/actionview/test/fixtures/project.rb b/actionview/test/fixtures/project.rb
index c124a9e605..404b12cbab 100644
--- a/actionview/test/fixtures/project.rb
+++ b/actionview/test/fixtures/project.rb
@@ -1,3 +1,7 @@
class Project < ActiveRecord::Base
has_and_belongs_to_many :developers, -> { uniq }
+
+ def self.collection_cache_key(collection = all, timestamp_column = :updated_at)
+ "projects-#{collection.count}"
+ end
end
diff --git a/actionview/test/template/asset_tag_helper_test.rb b/actionview/test/template/asset_tag_helper_test.rb
index 01fc66bed6..496b33b35e 100644
--- a/actionview/test/template/asset_tag_helper_test.rb
+++ b/actionview/test/template/asset_tag_helper_test.rb
@@ -588,11 +588,13 @@ class AssetTagHelperTest < ActionView::TestCase
end
end
- @controller.request.stubs(:ssl?).returns(false)
- assert_equal "http://assets15.example.com/images/xml.png", image_path("xml.png")
+ @controller.request.stub(:ssl?, false) do
+ assert_equal "http://assets15.example.com/images/xml.png", image_path("xml.png")
+ end
- @controller.request.stubs(:ssl?).returns(true)
- assert_equal "http://localhost/images/xml.png", image_path("xml.png")
+ @controller.request.stub(:ssl?, true) do
+ assert_equal "http://localhost/images/xml.png", image_path("xml.png")
+ end
end
end
diff --git a/actionview/test/template/digestor_test.rb b/actionview/test/template/digestor_test.rb
index f0afcdb5ae..dde757b5a2 100644
--- a/actionview/test/template/digestor_test.rb
+++ b/actionview/test/template/digestor_test.rb
@@ -1,5 +1,6 @@
require 'abstract_unit'
require 'fileutils'
+require 'action_view/dependency_tracker'
class FixtureTemplate
attr_reader :source, :handler
@@ -15,12 +16,13 @@ end
class FixtureFinder
FIXTURES_DIR = "#{File.dirname(__FILE__)}/../fixtures/digestor"
- attr_reader :details
+ attr_reader :details, :view_paths
attr_accessor :formats
attr_accessor :variants
def initialize
@details = {}
+ @view_paths = ActionView::PathSet.new(['digestor'])
@formats = []
@variants = []
end
@@ -75,6 +77,34 @@ class TemplateDigestorTest < ActionView::TestCase
end
end
+ def test_explicit_dependency_wildcard
+ assert_digest_difference("events/index") do
+ change_template("events/_completed")
+ end
+ end
+
+ def test_explicit_dependency_wildcard_picks_up_added_file
+ old_caching, ActionView::Resolver.caching = ActionView::Resolver.caching, false
+
+ assert_digest_difference("events/index") do
+ add_template("events/_uncompleted")
+ end
+ ensure
+ remove_template("events/_uncompleted")
+ ActionView::Resolver.caching = old_caching
+ end
+
+ def test_explicit_dependency_wildcard_picks_up_removed_file
+ old_caching, ActionView::Resolver.caching = ActionView::Resolver.caching, false
+ add_template("events/_subscribers_changed")
+
+ assert_digest_difference("events/index") do
+ remove_template("events/_subscribers_changed")
+ end
+ ensure
+ ActionView::Resolver.caching = old_caching
+ end
+
def test_second_level_dependency
assert_digest_difference("messages/show") do
change_template("comments/_comments")
@@ -219,7 +249,7 @@ class TemplateDigestorTest < ActionView::TestCase
end
def test_variants
- assert_digest_difference("messages/new", false, variants: [:iphone]) do
+ assert_digest_difference("messages/new", variants: [:iphone]) do
change_template("messages/new", :iphone)
change_template("messages/_header", :iphone)
end
@@ -239,16 +269,6 @@ class TemplateDigestorTest < ActionView::TestCase
assert_not_equal digest_phone, digest_fridge_phone
end
- def test_cache_template_loading
- resolver_before = ActionView::Resolver.caching
- ActionView::Resolver.caching = false
- assert_digest_difference("messages/edit", true) do
- change_template("comments/_comment")
- end
- ensure
- ActionView::Resolver.caching = resolver_before
- end
-
def test_digest_cache_cleanup_with_recursion
first_digest = digest("level/_recursion")
second_digest = digest("level/_recursion")
@@ -291,9 +311,9 @@ class TemplateDigestorTest < ActionView::TestCase
end
end
- def assert_digest_difference(template_name, persistent = false, options = {})
+ def assert_digest_difference(template_name, options = {})
previous_digest = digest(template_name, options)
- ActionView::Digestor.cache.clear unless persistent
+ ActionView::Digestor.cache.clear
yield
@@ -329,4 +349,9 @@ class TemplateDigestorTest < ActionView::TestCase
f.write "\nTHIS WAS CHANGED!"
end
end
+ alias_method :add_template, :change_template
+
+ def remove_template(template_name)
+ File.delete("digestor/#{template_name}.html.erb")
+ end
end
diff --git a/actionview/test/template/form_helper_test.rb b/actionview/test/template/form_helper_test.rb
index b8cb5bd746..aef137935a 100644
--- a/actionview/test/template/form_helper_test.rb
+++ b/actionview/test/template/form_helper_test.rb
@@ -1577,7 +1577,7 @@ class FormHelperTest < ActionView::TestCase
"<textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea>" +
"<input name='post[secret]' type='hidden' value='0' />" +
"<input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />" +
- "<input name='commit' type='submit' value='Create post' />" +
+ "<input name='commit' data-disable-with='Create post' type='submit' value='Create post' />" +
"<button name='button' type='submit'>Create post</button>" +
"<button name='button' type='submit'><span>Create post</span></button>"
end
@@ -1854,7 +1854,7 @@ class FormHelperTest < ActionView::TestCase
expected = whole_form("/posts/44", "edit_post_44", "edit_post", method: "patch") do
"<input name='post[title]' type='text' id='post_title' value='And his name will be forty and four.' />" +
- "<input name='commit' type='submit' value='Edit post' />"
+ "<input name='commit' data-disable-with='Edit post' type='submit' value='Edit post' />"
end
assert_dom_equal expected, output_buffer
@@ -1875,7 +1875,7 @@ class FormHelperTest < ActionView::TestCase
"<textarea name='other_name[body]' id='other_name_body'>\nBack to the hill and over it again!</textarea>" +
"<input name='other_name[secret]' value='0' type='hidden' />" +
"<input name='other_name[secret]' checked='checked' id='other_name_secret' value='1' type='checkbox' />" +
- "<input name='commit' value='Create post' type='submit' />"
+ "<input name='commit' value='Create post' data-disable-with='Create post' type='submit' />"
end
assert_dom_equal expected, output_buffer
@@ -2003,21 +2003,22 @@ class FormHelperTest < ActionView::TestCase
def test_form_for_with_remote_without_html
@post.persisted = false
- @post.stubs(:to_key).returns(nil)
- form_for(@post, remote: true) do |f|
- concat f.text_field(:title)
- concat f.text_area(:body)
- concat f.check_box(:secret)
- end
+ @post.stub(:to_key, nil) do
+ form_for(@post, remote: true) do |f|
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.check_box(:secret)
+ end
- expected = whole_form("/posts", "new_post", "new_post", remote: true) do
- "<input name='post[title]' type='text' id='post_title' value='Hello World' />" +
- "<textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea>" +
- "<input name='post[secret]' type='hidden' value='0' />" +
- "<input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />"
- end
+ expected = whole_form("/posts", "new_post", "new_post", remote: true) do
+ "<input name='post[title]' type='text' id='post_title' value='Hello World' />" +
+ "<textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea>" +
+ "<input name='post[secret]' type='hidden' value='0' />" +
+ "<input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />"
+ end
- assert_dom_equal expected, output_buffer
+ assert_dom_equal expected, output_buffer
+ end
end
def test_form_for_without_object
@@ -2083,7 +2084,7 @@ class FormHelperTest < ActionView::TestCase
expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do
"<div class='field_with_errors'><label for='post_author_name' class='label'>Author name</label></div>" +
"<div class='field_with_errors'><input name='post[author_name]' type='text' id='post_author_name' value='' /></div>" +
- "<input name='commit' type='submit' value='Create post' />"
+ "<input name='commit' data-disable-with='Create post' type='submit' value='Create post' />"
end
assert_dom_equal expected, output_buffer
@@ -2101,7 +2102,7 @@ class FormHelperTest < ActionView::TestCase
expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do
"<div class='field_with_errors'><label for='post_author_name' class='label'>Author name</label></div>" +
"<div class='field_with_errors'><input name='post[author_name]' type='text' id='post_author_name' value='' /></div>" +
- "<input name='commit' type='submit' value='Create post' />"
+ "<input name='commit' data-disable-with='Create post' type='submit' value='Create post' />"
end
assert_dom_equal expected, output_buffer
@@ -2220,16 +2221,17 @@ class FormHelperTest < ActionView::TestCase
def test_submit_with_object_as_new_record_and_locale_strings
with_locale :submit do
@post.persisted = false
- @post.stubs(:to_key).returns(nil)
- form_for(@post) do |f|
- concat f.submit
- end
+ @post.stub(:to_key, nil) do
+ form_for(@post) do |f|
+ concat f.submit
+ end
- expected = whole_form('/posts', 'new_post', 'new_post') do
- "<input name='commit' type='submit' value='Create Post' />"
- end
+ expected = whole_form('/posts', 'new_post', 'new_post') do
+ "<input name='commit' data-disable-with='Create Post' type='submit' value='Create Post' />"
+ end
- assert_dom_equal expected, output_buffer
+ assert_dom_equal expected, output_buffer
+ end
end
end
@@ -2240,7 +2242,7 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do
- "<input name='commit' type='submit' value='Confirm Post changes' />"
+ "<input name='commit' data-disable-with='Confirm Post changes' type='submit' value='Confirm Post changes' />"
end
assert_dom_equal expected, output_buffer
@@ -2254,7 +2256,7 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form do
- "<input name='commit' class='extra' type='submit' value='Save changes' />"
+ "<input name='commit' class='extra' data-disable-with='Save changes' type='submit' value='Save changes' />"
end
assert_dom_equal expected, output_buffer
@@ -2268,7 +2270,7 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form('/posts/123', 'edit_another_post', 'edit_another_post', method: 'patch') do
- "<input name='commit' type='submit' value='Update your Post' />"
+ "<input name='commit' data-disable-with='Update your Post' type='submit' value='Update your Post' />"
end
assert_dom_equal expected, output_buffer
@@ -2807,11 +2809,12 @@ class FormHelperTest < ActionView::TestCase
def test_nested_fields_label_translation_with_more_than_10_records
@post.comments = Array.new(11) { |id| Comment.new(id + 1) }
- I18n.expects(:t).with('post.comments.body', default: [:"comment.body", ''], scope: "helpers.label").times(11).returns "Write body here"
-
- form_for(@post) do |f|
- f.fields_for(:comments) do |cf|
- concat cf.label(:body)
+ params = 11.times.map { ['post.comments.body', default: [:"comment.body", ''], scope: "helpers.label"] }
+ assert_called_with(I18n, :t, params, returns: "Write body here") do
+ form_for(@post) do |f|
+ f.fields_for(:comments) do |cf|
+ concat cf.label(:body)
+ end
end
end
end
diff --git a/actionview/test/template/form_options_helper_i18n_test.rb b/actionview/test/template/form_options_helper_i18n_test.rb
index 4972ea6511..26ede09a5f 100644
--- a/actionview/test/template/form_options_helper_i18n_test.rb
+++ b/actionview/test/template/form_options_helper_i18n_test.rb
@@ -14,8 +14,9 @@ class FormOptionsHelperI18nTests < ActionView::TestCase
end
def test_select_with_prompt_true_translates_prompt_message
- I18n.expects(:translate).with('helpers.select.prompt', { :default => 'Please select' })
- select('post', 'category', [], :prompt => true)
+ assert_called_with(I18n, :translate, ['helpers.select.prompt', { :default => 'Please select' }]) do
+ select('post', 'category', [], :prompt => true)
+ end
end
def test_select_with_translated_prompt
diff --git a/actionview/test/template/form_tag_helper_test.rb b/actionview/test/template/form_tag_helper_test.rb
index f602c82c42..a9d9562580 100644
--- a/actionview/test/template/form_tag_helper_test.rb
+++ b/actionview/test/template/form_tag_helper_test.rb
@@ -433,6 +433,44 @@ class FormTagHelperTest < ActionView::TestCase
)
end
+ def test_empty_submit_tag
+ assert_dom_equal(
+ %(<input data-disable-with="Save" name='commit' type="submit" value="Save" />),
+ submit_tag("Save")
+ )
+ end
+
+ def test_empty_submit_tag_with_opt_out
+ ActionView::Base.automatically_disable_submit_tag = false
+ assert_dom_equal(
+ %(<input name='commit' type="submit" value="Save" />),
+ submit_tag("Save")
+ )
+ ensure
+ ActionView::Base.automatically_disable_submit_tag = true
+ end
+
+ def test_data_disable_with_string
+ assert_dom_equal(
+ %(<input data-disable-with="Processing..." data-confirm="Are you sure?" name='commit' type="submit" value="Save" />),
+ submit_tag("Save", { "data-disable-with" => "Processing...", "data-confirm" => "Are you sure?" })
+ )
+ end
+
+ def test_data_disable_with_boolean
+ assert_dom_equal(
+ %(<input data-confirm="Are you sure?" name='commit' type="submit" value="Save" />),
+ submit_tag("Save", { "data-disable-with" => false, "data-confirm" => "Are you sure?" })
+ )
+ end
+
+ def test_data_hash_disable_with_boolean
+ assert_dom_equal(
+ %(<input data-confirm="Are you sure?" name='commit' type="submit" value="Save" />),
+ submit_tag("Save", { :data => { :confirm => "Are you sure?", :disable_with => false } })
+ )
+ end
+
def test_submit_tag_with_no_onclick_options
assert_dom_equal(
%(<input name='commit' data-disable-with="Saving..." type="submit" value="Save" />),
@@ -442,7 +480,7 @@ class FormTagHelperTest < ActionView::TestCase
def test_submit_tag_with_confirmation
assert_dom_equal(
- %(<input name='commit' type='submit' value='Save' data-confirm="Are you sure?" />),
+ %(<input name='commit' type='submit' value='Save' data-confirm="Are you sure?" data-disable-with="Save" />),
submit_tag("Save", :data => { :confirm => "Are you sure?" })
)
end
diff --git a/actionview/test/template/lookup_context_test.rb b/actionview/test/template/lookup_context_test.rb
index 4f7823045e..14dafd7d63 100644
--- a/actionview/test/template/lookup_context_test.rb
+++ b/actionview/test/template/lookup_context_test.rb
@@ -108,10 +108,11 @@ class LookupContextTest < ActiveSupport::TestCase
end
test "found templates respects given formats if one cannot be found from template or handler" do
- ActionView::Template::Handlers::Builder.expects(:default_format).returns(nil)
- @lookup_context.formats = [:text]
- template = @lookup_context.find("hello", %w(test))
- assert_equal [:text], template.formats
+ assert_called(ActionView::Template::Handlers::Builder, :default_format, returns: nil) do
+ @lookup_context.formats = [:text]
+ template = @lookup_context.find("hello", %w(test))
+ assert_equal [:text], template.formats
+ end
end
test "adds fallbacks to view paths when required" do
@@ -210,45 +211,50 @@ end
class LookupContextWithFalseCaching < ActiveSupport::TestCase
def setup
@resolver = ActionView::FixtureResolver.new("test/_foo.erb" => ["Foo", Time.utc(2000)])
- ActionView::Resolver.stubs(:caching?).returns(false)
@lookup_context = ActionView::LookupContext.new(@resolver, {})
end
test "templates are always found in the resolver but timestamp is checked before being compiled" do
- template = @lookup_context.find("foo", %w(test), true)
- assert_equal "Foo", template.source
-
- # Now we are going to change the template, but it won't change the returned template
- # since the timestamp is the same.
- @resolver.hash["test/_foo.erb"][0] = "Bar"
- template = @lookup_context.find("foo", %w(test), true)
- assert_equal "Foo", template.source
-
- # Now update the timestamp.
- @resolver.hash["test/_foo.erb"][1] = Time.now.utc
- template = @lookup_context.find("foo", %w(test), true)
- assert_equal "Bar", template.source
+ ActionView::Resolver.stub(:caching?, false) do
+ template = @lookup_context.find("foo", %w(test), true)
+ assert_equal "Foo", template.source
+
+ # Now we are going to change the template, but it won't change the returned template
+ # since the timestamp is the same.
+ @resolver.hash["test/_foo.erb"][0] = "Bar"
+ template = @lookup_context.find("foo", %w(test), true)
+ assert_equal "Foo", template.source
+
+ # Now update the timestamp.
+ @resolver.hash["test/_foo.erb"][1] = Time.now.utc
+ template = @lookup_context.find("foo", %w(test), true)
+ assert_equal "Bar", template.source
+ end
end
test "if no template was found in the second lookup, with no cache, raise error" do
- template = @lookup_context.find("foo", %w(test), true)
- assert_equal "Foo", template.source
+ ActionView::Resolver.stub(:caching?, false) do
+ template = @lookup_context.find("foo", %w(test), true)
+ assert_equal "Foo", template.source
- @resolver.hash.clear
- assert_raise ActionView::MissingTemplate do
- @lookup_context.find("foo", %w(test), true)
+ @resolver.hash.clear
+ assert_raise ActionView::MissingTemplate do
+ @lookup_context.find("foo", %w(test), true)
+ end
end
end
test "if no template was cached in the first lookup, retrieval should work in the second call" do
- @resolver.hash.clear
- assert_raise ActionView::MissingTemplate do
- @lookup_context.find("foo", %w(test), true)
- end
+ ActionView::Resolver.stub(:caching?, false) do
+ @resolver.hash.clear
+ assert_raise ActionView::MissingTemplate do
+ @lookup_context.find("foo", %w(test), true)
+ end
- @resolver.hash["test/_foo.erb"] = ["Foo", Time.utc(2000)]
- template = @lookup_context.find("foo", %w(test), true)
- assert_equal "Foo", template.source
+ @resolver.hash["test/_foo.erb"] = ["Foo", Time.utc(2000)]
+ template = @lookup_context.find("foo", %w(test), true)
+ assert_equal "Foo", template.source
+ end
end
end
diff --git a/actionview/test/template/number_helper_test.rb b/actionview/test/template/number_helper_test.rb
index b70b750869..631d45586b 100644
--- a/actionview/test/template/number_helper_test.rb
+++ b/actionview/test/template/number_helper_test.rb
@@ -1,3 +1,4 @@
+# encoding: utf-8
require "abstract_unit"
class NumberHelperTest < ActionView::TestCase
@@ -21,6 +22,7 @@ class NumberHelperTest < ActionView::TestCase
assert_equal "&lt;b&gt;1,234,567,890.50&lt;/b&gt; $", number_to_currency("1234567890.50", format: "<b>%n</b> %u")
assert_equal "&lt;b&gt;1,234,567,890.50&lt;/b&gt; $", number_to_currency("-1234567890.50", negative_format: "<b>%n</b> %u")
assert_equal "&lt;b&gt;1,234,567,890.50&lt;/b&gt; $", number_to_currency("-1234567890.50", 'negative_format' => "<b>%n</b> %u")
+ assert_equal '₹ 12,30,000.00', number_to_currency(1230000, delimiter_pattern: /(\d+?)(?=(\d\d)+(\d)(?!\d))/, unit: '₹', format: "%u %n")
end
def test_number_to_percentage
diff --git a/actionview/test/template/template_test.rb b/actionview/test/template/template_test.rb
index d3b51cd629..921011b073 100644
--- a/actionview/test/template/template_test.rb
+++ b/actionview/test/template/template_test.rb
@@ -118,15 +118,17 @@ class TestERBTemplate < ActiveSupport::TestCase
def test_refresh_with_templates
@template = new_template("Hello", :virtual_path => "test/foo/bar")
@template.locals = [:key]
- @context.lookup_context.expects(:find_template).with("bar", %w(test/foo), false, [:key]).returns("template")
- assert_equal "template", @template.refresh(@context)
+ assert_called_with(@context.lookup_context, :find_template,["bar", %w(test/foo), false, [:key]], returns: "template") do
+ assert_equal "template", @template.refresh(@context)
+ end
end
def test_refresh_with_partials
@template = new_template("Hello", :virtual_path => "test/_foo")
@template.locals = [:key]
- @context.lookup_context.expects(:find_template).with("foo", %w(test), true, [:key]).returns("partial")
- assert_equal "partial", @template.refresh(@context)
+ assert_called_with(@context.lookup_context, :find_template,[ "foo", %w(test), true, [:key]], returns: "partial") do
+ assert_equal "partial", @template.refresh(@context)
+ end
end
def test_refresh_raises_an_error_without_virtual_path
diff --git a/actionview/test/template/test_case_test.rb b/actionview/test/template/test_case_test.rb
index 05c3dc0613..b057d43ee0 100644
--- a/actionview/test/template/test_case_test.rb
+++ b/actionview/test/template/test_case_test.rb
@@ -20,6 +20,7 @@ module ActionView
class TestCase
helper ASharedTestHelper
+ DeveloperStruct = Struct.new(:name)
module SharedTests
def self.included(test_case)
@@ -50,7 +51,7 @@ module ActionView
end
test "works without testing a helper module" do
- assert_equal 'Eloy', render('developers/developer', :developer => stub(:name => 'Eloy'))
+ assert_equal 'Eloy', render('developers/developer', :developer => DeveloperStruct.new('Eloy'))
end
test "can render a layout with block" do
@@ -69,13 +70,15 @@ module ActionView
end
test "delegates notice to request.flash[:notice]" do
- view.request.flash.expects(:[]).with(:notice)
- view.notice
+ assert_called_with(view.request.flash, :[], [:notice]) do
+ view.notice
+ end
end
test "delegates alert to request.flash[:alert]" do
- view.request.flash.expects(:[]).with(:alert)
- view.alert
+ assert_called_with(view.request.flash, :[], [:alert]) do
+ view.alert
+ end
end
test "uses controller lookup context" do
@@ -119,7 +122,7 @@ module ActionView
test "helper class that is being tested is always included in view instance" do
@controller.controller_path = 'test'
- @customers = [stub(:name => 'Eloy'), stub(:name => 'Manfred')]
+ @customers = [DeveloperStruct.new('Eloy'), DeveloperStruct.new('Manfred')]
assert_match(/Hello: EloyHello: Manfred/, render(:partial => 'test/from_helper'))
end
end
@@ -209,7 +212,7 @@ module ActionView
end
test "is able to use routes" do
- controller.request.assign_parameters(@routes, 'foo', 'index')
+ controller.request.assign_parameters(@routes, 'foo', 'index', {}, '/foo', [])
assert_equal '/foo', url_for
assert_equal '/bar', url_for(:controller => 'bar')
end
@@ -255,15 +258,15 @@ module ActionView
end
test "is able to render partials with local variables" do
- assert_equal 'Eloy', render('developers/developer', :developer => stub(:name => 'Eloy'))
+ assert_equal 'Eloy', render('developers/developer', :developer => DeveloperStruct.new('Eloy'))
assert_equal 'Eloy', render(:partial => 'developers/developer',
- :locals => { :developer => stub(:name => 'Eloy') })
+ :locals => { :developer => DeveloperStruct.new('Eloy') })
end
test "is able to render partials from templates and also use instance variables" do
@controller.controller_path = "test"
- @customers = [stub(:name => 'Eloy'), stub(:name => 'Manfred')]
+ @customers = [DeveloperStruct.new('Eloy'), DeveloperStruct.new('Manfred')]
assert_match(/Hello: EloyHello: Manfred/, render(:file => 'test/list'))
end
@@ -272,7 +275,7 @@ module ActionView
view
- @customers = [stub(:name => 'Eloy'), stub(:name => 'Manfred')]
+ @customers = [DeveloperStruct.new('Eloy'), DeveloperStruct.new('Manfred')]
assert_match(/Hello: EloyHello: Manfred/, render(:file => 'test/list'))
end
diff --git a/actionview/test/template/text_helper_test.rb b/actionview/test/template/text_helper_test.rb
index 5791f33069..fae1965ffa 100644
--- a/actionview/test/template/text_helper_test.rb
+++ b/actionview/test/template/text_helper_test.rb
@@ -366,6 +366,10 @@ class TextHelperTest < ActionView::TestCase
assert_equal options, passed_options
end
+ def test_word_wrap_with_custom_break_sequence
+ assert_equal("1234567890\r\n1234567890\r\n1234567890", word_wrap("1234567890 " * 3, line_width: 2, break_sequence: "\r\n"))
+ end
+
def test_pluralization
assert_equal("1 count", pluralize(1, "count"))
assert_equal("2 counts", pluralize(2, "count"))
diff --git a/actionview/test/template/translation_helper_test.rb b/actionview/test/template/translation_helper_test.rb
index 5dc281adb2..749d0dd7fd 100644
--- a/actionview/test/template/translation_helper_test.rb
+++ b/actionview/test/template/translation_helper_test.rb
@@ -42,14 +42,16 @@ class TranslationHelperTest < ActiveSupport::TestCase
end
def test_delegates_setting_to_i18n
- I18n.expects(:translate).with(:foo, :locale => 'en', :raise => true).returns("")
- translate :foo, :locale => 'en'
+ assert_called_with(I18n, :translate, [:foo, :locale => 'en', :raise => true], returns: "") do
+ translate :foo, :locale => 'en'
+ end
end
def test_delegates_localize_to_i18n
@time = Time.utc(2008, 7, 8, 12, 18, 38)
- I18n.expects(:localize).with(@time)
- localize @time
+ assert_called_with(I18n, :localize, [@time]) do
+ localize @time
+ end
end
def test_returns_missing_translation_message_wrapped_into_span
@@ -125,8 +127,9 @@ class TranslationHelperTest < ActiveSupport::TestCase
end
def test_translate_escapes_interpolations_in_translations_with_a_html_suffix
+ word_struct = Struct.new(:to_s)
assert_equal '<a>Hello &lt;World&gt;</a>', translate(:'translations.interpolated_html', :word => '<World>')
- assert_equal '<a>Hello &lt;World&gt;</a>', translate(:'translations.interpolated_html', :word => stub(:to_s => "<World>"))
+ assert_equal '<a>Hello &lt;World&gt;</a>', translate(:'translations.interpolated_html', :word => word_struct.new("<World>"))
end
def test_translate_with_html_count
diff --git a/actionview/test/template/url_helper_test.rb b/actionview/test/template/url_helper_test.rb
index 0e35c67516..027b72b354 100644
--- a/actionview/test/template/url_helper_test.rb
+++ b/actionview/test/template/url_helper_test.rb
@@ -1,5 +1,4 @@
require 'abstract_unit'
-require 'minitest/mock'
class UrlHelperTest < ActiveSupport::TestCase
@@ -500,6 +499,13 @@ class UrlHelperTest < ActiveSupport::TestCase
mail_to("david@loudthinking.com", "David Heinemeier Hansson", class: "admin")
end
+ def test_mail_to_with_special_characters
+ assert_dom_equal(
+ %{<a href="mailto:%23%21%24%25%26%27%2A%2B-%2F%3D%3F%5E_%60%7B%7D%7C%7E@example.org">#!$%&amp;&#39;*+-/=?^_`{}|~@example.org</a>},
+ mail_to("#!$%&'*+-/=?^_`{}|~@example.org")
+ )
+ end
+
def test_mail_with_options
assert_dom_equal(
%{<a href="mailto:me@example.com?cc=ccaddress%40example.com&amp;bcc=bccaddress%40example.com&amp;body=This%20is%20the%20body%20of%20the%20message.&amp;subject=This%20is%20an%20example%20email&amp;reply-to=foo%40bar.com">My email</a>},