With twitter search the punctuation and special characters will be considered part of the term you're searching for, so searching for '#twitter!' will return '#twitter!', "twitter?', '#twitter', etc. What this module does is check if the search includes any type of punctuation searched with and if it does you can sort the array to add those tweets first. This code does the trick but I feel like there might be a cleaner way to do this. Right now I am just using array.sort and setting the array attributes index to 0 if it matches the regex which is looking for a punctuation used in the search and matching it with the tweets.

require 'twitter'

module TwitterSearch
  extend self

  TWITTER_CLIENT = Twitter::REST::Client.new do |config|
    config.consumer_key        = ""
    config.consumer_secret     = ""
    config.access_token        = ""
    config.access_token_secret = ""

  # search returns  
  # Check out what @researchgoddess is up to at #sourcecon! 
  # What a welcome from @SourceCon! Thanks @CareerBuilder for hosting.#   
  # RT @JRoberts257: Happy hour at #SourceCon! Thanks @CareerBuilder for 
  # Happy hour at #SourceCon! Thanks @CareerBuilder for sponsoring. ht
  # @RT @cybsearchjoe: #SourceCon is rocking
  # etc 

  def search(text)
    tweets = TWITTER_CLIENT.search("#{text} filter:images", result_type: "recent").take(30).collect do |tweet|
    # looks to see if there is puncuation at the end of the text "!.?{}[]" It will ignore the # at the beginning 
    tweets = sort_tweets(text, tweets) if text[1..text.length] =~ /[[:punct:]]/
    puts tweets 

  # sorts tweets based off index given in match_phrase 
  def sort_tweets(text, tweets)
    tweets.sort do |phrase, other_phrase| 
      match_phrase(phrase, text, tweets) <=> match_phrase(other_phrase, text, tweets) 

  # if phrase matches punc_text(text) the phrase will be inserted at the beginning of the array else it will return its previous index. 
  def match_phrase(phrase, text, tweets)
    phrase.match(/#{punc_text(text)}/i).nil? ? tweets.index(phrase) + 1 : 0 

  # adds backslash to punctuation '#sourcecon//?|!|.'
  def punc_text(text)
    text[1..text.length].gsub(/([[:punct:]])/){|punc| "\\#{punc}"}


1 Answer 1


I don't think you can do too much better. The things I would have done differently would be:

  • Make the helper methods private using private_class_method ...

  • I'm not quite sure why you are stripping out the leading # in several places. If you know that all searches are going to start with # then I would strip it out at the beginning (or expect the caller not to pass it in).

  • if text[1..text.length] =~ /[[:punct:]]/ could be written as if text =~ /.[[:punct:]]/

  • text[1..text.length].gsub(/([[:punct:]])/){|punc| "\\#{punc}"} There are two better ways to do this (1) Using backreferences text[1..text.length].gsub(/([[:punct:]])/, '\\\1') but (2) it really looks like you are trying to duplicate RegExp.escape

  • phrase.match(/#{punc_text(text)}/i).nil?, I would think that phrase.downcase.include?(text.downcase) would be cleaner


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.