Skip to content

Commit

Permalink
Respond with NullObject if Tweet has no User
Browse files Browse the repository at this point in the history
Closes #415.
  • Loading branch information
sferik committed Jun 30, 2013
1 parent 810129b commit 17880f4
Show file tree
Hide file tree
Showing 11 changed files with 58 additions and 17 deletions.
6 changes: 5 additions & 1 deletion lib/twitter/api/users.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ module Users
# Twitter.settings
def settings(options={})
request_method = options.size.zero? ? :get : :post
object_from_response(Twitter::Settings, request_method, "/1.1/account/settings.json", options)
settings = object_from_response(Twitter::Settings, request_method, "/1.1/account/settings.json", options)
# https://dev.twitter.com/issues/59
trend_location = Array(settings.attrs[:trend_location]).first
settings.update(trend_location: trend_location)
settings
end

# Returns the requesting user if authentication was successful, otherwise raises {Twitter::Error::Unauthorized}
Expand Down
15 changes: 15 additions & 0 deletions lib/twitter/base.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'forwardable'
require 'twitter/null_object'

module Twitter
class Base
Expand Down Expand Up @@ -62,6 +63,20 @@ def new_without_self(klass, key1, key2)
attrs = @attrs.dup
value = attrs.delete(key1)
klass.new(value.update(key2 => attrs))
else
NullObject.new
end
end

# Create a new object (or NullObject) from attributes
#
# @param klass [Class]
# @param key [Symbol]
def new_or_null_object(klass, key)
if @attrs[key]
klass.new(@attrs[key])
else
NullObject.new
end
end

Expand Down
4 changes: 2 additions & 2 deletions lib/twitter/direct_message.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ class DirectMessage < Twitter::Identity

# @return [Twitter::User]
def recipient
@recipient ||= Twitter::User.new(@attrs[:recipient]) unless @attrs[:recipient].nil?
@recipient ||= new_or_null_object(Twitter::User, :recipient)
end

# @return [Twitter::User]
def sender
@sender ||= Twitter::User.new(@attrs[:sender]) unless @attrs[:sender].nil?
@sender ||= new_or_null_object(Twitter::User, :sender)
end

end
Expand Down
2 changes: 1 addition & 1 deletion lib/twitter/list.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class List < Twitter::Identity

# @return [Twitter::User]
def user
@user ||= Twitter::User.new(@attrs[:user]) unless @attrs[:user].nil?
@user ||= new_or_null_object(Twitter::User, :user)
end

end
Expand Down
16 changes: 16 additions & 0 deletions lib/twitter/null_object.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
class NullObject

def method_missing(*args, &block)
nil
end

def null?
true
end
alias nil? null?

def !
true
end

end
2 changes: 1 addition & 1 deletion lib/twitter/place.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class Place < Twitter::Identity

# @return [Twitter::Geo]
def bounding_box
@bounding_box ||= Twitter::GeoFactory.new(@attrs[:bounding_box]) unless @attrs[:bounding_box].nil?
@bounding_box ||= new_or_null_object(Twitter::GeoFactory, :bounding_box)
end

# @return [String]
Expand Down
4 changes: 2 additions & 2 deletions lib/twitter/relationship.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ def initialize(attrs={})

# @return [Twitter::SourceUser]
def source
@source ||= Twitter::SourceUser.new(@attrs[:source]) unless @attrs[:source].nil?
@source ||= new_or_null_object(Twitter::SourceUser, :source)
end

# @return [Twitter::TargetUser]
def target
@target ||= Twitter::TargetUser.new(@attrs[:target]) unless @attrs[:target].nil?
@target ||= new_or_null_object(Twitter::TargetUser, :target)
end

# Update the attributes of a Relationship
Expand Down
2 changes: 1 addition & 1 deletion lib/twitter/settings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class Settings < Twitter::Base

# @return [Twitter::Place]
def trend_location
@trend_location ||= Twitter::Place.new(Array(@attrs[:trend_location]).first) unless @attrs[:trend_location].nil?
@trend_location ||= new_or_null_object(Twitter::Place, :trend_location)
end

end
Expand Down
19 changes: 11 additions & 8 deletions lib/twitter/tweet.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ class Tweet < Twitter::Identity
:in_reply_to_screen_name, :in_reply_to_attrs_id, :in_reply_to_status_id,
:in_reply_to_user_id, :lang, :retweet_count, :retweeted, :source, :text,
:to_user, :to_user_id, :to_user_name, :truncated
alias in_reply_to_tweet_id in_reply_to_status_id
alias favorites_count favorite_count
alias favourite_count favorite_count
alias favourites_count favorite_count
alias favoriters_count favorite_count
alias favouriters_count favorite_count
alias favourited favorited
alias favourited? favorited?
alias in_reply_to_tweet_id in_reply_to_status_id
alias retweeters_count retweet_count
def_delegators :user, :profile_image_url, :profile_image_url_https

Expand All @@ -38,7 +38,7 @@ def filter_level
# @return [String]
# @note May be > 140 characters.
def full_text
if retweeted_status
if retweeted_status?
prefix = text[/\A(RT @[a-z0-9_]{1,20}: )/i, 1]
[prefix, retweeted_status.text].compact.join
else
Expand All @@ -48,7 +48,7 @@ def full_text

# @return [Twitter::Geo]
def geo
@geo ||= Twitter::GeoFactory.new(@attrs[:geo]) unless @attrs[:geo].nil?
@geo ||= new_or_null_object(Twitter::GeoFactory, :geo)
end

# @note Must include entities in your request for this method to work
Expand All @@ -65,12 +65,12 @@ def media

# @return [Twitter::Metadata]
def metadata
@metadata ||= Twitter::Metadata.new(@attrs[:metadata]) unless @attrs[:metadata].nil?
@metadata ||= new_or_null_object(Twitter::Metadata, :metadata)
end

# @return [Twitter::Place]
def place
@place ||= Twitter::Place.new(@attrs[:place]) unless @attrs[:place].nil?
@place ||= new_or_null_object(Twitter::Place, :place)
end

# @return [Boolean]
Expand All @@ -79,18 +79,21 @@ def reply?
end

# @return [Boolean]
def retweet?
def retweeted_status?
!!retweeted_status
end
alias retweet? retweeted_status?
alias retweeted? retweeted_status?
alias retweeted_tweet? retweeted_status?

# If this Tweet is a retweet, the original Tweet is available here.
#
# @return [Twitter::Tweet]
def retweeted_status
@retweeted_status ||= self.class.new(@attrs[:retweeted_status]) unless @attrs[:retweeted_status].nil?
@retweeted_status ||= new_or_null_object(self.class, :retweeted_status)
end
alias retweeted_tweet retweeted_status
alias retweet retweeted_status
alias retweeted_tweet retweeted_status

# @note Must include entities in your request for this method to work
# @return [Array<Twitter::Entity::Symbol>]
Expand Down
3 changes: 3 additions & 0 deletions lib/twitter/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,13 @@ def profile_image_url?
def status
@status ||= new_without_self(Twitter::Tweet, :status, :user)
end
alias tweet status

def status?
!@attrs[:status].nil?
end
alias tweet? status?
alias tweeted? status?

private

Expand Down
2 changes: 1 addition & 1 deletion spec/twitter/settings_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

describe "#trend_location" do
it "returns a Twitter::Place when set" do
place = Twitter::Settings.new(trend_location: [{countryCode: 'US', name: 'San Francisco', country: 'United States', placeType: {name: 'Town', code: 7}, woeid: 2487956, parentid: 23424977, url: 'http://where.yahooapis.com/v1/place/2487956'}])
place = Twitter::Settings.new(trend_location: {countryCode: 'US', name: 'San Francisco', country: 'United States', placeType: {name: 'Town', code: 7}, woeid: 2487956, parentid: 23424977, url: 'http://where.yahooapis.com/v1/place/2487956'})
expect(place.trend_location).to be_a Twitter::Place
end
it "returns nil when not set" do
Expand Down

0 comments on commit 17880f4

Please sign in to comment.