Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add happy scores for statuses

  • Loading branch information...
commit 563164b9ad30aab41021eeb1f35ac0569c5c7bf9 1 parent 3dd9fa3
@cimm authored
View
1  app/application.rb
@@ -17,6 +17,7 @@ def self.start
def self.archive_statuses
public_timeline = PublicTimeline.new(TWITTER_USER, Status.last_id)
public_timeline.statuses.each do |status|
+ status.classify
status.save!
end
end
View
38 app/classification.rb
@@ -0,0 +1,38 @@
+require "data_mapper"
+require "open-uri"
+require "json"
+require "settings"
+require "mood"
+
+class Classification
+
+ MOOD_CLASSIFICATION_BASE_URL = "http://uclassify.com/browse/prfekt/Mood/ClassifyText?text="
+ MOOD_CLASSIFICATION_URL_OPTIONS = "readkey=#{Settings.uclassify.read_key}&output=json"
+
+ def self.happy_score_for_text(text)
+ classification = new(text)
+ classification.happy_score
+ end
+
+ def initialize(text)
+ @text = text
+ end
+
+ def happy_score
+ mood = Mood.new(json_mood)
+ mood.happy_score
+ end
+
+ def raw_json_mood
+ open(mood_classification_url).read
+ end
+
+ def json_mood
+ JSON.parse(raw_json_mood)
+ end
+
+ def mood_classification_url
+ uri_encoded_text = URI.encode(@text)
+ "#{MOOD_CLASSIFICATION_BASE_URL}#{uri_encoded_text}&#{MOOD_CLASSIFICATION_URL_OPTIONS}"
+ end
+end
View
15 app/mood.rb
@@ -0,0 +1,15 @@
+class Mood
+ CLASSIFICATION_SECTION = "cls1"
+
+ def initialize(mood_json)
+ @mood_json = mood_json
+ end
+
+ def happy_score
+ round_score(@mood_json[CLASSIFICATION_SECTION]["happy"])
+ end
+
+ def round_score(score)
+ (score * 100).to_i
+ end
+end
View
8 app/status.rb
@@ -1,5 +1,6 @@
require "data_mapper"
require "settings"
+require "classification"
class Status
include DataMapper::Resource
@@ -22,6 +23,9 @@ class Status
property :in_reply_to_user_id, String
property :in_reply_to_status_id, String
property :text, String, :required => true, :length => MAXIMUM_STATUS_LENGTH
+ property :happy_score, Integer
+
+ validates_within :happy_score, :set => 0..100
def self.old
all(:created_at.lte => old_status_date)
@@ -58,6 +62,10 @@ def self.from_raw_status(raw_status)
status
end
+ def classify
+ self.happy_score = Classification.happy_score_for_text(text)
+ end
+
def take_offline(access_token)
response = access_token.post(take_offline_url)
if response.code == HTTP_SUCCESS_CODE
View
9 spec/application_spec.rb
@@ -35,7 +35,7 @@
Status.stub(:last_id => last_id)
PublicTimeline.stub(:new => public_timeline)
public_timeline.stub(:statuses => statuses)
- status.stub(:save!)
+ status.stub(:save! => nil, :classify => nil)
end
it "gets the id of the last archived status" do
@@ -53,6 +53,13 @@
Application.archive_statuses
end
+ it "classifies each of these statuses" do
+ statuses.each do |s|
+ s.should_receive(:classify)
+ end
+ Application.archive_statuses
+ end
+
it "persists each of these statuses" do
statuses.each do |s|
s.should_receive(:save!)
View
138 spec/classification_spec.rb
@@ -0,0 +1,138 @@
+require "spec_helper"
+require "classification"
+
+describe Classification do
+ MOOD_CLASSIFICATION_BASE_URL = "http://uclassify.com/browse/prfekt/Mood/ClassifyText?text="
+ MOOD_CLASSIFICATION_URL_OPTIONS = "readkey=#{Settings.uclassify.read_key}&output=json"
+
+ let(:text) { "Text to classify" }
+ let(:classification) { Classification.new(text) }
+
+ describe "self.happy_score_for_text" do
+ let(:text) { mock("Text") }
+ let(:new_classification) { mock("Classification") }
+ let(:happy_score) { mock("Happy score") }
+
+ before :each do
+ Classification.stub(:new => new_classification)
+ new_classification.stub(:happy_score => happy_score)
+ end
+
+ it "builds a new classification" do
+ Classification.should_receive(:new).with(text)
+ Classification.happy_score_for_text(text)
+ end
+
+ it "gets the happy score from the new classification" do
+ new_classification.should_receive(:happy_score)
+ Classification.happy_score_for_text(text)
+ end
+
+ it "returns the happy score" do
+ Classification.happy_score_for_text(text).should eql happy_score
+ end
+ end
+
+ describe :happy_score do
+ let(:json_mood) { mock("JSON mood") }
+ let(:mood) { mock("Mood") }
+ let(:happy_score) { mock("Happy score") }
+
+ before :each do
+ classification.stub(:json_mood => json_mood)
+ Mood.stub(:new => mood)
+ mood.stub(:happy_score => happy_score)
+ end
+
+ it "gets the JSON mood" do
+ classification.should_receive(:json_mood)
+ classification.happy_score
+ end
+
+ it "builds a mood from the JSON mood" do
+ Mood.should_receive(:new).with(json_mood)
+ classification.happy_score
+ end
+
+ it "gets the happy score from the mood" do
+ mood.should_receive(:happy_score)
+ classification.happy_score
+ end
+
+ it "returns the happy mood" do
+ classification.happy_score.should eql happy_score
+ end
+ end
+
+ describe :raw_json_mood do
+ let(:mood_classification_url) { "Mood classification URL" }
+ let(:url_handle) { mock("URL handle") }
+ let(:raw_json_mood) { mock("Raw JSON mood") }
+
+ before :each do
+ classification.stub(:mood_classification_url => mood_classification_url, :open => url_handle)
+ url_handle.stub(:read => raw_json_mood)
+ end
+
+ it "gets the mood classification URL" do
+ classification.should_receive(:mood_classification_url)
+ classification.raw_json_mood
+ end
+
+ it "opens the mood classification URL" do
+ classification.should_receive(:open).with(mood_classification_url)
+ classification.raw_json_mood
+ end
+
+ it "reads the mood" do
+ url_handle.should_receive(:read)
+ classification.raw_json_mood
+ end
+
+ it "returns the raw mood" do
+ classification.raw_json_mood.should eql raw_json_mood
+ end
+ end
+
+ describe :json_mood do
+ let(:raw_json_mood) { mock("Raw JSON mood") }
+ let(:json_mood) { mock("JSON mood") }
+
+ before :each do
+ classification.stub(:raw_json_mood => raw_json_mood)
+ JSON.stub(:parse => json_mood)
+ end
+
+ it "gets the raw JSON mood" do
+ classification.should_receive(:raw_json_mood)
+ classification.json_mood
+ end
+
+ it "parses the raw JSON mood" do
+ JSON.should_receive(:parse).with(raw_json_mood)
+ classification.json_mood
+ end
+
+ it "returns the JSON mood" do
+ classification.json_mood.should eql json_mood
+ end
+ end
+
+ describe :mood_classification_url do
+ let(:uri_encoded_text) { URI.encode(text) }
+ let(:mood_classification_url) { "#{MOOD_CLASSIFICATION_BASE_URL}#{uri_encoded_text}&#{MOOD_CLASSIFICATION_URL_OPTIONS}" }
+
+ before :each do
+ URI.stub(:encode => uri_encoded_text)
+ end
+
+ it "URI encodes the text" do
+ URI.should_receive(:encode)
+ classification.mood_classification_url
+ end
+
+ it "returns the URL needed to classify the mood of the text" do
+ classification.mood_classification_url.should eql mood_classification_url
+ end
+ end
+end
View
33 spec/mood_spec.rb
@@ -0,0 +1,33 @@
+require "spec_helper"
+require "mood"
+
+describe Mood do
+ CLASSIFICATION_SECTION = "cls1"
+
+ let(:mood_json) { mock("Raw mood JSON") }
+ let(:mood) { Mood.new(mood_json) }
+
+ describe :happy_score do
+ let(:happy_score) { 0.6070 }
+ let(:rounded_happy_score) { 60 }
+ let(:mood_json) { { CLASSIFICATION_SECTION => { "happy" => happy_score } } }
+
+ it "rounds the happy score" do
+ mood.should_receive(:round_score).with(happy_score)
+ mood.happy_score
+ end
+
+ it "returns the happy score" do
+ mood.happy_score.should eql rounded_happy_score
+ end
+ end
+
+ describe :round_score do
+ let(:score) { 0.6070 }
+ let(:rounded_score) { 60 }
+
+ it "returns the rounded score" do
+ mood.round_score(score).should eql rounded_score
+ end
+ end
+end
View
39 spec/status_spec.rb
@@ -110,6 +110,20 @@
status.errors[:text].should include("Text must be at most 144 characters long")
end
+ it "has a happy score" do
+ status.should respond_to(:happy_score)
+ status.should respond_to(:happy_score=)
+ end
+
+ it "has a happy score between 0 and 100" do
+ status.happy_score = -1
+ status.should_not be_valid
+ status.errors[:happy_score].should include("Happy score must be between 0 and 100")
+ status.happy_score = 101
+ status.should_not be_valid
+ status.errors[:happy_score].should include("Happy score must be between 0 and 100")
+ end
+
describe "self.old" do
let(:old_status_date) { mock("Old status date") }
let(:query) { {:created_at.lte => old_status_date } }
@@ -364,6 +378,31 @@
end
end
+ describe :classify do
+ let(:text) { mock("Text") }
+ let(:happy_score) { mock("Happy score") }
+
+ before :each do
+ status.stub(:text => text)
+ Classification.stub(:happy_score_for_text => happy_score)
+ end
+
+ it "gets the text from the status" do
+ status.should_receive(:text)
+ status.classify
+ end
+
+ it "calculates the happy score for this text" do
+ Classification.should_receive(:happy_score_for_text).with(text)
+ status.classify
+ end
+
+ it "sets the status happy score to this calculated score" do
+ status.should_receive(:happy_score=).with(happy_score)
+ status.classify
+ end
+ end
+
describe :take_offline do
let(:access_token) { mock("Access token") }
let(:take_offline_url) { mock("Take offline URL") }
Please sign in to comment.
Something went wrong with that request. Please try again.