hayesdavis-grackle 0.0.1 → 0.0.4
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/README.txt +29 -17
- data/grackle.gemspec +8 -8
- data/lib/grackle/client.rb +77 -60
- data/lib/grackle/handlers.rb +1 -1
- data/lib/grackle.rb +2 -2
- metadata +5 -5
data/README.txt
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
-
grackle
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
=grackle
|
2
|
+
by Hayes Davis
|
3
|
+
hayes@appozite.com
|
4
|
+
http://www.appozite.com
|
5
|
+
http://hayesdavis.net
|
5
6
|
|
6
7
|
== DESCRIPTION
|
7
8
|
Grackle is a lightweight Ruby wrapper around the Twitter REST and Search APIs. It's based on my experience using the
|
@@ -17,6 +18,7 @@ will potentially require, however, some modifications to your code that uses Gra
|
|
17
18
|
==USING GRACKLE
|
18
19
|
|
19
20
|
===Creating a Grackle::Client
|
21
|
+
|
20
22
|
require 'grackle'
|
21
23
|
client = Grackle::Client(:username=>'your_user',:password=>'yourpass')
|
22
24
|
|
@@ -27,10 +29,10 @@ Grackle uses a method syntax that corresponds to the Twitter API URLs with a few
|
|
27
29
|
a Twitter URL, that becomes a "." in a chained set of Grackle method calls. Each call in the method chain is used to build
|
28
30
|
Twitter URL path until a particular call is encountered which causes the request to be sent. Methods which will cause a
|
29
31
|
request to be execute include:
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
32
|
+
- A method call ending in "?" will cause an HTTP GET to be executed
|
33
|
+
- A method call ending in "!" will cause an HTTP POST to be executed
|
34
|
+
- If a valid format such as .json, .xml, .rss or .atom is encounted, a get will be executed with that format
|
35
|
+
- A format method can also include a ? or ! to determine GET or POST in that format respectively
|
34
36
|
|
35
37
|
===GETting Data
|
36
38
|
Invoking the API method "/users/show" in XML format for the Twitter user "some_user" looks like
|
@@ -59,17 +61,25 @@ Or, with JSON
|
|
59
61
|
Or, using the default format
|
60
62
|
client.statuses.update! :status=>'this status is from grackle' #POST to http://twitter.com/statuses/update.json
|
61
63
|
|
62
|
-
===
|
63
|
-
|
64
|
-
|
64
|
+
===Toggling APIs
|
65
|
+
By default, the Grackle::Client sends all requests to the Twitter REST API. If you want to send requests to the Twitter Search API, just
|
66
|
+
set Grackle::Client.api to :search. To toggle back, set it to be :rest. All requests made after setting this
|
67
|
+
attribute will go to that API.
|
68
|
+
|
69
|
+
If you want to make a specific request to one API and not change the Client's overall api setting beyond that request, you can use the
|
70
|
+
bracket syntax like so:
|
71
|
+
client[:search].trends.daily? :exclue=>'hashtags'
|
72
|
+
client[:rest].users.show? :id=>'hayesdavis'
|
73
|
+
|
74
|
+
Search and REST requests are all built using the same method chaining and termination conventions.
|
65
75
|
|
66
76
|
===Parameter handling
|
67
|
-
|
68
|
-
|
69
|
-
|
77
|
+
- All parameters are URL encoded as necessary.
|
78
|
+
- If you use a File object as a parameter it will be POSTed to Twitter in a multipart request.
|
79
|
+
- If you use a Time object as a parameter, .httpdate will be called on it and that value will be used
|
70
80
|
|
71
81
|
===Return Values
|
72
|
-
Regardless of the format used, Grackle returns a Grackle::TwitterStruct
|
82
|
+
Regardless of the format used, Grackle returns an OpenStruct (actually a Grackle::TwitterStruct) of data. The attributes
|
73
83
|
available on these structs correspond to the data returned by Twitter.
|
74
84
|
|
75
85
|
===Dealing with Errors
|
@@ -77,6 +87,8 @@ If the request to Twitter does not return a status code of 200, then a TwitterEr
|
|
77
87
|
the full request URI, the response status, the response body in text and a response object build by parsing the formatted error
|
78
88
|
returned by Twitter. It's a good idea to wrap your API calls with rescue clauses for Grackle::TwitterError.
|
79
89
|
|
90
|
+
If there is an unexpected connection error or Twitter returns data in the wrong format (which it can do), you'll still get a TwitterError.
|
91
|
+
|
80
92
|
===Formats
|
81
93
|
Twitter allows you to request data in particular formats. Grackle currently supports JSON and XML. The Grackle::Client has a
|
82
94
|
default_format you can specify. By default, the default_format is :json. If you don't include a named format in your method
|
@@ -85,8 +97,8 @@ chain as described above, but use a "?" or "!" then the Grackle::Client.default_
|
|
85
97
|
== REQUIREMENTS:
|
86
98
|
|
87
99
|
You'll need the following gems to use all features of Grackle:
|
88
|
-
|
89
|
-
|
100
|
+
- json_pure
|
101
|
+
- httpclient
|
90
102
|
|
91
103
|
== INSTALL:
|
92
104
|
|
data/grackle.gemspec
CHANGED
@@ -2,12 +2,12 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{grackle}
|
5
|
-
s.version = "0.0.
|
5
|
+
s.version = "0.0.4"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Hayes Davis"]
|
9
|
-
s.date = %q{2009-03-
|
10
|
-
s.description = %q{Grackle is a library for the Twitter REST and Search API
|
9
|
+
s.date = %q{2009-03-23}
|
10
|
+
s.description = %q{Grackle is a lightweight library for the Twitter REST and Search API.}
|
11
11
|
s.email = %q{hayes@appozite.com}
|
12
12
|
s.files = ["History.txt", "README.txt", "Rakefile", "bin/grackle", "grackle.gemspec", "lib/grackle.rb", "lib/grackle/client.rb", "lib/grackle/handlers.rb", "lib/grackle/transport.rb", "lib/grackle/utils.rb", "spec/grackle_spec.rb", "spec/spec_helper.rb", "test/test_grackle.rb"]
|
13
13
|
s.has_rdoc = true
|
@@ -16,7 +16,7 @@ Gem::Specification.new do |s|
|
|
16
16
|
s.require_paths = ["lib"]
|
17
17
|
s.rubyforge_project = %q{grackle}
|
18
18
|
s.rubygems_version = %q{1.3.1}
|
19
|
-
s.summary = %q{Grackle is a library for the Twitter REST and Search API}
|
19
|
+
s.summary = %q{Grackle is a library for the Twitter REST and Search API designed to not require a new release in the face Twitter API changes or errors.}
|
20
20
|
|
21
21
|
if s.respond_to? :specification_version then
|
22
22
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
@@ -24,16 +24,16 @@ Gem::Specification.new do |s|
|
|
24
24
|
|
25
25
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
26
26
|
s.add_runtime_dependency(%q<json>, [">= 0"])
|
27
|
-
s.add_runtime_dependency(%q<httpclient>, [">=
|
27
|
+
s.add_runtime_dependency(%q<httpclient>, [">= 0"])
|
28
28
|
s.add_development_dependency(%q<bones>, [">= 2.4.2"])
|
29
29
|
else
|
30
30
|
s.add_dependency(%q<json>, [">= 0"])
|
31
|
-
s.add_dependency(%q<httpclient>, [">=
|
31
|
+
s.add_dependency(%q<httpclient>, [">= 0"])
|
32
32
|
s.add_dependency(%q<bones>, [">= 2.4.2"])
|
33
33
|
end
|
34
34
|
else
|
35
35
|
s.add_dependency(%q<json>, [">= 0"])
|
36
|
-
s.add_dependency(%q<httpclient>, [">=
|
36
|
+
s.add_dependency(%q<httpclient>, [">= 0"])
|
37
37
|
s.add_dependency(%q<bones>, [">= 2.4.2"])
|
38
38
|
end
|
39
|
-
end
|
39
|
+
end
|
data/lib/grackle/client.rb
CHANGED
@@ -7,52 +7,65 @@ module Grackle
|
|
7
7
|
class TwitterError < StandardError
|
8
8
|
attr_accessor :method, :request_uri, :status, :response_body, :response_object
|
9
9
|
|
10
|
-
def initialize(method, request_uri, status, response_body)
|
10
|
+
def initialize(method, request_uri, status, response_body, msg=nil)
|
11
11
|
self.method = method
|
12
12
|
self.request_uri = request_uri
|
13
13
|
self.status = status
|
14
14
|
self.response_body = response_body
|
15
|
-
super("#{self.method} #{self.request_uri} => #{self.status}: #{self.response_body}")
|
15
|
+
super(msg||"#{self.method} #{self.request_uri} => #{self.status}: #{self.response_body}")
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
+
# The Client is the public interface to Grackle. You build Twitter API calls using method chains. See the README for details
|
20
|
+
# and new for information on valid options.
|
19
21
|
class Client
|
20
22
|
|
21
23
|
class Request
|
22
|
-
attr_accessor :path, :method
|
24
|
+
attr_accessor :path, :method, :api, :ssl
|
23
25
|
|
24
|
-
def
|
25
|
-
|
26
|
+
def initialize(api=:rest,ssl=true)
|
27
|
+
self.api = api
|
28
|
+
self.ssl = ssl
|
29
|
+
self.method = :get
|
30
|
+
self.path = ''
|
26
31
|
end
|
27
32
|
|
28
33
|
def <<(path)
|
29
34
|
self.path << path
|
30
35
|
end
|
31
36
|
|
32
|
-
def path
|
33
|
-
@path ||= ''
|
34
|
-
end
|
35
|
-
|
36
37
|
def path?
|
37
38
|
path.length > 0
|
38
39
|
end
|
40
|
+
|
41
|
+
def url
|
42
|
+
"#{scheme}://#{host}#{path}"
|
43
|
+
end
|
44
|
+
|
45
|
+
def host
|
46
|
+
APIS[api]
|
47
|
+
end
|
48
|
+
|
49
|
+
def scheme
|
50
|
+
ssl ? 'https' :'http'
|
51
|
+
end
|
39
52
|
end
|
40
53
|
|
41
54
|
VALID_METHODS = [:get,:post,:put,:delete]
|
42
55
|
VALID_FORMATS = [:json,:xml,:atom,:rss]
|
56
|
+
|
57
|
+
APIS = {:rest=>'twitter.com',:search=>'search.twitter.com'}
|
43
58
|
|
44
|
-
|
45
|
-
SEARCH_API_DOMAIN = 'search.twitter.com'
|
46
|
-
|
47
|
-
attr_accessor :username, :password, :handlers, :default_format, :headers, :ssl, :transport, :request
|
59
|
+
attr_accessor :username, :password, :handlers, :default_format, :headers, :ssl, :api, :transport, :request
|
48
60
|
|
49
61
|
# Arguments (all are optional):
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
#
|
62
|
+
# - :username - twitter username to authenticate with
|
63
|
+
# - :password - twitter password to authenticate with
|
64
|
+
# - :handlers - Hash of formats to Handler instances (e.g. {:json=>CustomJSONHandler.new})
|
65
|
+
# - :default_format - Symbol of format to use when no format is specified in an API call (e.g. :json, :xml)
|
66
|
+
# - :headers - Hash of string keys and values for headers to pass in the HTTP request to twitter
|
67
|
+
# - :ssl - true or false to turn SSL on or off. Default is off (i.e. http://)
|
68
|
+
# - :api - one of :rest or :search
|
56
69
|
def initialize(options={})
|
57
70
|
self.transport = Transport.new
|
58
71
|
self.username = options.delete(:username)
|
@@ -62,15 +75,10 @@ module Grackle
|
|
62
75
|
self.default_format = options[:default_format] || :json
|
63
76
|
self.headers = {'User-Agent'=>'Grackle/1.0'}.merge!(options[:headers]||{})
|
64
77
|
self.ssl = options[:ssl] == true
|
78
|
+
self.api = options[:api] || :rest
|
65
79
|
end
|
66
80
|
|
67
81
|
def method_missing(name,*args)
|
68
|
-
#Check for HTTP method and apply it to the request.
|
69
|
-
#Can use this for an explict HTTP method
|
70
|
-
if http_method_invocation?(name)
|
71
|
-
self.request.method = name
|
72
|
-
return self
|
73
|
-
end
|
74
82
|
#If method is a format name, execute using that format
|
75
83
|
if format_invocation?(name)
|
76
84
|
return call_with_format(name,*args)
|
@@ -92,35 +100,57 @@ module Grackle
|
|
92
100
|
self
|
93
101
|
end
|
94
102
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
103
|
+
# Used to toggle APIs for a particular request without setting the Client's default API
|
104
|
+
# client[:rest].users.show.hayesdavis?
|
105
|
+
def [](api_name)
|
106
|
+
request.api = api_name
|
107
|
+
self
|
108
|
+
end
|
99
109
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
110
|
+
#Clears any pending request built up by chained methods but not executed
|
111
|
+
def clear
|
112
|
+
self.request = nil
|
113
|
+
end
|
114
|
+
|
115
|
+
protected
|
104
116
|
def call_with_format(format,params={})
|
105
117
|
id = params.delete(:id)
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
118
|
+
request << "/#{id}" if id
|
119
|
+
request << ".#{format}"
|
120
|
+
res = send_request(params)
|
121
|
+
process_response(format,res)
|
122
|
+
ensure
|
123
|
+
clear
|
124
|
+
end
|
125
|
+
|
126
|
+
def send_request(params)
|
127
|
+
begin
|
128
|
+
transport.request(
|
129
|
+
request.method,request.url,:username=>self.username,:password=>self.password,:headers=>headers,:params=>params
|
130
|
+
)
|
131
|
+
rescue => e
|
132
|
+
puts e
|
133
|
+
raise TwitterError.new(request.method,request.url,nil,nil,"Unexpected failure making request: #{e}")
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def process_response(format,res)
|
138
|
+
fmt_handler = handler(format)
|
139
|
+
begin
|
140
|
+
unless res.status == 200
|
141
|
+
handle_error_response(res,fmt_handler)
|
142
|
+
else
|
143
|
+
fmt_handler.decode_response(res.body)
|
144
|
+
end
|
145
|
+
rescue TwitterError => e
|
146
|
+
raise e
|
147
|
+
rescue => e
|
148
|
+
raise TwitterError.new(res.method,res.request_uri,res.status,res.body,"Unable to decode response: #{e}")
|
119
149
|
end
|
120
150
|
end
|
121
151
|
|
122
152
|
def request
|
123
|
-
@request ||= Request.new
|
153
|
+
@request ||= Request.new(api,ssl)
|
124
154
|
end
|
125
155
|
|
126
156
|
def handler(format)
|
@@ -133,21 +163,8 @@ module Grackle
|
|
133
163
|
raise err
|
134
164
|
end
|
135
165
|
|
136
|
-
def http_method_invocation?(name)
|
137
|
-
!self.request.path? && VALID_METHODS.include?(name)
|
138
|
-
end
|
139
|
-
|
140
166
|
def format_invocation?(name)
|
141
167
|
self.request.path? && VALID_FORMATS.include?(name)
|
142
168
|
end
|
143
|
-
|
144
|
-
def request_host
|
145
|
-
self.request.path =~ /^\/search/ ? search_api_domain : rest_api_domain
|
146
|
-
end
|
147
|
-
|
148
|
-
def scheme
|
149
|
-
self.ssl ? 'https' :'http'
|
150
|
-
end
|
151
|
-
|
152
169
|
end
|
153
170
|
end
|
data/lib/grackle/handlers.rb
CHANGED
@@ -3,7 +3,7 @@ module Grackle
|
|
3
3
|
# This module contain handlers that know how to take a response body
|
4
4
|
# from Twitter and turn it into a TwitterStruct return value. Handlers are
|
5
5
|
# used by the Client to give back return values from API calls. A handler
|
6
|
-
# is intended to provide a +
|
6
|
+
# is intended to provide a +decode_response+ method which accepts the response body
|
7
7
|
# as a string.
|
8
8
|
module Handlers
|
9
9
|
|
data/lib/grackle.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Grackle
|
2
2
|
|
3
3
|
# :stopdoc:
|
4
|
-
VERSION = '0.0.
|
4
|
+
VERSION = '0.0.4'
|
5
5
|
LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
|
6
6
|
PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
|
7
7
|
# :startdoc:
|
@@ -24,4 +24,4 @@ require 'json'
|
|
24
24
|
require 'grackle/utils'
|
25
25
|
require 'grackle/transport'
|
26
26
|
require 'grackle/handlers'
|
27
|
-
require 'grackle/client'
|
27
|
+
require 'grackle/client'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hayesdavis-grackle
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hayes Davis
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-03-
|
12
|
+
date: 2009-03-23 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -30,7 +30,7 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: "0"
|
34
34
|
version:
|
35
35
|
- !ruby/object:Gem::Dependency
|
36
36
|
name: bones
|
@@ -42,7 +42,7 @@ dependencies:
|
|
42
42
|
- !ruby/object:Gem::Version
|
43
43
|
version: 2.4.2
|
44
44
|
version:
|
45
|
-
description: Grackle is a library for the Twitter REST and Search API
|
45
|
+
description: Grackle is a lightweight library for the Twitter REST and Search API.
|
46
46
|
email: hayes@appozite.com
|
47
47
|
executables: []
|
48
48
|
|
@@ -90,6 +90,6 @@ rubyforge_project: grackle
|
|
90
90
|
rubygems_version: 1.2.0
|
91
91
|
signing_key:
|
92
92
|
specification_version: 2
|
93
|
-
summary: Grackle is a library for the Twitter REST and Search API
|
93
|
+
summary: Grackle is a library for the Twitter REST and Search API designed to not require a new release in the face Twitter API changes or errors.
|
94
94
|
test_files: []
|
95
95
|
|