class T::CLI

Constants

DEFAULT_NUM_RESULTS
DIRECT_MESSAGE_HEADINGS
MAX_SEARCH_RESULTS
TREND_HEADINGS

Public Class Methods

new(*) click to toggle source
Calls superclass method
# File lib/t/cli.rb, line 36
def initialize(*)
  @rcfile = T::RCFile.instance
  super
end

Public Instance Methods

accounts() click to toggle source
# File lib/t/cli.rb, line 42
def accounts
  @rcfile.path = options['profile'] if options['profile']
  @rcfile.profiles.each do |profile|
    say profile[0]
    profile[1].each_key do |key|
      say "  #{key}#{@rcfile.active_profile[0] == profile[0] && @rcfile.active_profile[1] == key ? ' (active)' : nil}"
    end
  end
end
authorize() click to toggle source
# File lib/t/cli.rb, line 54
def authorize
  @rcfile.path = options['profile'] if options['profile']
  if @rcfile.empty?
    say "Welcome! Before you can use t, you'll first need to register an"
    say 'application with Twitter. Just follow the steps below:'
    say '  1. Sign in to the Twitter Application Management site and click'
    say '     "Create New App".'
    say '  2. Complete the required fields and submit the form.'
    say '     Note: Your application must have a unique name.'
    say '  3. Go to the Permissions tab of your application, and change the'
    say '     Access setting to "Read, Write and Access direct messages".'
    say '  4. Go to the Keys and Access Tokens tab to view the consumer key'
    say "     and secret which you'll need to copy and paste below when"
    say '     prompted.'
  else
    say "It looks like you've already registered an application with Twitter."
    say 'To authorize a new account, just follow the steps below:'
    say '  1. Sign in to the Twitter Developer site.'
    say "  2. Select the application for which you'd like to authorize an account."
    say '  3. Copy and paste the consumer key and secret below when prompted.'
  end
  say
  ask 'Press [Enter] to open the Twitter Developer site.'
  say
  require 'launchy'
  open_or_print('https://apps.twitter.com', dry_run: options['display-uri'])
  key = ask 'Enter your API key:'
  secret = ask 'Enter your API secret:'
  consumer = OAuth::Consumer.new(key, secret, site: Twitter::REST::Client::BASE_URL)
  request_token = consumer.get_request_token
  uri = generate_authorize_uri(consumer, request_token)
  say
  say 'In a moment, you will be directed to the Twitter app authorization page.'
  say 'Perform the following steps to complete the authorization process:'
  say '  1. Sign in to Twitter.'
  say '  2. Press "Authorize app".'
  say '  3. Copy and paste the supplied PIN below when prompted.'
  say
  ask 'Press [Enter] to open the Twitter app authorization page.'
  say
  open_or_print(uri, dry_run: options['display-uri'])
  pin = ask 'Enter the supplied PIN:'
  access_token = request_token.get_access_token(oauth_verifier: pin.chomp)
  oauth_response = access_token.get('/1.1/account/verify_credentials.json?skip_status=true')
  screen_name = oauth_response.body.match(/"screen_name"\s*:\s*"(.*?)"/).captures.first
  @rcfile[screen_name] = {
    key => {
      'username' => screen_name,
      'consumer_key' => key,
      'consumer_secret' => secret,
      'token' => access_token.token,
      'secret' => access_token.secret,
    },
  }
  @rcfile.active_profile = {'username' => screen_name, 'consumer_key' => key}
  say 'Authorization successful.'
end
block(user, *users) click to toggle source
# File lib/t/cli.rb, line 114
def block(user, *users)
  blocked_users, number = fetch_users(users.unshift(user), options) do |users_to_block|
    client.block(users_to_block)
  end
  say "@#{@rcfile.active_profile[0]} blocked #{pluralize(number, 'user')}."
  say
  say "Run `#{File.basename($PROGRAM_NAME)} delete block #{blocked_users.collect { |blocked_user| "@#{blocked_user.screen_name}" }.join(' ')}` to unblock."
end
direct_messages() click to toggle source
# File lib/t/cli.rb, line 130
def direct_messages
  count = options['number'] || DEFAULT_NUM_RESULTS
  opts = {}
  opts[:include_entities] = !!options['decode_uris']
  direct_messages = collect_with_count(count) do |count_opts|
    client.direct_messages(count_opts.merge(opts))
  end
  direct_messages.reverse! if options['reverse']
  if options['csv']
    require 'csv'
    say DIRECT_MESSAGE_HEADINGS.to_csv unless direct_messages.empty?
    direct_messages.each do |direct_message|
      say [direct_message.id, csv_formatted_time(direct_message), direct_message.sender.screen_name, decode_full_text(direct_message, options['decode_uris'])].to_csv
    end
  elsif options['long']
    array = direct_messages.collect do |direct_message|
      [direct_message.id, ls_formatted_time(direct_message), "@#{direct_message.sender.screen_name}", decode_full_text(direct_message, options['decode_uris']).gsub(/\n+/, ' ')]
    end
    format = options['format'] || Array.new(DIRECT_MESSAGE_HEADINGS.size) { '%s' }
    print_table_with_headings(array, DIRECT_MESSAGE_HEADINGS, format)
  else
    direct_messages.each do |direct_message|
      print_message(direct_message.sender.screen_name, direct_message.text)
    end
  end
end
direct_messages_sent() click to toggle source
# File lib/t/cli.rb, line 165
def direct_messages_sent
  count = options['number'] || DEFAULT_NUM_RESULTS
  opts = {}
  opts[:include_entities] = !!options['decode_uris']
  direct_messages = collect_with_count(count) do |count_opts|
    client.direct_messages_sent(count_opts.merge(opts))
  end
  direct_messages.reverse! if options['reverse']
  if options['csv']
    require 'csv'
    say DIRECT_MESSAGE_HEADINGS.to_csv unless direct_messages.empty?
    direct_messages.each do |direct_message|
      say [direct_message.id, csv_formatted_time(direct_message), direct_message.recipient.screen_name, decode_full_text(direct_message, options['decode_uris'])].to_csv
    end
  elsif options['long']
    array = direct_messages.collect do |direct_message|
      [direct_message.id, ls_formatted_time(direct_message), "@#{direct_message.recipient.screen_name}", decode_full_text(direct_message, options['decode_uris']).gsub(/\n+/, ' ')]
    end
    format = options['format'] || Array.new(DIRECT_MESSAGE_HEADINGS.size) { '%s' }
    print_table_with_headings(array, DIRECT_MESSAGE_HEADINGS, format)
  else
    direct_messages.each do |direct_message|
      print_message(direct_message.recipient.screen_name, direct_message.text)
    end
  end
end
dm(user, message) click to toggle source
# File lib/t/cli.rb, line 195
def dm(user, message)
  require 't/core_ext/string'
  user = options['id'] ? user.to_i : user.strip_ats
  direct_message = client.create_direct_message(user, message)
  say "Direct Message sent from @#{@rcfile.active_profile[0]} to @#{direct_message.recipient.screen_name}."
end
does_contain(user_list, user = nil) click to toggle source
# File lib/t/cli.rb, line 205
def does_contain(user_list, user = nil)
  owner, list_name = extract_owner(user_list, options)
  if user.nil?
    user = @rcfile.active_profile[0]
  else
    require 't/core_ext/string'
    user = options['id'] ? client.user(user.to_i).screen_name : user.strip_ats
  end
  if client.list_member?(owner, list_name, user)
    say "Yes, #{list_name} contains @#{user}."
  else
    abort "No, #{list_name} does not contain @#{user}."
  end
end
does_follow(user1, user2 = nil) click to toggle source
# File lib/t/cli.rb, line 223
def does_follow(user1, user2 = nil)
  abort 'No, you are not following yourself.' if user2.nil? && @rcfile.active_profile[0].casecmp(user1).zero?
  abort "No, @#{user1} is not following themself." if user1 == user2
  require 't/core_ext/string'
  thread1 = if options['id']
    Thread.new { client.user(user1.to_i).screen_name }
  else
    Thread.new { user1.strip_ats }
  end
  thread2 = if user2.nil?
    Thread.new { @rcfile.active_profile[0] }
  elsif options['id']
    Thread.new { client.user(user2.to_i).screen_name }
  else
    Thread.new { user2.strip_ats }
  end
  user1 = thread1.value
  user2 = thread2.value
  if client.friendship?(user1, user2)
    say "Yes, @#{user1} follows @#{user2}."
  else
    abort "No, @#{user1} does not follow @#{user2}."
  end
end
favorite(status_id, *status_ids) click to toggle source
# File lib/t/cli.rb, line 250
def favorite(status_id, *status_ids)
  status_ids.unshift(status_id)
  status_ids.collect!(&:to_i)
  require 'retryable'
  favorites = Retryable.retryable(tries: 3, on: Twitter::Error, sleep: 0) do
    client.favorite(status_ids)
  end
  number = favorites.length
  say "@#{@rcfile.active_profile[0]} favorited #{pluralize(number, 'tweet')}."
  say
  say "Run `#{File.basename($PROGRAM_NAME)} delete favorite #{status_ids.join(' ')}` to unfavorite."
end
favorites(user = nil) click to toggle source
# File lib/t/cli.rb, line 274
def favorites(user = nil)
  count = options['number'] || DEFAULT_NUM_RESULTS
  opts = {}
  opts[:exclude_replies] = true if options['exclude'] == 'replies'
  opts[:include_entities] = !!options['decode_uris']
  opts[:include_rts] = false if options['exclude'] == 'retweets'
  opts[:max_id] = options['max_id'] if options['max_id']
  opts[:since_id] = options['since_id'] if options['since_id']
  if user
    require 't/core_ext/string'
    user = options['id'] ? user.to_i : user.strip_ats
  end
  tweets = collect_with_count(count) do |count_opts|
    client.favorites(user, count_opts.merge(opts))
  end
  print_tweets(tweets)
end
follow(user, *users) click to toggle source
# File lib/t/cli.rb, line 295
def follow(user, *users)
  followed_users, number = fetch_users(users.unshift(user), options) do |users_to_follow|
    client.follow(users_to_follow)
  end
  say "@#{@rcfile.active_profile[0]} is now following #{pluralize(number, 'more user')}."
  say
  say "Run `#{File.basename($PROGRAM_NAME)} unfollow #{followed_users.collect { |followed_user| "@#{followed_user.screen_name}" }.join(' ')}` to stop."
end
followers(user = nil) click to toggle source
# File lib/t/cli.rb, line 360
def followers(user = nil)
  if user
    require 't/core_ext/string'
    user = options['id'] ? user.to_i : user.strip_ats
  end
  follower_ids = client.follower_ids(user).to_a
  require 'retryable'
  users = Retryable.retryable(tries: 3, on: Twitter::Error, sleep: 0) do
    client.users(follower_ids)
  end
  print_users(users)
end
followings(user = nil) click to toggle source
# File lib/t/cli.rb, line 312
def followings(user = nil)
  if user
    require 't/core_ext/string'
    user = options['id'] ? user.to_i : user.strip_ats
  end
  following_ids = client.friend_ids(user).to_a
  require 'retryable'
  users = Retryable.retryable(tries: 3, on: Twitter::Error, sleep: 0) do
    client.users(following_ids)
  end
  print_users(users)
end
followings_following(user1, user2 = nil) click to toggle source
# File lib/t/cli.rb, line 333
def followings_following(user1, user2 = nil)
  require 't/core_ext/string'
  user1 = options['id'] ? user1.to_i : user1.strip_ats
  user2 = if user2.nil?
    @rcfile.active_profile[0]
  else
    options['id'] ? user2.to_i : user2.strip_ats
  end
  follower_ids = Thread.new { client.follower_ids(user1).to_a }
  following_ids = Thread.new { client.friend_ids(user2).to_a }
  followings_following_ids = follower_ids.value & following_ids.value
  require 'retryable'
  users = Retryable.retryable(tries: 3, on: Twitter::Error, sleep: 0) do
    client.users(followings_following_ids)
  end
  print_users(users)
end
friends(user = nil) click to toggle source
# File lib/t/cli.rb, line 381
def friends(user = nil)
  user = if user
    require 't/core_ext/string'
    options['id'] ? user.to_i : user.strip_ats
  else
    client.verify_credentials.screen_name
  end
  following_ids = Thread.new { client.friend_ids(user).to_a }
  follower_ids = Thread.new { client.follower_ids(user).to_a }
  friend_ids = following_ids.value & follower_ids.value
  require 'retryable'
  users = Retryable.retryable(tries: 3, on: Twitter::Error, sleep: 0) do
    client.users(friend_ids)
  end
  print_users(users)
end
groupies(user = nil) click to toggle source
# File lib/t/cli.rb, line 406
def groupies(user = nil)
  user = if user
    require 't/core_ext/string'
    options['id'] ? user.to_i : user.strip_ats
  else
    client.verify_credentials.screen_name
  end
  follower_ids = Thread.new { client.follower_ids(user).to_a }
  following_ids = Thread.new { client.friend_ids(user).to_a }
  groupie_ids = (follower_ids.value - following_ids.value)
  require 'retryable'
  users = Retryable.retryable(tries: 3, on: Twitter::Error, sleep: 0) do
    client.users(groupie_ids)
  end
  print_users(users)
end
intersection(first_user, *users) click to toggle source
# File lib/t/cli.rb, line 433
def intersection(first_user, *users)
  users.push(first_user)
  # If only one user is specified, compare to the authenticated user
  users.push(@rcfile.active_profile[0]) if users.size == 1
  require 't/core_ext/string'
  options['id'] ? users.collect!(&:to_i) : users.collect!(&:strip_ats)
  sets = parallel_map(users) do |user|
    case options['type']
    when 'followings'
      client.friend_ids(user).to_a
    when 'followers'
      client.follower_ids(user).to_a
    end
  end
  intersection = sets.reduce(:&)
  require 'retryable'
  users = Retryable.retryable(tries: 3, on: Twitter::Error, sleep: 0) do
    client.users(intersection)
  end
  print_users(users)
end
leaders(user = nil) click to toggle source
# File lib/t/cli.rb, line 464
def leaders(user = nil)
  user = if user
    require 't/core_ext/string'
    options['id'] ? user.to_i : user.strip_ats
  else
    client.verify_credentials.screen_name
  end
  following_ids = Thread.new { client.friend_ids(user).to_a }
  follower_ids = Thread.new { client.follower_ids(user).to_a }
  leader_ids = (following_ids.value - follower_ids.value)
  require 'retryable'
  users = Retryable.retryable(tries: 3, on: Twitter::Error, sleep: 0) do
    client.users(leader_ids)
  end
  print_users(users)
end
lists(user = nil) click to toggle source
# File lib/t/cli.rb, line 489
def lists(user = nil)
  lists = if user
    require 't/core_ext/string'
    user = options['id'] ? user.to_i : user.strip_ats
    client.lists(user)
  else
    client.lists
  end
  print_lists(lists)
end
matrix() click to toggle source
# File lib/t/cli.rb, line 501
def matrix
  opts = {count: MAX_SEARCH_RESULTS, include_entities: false}
  tweets = client.search('lang:ja', opts)
  tweets.each do |tweet|
    say(tweet.text.gsub(/[^\u3000\u3040-\u309f]/, '').reverse, [:bold, :green, :on_black], false)
  end
end
mentions() click to toggle source
# File lib/t/cli.rb, line 516
def mentions
  count = options['number'] || DEFAULT_NUM_RESULTS
  opts = {}
  opts[:include_entities] = !!options['decode_uris']
  tweets = collect_with_count(count) do |count_opts|
    client.mentions(count_opts.merge(opts))
  end
  print_tweets(tweets)
end
mute(user, *users) click to toggle source
# File lib/t/cli.rb, line 529
def mute(user, *users)
  muted_users, number = fetch_users(users.unshift(user), options) do |users_to_mute|
    client.mute(users_to_mute)
  end
  say "@#{@rcfile.active_profile[0]} muted #{pluralize(number, 'user')}."
  say
  say "Run `#{File.basename($PROGRAM_NAME)} delete mute #{muted_users.collect { |muted_user| "@#{muted_user.screen_name}" }.join(' ')}` to unmute."
end
muted() click to toggle source
# File lib/t/cli.rb, line 545
def muted
  muted_ids = client.muted_ids.to_a
  require 'retryable'
  muted_users = Retryable.retryable(tries: 3, on: Twitter::Error, sleep: 0) do
    client.users(muted_ids)
  end
  print_users(muted_users)
end
open(user) click to toggle source
# File lib/t/cli.rb, line 559
def open(user)
  require 'launchy'
  if options['id']
    user = client.user(user.to_i)
    open_or_print(user.uri, dry_run: options['display-uri'])
  elsif options['status']
    status = client.status(user.to_i, include_my_retweet: false)
    open_or_print(status.uri, dry_run: options['display-uri'])
  else
    require 't/core_ext/string'
    open_or_print("https://twitter.com/#{user.strip_ats}", dry_run: options['display-uri'])
  end
end
reach(tweet_id) click to toggle source
# File lib/t/cli.rb, line 574
def reach(tweet_id)
  require 't/core_ext/string'
  require 'set'
  status_thread = Thread.new { client.status(tweet_id.to_i, include_my_retweet: false) }
  threads = []
  client.retweeters_ids(tweet_id.to_i).each do |retweeter_id|
    threads << Thread.new(retweeter_id) do |user_id|
      client.follower_ids(user_id).to_a
    end
  end
  status = status_thread.value
  threads << Thread.new(status.user.id) do |user_id|
    client.follower_ids(user_id).to_a
  end
  reach = ::Set.new
  threads.each { |thread| reach += thread.value }
  reach.delete(status.user.id)
  say number_with_delimiter(reach.size)
end
reply(status_id, message = nil) click to toggle source
# File lib/t/cli.rb, line 598
def reply(status_id, message = nil)
  message = T::Editor.gets if message.to_s.empty?
  status = client.status(status_id.to_i, include_my_retweet: false)
  users = Array(status.user.screen_name)
  if options['all']
    users += extract_mentioned_screen_names(status.full_text)
    users.uniq!
  end
  users.delete(@rcfile.active_profile[0])
  require 't/core_ext/string'
  users.collect!(&:prepend_at)
  opts = {in_reply_to_status_id: status.id, trim_user: true}
  add_location!(options, opts)
  reply = if options['file']
    client.update_with_media("#{users.join(' ')} #{message}", File.new(File.expand_path(options['file'])), opts)
  else
    client.update("#{users.join(' ')} #{message}", opts)
  end
  say "Reply posted by @#{@rcfile.active_profile[0]} to #{users.join(' ')}."
  say
  say "Run `#{File.basename($PROGRAM_NAME)} delete status #{reply.id}` to delete."
end
report_spam(user, *users) click to toggle source
# File lib/t/cli.rb, line 623
def report_spam(user, *users)
  _, number = fetch_users(users.unshift(user), options) do |users_to_report|
    client.report_spam(users_to_report)
  end
  say "@#{@rcfile.active_profile[0]} reported #{pluralize(number, 'user')}."
end
retweet(status_id, *status_ids) click to toggle source
# File lib/t/cli.rb, line 632
def retweet(status_id, *status_ids)
  status_ids.unshift(status_id)
  status_ids.collect!(&:to_i)
  require 'retryable'
  retweets = Retryable.retryable(tries: 3, on: Twitter::Error, sleep: 0) do
    client.retweet(status_ids, trim_user: true)
  end
  number = retweets.length
  say "@#{@rcfile.active_profile[0]} retweeted #{pluralize(number, 'tweet')}."
  say
  say "Run `#{File.basename($PROGRAM_NAME)} delete status #{retweets.collect(&:id).join(' ')}` to undo."
end
retweets(user = nil) click to toggle source
# File lib/t/cli.rb, line 654
def retweets(user = nil)
  count = options['number'] || DEFAULT_NUM_RESULTS
  opts = {}
  opts[:include_entities] = !!options['decode_uris']
  tweets = if user
    require 't/core_ext/string'
    user = options['id'] ? user.to_i : user.strip_ats
    collect_with_count(count) do |count_opts|
      client.retweeted_by_user(user, count_opts.merge(opts))
    end
  else
    collect_with_count(count) do |count_opts|
      client.retweeted_by_me(count_opts.merge(opts))
    end
  end
  print_tweets(tweets)
end
retweets_of_me() click to toggle source
# File lib/t/cli.rb, line 680
def retweets_of_me
  count = options['number'] || DEFAULT_NUM_RESULTS
  opts = {}
  opts[:include_entities] = !!options['decode_uris']
  tweets = collect_with_count(count) do |count_opts|
    client.retweets_of_me(count_opts.merge(opts))
  end
  print_tweets(tweets)
end
ruler() click to toggle source
# File lib/t/cli.rb, line 693
def ruler
  markings = '----|'.chars.cycle.take(140).join
  say "#{' ' * options['indent'].to_i}#{markings}"
end
status(status_id) click to toggle source
# File lib/t/cli.rb, line 703
def status(status_id) # rubocop:disable CyclomaticComplexity
  opts = {include_my_retweet: false}
  opts[:include_entities] = !!options['decode_uris']
  status = client.status(status_id.to_i, opts)
  location = if status.place?
    if status.place.name? && status.place.attributes? && status.place.attributes[:street_address] && status.place.attributes[:locality] && status.place.attributes[:region] && status.place.country?
      [status.place.name, status.place.attributes[:street_address], status.place.attributes[:locality], status.place.attributes[:region], status.place.country].join(', ')
    elsif status.place.name? && status.place.attributes? && status.place.attributes[:locality] && status.place.attributes[:region] && status.place.country?
      [status.place.name, status.place.attributes[:locality], status.place.attributes[:region], status.place.country].join(', ')
    elsif status.place.full_name? && status.place.attributes? && status.place.attributes[:region] && status.place.country?
      [status.place.full_name, status.place.attributes[:region], status.place.country].join(', ')
    elsif status.place.full_name? && status.place.country?
      [status.place.full_name, status.place.country].join(', ')
    elsif status.place.full_name?
      status.place.full_name
    else
      status.place.name
    end
  elsif status.geo?
    reverse_geocode(status.geo)
  end
  status_headings = ['ID', 'Posted at', 'Screen name', 'Text', 'Retweets', 'Favorites', 'Source', 'Location']
  if options['csv']
    require 'csv'
    say status_headings.to_csv
    say [status.id, csv_formatted_time(status), status.user.screen_name, decode_full_text(status, options['decode_uris']), status.retweet_count, status.favorite_count, strip_tags(status.source), location].to_csv
  elsif options['long']
    array = [status.id, ls_formatted_time(status), "@#{status.user.screen_name}", decode_full_text(status, options['decode_uris']).gsub(/\n+/, ' '), status.retweet_count, status.favorite_count, strip_tags(status.source), location]
    format = options['format'] || Array.new(status_headings.size) { '%s' }
    print_table_with_headings([array], status_headings, format)
  else
    array = []
    array << ['ID', status.id.to_s]
    array << ['Text', decode_full_text(status, options['decode_uris']).gsub(/\n+/, ' ')]
    array << ['Screen name', "@#{status.user.screen_name}"]
    array << ['Posted at', "#{ls_formatted_time(status, :created_at, false)} (#{time_ago_in_words(status.created_at)} ago)"]
    array << ['Retweets', number_with_delimiter(status.retweet_count)]
    array << ['Favorites', number_with_delimiter(status.favorite_count)]
    array << ['Source', strip_tags(status.source)]
    array << ['Location', location] unless location.nil?
    print_table(array)
  end
end
timeline(user = nil) click to toggle source
# File lib/t/cli.rb, line 758
def timeline(user = nil)
  count = options['number'] || DEFAULT_NUM_RESULTS
  opts = {}
  opts[:exclude_replies] = true if options['exclude'] == 'replies'
  opts[:include_entities] = !!options['decode_uris']
  opts[:include_rts] = false if options['exclude'] == 'retweets'
  opts[:max_id] = options['max_id'] if options['max_id']
  opts[:since_id] = options['since_id'] if options['since_id']
  if user
    require 't/core_ext/string'
    user = options['id'] ? user.to_i : user.strip_ats
    tweets = collect_with_count(count) do |count_opts|
      client.user_timeline(user, count_opts.merge(opts))
    end
  else
    tweets = collect_with_count(count) do |count_opts|
      client.home_timeline(count_opts.merge(opts))
    end
  end
  print_tweets(tweets)
end
trend_locations() click to toggle source
# File lib/t/cli.rb, line 797
def trend_locations
  places = client.trend_locations
  unless options['unsorted']
    places = case options['sort']
    when 'country'
      places.sort_by { |place| place.country.downcase }
    when 'parent'
      places.sort_by { |place| place.parent_id.to_i }
    when 'type'
      places.sort_by { |place| place.place_type.downcase }
    when 'woeid'
      places.sort_by { |place| place.woeid.to_i }
    else
      places.sort_by { |place| place.name.downcase }
    end
  end
  places.reverse! if options['reverse']
  if options['csv']
    require 'csv'
    say TREND_HEADINGS.to_csv unless places.empty?
    places.each do |place|
      say [place.woeid, place.parent_id, place.place_type, place.name, place.country].to_csv
    end
  elsif options['long']
    array = places.collect do |place|
      [place.woeid, place.parent_id, place.place_type, place.name, place.country]
    end
    format = options['format'] || Array.new(TREND_HEADINGS.size) { '%s' }
    print_table_with_headings(array, TREND_HEADINGS, format)
  else
    print_attribute(places, :name)
  end
end
unfollow(user, *users) click to toggle source
# File lib/t/cli.rb, line 834
def unfollow(user, *users)
  unfollowed_users, number = fetch_users(users.unshift(user), options) do |users_to_unfollow|
    client.unfollow(users_to_unfollow)
  end
  say "@#{@rcfile.active_profile[0]} is no longer following #{pluralize(number, 'user')}."
  say
  say "Run `#{File.basename($PROGRAM_NAME)} follow #{unfollowed_users.collect { |unfollowed_user| "@#{unfollowed_user.screen_name}" }.join(' ')}` to follow again."
end
update(message = nil) click to toggle source
# File lib/t/cli.rb, line 846
def update(message = nil)
  message = T::Editor.gets if message.to_s.empty?
  opts = {trim_user: true}
  add_location!(options, opts)
  status = if options['file']
    client.update_with_media(message, File.new(File.expand_path(options['file'])), opts)
  else
    client.update(message, opts)
  end
  say "Tweet posted by @#{@rcfile.active_profile[0]}."
  say
  say "Run `#{File.basename($PROGRAM_NAME)} delete status #{status.id}` to delete."
end
users(user, *users) click to toggle source
# File lib/t/cli.rb, line 869
def users(user, *users)
  users.unshift(user)
  require 't/core_ext/string'
  options['id'] ? users.collect!(&:to_i) : users.collect!(&:strip_ats)
  require 'retryable'
  users = Retryable.retryable(tries: 3, on: Twitter::Error, sleep: 0) do
    client.users(users)
  end
  print_users(users)
end
version() click to toggle source
# File lib/t/cli.rb, line 882
def version
  require 't/version'
  say T::Version
end
whoami() click to toggle source
# File lib/t/cli.rb, line 927
def whoami
  if @rcfile.active_profile && @rcfile.active_profile[0]
    user = @rcfile.active_profile[0]
    whois(user)
  else
    $stderr.puts "You haven't authorized an account, run `t authorize` to get started."
  end
end
whois(user) click to toggle source
# File lib/t/cli.rb, line 894
def whois(user)
  require 't/core_ext/string'
  opts = {}
  opts[:include_entities] = !!options['decode_uris']
  user = options['id'] ? user.to_i : user.strip_ats
  user = client.user(user, opts)
  if options['csv'] || options['long']
    print_users([user])
  else
    array = []
    array << ['ID', user.id.to_s]
    array << ['Since', "#{ls_formatted_time(user, :created_at, false)} (#{time_ago_in_words(user.created_at)} ago)"]
    array << ['Last update', "#{decode_full_text(user.status, options['decode_uris']).gsub(/\n+/, ' ')} (#{time_ago_in_words(user.status.created_at)} ago)"] unless user.status.nil?
    array << ['Screen name', "@#{user.screen_name}"]
    array << [user.verified? ? 'Name (Verified)' : 'Name', user.name] unless user.name.nil? # rubocop:disable BlockNesting
    array << ['Tweets', number_with_delimiter(user.statuses_count)]
    array << ['Favorites', number_with_delimiter(user.favorites_count)]
    array << ['Listed', number_with_delimiter(user.listed_count)]
    array << ['Following', number_with_delimiter(user.friends_count)]
    array << ['Followers', number_with_delimiter(user.followers_count)]
    array << ['Bio', user.description.gsub(/\n+/, ' ')] unless user.description.nil?
    array << ['Location', user.location] unless user.location.nil?
    array << ['URL', user.website] unless user.website.nil?
    print_table(array)
  end
end

Private Instance Methods

add_location!(options, opts) click to toggle source
# File lib/t/cli.rb, line 983
def add_location!(options, opts)
  return nil unless options['location']
  lat, lng = options['location'] == 'location' ? [location.lat, location.lng] : options['location'].split(',').collect(&:to_f)
  opts.merge!(lat: lat, long: lng)
end
extract_mentioned_screen_names(text) click to toggle source
# File lib/t/cli.rb, line 953
def extract_mentioned_screen_names(text)
  valid_mention_preceding_chars = /(?:[^a-zA-Z0-9_!#\$%&*@@]|^|RT:?)/o
  at_signs = /[@@]/
  valid_mentions = /
    (#{valid_mention_preceding_chars})  # $1: Preceeding character
    (#{at_signs})                       # $2: At mark
    ([a-zA-Z0-9_]{1,20})                # $3: Screen name
  /ox

  return [] if text !~ at_signs

  text.to_s.scan(valid_mentions).collect do |_, _, screen_name|
    screen_name
  end
end
generate_authorize_uri(consumer, request_token) click to toggle source
# File lib/t/cli.rb, line 969
def generate_authorize_uri(consumer, request_token)
  request = consumer.create_signed_request(:get, consumer.authorize_path, request_token, pin_auth_parameters)
  params = request['Authorization'].sub(/^OAuth\s+/, '').split(/,\s+/).collect do |param|
    key, value = param.split('=')
    value =~ /"(.*?)"/
    "#{key}=#{CGI.escape(Regexp.last_match[1])}"
  end.join('&')
  "#{Twitter::REST::Client::BASE_URL}#{request.path}?#{params}"
end
location() click to toggle source
# File lib/t/cli.rb, line 989
def location
  return @location if @location
  require 'geokit'
  require 'open-uri'
  ip_address = Kernel.open('http://checkip.dyndns.org/') do |body|
    /(?:\d{1,3}\.){3}\d{1,3}/.match(body.read)[0]
  end
  @location = Geokit::Geocoders::MultiGeocoder.geocode(ip_address)
end
pin_auth_parameters() click to toggle source
# File lib/t/cli.rb, line 979
def pin_auth_parameters
  {oauth_callback: 'oob'}
end
reverse_geocode(geo) click to toggle source
# File lib/t/cli.rb, line 999
def reverse_geocode(geo)
  require 'geokit'
  geoloc = Geokit::Geocoders::MultiGeocoder.reverse_geocode(geo.coordinates)
  if geoloc.city && geoloc.state && geoloc.country
    [geoloc.city, geoloc.state, geoloc.country].join(', ')
  elsif geoloc.state && geoloc.country
    [geoloc.state, geoloc.country].join(', ')
  else
    geoloc.country
  end
end