提交 5373bf22 编写于 作者: R Richard Schneeman

Merge pull request #21057 from schneems/schneems/journey-formatter-objects

Beyond Ludicrous Speed
......@@ -41,7 +41,11 @@ def url_options
if original_script_name
options[:original_script_name] = original_script_name
else
options[:script_name] = same_origin ? request.script_name.dup : script_name
if same_origin
options[:script_name] = request.script_name.empty? ? "".freeze : request.script_name.dup
else
options[:script_name] = script_name
end
end
options.freeze
else
......
......@@ -14,7 +14,7 @@ def initialize(routes)
def generate(name, options, path_parameters, parameterize = nil)
constraints = path_parameters.merge(options)
missing_keys = []
missing_keys = nil # need for variable scope
match_route(name, constraints) do |route|
parameterized_parts = extract_parameterized_parts(route, options, path_parameters, parameterize)
......@@ -25,22 +25,22 @@ def generate(name, options, path_parameters, parameterize = nil)
next unless name || route.dispatcher?
missing_keys = missing_keys(route, parameterized_parts)
next unless missing_keys.empty?
next if missing_keys && missing_keys.any?
params = options.dup.delete_if do |key, _|
parameterized_parts.key?(key) || route.defaults.key?(key)
end
defaults = route.defaults
required_parts = route.required_parts
parameterized_parts.delete_if do |key, value|
value.to_s == defaults[key].to_s && !required_parts.include?(key)
parameterized_parts.keep_if do |key, value|
defaults[key].nil? || value.to_s != defaults[key].to_s || required_parts.include?(key)
end
return [route.format(parameterized_parts), params]
end
message = "No route matches #{Hash[constraints.sort_by{|k,v| k.to_s}].inspect}"
message << " missing required keys: #{missing_keys.sort.inspect}" unless missing_keys.empty?
message << " missing required keys: #{missing_keys.sort.inspect}" if missing_keys && missing_keys.any?
raise ActionController::UrlGenerationError, message
end
......@@ -54,12 +54,12 @@ def clear
def extract_parameterized_parts(route, options, recall, parameterize = nil)
parameterized_parts = recall.merge(options)
keys_to_keep = route.parts.reverse.drop_while { |part|
keys_to_keep = route.parts.reverse_each.drop_while { |part|
!options.key?(part) || (options[part] || recall[part]).nil?
} | route.required_parts
(parameterized_parts.keys - keys_to_keep).each do |bad_key|
parameterized_parts.delete(bad_key)
parameterized_parts.delete_if do |bad_key, _|
!keys_to_keep.include?(bad_key)
end
if parameterize
......@@ -110,15 +110,36 @@ def non_recursive(cache, options)
routes
end
module RegexCaseComparator
DEFAULT_INPUT = /[-_.a-zA-Z0-9]+\/[-_.a-zA-Z0-9]+/
DEFAULT_REGEX = /\A#{DEFAULT_INPUT}\Z/
def self.===(regex)
DEFAULT_INPUT == regex
end
end
# Returns an array populated with missing keys if any are present.
def missing_keys(route, parts)
missing_keys = []
missing_keys = nil
tests = route.path.requirements
route.required_parts.each { |key|
if tests.key?(key)
missing_keys << key unless /\A#{tests[key]}\Z/ === parts[key]
case tests[key]
when nil
unless parts[key]
missing_keys ||= []
missing_keys << key
end
when RegexCaseComparator
unless RegexCaseComparator::DEFAULT_REGEX === parts[key]
missing_keys ||= []
missing_keys << key
end
else
missing_keys << key unless parts[key]
unless /\A#{tests[key]}\Z/ === parts[key]
missing_keys ||= []
missing_keys << key
end
end
}
missing_keys
......
......@@ -267,9 +267,13 @@ def handle_positional_args(controller_options, inner_options, args, result, path
path_params -= controller_options.keys
path_params -= result.keys
end
path_params -= inner_options.keys
path_params.take(args.size).each do |param|
result[param] = args.shift
inner_options.each do |key, _|
path_params.delete(key)
end
args.each_with_index do |arg, index|
param = path_params[index]
result[param] = arg if param
end
end
......@@ -594,8 +598,8 @@ class Generator
def initialize(named_route, options, recall, set)
@named_route = named_route
@options = options.dup
@recall = recall.dup
@options = options
@recall = recall
@set = set
normalize_recall!
......@@ -617,7 +621,7 @@ def current_controller
def use_recall_for(key)
if @recall[key] && (!@options.key?(key) || @options[key] == @recall[key])
if !named_route_exists? || segment_keys.include?(key)
@options[key] = @recall.delete(key)
@options[key] = @recall[key]
end
end
end
......@@ -671,12 +675,18 @@ def use_relative_controller!
# Remove leading slashes from controllers
def normalize_controller!
@options[:controller] = controller.sub(%r{^/}, ''.freeze) if controller
if controller
if m = controller.match(/\A\/(?<controller_without_leading_slash>.*)/)
@options[:controller] = m[:controller_without_leading_slash]
else
@options[:controller] = controller
end
end
end
# Move 'index' action from options to recall
def normalize_action!
if @options[:action] == 'index'
if @options[:action] == 'index'.freeze
@recall[:action] = @options.delete(:action)
end
end
......
......@@ -60,7 +60,7 @@ def javascript_include_tag(*sources)
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
......
......@@ -681,7 +681,7 @@ def time_tag(date_or_time, *args, &block)
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 +809,7 @@ def select_month
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 +971,7 @@ def build_options(selected, options = {})
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 +991,11 @@ def build_select(type, select_options_as_html)
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 +1012,7 @@ def prompt_option_tag(type, options)
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.
......
......@@ -456,7 +456,7 @@ def option_groups_from_collection_for_select(collection, group_method, group_lab
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 @@ def grouped_options_for_select(grouped_options, selected_key = nil, options = {}
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 @@ def grouped_options_for_select(grouped_options, selected_key = nil, options = {}
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 @@ def time_zone_options_for_select(selected = nil, priority_zones = nil, model = :
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
......
......@@ -140,15 +140,15 @@ def select_tag(name, option_tags = nil, options = {})
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
......@@ -568,7 +568,7 @@ def image_submit_tag(source, options = {})
# # => <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
......
......@@ -47,8 +47,8 @@ def escape_javascript(javascript)
# tag.
#
# javascript_tag "alert('All is good')", defer: 'defer'
#
# Returns:
#
# Returns:
# <script defer="defer">
# //<![CDATA[
# alert('All is good')
......@@ -70,7 +70,7 @@ def javascript_tag(content_or_options_with_block = nil, html_options = {}, &bloc
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:
......
......@@ -22,9 +22,10 @@ module TagHelper
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,25 @@ def escape_once(html)
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 + prefix_tag_option(key, k, v, escape)
end
elsif BOOLEAN_ATTRIBUTES.include?(key)
attrs << boolean_tag_option(key) if value
output << sep + boolean_tag_option(key) if value
elsif !value.nil?
attrs << tag_option(key, value, escape)
output << sep + 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 +179,7 @@ def boolean_tag_option(key)
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
......
......@@ -184,9 +184,9 @@ def link_to(name = nil, options = nil, html_options = nil, &block)
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
......@@ -471,7 +471,7 @@ def mail_to(email_address, name = nil, html_options = {}, &block)
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+.
......
......@@ -520,7 +520,7 @@ def retrieve_template_keys
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
......
......@@ -154,7 +154,7 @@ def supports_streaming?
# 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
......@@ -348,7 +348,12 @@ def identifier_method_name #:nodoc:
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+)/
......
......@@ -230,7 +230,15 @@ def column_for_attribute(name)
# person.respond_to(:nothing) # => false
def respond_to?(name, include_private = false)
return false unless super
name = name.to_s
case name
when :to_partial_path
name = "to_partial_path".freeze
when :to_model
name = "to_model".freeze
else
name = name.to_s
end
# If the result is true then check for the select case.
# For queries selecting a subset of columns, return false for unselected columns.
......
......@@ -164,7 +164,7 @@ def deconstantize
#
# <%= link_to(@person.name, person_path) %>
# # => <a href="/person/1-donald-e-knuth">Donald E. Knuth</a>
def parameterize(sep = '-')
def parameterize(sep = '-'.freeze)
ActiveSupport::Inflector.parameterize(self, sep)
end
......
......@@ -27,6 +27,37 @@ module Inflector
class Inflections
@__instance__ = ThreadSafe::Cache.new
class Uncountables < Array
def initialize
@regex_array = []
super
end
def delete(entry)
super entry
@regex_array.delete(to_regex(entry))
end
def <<(*word)
add(word)
end
def add(words)
self.concat(words.flatten.map(&:downcase))
@regex_array += self.map {|word| to_regex(word) }
self
end
def uncountable?(str)
@regex_array.detect {|regex| regex.match(str) }
end
private
def to_regex(string)
/\b#{::Regexp.escape(string)}\Z/i
end
end
def self.instance(locale = :en)
@__instance__[locale] ||= new
end
......@@ -34,7 +65,7 @@ def self.instance(locale = :en)
attr_reader :plurals, :singulars, :uncountables, :humans, :acronyms, :acronym_regex
def initialize
@plurals, @singulars, @uncountables, @humans, @acronyms, @acronym_regex = [], [], [], [], {}, /(?=a)b/
@plurals, @singulars, @uncountables, @humans, @acronyms, @acronym_regex = [], [], Uncountables.new, [], {}, /(?=a)b/
end
# Private, for the test suite.
......@@ -160,7 +191,7 @@ def irregular(singular, plural)
# uncountable 'money', 'information'
# uncountable %w( money information rice )
def uncountable(*words)
@uncountables += words.flatten.map(&:downcase)
@uncountables.add(words)
end
# Specifies a humanized form of a string by a regular expression rule or
......@@ -185,7 +216,7 @@ def human(rule, replacement)
def clear(scope = :all)
case scope
when :all
@plurals, @singulars, @uncountables, @humans = [], [], [], []
@plurals, @singulars, @uncountables, @humans = [], [], Uncountables.new, []
else
instance_variable_set "@#{scope}", []
end
......
......@@ -354,7 +354,7 @@ def ordinalize(number)
# const_regexp("Foo::Bar::Baz") # => "Foo(::Bar(::Baz)?)?"
# const_regexp("::") # => "::"
def const_regexp(camel_cased_word) #:nodoc:
parts = camel_cased_word.split("::")
parts = camel_cased_word.split("::".freeze)
return Regexp.escape(camel_cased_word) if parts.blank?
......@@ -372,7 +372,7 @@ def const_regexp(camel_cased_word) #:nodoc:
def apply_inflections(word, rules)
result = word.to_s.dup
if word.empty? || inflections.uncountables.include?(result.downcase[/\b\w+\Z/])
if word.empty? || inflections.uncountables.uncountable?(result)
result
else
rules.each { |(rule, replacement)| break if result.sub!(rule, replacement) }
......
......@@ -58,7 +58,7 @@ module Inflector
# I18n.locale = :de
# transliterate('Jürgen')
# # => "Juergen"
def transliterate(string, replacement = "?")
def transliterate(string, replacement = "?".freeze)
I18n.transliterate(ActiveSupport::Multibyte::Unicode.normalize(
ActiveSupport::Multibyte::Unicode.tidy_bytes(string), :c),
:replacement => replacement)
......@@ -75,13 +75,21 @@ def parameterize(string, sep = '-')
# Turn unwanted chars into the separator
parameterized_string.gsub!(/[^a-z0-9\-_]+/i, sep)
unless sep.nil? || sep.empty?
re_sep = Regexp.escape(sep)
if sep == "-".freeze
re_duplicate_seperator = /-{2,}/
re_leading_trailing_separator = /^-|-$/i
else
re_sep = Regexp.escape(sep)
re_duplicate_seperator = /#{re_sep}{2,}/
re_leading_trailing_separator = /^#{re_sep}|#{re_sep}$/i
end
# No more than one of the separator in a row.
parameterized_string.gsub!(/#{re_sep}{2,}/, sep)
parameterized_string.gsub!(re_duplicate_seperator, sep)
# Remove leading/trailing separator.
parameterized_string.gsub!(/^#{re_sep}|#{re_sep}$/i, ''.freeze)
parameterized_string.gsub!(re_leading_trailing_separator, ''.freeze)
end
parameterized_string.downcase
parameterized_string.downcase!
parameterized_string
end
end
end
......@@ -273,7 +273,7 @@ def normalize(string, form=nil)
compose(reorder_characters(decompose(:compatibility, codepoints)))
else
raise ArgumentError, "#{form} is not a valid normalization variant", caller
end.pack('U*')
end.pack('U*'.freeze)
end
def downcase(string)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册