Skip to content

Commit

Permalink
Add question-mark methods for all possible NullObjects
Browse files Browse the repository at this point in the history
  • Loading branch information
sferik committed Jul 28, 2013
1 parent a7955d5 commit eac5522
Show file tree
Hide file tree
Showing 15 changed files with 267 additions and 54 deletions.
41 changes: 37 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -260,13 +260,46 @@ removed:
* `#from_user_id`
* `#from_user_name`
* `#to_user`
* `$to_user_id`
* `to_user_name`
* `profile_image_url`
* `profile_image_url_https`
* `#to_user_id`
* `#to_user_name`
* `#profile_image_url`
* `#profile_image_url_https`

These attributes can be accessed through the `#user` method.

### Null Objects
In version 4, methods you would expect to return a `Twitter` object would
return `nil` if that object was missing. This may have resulted in errors like
this:

NoMethodError: undefined method for nil:NilClass

To prevent such errors, you may have introduced checks for the truthiness of
the response, for example:

```ruby
status = client.status(55709764298092545)
if status.place
# Do something with the Twitter::Place object
elsif status.geo
# Do something with the Twitter::Geo object
end
```
In version 5, all such methods will return a `Twitter::NullObject` instead of
`nil`. This should prevent `NoMethodError` but may result in unexpected
behavior if you have truthiness checks in place, since everything is truthy in
Ruby execpt `false` and `nil`. For these cases, there are now predicate
methods:

```ruby
status = client.status(55709764298092545)
if status.place?
# Do something with the Twitter::Place object
elsif status.geo?
# Do something with the Twitter::Geo object
end
```

## Configuration
Twitter API v1.1 requires you to authenticate via OAuth, so you'll need to
[register your application with Twitter][register]. Once you've registered an
Expand Down
14 changes: 12 additions & 2 deletions lib/twitter/direct_message.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,25 @@ class DirectMessage < Twitter::Identity
attr_reader :text
alias full_text text

# @return [Twitter::User]
# @return [Twitter::User, Twitter::NullObject]
def recipient
new_or_null_object(Twitter::User, :recipient)
end

# @return [Twitter::User]
# @return [Boolean]
def recipient?
!recipient.nil?
end

# @return [Twitter::User, Twitter::NullObject]
def sender
new_or_null_object(Twitter::User, :sender)
end

# @return [Boolean]
def sender?
!sender.nil?
end

end
end
7 changes: 6 additions & 1 deletion lib/twitter/list.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@ class List < Twitter::Identity
attr_reader :description, :following, :full_name, :member_count,
:mode, :name, :slug, :subscriber_count, :uri

# @return [Twitter::User]
# @return [Twitter::User, Twitter::NullObject]
def user
new_or_null_object(Twitter::User, :user)
end

# @return [Boolean]
def user?
!user.nil?
end

end
end
7 changes: 6 additions & 1 deletion lib/twitter/place.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,16 @@ class Place < Twitter::Identity
attr_reader :attributes, :country, :full_name, :name, :url, :woeid
alias woe_id woeid

# @return [Twitter::Geo]
# @return [Twitter::Geo, Twitter::NullObject]
def bounding_box
new_or_null_object(Twitter::GeoFactory, :bounding_box)
end

# @return [Boolean]
def bounding_box?
!bounding_box.nil?
end

# @return [String]
def country_code
@country_code ||= @attrs[:country_code] || @attrs[:countryCode]
Expand Down
14 changes: 12 additions & 2 deletions lib/twitter/relationship.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,26 @@ def initialize(attrs={})
@attrs = attrs[:relationship]
end

# @return [Twitter::SourceUser]
# @return [Twitter::SourceUser, Twitter::NullObject]
def source
new_or_null_object(Twitter::SourceUser, :source)
end

# @return [Twitter::TargetUser]
# @return [Boolean]
def source?
!source.nil?
end

# @return [Twitter::TargetUser, Twitter::NullObject]
def target
new_or_null_object(Twitter::TargetUser, :target)
end

# @return [Boolean]
def target?
!target.nil?
end

# Update the attributes of a Relationship
#
# @param attrs [Hash]
Expand Down
7 changes: 6 additions & 1 deletion lib/twitter/settings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,15 @@ class Settings < Twitter::Base
:language, :protected, :screen_name, :show_all_inline_media, :sleep_time,
:time_zone

# @return [Twitter::Place]
# @return [Twitter::Place, Twitter::NullObject]
def trend_location
new_or_null_object(Twitter::Place, :trend_location)
end

# @return [Boolean]
def trend_location?
!trend_location.nil?
end

end
end
2 changes: 2 additions & 0 deletions lib/twitter/trend_results.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ def as_of
@as_of ||= Time.parse(@attrs[:as_of]) unless @attrs[:as_of].nil?
end

# @return [Twitter::Place, NullObject]
def location
@location ||= if location?
Twitter::Place.new(@attrs[:locations].first)
Expand All @@ -53,6 +54,7 @@ def location
end
end

# @return [Boolean]
def location?
!@attrs[:locations].nil? && !@attrs[:locations].first.nil?
end
Expand Down
26 changes: 24 additions & 2 deletions lib/twitter/tweet.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ def geo
new_or_null_object(Twitter::GeoFactory, :geo)
end

# @return [Boolean]
def geo?
!geo.nil?
end

# @note Must include entities in your request for this method to work
# @return [Array<Twitter::Entity::Hashtag>]
def hashtags
Expand All @@ -54,16 +59,26 @@ def media
@media ||= entities(Twitter::MediaFactory, :media)
end

# @return [Twitter::Metadata]
# @return [Twitter::Metadata, Twitter::NullObject]
def metadata
new_or_null_object(Twitter::Metadata, :metadata)
end

# @return [Twitter::Place]
# @return [Boolean]
def metadata?
!metadata.nil?
end

# @return [Twitter::Place, Twitter::NullObject]
def place
new_or_null_object(Twitter::Place, :place)
end

# @return [Boolean]
def place?
!place.nil?
end

# @return [Boolean]
def reply?
!!in_reply_to_status_id
Expand All @@ -86,6 +101,13 @@ def retweeted_status
alias retweet retweeted_status
alias retweeted_tweet retweeted_status

# @return [Boolean]
def retweeted_status?
!retweeted_status.nil?
end
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>]
def symbols
Expand Down
38 changes: 30 additions & 8 deletions spec/twitter/direct_message_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,23 +44,45 @@

describe "#recipient" do
it "returns a User when recipient is set" do
recipient = Twitter::DirectMessage.new(:id => 1825786345, :recipient => {:id => 7505382}).recipient
expect(recipient).to be_a Twitter::User
direct_message = Twitter::DirectMessage.new(:id => 1825786345, :recipient => {:id => 7505382})
expect(direct_message.recipient).to be_a Twitter::User
end
it "returns nil when recipient is not set" do
recipient = Twitter::DirectMessage.new(:id => 1825786345).recipient
expect(recipient).to be_nil
direct_message = Twitter::DirectMessage.new(:id => 1825786345)
expect(direct_message.recipient).to be_nil
end
end

describe "#recipient?" do
it "returns true when recipient is set" do
direct_message = Twitter::DirectMessage.new(:id => 1825786345, :recipient => {:id => 7505382})
expect(direct_message.recipient?).to be_true
end
it "returns false when recipient is not set" do
direct_message = Twitter::DirectMessage.new(:id => 1825786345)
expect(direct_message.recipient?).to be_false
end
end

describe "#sender" do
it "returns a User when sender is set" do
sender = Twitter::DirectMessage.new(:id => 1825786345, :sender => {:id => 7505382}).sender
expect(sender).to be_a Twitter::User
direct_message = Twitter::DirectMessage.new(:id => 1825786345, :sender => {:id => 7505382})
expect(direct_message.sender).to be_a Twitter::User
end
it "returns nil when sender is not set" do
sender = Twitter::DirectMessage.new(:id => 1825786345).sender
expect(sender).to be_nil
direct_message = Twitter::DirectMessage.new(:id => 1825786345)
expect(direct_message.sender).to be_nil
end
end

describe "#sender?" do
it "returns true when sender is set" do
direct_message = Twitter::DirectMessage.new(:id => 1825786345, :sender => {:id => 7505382})
expect(direct_message.sender?).to be_true
end
it "returns false when sender is not set" do
direct_message = Twitter::DirectMessage.new(:id => 1825786345)
expect(direct_message.sender?).to be_false
end
end

Expand Down
19 changes: 15 additions & 4 deletions spec/twitter/list_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,23 @@

describe "#user" do
it "returns a User when user is set" do
user = Twitter::List.new(:id => 8863586, :user => {:id => 7505382}).user
expect(user).to be_a Twitter::User
list = Twitter::List.new(:id => 8863586, :user => {:id => 7505382})
expect(list.user).to be_a Twitter::User
end
it "returns nil when status is not set" do
user = Twitter::List.new(:id => 8863586).user
expect(user).to be_nil
list = Twitter::List.new(:id => 8863586)
expect(list.user).to be_nil
end
end

describe "#user?" do
it "returns true when user is set" do
list = Twitter::List.new(:id => 8863586, :user => {:id => 7505382})
expect(list.user?).to be_true
end
it "returns false when user is not set" do
list = Twitter::List.new(:id => 8863586)
expect(list.user?).to be_false
end
end

Expand Down
15 changes: 13 additions & 2 deletions spec/twitter/place_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,27 @@
end

describe "#bounding_box" do
it "returns a Twitter::Place when set" do
it "returns a Twitter::Place when bounding_box is set" do
place = Twitter::Place.new(:id => "247f43d441defc03", :bounding_box => {:type => "Polygon", :coordinates => [[[-122.40348192, 37.77752898], [-122.387436, 37.77752898], [-122.387436, 37.79448597], [-122.40348192, 37.79448597]]]})
expect(place.bounding_box).to be_a Twitter::Geo::Polygon
end
it "returns nil when not set" do
it "returns nil when not bounding_box is not set" do
place = Twitter::Place.new(:id => "247f43d441defc03")
expect(place.bounding_box).to be_nil
end
end

describe "#bounding_box?" do
it "returns true when bounding_box is set" do
place = Twitter::Place.new(:id => "247f43d441defc03", :bounding_box => {:type => "Polygon", :coordinates => [[[-122.40348192, 37.77752898], [-122.387436, 37.77752898], [-122.387436, 37.79448597], [-122.40348192, 37.79448597]]]})
expect(place.bounding_box?).to be_true
end
it "returns false when bounding_box is not set" do
place = Twitter::Place.new(:id => "247f43d441defc03")
expect(place.bounding_box?).to be_false
end
end

describe "#country_code" do
it "returns a country code when set with country_code" do
place = Twitter::Place.new(:id => "247f43d441defc03", :country_code => "US")
Expand Down
38 changes: 30 additions & 8 deletions spec/twitter/relationship_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,45 @@

describe "#source" do
it "returns a User when source is set" do
source = Twitter::Relationship.new(:relationship => {:source => {:id => 7505382}}).source
expect(source).to be_a Twitter::SourceUser
relationship = Twitter::Relationship.new(:relationship => {:source => {:id => 7505382}})
expect(relationship.source).to be_a Twitter::SourceUser
end
it "returns nil when source is not set" do
source = Twitter::Relationship.new(:relationship => {}).source
expect(source).to be_nil
relationship = Twitter::Relationship.new(:relationship => {})
expect(relationship.source).to be_nil
end
end

describe "#source?" do
it "returns true when source is set" do
relationship = Twitter::Relationship.new(:relationship => {:source => {:id => 7505382}})
expect(relationship.source?).to be_true
end
it "returns false when source is not set" do
relationship = Twitter::Relationship.new(:relationship => {})
expect(relationship.source?).to be_false
end
end

describe "#target" do
it "returns a User when target is set" do
target = Twitter::Relationship.new(:relationship => {:target => {:id => 7505382}}).target
expect(target).to be_a Twitter::TargetUser
relationship = Twitter::Relationship.new(:relationship => {:target => {:id => 7505382}})
expect(relationship.target).to be_a Twitter::TargetUser
end
it "returns nil when target is not set" do
target = Twitter::Relationship.new(:relationship => {}).target
expect(target).to be_nil
relationship = Twitter::Relationship.new(:relationship => {})
expect(relationship.target).to be_nil
end
end

describe "#target?" do
it "returns true when target is set" do
relationship = Twitter::Relationship.new(:relationship => {:target => {:id => 7505382}})
expect(relationship.target?).to be_true
end
it "returns false when target is not set" do
relationship = Twitter::Relationship.new(:relationship => {})
expect(relationship.target?).to be_false
end
end

Expand Down
Loading

0 comments on commit eac5522

Please sign in to comment.