Jan 16 2016
My friends from college and I all stay in touch by using the popular messaging app, GroupMe. We have one main group, and then a number of smaller groups for things like fantasy football, investing, etc.. After talking with a friend one day, I thought it would be fun to create a CLI app that pulls stats down and crunches some numbers by using the GroupMe API. An afternoon later I had a nice working demo, and some fun information to share with my friends. All this code is hosted on GitHub if you would like to take it for a spin.
I tried to keep things nice and OOP, and embarked on this project right after
watching a great
screencast
on API wrapping by Gary Bernhardt on his site Destroy All Software. After
getting my developer key from GroupMe (2 mins), I played around a little with
the end points and decided that I would need 3 resources from GroupMe; Groups,
Members, and Messages. The end goal is a CLI where the user can run the program,
be prompted with a display of all the groups that they are members of, and then
select one to generate the stats. Starting from that step 1, we need to get
groups. I really like the gem HTTParty
for HTTP requests in ruby, so I will be
using that. Also, my GroupMe Access Token is stored in a constant up at the top
of the file.
class Groups
attr_reader :options
attr_writer :groups
def initialize
@options = { :query => { :access_token => ACCESS_TOKEN } }
end
def groups
@groups ||= HTTParty.get(url, options)["response"]
end
def url
"http://api.groupme.com/v3/groups"
end
def list_groups
puts "Please select the number of the group you want to see stats for"
groups.each_with_index do |group, i|
puts "#{(i + 1).to_s}. #{group["name"]}"
end
end
end
Now we can prompt the user when the program runs and print a nice little list of the users groups. We will get the input, strip it of white space, and decrease it by 1 (because in the groups class we increased the index by one for more user friendly numbering).
groups = Groups.new groups.list_groups
group_index = gets.chomp.to_i
group_id = groups.groups[group_index-1]['group_id']
Running it to test
GroupMeStats master => ruby stats.rb
Please select the number of the group you want to see stats for
1. Vandy Friends
2. Fantasy Football
3. Investor Club
Success!
You can see in the code that I do a similar class for both Members and Messages, but then I have a 4th class for fetching the messages. This is because the rate limit of the GroupMe API for fetching messages is 100, so I need to make multiple calls to fetch my full history. The rescue clause is because we don't know how many messages there will be in the history, so its easiest to just break when we encounter a nil caused error.
class FetchMessages
attr_accessor :messages
attr_reader :group_id
RATE_LIMIT = 100
def initialize(num, group_id)
@messages = []
@num = num
@group_id = group_id
populate_last_x_messages(num)
end
def populate_last_x_messages(num)
before_id = nil
while messages.count < num
begin
self.messages += Messages.new(group_id, RATE_LIMIT, before_id).messages
before_id = messages.last['id']
rescue
break
end
end
end
end
There is a main stats class where I do the actual processing of and displaying of stats built from the other objects. If I were to refactor this, the first thing I would do would be to separate the processing from the displaying within this class. I did a number of different stats but here are a couple of them.
1) Group Member and their Messages to Likes ratios:
def print_message_stats
messages_by_members.each do |member, messages|
total_likes = messages.reduce(0) do |sum, message|
sum += message['favorited_by'].count
end
puts 'Member: #{member['nickname']}: #{messages.count} messages and #{total_likes} likes for a ratio of #{(total_likes.to_f / messages.count).round(2)} likes per message'
end
return nil
end
2) Self Likes (How many of times has each person liked their own posts :D)
def print_self_likes
puts 'Self Likes Given'
members.each do |member|
puts '#{member['nickname']}: #{self.self_likes[member['user_id']]}' if self.self_likes[member['user_id']] <> 0
end
end
and so on…
At the end we can put our final execution code
puts 'Loading Stats for Group: #{groups.groups[group_index-1]['name']} '
stats = Stats.new(MAX_MESSAGES_FETCHED, group_id)
puts 'Last #{stats.messages.count} Messages'
stats.run
And we give it a run!
Please select the number of the group you want to see stats for
1. Vandy Friends
2. Fantasy Football
3. Investor Club
1
Loading Stats for Group: Vandy Friends
Last 2000 Messages
Member: Matt: 166 messages and 331 likes for a ratio of 1.99 likes per message
Member: Luke: 93 messages and 419 likes for a ratio of 4.51 likes per message
Member: Todd: 127 messages and 472 likes for a ratio of 3.72 likes per message
Member: Rick: 53 messages and 253 likes for a ratio of 4.77 likes per message
Member: Rory: 20 messages and 107 likes for a ratio of 5.35 likes per message
Top 25 Messages
1. redacted
2. redacted
...
Total Likes Given
Matt: 169
Luke: 508
Todd: 425
Rick: 323
Rory: 253
Self Likes Given
Luke: 2
Todd: 7
Rick: 2
Kevin: 17
Rory: 2
This was a fun afternoon exercise that gave my group of friends a good laugh. Please feel free to take it for a spin: Github Repo and let me know if you have any questions.
-Jack