Skip to content

Commit

Permalink
Always return URIs instead of strings
Browse files Browse the repository at this point in the history
Standardize on URI over URL.
  • Loading branch information
sferik committed Jul 28, 2013
1 parent f6deb7d commit 341f68d
Show file tree
Hide file tree
Showing 27 changed files with 695 additions and 256 deletions.
81 changes: 37 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,23 +200,23 @@ end</code></pre>
</tbody>
</table>

In the examples above, *n* is dependent on the number of people the
authenticated user follows on Twitter (divided by 20, the number of friends you
can fetch per request). So, if the user followers 85 people, calling
`Twitter.friends.take(20)` would make 6 HTTP requests in version 4. In version
In the examples above, *n* varies with the number of people the authenticated
user follows on Twitter. This resource returns up to 20 friends per HTTP GET,
so if the authenticated user follows 200 people, calling
`Twitter.friends.take(20)` would make 11 HTTP requests in version 4. In version
5, it makes just 1 HTTP request. Keep in mind, eliminating a single HTTP
request to the Twitter API will reduce the latency of your application by
[about 500 ms][status].

[status]: https://dev.twitter.com/status

The last example might seem contrived ("Why would I need to call
The last example might seem contrived ("Why would I call
`Twitter.friends.take(20)` twice?") but it applies to any
[`Enumerable`][enumerable] method you might call on a cursor, including:
`#all?`, `#collect`, `#count`, `#each`, `#inject`, `#max`, `#min`, `#reject`,
`#reverse_each`, `#select`, `#sort`, `#sort_by`, and `#to_a`. In version 4,
each time you called one of those methods, it would perform *n+1* HTTP
requests. In version 5, it will only perform those HTTP requests the first time
requests. In version 5, it only performs those HTTP requests the first time any
one of those methods is called. Each subsequent call fetches data from a
[cache][].

Expand All @@ -232,34 +232,35 @@ before yielding any data.

Here is a list of the interface changes to `Twitter::Cursor`:

* `#all` has been replaced by `#to_a`.
* `#last` has been replaced by `#last?`.
* `#first` has been replaced by `#first?`.
* `#first` now returns the first element in the collection, as prescribed by `Enumerable`.
* `#last` has been replaced by `#last?`.
* `#all` has been replaced by `#to_a`.
* `#collection` and its aliases have been removed.

### Search Results
The `Twitter::SearchResults` class has also been redesigned to have an
[`Enumerable`][enumerable] interface. The `#statuses` method and its aliases
(`#collection` and `#results`) have been replaced by `#to_a`. Additionally,
this class no longer inherits from `Twitter::Base`. As a result, the `#[]`
method has been removed without replacement.
method has been removed.

### Trend Results
The `Twitter.trends` method now returns an [`Enumerable`][enumerable]
`Twitter::TrendResults` object instead of an array. This object exposes the
recency of the trend (via `#as_of`), when the trend started (via
`#created_at`), and the location of the trend (via `#location`). This
information was previously unavailable.
`Twitter::TrendResults` object instead of an array. This object provides
methods to determinte the recency of the trend (`#as_of`), when the trend
started (`#created_at`), and the location of the trend (`#location`). This data
was previously unavailable.

### Geo Results
The `Twitter.reverse_geocode`, `Twitter.geo_search`, and
Similarly, the `Twitter.reverse_geocode`, `Twitter.geo_search`, and
`Twitter.similar_places` methods now return an [`Enumerable`][enumerable]
`Twitter::GeoResults` object instead of an array. This object exposes the token
to create a new place (via `#token`), which was previously unavailable.
`Twitter::GeoResults` object instead of an array. This object provides access
to the token to create a new place (`#token`), which was previously
unavailable.

### Users
The `Twitter::User` object has been cleaned up. The following methods have been
### Tweets
The `Twitter::Tweet` object has been cleaned up. The following methods have been
removed:

* `#from_user`
Expand All @@ -271,17 +272,14 @@ removed:
* `#profile_image_url`
* `#profile_image_url_https`

These attributes can be accessed through the `#user` method.
These attributes can be accessed on the `Twitter::User` object, returned
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:
return `nil` if that object was missing. This may have resulted in a
`NoMethodError`. To prevent such errors, you may have introduced checks for the
truthiness of the response, for example:

```ruby
status = Twitter.status(55709764298092545)
Expand All @@ -306,23 +304,18 @@ elsif status.geo?
end
```

### URL Methods
`Twitter::List`, `Twitter::Tweet`, and `Twitter::User` objects all have `#url`
methods, which generate an HTTPS URL to twitter.com. You may specify a
different protocol by passing it to the `#url` method. For example:

```ruby
status = Twitter.status(55709764298092545)
status.url #=> https://twitter.com/sferik/status/55709764298092545
status.url("http") #=> http://twitter.com/sferik/status/55709764298092545
```
### URI Methods
The `Twitter::List`, `Twitter::Tweet`, and `Twitter::User` objects all have a
`#uri` method, which returnis an HTTPS URI to twitter.com. This clobbers the
`Twitter::List#uri` method, which previously returned the list URI's path (not
a URI).

`Twitter::User` previously had a method called `#url`, which returned the URL
to the user's website. This URL is now accessible via the `#website` method.
These methods are aliased to `#url` for users who prefer that nomenclature.
`Twitter::User` previously had a `#url` method, which returned the user's
website. This URI is now available via the `#website` method.

These methods are aliased to `#uri`, for users who prefer that nomenclature.
This clobbers the `Twitter::List#uri` method, which previously returned the
list's path (not a full URI).
All `#uri` methods now return `URI` objects instead of strings. To convert a
`URI` object to a string, call `#to_s` on it.

## Configuration
Twitter API v1.1 requires you to authenticate via OAuth, so you'll need to
Expand Down Expand Up @@ -525,9 +518,9 @@ recommend [Oj][].
## Statistics
Here are some fun facts about this library:
* It is implemented in just 2,000 lines of Ruby code
* With over 5,000 lines of specs, the spec-to-code ratio is about 2.5:1
* The spec suite contains over 800 examples and runs in about 5 seconds
* It is implemented in just 2,500 lines of Ruby code
* With over 6,250 lines of specs, the spec-to-code ratio is about 2.5:1
* The spec suite contains over 900 examples and runs in about 5 seconds
* It has 100% C0 code coverage (the tests execute every line of
source code at least once)
* It is comprehensive: you can request all documented Twitter REST API
Expand Down
3 changes: 2 additions & 1 deletion lib/twitter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
require 'twitter/entity'
require 'twitter/entity/hashtag'
require 'twitter/entity/symbol'
require 'twitter/entity/url'
require 'twitter/entity/uri'
require 'twitter/entity/user_mention'
require 'twitter/geo_factory'
require 'twitter/language'
Expand All @@ -30,6 +30,7 @@
require 'twitter/trend'
require 'twitter/tweet'
require 'twitter/user'
require 'uri'

module Twitter
class << self
Expand Down
8 changes: 4 additions & 4 deletions lib/twitter/api/undocumented.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,19 @@ def following_followers_of(*args)
cursor_from_response_with_user(:users, Twitter::User, :get, "/users/following_followers_of.json", args)
end

# Returns Tweets count for a URL
# Returns Tweets count for a URI
#
# @note Undocumented
# @rate_limited No
# @authentication Not required
# @return [Integer]
# @param url [Integer] A URL.
# @param uri [String, URI] A URI.
# @param options [Hash] A customizable set of options.
# @example Return Tweet count for http://twitter.com
# Twitter.tweet_count("http://twitter.com/")
def tweet_count(url, options={})
def tweet_count(uri, options={})
connection = Faraday.new("https://cdn.api.twitter.com", @connection_options.merge(:builder => @middleware))
connection.get("/1/urls/count.json", options.merge(:url => url)).body[:count]
connection.get("/1/urls/count.json", options.merge(:url => uri.to_s)).body[:count]
end

end
Expand Down
10 changes: 5 additions & 5 deletions lib/twitter/api/utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ module Utils
# @return [Integer]
def extract_id(object)
case object
when Integer
when ::Integer
object
when String
when ::String
object.split("/").last.to_i
when URI
when ::URI
object.path.split("/").last.to_i
when Twitter::Identity
object.id
Expand Down Expand Up @@ -167,7 +167,7 @@ def merge_user!(hash, user, prefix=nil)
else
hash[[prefix, "screen_name"].compact.join("_").to_sym] = user
end
when URI
when ::URI
hash[[prefix, "screen_name"].compact.join("_").to_sym] = user.path.split("/").last
when Twitter::User
hash[[prefix, "user_id"].compact.join("_").to_sym] = user.id
Expand Down Expand Up @@ -201,7 +201,7 @@ def merge_users!(hash, users)
else
screen_names << user
end
when URI
when ::URI
screen_names << user.path.split("/").last
when Twitter::User
user_ids << user.id
Expand Down
2 changes: 1 addition & 1 deletion lib/twitter/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ def bearer_auth_header
end

def oauth_auth_header(method, path, params={})
uri = URI(@endpoint + path)
uri = ::URI.parse(@endpoint + path)
SimpleOAuth::Header.new(method, uri, params, credentials)
end
end
Expand Down
2 changes: 2 additions & 0 deletions lib/twitter/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ module Twitter
class Configuration < Twitter::Base
attr_reader :characters_reserved_per_media, :max_media_per_upload,
:non_username_paths, :photo_size_limit, :short_url_length, :short_url_length_https
alias short_uri_length short_url_length
alias short_uri_length_https short_url_length_https

# Returns an array of photo sizes
#
Expand Down
49 changes: 49 additions & 0 deletions lib/twitter/entity/uri.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
require 'twitter/entity'

module Twitter
class Entity
class URI < Twitter::Entity

# @return [URI]
def display_uri
@display_uri ||= ::URI.parse(@attrs[:display_url]) if display_uri?
end
alias display_url display_uri

# @return [Boolean]
def display_uri?
!!@attrs[:display_url]
end
alias display_url? display_uri?

# @return [URI]
def expanded_uri
@expanded_uri ||= ::URI.parse(@attrs[:expanded_url]) if expanded_uri?
end
alias expanded_url expanded_uri

# @return [Boolean]
def expanded_uri?
!!@attrs[:expanded_url]
end
alias expanded_url? expanded_uri?

# @return [URI]
def uri
@uri ||= ::URI.parse(@attrs[:url]) if uri?
end
alias url uri

# @return [Boolean]
def uri?
!!@attrs[:url]
end
alias url? uri?

end

Uri = URI
URL = URI
Url = URI
end
end
9 changes: 0 additions & 9 deletions lib/twitter/entity/url.rb

This file was deleted.

24 changes: 12 additions & 12 deletions lib/twitter/list.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,23 @@ class List < Twitter::Identity
:mode, :name, :slug, :subscriber_count
object_attr_reader :User, :user

# @return [String] The URL to the list members.
def members_url(protocol="https")
"#{protocol}://twitter.com/#{user.screen_name}/#{slug}/members"
# @return [URI] The URI to the list members.
def members_uri
@members_uri ||= ::URI.parse("https://twitter.com/#{user.screen_name}/#{slug}/members")
end
alias members_uri members_url
alias members_url members_uri

# @return [String] The URL to the list subscribers.
def subscribers_url(protocol="https")
"#{protocol}://twitter.com/#{user.screen_name}/#{slug}/subscribers"
# @return [URI] The URI to the list subscribers.
def subscribers_uri
@subscribers_uri ||= ::URI.parse("https://twitter.com/#{user.screen_name}/#{slug}/subscribers")
end
alias subscribers_uri subscribers_url
alias subscribers_url subscribers_uri

# @return [String] The URL to the list.
def url(protocol="https")
"#{protocol}://twitter.com/#{user.screen_name}/#{slug}"
# @return [URI] The URI to the list.
def uri
@uri ||= ::URI.parse("https://twitter.com/#{user.screen_name}/#{slug}")
end
alias uri url
alias url uri

end
end
Loading

0 comments on commit 341f68d

Please sign in to comment.