Skip to content

Instantly share code, notes, and snippets.

@tenderlove
Created February 12, 2012 05:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tenderlove/1806575 to your computer and use it in GitHub Desktop.
Save tenderlove/1806575 to your computer and use it in GitHub Desktop.
require 'active_support/inflector'
require 'benchmark'
# QUICK HACK
class RuleSet
def initialize
@rules = []
@regexp = nil
end
def prepend_rule(pattern, replacement)
@rules.unshift([pattern, replacement])
patterns = @rules.each_with_index.map {|rule, i| build_regexp(rule.first, i)}
@regexp = Regexp.union(*patterns)
end
def build_regexp(pattern, i)
pattern = Regexp.quote(pattern) if pattern.is_a?(String)
/(?<_#{i}>#{pattern})/
end
def apply(word)
word = word.to_s.dup
if md = @regexp.match(word)
name = md.names.detect {|n| md[n]}
index = name[/\d+/, 0].to_i
word.gsub!(@rules[index][0], @rules[index][1])
end
word
end
end
class OMG
def initialize
@replacements = {}
@patterns = []
@regexp = nil
@rules = []
end
def unshift pattern, replacement
if pattern.source =~ /^\([\w|]*\)\w+\$/
precompile pattern, replacement
@patterns.unshift pattern
@regexp = Regexp.union @patterns
else
@rules << [pattern, replacement]
end
end
def apply word
result = word.to_s.dup
return result if result.gsub!(@regexp) { |m|
m.gsub(*@replacements[m.downcase])
}
@rules.find { |rule, replacement|
break result if result.gsub!(rule, replacement)
}
end
private
def precompile pattern, replacement
match = /^\(([\w|]*)\)(.*)\$/.match pattern.source
match[1].split('|').each do |str|
@replacements["#{str}#{match[2]}"] = [pattern, replacement]
end
end
end
def bench words
rs = RuleSet.new
omg = OMG.new
ActiveSupport::Inflector::Inflections.instance.plurals.each do |pattern, replacement|
rs.prepend_rule(pattern, replacement)
omg.unshift(pattern, replacement)
end
Benchmark.bm(13) do |x|
words.each do |word|
x.report("AS: #{word.length}") {
ActiveSupport::Inflector.pluralize(word)
}
x.report("RS: #{word.length}") {
rs.apply(word)
}
x.report("OM: #{word.length}") {
omg.apply(word)
}
end
end
end
def words match_word
words = [10, 100, 10000, 1000000].map { |i|
("x" * (i - match_word.length)) + match_word
}
end
puts "best case"
bench words "zombies"
puts
puts "worst case"
bench words ""
__END__
best case
user system total real
AS: 10 0.000000 0.000000 0.000000 ( 0.000246)
RS: 10 0.000000 0.000000 0.000000 ( 0.000136)
OM: 10 0.000000 0.000000 0.000000 ( 0.000052)
AS: 100 0.000000 0.000000 0.000000 ( 0.001411)
RS: 100 0.000000 0.000000 0.000000 ( 0.000426)
OM: 100 0.000000 0.000000 0.000000 ( 0.000346)
AS: 10000 0.000000 0.000000 0.000000 ( 0.000455)
RS: 10000 0.040000 0.000000 0.040000 ( 0.035807)
OM: 10000 0.030000 0.000000 0.030000 ( 0.034324)
AS: 1000000 0.010000 0.000000 0.010000 ( 0.010814)
RS: 1000000 3.510000 0.000000 3.510000 ( 3.540499)
OM: 1000000 3.360000 0.000000 3.360000 ( 3.364361)
worst case
user system total real
AS: 10 0.000000 0.000000 0.000000 ( 0.000329)
RS: 10 0.000000 0.000000 0.000000 ( 0.000086)
OM: 10 0.000000 0.000000 0.000000 ( 0.000065)
AS: 100 0.000000 0.000000 0.000000 ( 0.000295)
RS: 100 0.000000 0.000000 0.000000 ( 0.000550)
OM: 100 0.000000 0.000000 0.000000 ( 0.000279)
AS: 10000 0.010000 0.000000 0.010000 ( 0.009604)
RS: 10000 0.050000 0.000000 0.050000 ( 0.046098)
OM: 10000 0.030000 0.000000 0.030000 ( 0.027438)
AS: 1000000 0.940000 0.000000 0.940000 ( 0.943796)
RS: 1000000 4.400000 0.010000 4.410000 ( 4.614616)
OM: 1000000 2.610000 0.010000 2.620000 ( 2.881990)
@ahoward
Copy link

ahoward commented Feb 12, 2012

wonder how fast it is to convert @name to @name.to_s ... ;-/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment