look-twitter-search 0.5.6 → 0.5.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.textile +16 -0
- data/README.markdown +30 -9
- data/Rakefile +2 -2
- data/lib/trends.rb +5 -17
- data/lib/tweets.rb +4 -16
- data/lib/twitter_search.rb +32 -27
- metadata +3 -2
data/CHANGELOG.textile
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
h2. 0.5.8 (June 30, 2009)
|
|
2
|
+
|
|
3
|
+
* subclass Tweets and Trends from Array. (Dan Croak)
|
|
4
|
+
* change test suite to use cURL'd JSON fixtures & Fakeweb for just HTTP calls
|
|
5
|
+
for more surgical tests. (Dan Croak)
|
|
6
|
+
|
|
7
|
+
h2. 0.5.7 (June 30, 2009)
|
|
8
|
+
|
|
9
|
+
* improved Fakeweb usage. (Matt Jankowski)
|
|
10
|
+
* account for possible 403 response, plus user-friendly message. (Matt Jankowski)
|
|
11
|
+
|
|
12
|
+
h2. 0.5.6 (June 6, 2009)
|
|
13
|
+
|
|
14
|
+
* When Twitter returns a 404, raise a TwitterSearch::SearchServerError instead
|
|
15
|
+
of a JSON parse error. (Luke Francl)
|
|
16
|
+
|
|
1
17
|
h2. 0.5.5 (May 18, 2009)
|
|
2
18
|
|
|
3
19
|
* raise error when query contains :near or :within:. (Dan Croak)
|
data/README.markdown
CHANGED
|
@@ -14,17 +14,17 @@ Require the gem.
|
|
|
14
14
|
|
|
15
15
|
Set up a TwitterSearch::Client. Name your client (a.k.a. 'user agent') to something meaningful, such as your app's name. This helps Twitter Search answer any questions about your use of the API.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
client = TwitterSearch::Client.new('thunderthimble')
|
|
18
18
|
|
|
19
19
|
### Search
|
|
20
20
|
|
|
21
21
|
Request tweets by calling the query method of your client. It takes either a String or a Hash of arguments.
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
tweets = client.query('twitter search')
|
|
24
24
|
|
|
25
25
|
The String form uses the default Twitter Search behavior, which in this example finds tweets containing both "twitter" and "search". It is identical to the more verbose, explicit version:
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
tweets = client.query(:q => 'twitter search')
|
|
28
28
|
|
|
29
29
|
Use the Twitter Search API's query operators with the :q key to access a variety of behavior.
|
|
30
30
|
|
|
@@ -32,11 +32,11 @@ Use the Twitter Search API's query operators with the :q key to access a variety
|
|
|
32
32
|
|
|
33
33
|
Request the current trending topics by calling the trends method of your client. It takes an optional Hash of arguments.
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
trends = client.trends
|
|
36
36
|
|
|
37
37
|
The only supported option currently is exclude_hashtags to return trends that are not hashtags only.
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
trends = client.trends(:exclude_hashtags => true)
|
|
40
40
|
|
|
41
41
|
## Search Operators
|
|
42
42
|
|
|
@@ -61,26 +61,47 @@ The following operator examples find tweets...
|
|
|
61
61
|
|
|
62
62
|
The Twitter Search API supports foreign languages, accessible via the :lang key. Use the [ISO 639-1](http://en.wikipedia.org/wiki/ISO_639-1) codes as the value:
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
tweets = client.query(:q => 'programmé', :lang => 'fr')
|
|
65
65
|
|
|
66
66
|
### Pagination
|
|
67
67
|
|
|
68
68
|
Alter the number of Tweets returned per page with the :rpp key. Stick with 10, 15, 20, 25, 30, or 50.
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
tweets = client.query(:q => 'Boston Celtics', :rpp => '30')
|
|
71
71
|
|
|
72
72
|
## Gotchas
|
|
73
73
|
|
|
74
74
|
* Searches are case-insenstive.
|
|
75
75
|
* The "near" operator available in the Twitter Search web interface is not available via the API. You must geocode before making your Twitter Search API call, and use the :geocode key in your request using the pattern lat,lngmi or lat,lngkm:
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
tweets = client.query(:q => 'Pearl Jam', :geocode => '43.4411,-70.9846mi')
|
|
78
78
|
|
|
79
79
|
* Searching for a positive attitude :) returns tweets containing the text :), =), :D, and :-)
|
|
80
80
|
|
|
81
|
+
## Contributing
|
|
82
|
+
|
|
83
|
+
Get the source and clone it.
|
|
84
|
+
|
|
85
|
+
The test suite uses JSON fixtures which were created from cURL. Usage example:
|
|
86
|
+
|
|
87
|
+
query = { :q => 'rails training' }
|
|
88
|
+
fake_query(query, 'rails_training.json')
|
|
89
|
+
@tweets = TwitterSearch::Client.new.query(query)
|
|
90
|
+
|
|
91
|
+
Then you assert any necessary expectations on @tweets.
|
|
92
|
+
|
|
93
|
+
To create your own JSON fixtures, first get the CGI escaped querystring in irb:
|
|
94
|
+
|
|
95
|
+
require 'lib/twitter_search'
|
|
96
|
+
TwitterSearch::Client.new.sanitize_query({ :q => 'rails training' })
|
|
97
|
+
|
|
98
|
+
Then take the output and append it to a simple cURL, sending the output into your new file:
|
|
99
|
+
|
|
100
|
+
curl -i 'http://search.twitter.com/search.json?q=rails+training' > test/json/rails_training.json
|
|
101
|
+
|
|
81
102
|
## Contributors
|
|
82
103
|
|
|
83
|
-
Dustin Sallings, Dan Croak, Luke Francl, Matt Sanford, Alejandro Crosa, Danny Burkes, Don Brown, & HotFusionMan.
|
|
104
|
+
Dustin Sallings, Dan Croak, Luke Francl, Matt Jankowski, Matt Sanford, Alejandro Crosa, Danny Burkes, Don Brown, & HotFusionMan.
|
|
84
105
|
|
|
85
106
|
## Resources
|
|
86
107
|
|
data/Rakefile
CHANGED
|
@@ -13,12 +13,12 @@ task :default => :test
|
|
|
13
13
|
|
|
14
14
|
gem_spec = Gem::Specification.new do |gem_spec|
|
|
15
15
|
gem_spec.name = "twitter-search"
|
|
16
|
-
gem_spec.version = "0.5.
|
|
16
|
+
gem_spec.version = "0.5.8"
|
|
17
17
|
gem_spec.summary = "Ruby client for Twitter Search. Includes trends."
|
|
18
18
|
gem_spec.email = "dcroak@thoughtbot.com"
|
|
19
19
|
gem_spec.homepage = "http://github.com/dancroak/twitter-search"
|
|
20
20
|
gem_spec.description = "Ruby client for Twitter Search."
|
|
21
|
-
gem_spec.authors = ["Dustin Sallings", "Dan Croak", "Luke Francl", "Matt Sanford", "Alejandro Crosa", "Danny Burkes", "Don Brown", "HotFusionMan"]
|
|
21
|
+
gem_spec.authors = ["Dustin Sallings", "Dan Croak", "Luke Francl", "Matt Jankowski", "Matt Sanford", "Alejandro Crosa", "Danny Burkes", "Don Brown", "HotFusionMan"]
|
|
22
22
|
gem_spec.files = FileList["[A-Z]*", "{lib,shoulda_macros}/**/*"]
|
|
23
23
|
gem_spec.add_dependency('json', '>= 1.1.2')
|
|
24
24
|
end
|
data/lib/trends.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
module TwitterSearch
|
|
2
2
|
class Trend
|
|
3
|
-
VARS = [
|
|
3
|
+
VARS = [:query, :name]
|
|
4
4
|
attr_reader *VARS
|
|
5
5
|
attr_reader :exclude_hashtags
|
|
6
6
|
|
|
@@ -10,27 +10,15 @@ module TwitterSearch
|
|
|
10
10
|
end
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
class Trends
|
|
13
|
+
class Trends < Array
|
|
14
14
|
VARS = [:date]
|
|
15
15
|
attr_reader *VARS
|
|
16
16
|
|
|
17
|
-
include Enumerable
|
|
18
|
-
|
|
19
17
|
def initialize(opts)
|
|
20
|
-
|
|
18
|
+
trends = opts('trends').delete
|
|
19
|
+
trends = trends.values.first.collect { |each| Trend.new(each) }
|
|
20
|
+
super(trends)
|
|
21
21
|
VARS.each { |each| instance_variable_set "@#{each}", opts[each.to_s] }
|
|
22
22
|
end
|
|
23
|
-
|
|
24
|
-
def each(&block)
|
|
25
|
-
@trends.each(&block)
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def size
|
|
29
|
-
@trends.size
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def [](index)
|
|
33
|
-
@trends[index]
|
|
34
|
-
end
|
|
35
23
|
end
|
|
36
24
|
end
|
data/lib/tweets.rb
CHANGED
|
@@ -10,29 +10,17 @@ module TwitterSearch
|
|
|
10
10
|
end
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
class Tweets
|
|
13
|
+
class Tweets < Array
|
|
14
14
|
VARS = [:since_id, :max_id, :results_per_page, :page, :query, :next_page]
|
|
15
15
|
attr_reader *VARS
|
|
16
16
|
|
|
17
|
-
include Enumerable
|
|
18
|
-
|
|
19
17
|
def initialize(opts)
|
|
20
|
-
|
|
18
|
+
results = opts.delete('results') || []
|
|
19
|
+
results.collect! { |each| Tweet.new(each) }
|
|
20
|
+
super(results)
|
|
21
21
|
VARS.each { |each| instance_variable_set "@#{each}", opts[each.to_s] }
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
-
def each(&block)
|
|
25
|
-
@results.each(&block)
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def size
|
|
29
|
-
@results.size
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def [](index)
|
|
33
|
-
@results[index]
|
|
34
|
-
end
|
|
35
|
-
|
|
36
24
|
def has_next_page?
|
|
37
25
|
! @next_page.nil?
|
|
38
26
|
end
|
data/lib/twitter_search.rb
CHANGED
|
@@ -21,7 +21,7 @@ module TwitterSearch
|
|
|
21
21
|
attr_accessor :timeout
|
|
22
22
|
|
|
23
23
|
def initialize(agent = 'twitter-search', timeout = DEFAULT_TIMEOUT)
|
|
24
|
-
@agent
|
|
24
|
+
@agent = agent
|
|
25
25
|
@timeout = timeout
|
|
26
26
|
end
|
|
27
27
|
|
|
@@ -43,14 +43,21 @@ module TwitterSearch
|
|
|
43
43
|
res = http.start { |http|
|
|
44
44
|
http.get("#{url.path}?#{url.query}", headers)
|
|
45
45
|
}
|
|
46
|
-
|
|
46
|
+
|
|
47
47
|
if res.code == '404'
|
|
48
|
-
raise TwitterSearch::SearchServerError,
|
|
48
|
+
raise TwitterSearch::SearchServerError,
|
|
49
|
+
"Twitter responded with a 404 for your query."
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
json = res.body
|
|
53
|
+
parsed_json = JSON.parse(json)
|
|
54
|
+
|
|
55
|
+
if parsed_json['error']
|
|
56
|
+
raise TwitterSearch::SearchServerError,
|
|
57
|
+
"Twitter responded with an error body: #{parsed_json['error']}"
|
|
49
58
|
end
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
Tweets.new JSON.parse(json)
|
|
59
|
+
|
|
60
|
+
Tweets.new parsed_json
|
|
54
61
|
end
|
|
55
62
|
|
|
56
63
|
def trends(opts = {})
|
|
@@ -66,33 +73,31 @@ module TwitterSearch
|
|
|
66
73
|
json = http.start { |http|
|
|
67
74
|
http.get("#{url.path}?#{url.query}", headers)
|
|
68
75
|
}.body
|
|
69
|
-
|
|
76
|
+
|
|
70
77
|
Trends.new JSON.parse(json)
|
|
71
78
|
end
|
|
72
79
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
elsif opts.is_a? Hash
|
|
79
|
-
"#{sanitize_query_hash(opts)}"
|
|
80
|
-
end
|
|
80
|
+
def sanitize_query(opts)
|
|
81
|
+
if opts.is_a? String
|
|
82
|
+
"q=#{CGI.escape(opts)}"
|
|
83
|
+
elsif opts.is_a? Hash
|
|
84
|
+
"#{sanitize_query_hash(opts)}"
|
|
81
85
|
end
|
|
86
|
+
end
|
|
82
87
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
+
def sanitize_query_hash(query_hash)
|
|
89
|
+
query_hash.collect { |key, value|
|
|
90
|
+
"#{CGI.escape(key.to_s)}=#{CGI.escape(value.to_s)}"
|
|
91
|
+
}.join('&')
|
|
92
|
+
end
|
|
88
93
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
end
|
|
94
|
+
def ensure_no_location_operators(query_string)
|
|
95
|
+
if query_string.include?("near%3A") ||
|
|
96
|
+
query_string.include?("within%3A")
|
|
97
|
+
raise TwitterSearch::SearchOperatorError,
|
|
98
|
+
"near: and within: are available from the Twitter Search web interface, but not the API. The API requires the geocode parameter. See dancroak/twitter-search README."
|
|
95
99
|
end
|
|
100
|
+
end
|
|
96
101
|
|
|
97
102
|
end
|
|
98
103
|
end
|
metadata
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: look-twitter-search
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.5.
|
|
4
|
+
version: 0.5.8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dustin Sallings
|
|
8
8
|
- Dan Croak
|
|
9
9
|
- Luke Francl
|
|
10
|
+
- Matt Jankowski
|
|
10
11
|
- Matt Sanford
|
|
11
12
|
- Alejandro Crosa
|
|
12
13
|
- Danny Burkes
|
|
@@ -16,7 +17,7 @@ autorequire:
|
|
|
16
17
|
bindir: bin
|
|
17
18
|
cert_chain: []
|
|
18
19
|
|
|
19
|
-
date: 2009-
|
|
20
|
+
date: 2009-06-29 21:00:00 -07:00
|
|
20
21
|
default_executable:
|
|
21
22
|
dependencies:
|
|
22
23
|
- !ruby/object:Gem::Dependency
|