Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save jodosha/7775 to your computer and use it in GitHub Desktop.
Save jodosha/7775 to your computer and use it in GitHub Desktop.
From 837ab30d309d44511429cf58b24fe72cb6250474 Mon Sep 17 00:00:00 2001
From: Luca Guidi <guidi.luca@gmail.com>
Date: Fri, 29 Aug 2008 16:05:01 +0200
Subject: [PATCH] Speed up for Backend::Simple#interpolate
---
lib/i18n/backend/simple.rb | 37 ++++++++++++++++++++-----------------
1 files changed, 20 insertions(+), 17 deletions(-)
diff --git a/lib/i18n/backend/simple.rb b/lib/i18n/backend/simple.rb
index 2e966a5..da89b30 100644
--- a/lib/i18n/backend/simple.rb
+++ b/lib/i18n/backend/simple.rb
@@ -3,6 +3,9 @@ require 'strscan'
module I18n
module Backend
class Simple
+ INTERPOLATION_RESERVED_KEYS = %w(scope default)
+ MATCH = /(\\\\)?\{\{([^\}]+)\}\}/
+
# Accepts a list of paths to translation files. Loads translations from
# plain Ruby (*.rb) or YAML files (*.yml). See #load_rb and #load_yml
# for details.
@@ -114,29 +117,29 @@ module I18n
# the <tt>{{...}}</tt> key in a string (once for the string and once for the
# interpolation).
def interpolate(locale, string, values = {})
- return string if !string.is_a?(String)
+ return string unless string.is_a?(String)
string = string.gsub(/%d/, '{{count}}').gsub(/%s/, '{{value}}')
+
if string.respond_to?(:force_encoding)
- original_encoding = string.encoding
- string.force_encoding(Encoding::BINARY)
- end
- s = StringScanner.new(string)
-
- while s.skip_until(/\{\{/)
- s.string[s.pos - 3, 1] = '' and next if s.pre_match[-1, 1] == '\\'
- start_pos = s.pos - 2
- key = s.scan_until(/\}\}/)[0..-3]
- end_pos = s.pos - 1
+ original_encoding = string.encoding
+ string.force_encoding(Encoding::BINARY)
+ end
- raise ReservedInterpolationKey.new(key, string) if %w(scope default).include?(key)
- raise MissingInterpolationArgument.new(key, string) unless values.has_key? key.to_sym
+ result = string.gsub(MATCH) do
+ escaped, pattern, key = $1, $2, $2.to_sym
- s.string[start_pos..end_pos] = values[key.to_sym].to_s
- s.unscan
+ if escaped
+ pattern
+ elsif INTERPOLATION_RESERVED_KEYS.include?(pattern)
+ raise ReservedInterpolationKey.new(pattern, string)
+ elsif !values.include?(key)
+ raise MissingInterpolationArgument.new(pattern, string)
+ else
+ values[key].to_s
+ end
end
-
- result = s.string
+
result.force_encoding(original_encoding) if original_encoding
result
end
--
1.5.4.5
# bench/interpolate_bench.rb
$:.unshift File.dirname(__FILE__) + '/../lib'
require "rubygems"
require "rbench"
require 'i18n'
require 'i18n/backend/quite_simple'
require 'time'
TIMES = 100_000
RBench.run(TIMES) do
column :times
column :one, :title => "actual #interpolate"
column :two, :title => "new #interpolate"
column :diff, :title => "#1/#2", :compare => [:one,:two]
report "given_a_value_hash_interpolates_the_values_to_the_string" do
@simple = I18n::Backend::Simple.new
@quite_simple = I18n::Backend::QuiteSimple.new
one { @simple.send(:interpolate, nil, 'Hi {{name}}!', :name => 'David') }
two { @quite_simple.send(:interpolate, nil, 'Hi {{name}}!', :name => 'David') }
end
report "given_a_value_hash_interpolates_into_unicode_string" do
@simple = I18n::Backend::Simple.new
@quite_simple = I18n::Backend::QuiteSimple.new
one { @simple.send(:interpolate, nil, 'Häi {{name}}!', :name => 'David') }
two { @quite_simple.send(:interpolate, nil, 'Häi {{name}}!', :name => 'David') }
end
report "given_nil_as_a_string_returns_nil" do
@simple = I18n::Backend::Simple.new
@quite_simple = I18n::Backend::QuiteSimple.new
one { @simple.send(:interpolate, nil, nil, :name => 'David') }
two { @quite_simple.send(:interpolate, nil, nil, :name => 'David') }
end
report "given_an_non_string_as_a_string_returns_nil" do
@simple = I18n::Backend::Simple.new
@quite_simple = I18n::Backend::QuiteSimple.new
one { @simple.send(:interpolate, nil, [], :name => 'David') }
two { @quite_simple.send(:interpolate, nil, [], :name => 'David') }
end
report "given_a_values_hash_with_nil_values_interpolates_the_string" do
@simple = I18n::Backend::Simple.new
@quite_simple = I18n::Backend::QuiteSimple.new
one { @simple.send(:interpolate, nil, 'Hi {{name}}!', {:name => nil}) }
two { @quite_simple.send(:interpolate, nil, 'Hi {{name}}!', {:name => nil}) }
end
report "given_an_empty_values_hash_raises_missing_interpolation_argument" do
@simple = I18n::Backend::Simple.new
@quite_simple = I18n::Backend::QuiteSimple.new
one { @simple.send(:interpolate, nil, 'Hi {{name}}!', {}) rescue nil }
two { @quite_simple.send(:interpolate, nil, 'Hi {{name}}!', {}) rescue nil }
end
report "given_a_string_containing_a_reserved_key_raises_reserved_interpolation_key" do
@simple = I18n::Backend::Simple.new
@quite_simple = I18n::Backend::QuiteSimple.new
one { @simple.send(:interpolate, nil, '{{default}}', {:default => nil}) rescue nil }
two { @quite_simple.send(:interpolate, nil, '{{default}}', {:default => nil}) rescue nil }
end
end
# lib/i18n/backend/quite_simple.rb
module I18n
module Backend
class QuiteSimple < Simple
INTERPOLATION_RESERVED_KEYS = %w(scope default)
MATCH = /(\\\\)?\{\{([^\}]+)\}\}/
protected
def interpolate(locale, string, values = {})
return string unless string.is_a?(String)
string = string.gsub(/%d/, '{{count}}').gsub(/%s/, '{{value}}')
if string.respond_to?(:force_encoding)
original_encoding = string.encoding
string.force_encoding(Encoding::BINARY)
end
result = string.gsub(MATCH) do
escaped, pattern, key = $1, $2, $2.to_sym
if escaped
pattern
elsif INTERPOLATION_RESERVED_KEYS.include?(pattern)
raise ReservedInterpolationKey.new(pattern, string)
elsif !values.include?(key)
raise MissingInterpolationArgument.new(pattern, string)
else
values[key].to_s
end
end
result.force_encoding(original_encoding) if original_encoding
result
end
end
end
end
| actual #interpolate | new #interpolate | #1/#2 |
-----------------------------------------------------------------------------------------------------------------------------------------------
given_a_value_hash_interpolates_the_values_to_the_string x100000 | 2.371 | 1.493 | 1.59x |
given_a_value_hash_interpolates_into_unicode_string x100000 | 2.365 | 1.474 | 1.60x |
given_nil_as_a_string_returns_nil x100000 | 0.331 | 0.425 | 0.78x |
given_an_non_string_as_a_string_returns_nil x100000 | 0.382 | 0.373 | 1.02x |
given_a_values_hash_with_nil_values_interpolates_the_string x100000 | 2.433 | 1.542 | 1.58x |
given_an_empty_values_hash_raises_missing_interpolation_argument x100000 | 5.751 | 5.533 | 1.04x |
given_a_string_containing_a_reserved_key_raises_reserved_interpolation_key x100000 | 5.753 | 5.666 | 1.02x |
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment