Skip to content

Instantly share code, notes, and snippets.

@mislav
Created August 18, 2012 15:32
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mislav/3387743 to your computer and use it in GitHub Desktop.
Save mislav/3387743 to your computer and use it in GitHub Desktop.
Raise error if "initialize" method name is misspelled
# Public: Implementation of "Strike a match" algorithm for calculating
# similarity between strings.
#
# http://www.catalysoft.com/articles/StrikeAMatch.html
#
# Examples
#
# checker = StringSimilarityChecker.new('Quick brown fox')
#
# checker =~ 'quick brown ox' #=> true
# checker.similarity_index('quick brown ox') #=> 0.947
#
# checker =~ 'quick frown pox' #=> true
# checker.similarity_index('quick frown pox') #=> 0.8
#
# checker =~ 'quick lawn ducks' #=> false
# checker.similarity_index('quick lawn ducks') #=> 0.476
class StringSimilarityChecker
def initialize base_string, similarity_treshold = 0.8
@base_pairs = character_pairs base_string
@treshold = similarity_treshold
end
# Public: Check if similarity index with given string passes the treshold.
def similar_to? string
similarity_index(string) >= @treshold
end
alias =~ similar_to?
# Public: Calculate similarity index between given and base strings.
#
# Returns a Float between 0 and 1.
def similarity_index string
pairs = character_pairs string
shared = count_identical_pairs @base_pairs, pairs
(2 * shared).to_f / (@base_pairs.size + pairs.size)
end
SPACE = ' '
# Internal: Break string into pairs of adjacent characters, excluding ones
# that contain spaces.
def character_pairs str
str = str.to_str.downcase
(0..(str.size-2)).map {|pos| str[pos,2] }.reject {|pair| pair.include? SPACE }
end
# Internal: Measure the intersection between two arrays of character pairs.
def count_identical_pairs pairs1, pairs2
size, pairs2 = 0, pairs2.dup
pairs1.each do |pair|
if found = pairs2.index(pair)
size += 1
pairs2.delete_at found
end
end
size
end
end
class Class
initializer_name = 'initialize'
initializer_spelling_checker = StringSimilarityChecker.new initializer_name
# Raise error if a new method is similar but not identical to "initialize".
# WARNING this is not something you should actually use in your apps.
define_method(:method_added) do |name|
name = name.to_s
if name != initializer_name and initializer_spelling_checker =~ name
raise "method name too similar to 'initialize': '#{name}'"
end
end
end
class ThisWorks
def initialize # properly spelled method
end
def init # valid method name
end
end
class ThisFails
def initializer # wrong name
end
end
class ThisAlsoFails
def initilize # spelling error
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment