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 CHANGED
@@ -1,7 +1,8 @@
1
- grackle
2
- by Hayes Davis
3
- http://www.appozite.com
4
- http://hayesdavis.net
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
- *A method call ending in "?" will cause an HTTP GET to be executed
31
- *A method call ending in "!" will cause an HTTP POST to be executed
32
- *If a valid format such as .json, .xml, .rss or .atom is encounted, a get will be executed with that format
33
- *A format method can also include a ? or ! to determine GET or POST in that format respectively
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
- ===Search
63
- Search works the same as everything else but your queries get submitted to search.twitter.com
64
- client.search? :q=>'grackle' #http://search.twitter.com/search.json?q=grackle
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
- *All parameters are URL encoded as necessary.
68
- *If you use a File object as a parameter it will be POSTed to Twitter in a multipart request.
69
- *If you use a Time object as a parameter, .httpdate will be called on it and that value will be used
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 (which is mostly just an OpenStruct) of data. The attributes
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
- *json_pure
89
- *httpclient
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.1"
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-22}
10
- s.description = %q{Grackle is a library for the Twitter REST and Search API that aims to go with the flow.}
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>, [">= 2.1.4"])
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>, [">= 2.1.4"])
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>, [">= 2.1.4"])
36
+ s.add_dependency(%q<httpclient>, [">= 0"])
37
37
  s.add_dependency(%q<bones>, [">= 2.4.2"])
38
38
  end
39
- end
39
+ end
@@ -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 method
25
- @method ||= :get
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
- REST_API_DOMAIN = 'twitter.com'
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
- # :username - twitter username to authenticate with
51
- # :password - twitter password to authenticate with
52
- # :handlers - Hash of formats to Handler instances (e.g. {:json=>CustomJSONHandler.new})
53
- # :default_format - Symbol of format to use when no format is specified in an API call (e.g. :json)
54
- # :headers - Hash of string keys and values for headers to pass in the HTTP request to twitter
55
- # :ssl - true or false to turn SSL on or off. Default is off (i.e. http://)
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
- protected
96
- def rest_api_domain
97
- REST_API_DOMAIN
98
- end
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
- def search_api_domain
101
- SEARCH_API_DOMAIN
102
- end
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
- self.request << "/#{id}" if id
107
- self.request << ".#{format}"
108
- url = "#{scheme}://#{request_host}#{self.request.path}"
109
- req_info = self.request
110
- self.request = nil
111
- res = transport.request(
112
- req_info.method,url,:username=>self.username,:password=>self.password,:headers=>headers,:params=>params
113
- )
114
- fmt_handler = handler(format)
115
- unless res.status == 200
116
- handle_error_response(res,fmt_handler)
117
- else
118
- fmt_handler.decode_response(res.body)
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
@@ -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 +decode+ method which accepts the response body
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.1'
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.1
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-22 00:00:00 -07:00
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: 2.1.4
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 that aims to go with the flow.
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