resourceful 0.2 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -12,6 +12,7 @@ task :test => :spec
12
12
 
13
13
  desc "Verify Resourceful against it's specs"
14
14
  Spec::Rake::SpecTask.new(:spec) do |t|
15
+ t.spec_opts << '--options' << 'spec/spec.opts' if File.exists?('spec/spec.opts')
15
16
  t.libs << 'lib'
16
17
  t.pattern = 'spec/**/*_spec.rb'
17
18
  end
@@ -34,7 +35,7 @@ task :clean
34
35
  # Packaging & Installation
35
36
  ##############################################################################
36
37
 
37
- RESOURCEFUL_VERSION = "0.2"
38
+ RESOURCEFUL_VERSION = "0.2.1"
38
39
 
39
40
  windows = (PLATFORM =~ /win32|cygwin/) rescue nil
40
41
 
@@ -62,7 +63,6 @@ spec = Gem::Specification.new do |s|
62
63
  s.add_dependency "addressable"
63
64
  s.add_dependency "httpauth"
64
65
  s.add_dependency "rspec"
65
- s.add_dependency "thin"
66
66
  s.add_dependency "facets"
67
67
 
68
68
  s.required_ruby_version = ">= 1.8.6"
@@ -87,3 +87,7 @@ task :uninstall => :clean do
87
87
  sh %{#{SUDO} gem uninstall resourceful}
88
88
  end
89
89
 
90
+ desc "Update rubyforge documentation"
91
+ task :update_docs do
92
+ puts %x{rsync -aPz doc/* psadauskas@resourceful.rubyforge.org:/var/www/gforge-projects/resourceful/}
93
+ end
@@ -27,6 +27,15 @@ module Resourceful
27
27
  # The response to be stored.
28
28
  def store(request, response); end
29
29
 
30
+ # Invalidates a all cached entries for a uri.
31
+ #
32
+ # This is used, for example, to invalidate the cache for a resource
33
+ # that gets POSTed to.
34
+ #
35
+ # @param uri<String>
36
+ # The uri of the resource to be invalidated
37
+ def invalidate(uri); end
38
+
30
39
  # Selects the headers from the request named by the response's Vary header
31
40
  # http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.5.6
32
41
  #
@@ -37,7 +46,8 @@ module Resourceful
37
46
  def select_request_headers(request, response)
38
47
  header = Resourceful::Header.new
39
48
 
40
- response.header['Vary'].each do |name|
49
+ response.header['Vary'].first.split(',').each do |name|
50
+ name.strip!
41
51
  header[name] = request.header[name]
42
52
  end if response.header['Vary']
43
53
 
@@ -63,11 +73,11 @@ module Resourceful
63
73
  class InMemoryCacheManager < CacheManager
64
74
 
65
75
  def initialize
66
- @collection = Hash.new(CacheEntryCollection.new)
76
+ @collection = Hash.new{ |h,k| h[k] = CacheEntryCollection.new}
67
77
  end
68
78
 
69
79
  def lookup(request)
70
- entry = @collection[request.resource.uri][request]
80
+ entry = @collection[request.uri.to_s][request]
71
81
  response = entry.response if entry
72
82
  response.authoritative = false if response
73
83
 
@@ -81,7 +91,11 @@ module Resourceful
81
91
  select_request_headers(request, response),
82
92
  response)
83
93
 
84
- @collection[request.resource.uri][request] = entry
94
+ @collection[request.uri.to_s][request] = entry
95
+ end
96
+
97
+ def invalidate(uri)
98
+ @collection.delete(uri)
85
99
  end
86
100
 
87
101
  # The collection of all cached entries for a single resource (uri).
@@ -23,7 +23,7 @@ module Resourceful
23
23
  end
24
24
 
25
25
  def capitalize(k)
26
- k.to_s.downcase.gsub(/^.|[-_\s]./) { |x| x.upcase }
26
+ k.to_s.downcase.gsub(/^.|[-_\s]./) { |x| x.upcase }.gsub('_', '-')
27
27
  end
28
28
  end
29
29
  end
@@ -8,6 +8,22 @@ require 'resourceful/resource'
8
8
  require 'resourceful/stubbed_resource_proxy'
9
9
 
10
10
  module Resourceful
11
+ # This is an imitation Logger used when no real logger is
12
+ # registered. This allows most of the code to assume that there
13
+ # is always a logger available, which significantly improved the
14
+ # readability of the logging related code.
15
+ class BitBucketLogger
16
+ def warn(*args); end
17
+ def info(*args); end
18
+ def debug(*args); end
19
+ end
20
+
21
+ # This is the simplest logger. It just writes everything to STDOUT.
22
+ class StdOutLogger
23
+ def warn(*args); puts args; end
24
+ def info(*args); puts args; end
25
+ def debug(*args); puts args; end
26
+ end
11
27
 
12
28
  # This class provides a simple interface to the functionality
13
29
  # provided by the Resourceful library. Conceptually this object
@@ -15,16 +31,6 @@ module Resourceful
15
31
  class HttpAccessor
16
32
  RESOURCEFUL_USER_AGENT_TOKEN = "Resourceful/#{RESOURCEFUL_VERSION}(Ruby/#{RUBY_VERSION})"
17
33
 
18
- # This is an imitation Logger used when no real logger is
19
- # registered. This allows most of the code to assume that there
20
- # is always a logger available, which significantly improved the
21
- # readability of the logging related code.
22
- class BitBucketLogger
23
- def warn(*args); end
24
- def info(*args); end
25
- def debug(*args); end
26
- end
27
-
28
34
  # A logger object to which messages about the activities of this
29
35
  # object will be written. This should be an object that responds
30
36
  # to +#info(message)+ and +#debug(message)+.
@@ -38,7 +44,7 @@ module Resourceful
38
44
  attr_reader :user_agent_tokens
39
45
 
40
46
  INIT_OPTIONS = OptionsInterpreter.new do
41
- option(:logger, :default => BitBucketLogger.new)
47
+ option(:logger, :default => Resourceful::BitBucketLogger.new)
42
48
  option(:user_agent, :default => []) {|ua| [ua].flatten}
43
49
  option(:cache_manager, :default => NullCacheManager.new)
44
50
  end
@@ -8,8 +8,10 @@ require Pathname(__FILE__).dirname + 'header'
8
8
  module Addressable
9
9
  class URI
10
10
  def absolute_path
11
- absolute_path = self.path.to_s
11
+ absolute_path = ""
12
+ absolute_path << self.path.to_s
12
13
  absolute_path << "?#{self.query}" if self.query != nil
14
+ absolute_path << "##{self.fragment}" if self.fragment != nil
13
15
  return absolute_path
14
16
  end
15
17
  end
@@ -1,4 +1,5 @@
1
1
  require 'pathname'
2
+ require 'benchmark'
2
3
  require Pathname(__FILE__).dirname + 'response'
3
4
  require Pathname(__FILE__).dirname + 'net_http_adapter'
4
5
 
@@ -21,21 +22,9 @@ module Resourceful
21
22
  def response
22
23
  @request_time = Time.now
23
24
 
24
- cached_response = resource.accessor.cache_manager.lookup(self)
25
- return cached_response if cached_response and not cached_response.stale?
26
-
27
- set_validation_headers(cached_response) if cached_response and cached_response.stale?
28
-
29
25
  http_resp = NetHttpAdapter.make_request(@method, @resource.uri, @body, @header)
30
26
  response = Resourceful::Response.new(uri, *http_resp)
31
27
 
32
- if response.code == 304
33
- cached_response.header.merge(response.header)
34
- response = cached_response
35
- end
36
-
37
- resource.accessor.cache_manager.store(self, response)
38
-
39
28
  response.authoritative = true
40
29
  response
41
30
  end
@@ -58,6 +47,10 @@ module Resourceful
58
47
  def uri
59
48
  resource.uri
60
49
  end
50
+
51
+ def logger
52
+ resource.logger
53
+ end
61
54
 
62
55
  end
63
56
 
@@ -75,8 +75,10 @@ module Resourceful
75
75
  #
76
76
  # @raise [UnsuccessfulHttpRequestError] unless the request is a
77
77
  # success, ie the final request returned a 2xx response code
78
- def get
79
- do_read_request(:get)
78
+ def get(header = {})
79
+ log_request_with_time "GET [#{uri}]" do
80
+ do_read_request(:get, header)
81
+ end
80
82
  end
81
83
 
82
84
  # :call-seq:
@@ -98,7 +100,9 @@ module Resourceful
98
100
  def post(data = "", options = {})
99
101
  raise ArgumentError, ":content_type must be specified" unless options.has_key?(:content_type)
100
102
 
101
- do_write_request(:post, data, {'Content-Type' => options[:content_type]})
103
+ log_request_with_time "POST [#{uri}]" do
104
+ do_write_request(:post, data, options)
105
+ end
102
106
  end
103
107
 
104
108
  # :call-seq:
@@ -120,7 +124,9 @@ module Resourceful
120
124
  def put(data = "", options = {})
121
125
  raise ArgumentError, ":content_type must be specified" unless options.has_key?(:content_type)
122
126
 
123
- do_write_request(:put, data, {'Content-Type' => options[:content_type]})
127
+ log_request_with_time "PUT [#{uri}]" do
128
+ do_write_request(:put, data, options)
129
+ end
124
130
  end
125
131
 
126
132
  # Performs a DELETE on the resource, following redirects as neccessary.
@@ -129,8 +135,10 @@ module Resourceful
129
135
  #
130
136
  # @raise [UnsuccessfulHttpRequestError] unless the request is a
131
137
  # success, ie the final request returned a 2xx response code
132
- def delete
133
- do_write_request(:delete, {}, nil)
138
+ def delete(options = {})
139
+ log_request_with_time "DELETE [#{uri}]" do
140
+ do_write_request(:delete, {}, options)
141
+ end
134
142
  end
135
143
 
136
144
  # Performs a read request (HEAD, GET). Users should use the #get, etc methods instead.
@@ -144,32 +152,51 @@ module Resourceful
144
152
  # @raise [UnsuccessfulHttpRequestError] unless the request is a
145
153
  # success, ie the final request returned a 2xx response code
146
154
  #
147
- # --
148
- # @private
149
- def do_read_request(method)
150
- request = Resourceful::Request.new(method, self)
155
+ def do_read_request(method, header = {})
156
+ request = Resourceful::Request.new(method, self, nil, header)
151
157
  accessor.auth_manager.add_credentials(request)
152
158
 
159
+ cached_response = accessor.cache_manager.lookup(request)
160
+ if cached_response
161
+ logger.debug(" Retrieved from cache")
162
+ if not cached_response.stale?
163
+ # We're done!
164
+ return cached_response
165
+ else
166
+ logger.debug(" Cache entry is stale")
167
+ request.set_validation_headers(cached_response)
168
+ end
169
+ end
170
+
153
171
  response = request.response
154
172
 
173
+ if response.is_not_modified?
174
+ cached_response.header.merge(response.header)
175
+ response = cached_response
176
+ response.authoritative = true
177
+ end
178
+
155
179
  if response.is_redirect? and request.should_be_redirected?
156
180
  if response.is_permanent_redirect?
157
181
  @uris.unshift response.header['Location'].first
158
- response = do_read_request(method)
182
+ response = do_read_request(method, header)
159
183
  else
160
184
  redirected_resource = Resourceful::Resource.new(self.accessor, response.header['Location'].first)
161
- response = redirected_resource.do_read_request(method)
185
+ response = redirected_resource.do_read_request(method, header)
162
186
  end
163
187
  end
164
188
 
165
189
  if response.is_not_authorized? && !@already_tried_with_auth
166
190
  @already_tried_with_auth = true
167
191
  accessor.auth_manager.associate_auth_info(response)
168
- response = do_read_request(method)
192
+ logger.debug("Authentication Required. Retrying with auth info")
193
+ response = do_read_request(method, header)
169
194
  end
170
195
 
171
196
  raise UnsuccessfulHttpRequestError.new(request,response) unless response.is_success?
172
197
 
198
+ accessor.cache_manager.store(request, response) if response.is_success?
199
+
173
200
  return response
174
201
  end
175
202
 
@@ -186,31 +213,50 @@ module Resourceful
186
213
  #
187
214
  # @raise [UnsuccessfulHttpRequestError] unless the request is a
188
215
  # success, ie the final request returned a 2xx response code
189
- # --
190
- # @private
191
216
  def do_write_request(method, data = nil, header = {})
192
217
  request = Resourceful::Request.new(method, self, data, header)
193
218
  accessor.auth_manager.add_credentials(request)
194
219
 
195
220
  response = request.response
196
-
221
+
197
222
  if response.is_redirect? and request.should_be_redirected?
198
223
  if response.is_permanent_redirect?
199
224
  @uris.unshift response.header['Location'].first
200
225
  response = do_write_request(method, data, header)
201
226
  elsif response.code == 303 # see other, must use GET for new location
202
227
  redirected_resource = Resourceful::Resource.new(self.accessor, response.header['Location'].first)
203
- response = redirected_resource.do_read_request(:get)
228
+ response = redirected_resource.do_read_request(:get, header)
204
229
  else
205
230
  redirected_resource = Resourceful::Resource.new(self.accessor, response.header['Location'].first)
206
231
  response = redirected_resource.do_write_request(method, data, header)
207
232
  end
208
233
  end
209
234
 
235
+ if response.is_not_authorized? && !@already_tried_with_auth
236
+ @already_tried_with_auth = true
237
+ accessor.auth_manager.associate_auth_info(response)
238
+ logger.debug("Authentication Required. Retrying with auth info")
239
+ response = do_write_request(method, data, header)
240
+ end
241
+
210
242
  raise UnsuccessfulHttpRequestError.new(request,response) unless response.is_success?
243
+
244
+ accessor.cache_manager.invalidate(uri)
211
245
  return response
212
246
  end
213
247
 
248
+ def log_request_with_time(msg, indent = 2)
249
+ logger.info(" " * indent + msg)
250
+ result = nil
251
+ time = Benchmark.measure { result = yield }
252
+ logger.info(" " * indent + "-> Returned #{result.code} in %.4fs" % time.real)
253
+ result
254
+ end
255
+
256
+ def logger
257
+ accessor.logger
258
+ end
259
+
214
260
  end
215
261
 
216
262
  end
@@ -2,6 +2,7 @@ require 'net/http'
2
2
  require 'time'
3
3
  require 'rubygems'
4
4
  require 'facets/kernel/ergo'
5
+ require 'zlib'
5
6
 
6
7
  module Resourceful
7
8
  # Exception indicating that the server used a content coding scheme
@@ -23,35 +24,105 @@ module Resourceful
23
24
  @response_time = Time.now
24
25
  end
25
26
 
27
+ # Is the response code sucessful? True for only 2xx series
28
+ # response codes.
29
+ #
30
+ # @return true|false
26
31
  def is_success?
27
32
  @code.in? 200..299
28
33
  end
34
+ alias was_successful? is_success?
35
+
36
+ # Is the response the result of a server error? True for
37
+ # 5xx series response codes
38
+ #
39
+ # @return true|false
40
+ def is_server_error?
41
+ @code.in? 500..599
42
+ end
43
+ alias was_server_error? is_server_error?
44
+
45
+ # Is the response the result of a client error? True for
46
+ # 4xx series response codes
47
+ #
48
+ # @return true|false
49
+ def is_client_error?
50
+ @code.in? 400..499
51
+ end
52
+ alias was_client_error? is_client_error?
53
+
54
+ # Is the response the result of any kind of error? True for
55
+ # 4xx and 5xx series response codes
56
+ #
57
+ # @return true|false
58
+ def is_error?
59
+ is_server_error? || is_client_error?
60
+ end
61
+ alias was_error? is_error?
62
+
63
+ # Is the response not a success? True for
64
+ # 3xx, 4xx and 5xx series response codes
65
+ #
66
+ # @return true|false
67
+ def is_unsuccesful?
68
+ is_error? || is_redirect?
69
+ end
70
+ alias was_unsuccessful? is_unsuccesful?
29
71
 
72
+ # Is the response a redirect response code? True for
73
+ # 3xx codes that are redirects (301, 302, 303, 307)
74
+ #
75
+ # @return true|false
30
76
  def is_redirect?
31
77
  @code.in? REDIRECT_RESPONSE_CODES
32
78
  end
33
79
  alias was_redirect? is_redirect?
34
80
 
81
+ # Is the response a Permanent Redirect (301) ?
82
+ #
83
+ # @return true|false
35
84
  def is_permanent_redirect?
36
85
  @code == 301
37
86
  end
38
87
 
88
+ # Is the response a Temporary Redirect (anything but 301) ?
89
+ #
90
+ # @return true|false
39
91
  def is_temporary_redirect?
40
92
  is_redirect? and not is_permanent_redirect?
41
93
  end
42
94
 
95
+ # Is the response a client error of Not Authorized (401) ?
96
+ #
97
+ # @return true|false
43
98
  def is_not_authorized?
44
99
  @code == 401
45
100
  end
46
101
 
102
+ # Is the response not modified (304) ?
103
+ #
104
+ # @return true|false
105
+ def is_not_modified?
106
+ @code == 304
107
+ end
108
+
109
+ # Is this a cached response that has expired?
110
+ #
111
+ # @return true|false
47
112
  def expired?
48
113
  if header['Expire']
49
114
  return true if Time.httpdate(header['Expire'].first) < Time.now
50
115
  end
116
+ if header['Cache-Control'] and header['Cache-Control'].include?('max-age')
117
+ return true if current_age > max_age
118
+ end
51
119
 
52
120
  false
53
121
  end
54
122
 
123
+ # Is this a cached response that is stale?
124
+ #
125
+ # @return true|false
55
126
  def stale?
56
127
  return true if expired?
57
128
  if header['Cache-Control']
@@ -62,6 +133,9 @@ module Resourceful
62
133
  false
63
134
  end
64
135
 
136
+ # Is this response cachable?
137
+ #
138
+ # @return true|false
65
139
  def cachable?
66
140
  return false if header['Vary'] and header['Vary'].include?('*')
67
141
  return false if header['Cache-Control'] and header['Cache-Control'].include?('no-store')
@@ -86,7 +160,7 @@ module Resourceful
86
160
  # body is identity encoded; just return it
87
161
  @body
88
162
  when /^\s*gzip\s*$/i
89
- gz_in = Zlib::GzipReader.new(StringIO.new(@body, 'r'))
163
+ gz_in = ::Zlib::GzipReader.new(StringIO.new(@body, 'r'))
90
164
  @body = gz_in.read
91
165
  gz_in.close
92
166
  header.delete('Content-Encoding')
@@ -23,6 +23,14 @@ describe Resourceful do
23
23
  resp.header['Content-Type'].should == ['text/plain']
24
24
  end
25
25
 
26
+ it 'should set additional headers on the #get' do
27
+ resource = @accessor.resource('http://localhost:3000/echo_header')
28
+ resp = resource.get(:foo => :bar)
29
+ resp.should be_instance_of(Resourceful::Response)
30
+ resp.code.should == 200
31
+ resp.body.should =~ /"HTTP_FOO"=>"bar"/
32
+ end
33
+
26
34
  it 'should #post a resource, and return the response' do
27
35
  resource = @accessor.resource('http://localhost:3000/post')
28
36
  resp = resource.post('Hello world from POST', :content_type => 'text/plain')
@@ -191,6 +199,17 @@ describe Resourceful do
191
199
  resp2.should == resp
192
200
  end
193
201
 
202
+ it 'should not use a cached document for a resource that has been posted to' do
203
+ resource = @accessor.resource('http://localhost:3000/get')
204
+ resp = resource.get
205
+ resp.authoritative?.should be_true
206
+
207
+ resource.post("foo", :content_type => 'text/plain')
208
+
209
+ resp2 = resource.get
210
+ resp2.should_not == resp
211
+ end
212
+
194
213
  describe 'Cache-Control' do
195
214
 
196
215
  it 'should cache anything with "Cache-Control: public"' do
@@ -20,6 +20,10 @@ describe Resourceful::CacheManager do
20
20
  @cm.should respond_to(:store)
21
21
  end
22
22
 
23
+ it 'should have a invalidate method' do
24
+ @cm.should respond_to(:invalidate)
25
+ end
26
+
23
27
  describe '#select_request_headers' do
24
28
  before do
25
29
  @req_header = mock('header', :[] => nil)
@@ -35,7 +39,7 @@ describe Resourceful::CacheManager do
35
39
  end
36
40
 
37
41
  it 'should pull the values from the request that match keys in the vary header' do
38
- @resp_header.should_receive(:[]).with('Vary').twice.and_return(['foo', 'bar'])
42
+ @resp_header.should_receive(:[]).with('Vary').twice.and_return(['foo, bar'])
39
43
  @req_header.should_receive(:[]).with('foo').and_return('oof')
40
44
  @req_header.should_receive(:[]).with('bar').and_return('rab')
41
45
 
@@ -64,16 +68,16 @@ describe Resourceful::NullCacheManager do
64
68
  @ncm.should respond_to(:store)
65
69
 
66
70
  lambda { @ncm.store(:foo, :bar) }.should_not raise_error
67
-
68
71
  end
69
72
 
70
73
  end
71
74
 
72
75
  describe Resourceful::InMemoryCacheManager do
73
76
  before do
74
- @request = mock('request', :resource => mock('resource', :uri => 'uri'),
75
- :request_time => Time.utc(2008,5,22,15,00))
76
- @response = mock('response', :header => {})
77
+ @request = mock('request', :resource => mock('resource'),
78
+ :request_time => Time.utc(2008,5,22,15,00),
79
+ :uri => 'uri')
80
+ @response = mock('response', :header => {}, :cachable? => true)
77
81
 
78
82
  @entry = mock('cache entry', :response => @response, :valid_for? => true)
79
83
  Resourceful::InMemoryCacheManager::CacheEntry.stub!(:new).and_return(@entry)
@@ -98,10 +102,6 @@ describe Resourceful::InMemoryCacheManager do
98
102
  end
99
103
 
100
104
  describe 'saving' do
101
- before do
102
- @response.stub!(:cachable?).and_return(true)
103
- end
104
-
105
105
  it 'should make a new cache entry' do
106
106
  Resourceful::InMemoryCacheManager::CacheEntry.should_receive(:new).with(
107
107
  Time.utc(2008,5,22,15,00),
@@ -131,6 +131,15 @@ describe Resourceful::InMemoryCacheManager do
131
131
  end
132
132
  end
133
133
 
134
+ describe 'invalidating' do
135
+ it 'should remove an entry from the cache by uri' do
136
+ @imcm.store(@request, @response)
137
+ @imcm.invalidate('uri')
138
+ col = @imcm.instance_variable_get("@collection")
139
+ col.should_not have_key('uri')
140
+ end
141
+ end
142
+
134
143
  end
135
144
 
136
145
  describe Resourceful::InMemoryCacheManager::CacheEntryCollection do
@@ -23,7 +23,7 @@ describe Resourceful::Header do
23
23
 
24
24
  h.capitalize("foo").should == "Foo"
25
25
  h.capitalize("foo-bar").should == "Foo-Bar"
26
- h.capitalize("foo_bar").should == "Foo_Bar"
26
+ h.capitalize("foo_bar").should == "Foo-Bar"
27
27
  h.capitalize("foo bar").should == "Foo Bar"
28
28
  h.capitalize("foo-bar-quux").should == "Foo-Bar-Quux"
29
29
  h.capitalize("foo-bar-2quux").should == "Foo-Bar-2quux"
@@ -18,7 +18,7 @@ describe Resourceful::HttpAccessor, 'init' do
18
18
  it 'should provide logger object even when no logger is specified' do
19
19
  ha = Resourceful::HttpAccessor.new()
20
20
 
21
- ha.logger.should be_instance_of(Resourceful::HttpAccessor::BitBucketLogger)
21
+ ha.logger.should be_instance_of(Resourceful::BitBucketLogger)
22
22
  end
23
23
 
24
24
  it 'should raise arg error if unrecognized options are passed' do
@@ -87,4 +87,10 @@ describe Addressable::URI, '#absolute_path monkey patch' do
87
87
  uri.absolute_path.should == '/foo'
88
88
  end
89
89
 
90
+ it 'should not add the query parameter twice' do
91
+ uri = Addressable::URI.parse('http://localhost/foo?bar=baz')
92
+ uri.absolute_path.should == '/foo?bar=baz'
93
+ uri.absolute_path.should == '/foo?bar=baz'
94
+ end
95
+
90
96
  end
@@ -6,7 +6,7 @@ require 'addressable/uri'
6
6
  describe Resourceful::Request do
7
7
  before do
8
8
  @uri = Addressable::URI.parse('http://www.example.com')
9
- @resource = mock('resource')
9
+ @resource = mock('resource', :logger => Resourceful::BitBucketLogger.new)
10
10
  @resource.stub!(:uri).and_return(@uri)
11
11
 
12
12
  @request = Resourceful::Request.new(:get, @resource)
@@ -14,7 +14,7 @@ describe Resourceful::Request do
14
14
  @cachemgr = mock('cache_mgr')
15
15
  @cachemgr.stub!(:lookup).and_return(nil)
16
16
  @cachemgr.stub!(:store)
17
- @resource.stub!(:accessor).and_return(mock('accessor', :cache_manager => @cachemgr))
17
+ @resource.stub!(:accessor).and_return(mock('accessor', :cache_manager => @cachemgr, :logger => Resourceful::BitBucketLogger.new))
18
18
  end
19
19
 
20
20
  describe 'init' do
@@ -50,7 +50,7 @@ describe Resourceful::Request do
50
50
  @net_http_adapter_response = mock('net_http_adapter_response')
51
51
  Resourceful::NetHttpAdapter.stub!(:make_request).and_return(@net_http_adapter_response)
52
52
 
53
- @response = mock('response', :code => 200, :authoritative= => true)
53
+ @response = mock('response', :code => 200, :authoritative= => true, :was_unsuccessful? => false)
54
54
  Resourceful::Response.stub!(:new).and_return(@response)
55
55
  end
56
56
 
@@ -63,145 +63,13 @@ describe Resourceful::Request do
63
63
  end
64
64
 
65
65
  it 'should set the request_time to now' do
66
- now = mock('now')
66
+ now = Time.now
67
67
  Time.stub!(:now).and_return(now)
68
68
 
69
69
  @request.response
70
70
  @request.request_time.should == now
71
71
  end
72
72
 
73
- describe 'Caching' do
74
- before do
75
- @cached_response = mock('cached_response', :body => "", :authoritative= => true)
76
- @cached_response.stub!(:stale?).and_return(false)
77
-
78
- @cached_response_header = mock('header', :[] => nil, :has_key? => false)
79
- @cached_response.stub!(:header).and_return(@cached_response_header)
80
-
81
- @cachemgr.stub!(:lookup).and_return(@cached_response)
82
- end
83
-
84
- it 'should lookup the request in the cache' do
85
- @cachemgr.should_receive(:lookup).with(@request)
86
- @request.response
87
- end
88
-
89
- it 'should check if the cached response is stale' do
90
- @cached_response.should_receive(:stale?).and_return(false)
91
- @request.response
92
- end
93
-
94
- describe 'cached' do
95
-
96
- it 'should return the cached response if it was found and not stale' do
97
- @cached_response.stale?.should_not be_true
98
- @request.response.should == @cached_response
99
- end
100
-
101
- end
102
-
103
- describe 'cached but stale' do
104
- before do
105
- @cached_response.stub!(:stale?).and_return(true)
106
- end
107
-
108
- it 'should add the validation headers from the cached_response to it\'s header' do
109
- @request.should_receive(:set_validation_headers).with(@cached_response)
110
-
111
- @request.response
112
- end
113
-
114
- it 'should #get the uri from the NetHttpAdapter' do
115
- Resourceful::NetHttpAdapter.should_receive(:make_request).
116
- with(:get, @uri, nil, anything).and_return(@net_http_adapter_response)
117
- @request.response
118
- end
119
-
120
- it 'should create a Resourceful::Response object from the NetHttpAdapter response' do
121
- Resourceful::Response.should_receive(:new).with(@request.uri, @net_http_adapter_response).and_return(@response)
122
- @request.response
123
- end
124
-
125
- it 'should merge the response\'s headers with the cached response\'s if the response was a 304' do
126
- @response_header = mock('header')
127
- @response.stub!(:header).and_return(@response_header)
128
- @response.stub!(:code).and_return(304)
129
- @cached_response_header.should_receive(:merge).with(@response_header)
130
- @request.response
131
- end
132
-
133
- it 'should store the response in the cache manager' do
134
- @cachemgr.should_receive(:store).with(@request, @response)
135
- @request.response
136
- end
137
-
138
- end
139
-
140
- describe 'not cached' do
141
- before do
142
- @cachemgr.stub!(:lookup).and_return(nil)
143
- end
144
-
145
- it 'should #get the uri from the NetHttpAdapter' do
146
- Resourceful::NetHttpAdapter.should_receive(:make_request).
147
- with(:get, @uri, nil, anything).and_return(@net_http_adapter_response)
148
- @request.response
149
- end
150
-
151
- it 'should create a Resourceful::Response object from the NetHttpAdapter response' do
152
- Resourceful::Response.should_receive(:new).with(@request.uri, @net_http_adapter_response).and_return(@response)
153
- @request.response
154
- end
155
-
156
- it 'should store the response in the cache manager' do
157
- @cachemgr.should_receive(:store).with(@request, @response)
158
- @request.response
159
- end
160
-
161
- end
162
-
163
- describe '#set_validation_headers' do
164
- it 'should have an #set_validation_headers method' do
165
- @request.should respond_to(:set_validation_headers)
166
- end
167
-
168
- it 'should set If-None-Match to the cached response\'s ETag' do
169
- @cached_response_header.should_receive(:[]).with('ETag').and_return('some etag')
170
- @cached_response_header.should_receive(:has_key?).with('ETag').and_return(true)
171
- @request.set_validation_headers(@cached_response)
172
-
173
- @request.header['If-None-Match'].should == 'some etag'
174
- end
175
-
176
- it 'should not set If-None-Match if the cached response does not have an ETag' do
177
- @request.set_validation_headers(@cached_response)
178
- @request.header.should_not have_key('If-None-Match')
179
- end
180
-
181
- it 'should set If-Modified-Since to the cached response\'s Last-Modified' do
182
- @cached_response_header.should_receive(:[]).with('Last-Modified').and_return('some date')
183
- @cached_response_header.should_receive(:has_key?).with('Last-Modified').and_return(true)
184
- @request.set_validation_headers(@cached_response)
185
-
186
- @request.header['If-Modified-Since'].should == 'some date'
187
- end
188
-
189
- it 'should not set If-Modified-Since if the cached response does not have Last-Modified' do
190
- @request.set_validation_headers(@cached_response)
191
- @request.header.should_not have_key('If-Modified-Since')
192
- end
193
-
194
- it 'should add "Cache-Control: max-age=0" to the request when revalidating a response that has "Cache-Control: must-revalidate" set' do
195
- @cached_response_header.should_receive(:[]).with('Cache-Control').and_return(['must-revalidate'])
196
- @cached_response_header.should_receive(:has_key?).with('Cache-Control').and_return(true)
197
- @request.set_validation_headers(@cached_response)
198
-
199
- @request.header['Cache-Control'].should include('max-age=0')
200
- end
201
- end
202
-
203
- end
204
-
205
73
  end
206
74
 
207
75
  describe '#should_be_redirected?' do
@@ -209,7 +77,7 @@ describe Resourceful::Request do
209
77
  @net_http_adapter_response = mock('net_http_adapter_response')
210
78
  Resourceful::NetHttpAdapter.stub!(:make_request).and_return(@net_http_adapter_response)
211
79
 
212
- @response = mock('response', :code => 200, :authoritative= => true)
80
+ @response = mock('response', :code => 200, :authoritative= => true, :was_unsuccessful? => false)
213
81
  Resourceful::Response.stub!(:new).and_return(@response)
214
82
  end
215
83
 
@@ -257,5 +125,55 @@ describe Resourceful::Request do
257
125
  end
258
126
  end
259
127
 
128
+ describe '#set_validation_headers' do
129
+ before do
130
+ @cached_response = mock('cached_response')
131
+
132
+ @cached_response_header = mock('header', :[] => nil, :has_key? => false)
133
+ @cached_response.stub!(:header).and_return(@cached_response_header)
134
+
135
+ @cachemgr.stub!(:lookup).and_return(@cached_response)
136
+ end
137
+
138
+ it 'should have an #set_validation_headers method' do
139
+ @request.should respond_to(:set_validation_headers)
140
+ end
141
+
142
+ it 'should set If-None-Match to the cached response\'s ETag' do
143
+ @cached_response_header.should_receive(:[]).with('ETag').and_return('some etag')
144
+ @cached_response_header.should_receive(:has_key?).with('ETag').and_return(true)
145
+ @request.set_validation_headers(@cached_response)
146
+
147
+ @request.header['If-None-Match'].should == 'some etag'
148
+ end
149
+
150
+ it 'should not set If-None-Match if the cached response does not have an ETag' do
151
+ @request.set_validation_headers(@cached_response)
152
+ @request.header.should_not have_key('If-None-Match')
153
+ end
154
+
155
+ it 'should set If-Modified-Since to the cached response\'s Last-Modified' do
156
+ @cached_response_header.should_receive(:[]).with('Last-Modified').and_return('some date')
157
+ @cached_response_header.should_receive(:has_key?).with('Last-Modified').and_return(true)
158
+ @request.set_validation_headers(@cached_response)
159
+
160
+ @request.header['If-Modified-Since'].should == 'some date'
161
+ end
162
+
163
+ it 'should not set If-Modified-Since if the cached response does not have Last-Modified' do
164
+ @request.set_validation_headers(@cached_response)
165
+ @request.header.should_not have_key('If-Modified-Since')
166
+ end
167
+
168
+ it 'should add "Cache-Control: max-age=0" to the request when revalidating a response that has "Cache-Control: must-revalidate" set' do
169
+ @cached_response_header.should_receive(:[]).with('Cache-Control').and_return(['must-revalidate'])
170
+ @cached_response_header.should_receive(:has_key?).with('Cache-Control').and_return(true)
171
+ @request.set_validation_headers(@cached_response)
172
+
173
+ @request.header['Cache-Control'].should include('max-age=0')
174
+ end
175
+
176
+ end
177
+
260
178
  end
261
179
 
@@ -5,13 +5,23 @@ require 'resourceful/resource'
5
5
 
6
6
  describe Resourceful::Resource do
7
7
  before do
8
- @accessor = mock('http_accessor', :auth_manager => mock('authmgr', :add_credentials => nil))
8
+ @auth_manager = mock('auth_manager', :add_credentials => nil)
9
+ @cache_manager = mock('cache_manager', :lookup => nil, :store => nil, :invalidate => nil)
10
+ @logger = mock('logger', :debug => nil, :info => nil)
11
+ @accessor = mock('accessor', :auth_manager => @auth_manager,
12
+ :cache_manager => @cache_manager,
13
+ :logger => @logger)
14
+
9
15
  @uri = 'http://www.example.com/'
10
16
  @resource = Resourceful::Resource.new(@accessor, @uri)
11
17
 
12
- @response = mock('response', :code => 200, :is_redirect? => false, :is_not_authorized? => false, :is_success? => true)
18
+ @response = mock('response', :code => 200,
19
+ :is_redirect? => false,
20
+ :is_not_authorized? => false,
21
+ :is_success? => true,
22
+ :is_not_modified? => false)
13
23
 
14
- @request = mock('request', :response => @response, :should_be_redirected? => true)
24
+ @request = mock('request', :response => @response, :should_be_redirected? => true, :uri => @uri)
15
25
  Resourceful::Request.stub!(:new).and_return(@request)
16
26
  end
17
27
 
@@ -48,10 +58,15 @@ describe Resourceful::Resource do
48
58
  end
49
59
 
50
60
  it 'should make a new request object from the method' do
51
- Resourceful::Request.should_receive(:new).with(:some_method, @resource).and_return(@request)
61
+ Resourceful::Request.should_receive(:new).with(:some_method, @resource, nil, {}).and_return(@request)
52
62
  make_request
53
63
  end
54
64
 
65
+ it 'should set the header of the request from the header arg' do
66
+ Resourceful::Request.should_receive(:new).with(:some_method, @resource, nil, :foo => :bar).and_return(@request)
67
+ @resource.do_read_request(:some_method, :foo => :bar)
68
+ end
69
+
55
70
  describe 'non-success responses' do
56
71
  before do
57
72
  @uri = 'http://www.example.com/code/404'
@@ -63,6 +78,7 @@ describe Resourceful::Resource do
63
78
  :is_redirect? => false,
64
79
  :is_success? => false,
65
80
  :is_not_authorized? => false,
81
+ :is_not_modified? => false,
66
82
  :code => 404)
67
83
 
68
84
  @request.stub!(:response).and_return(@redirect_response, @response)
@@ -92,7 +108,8 @@ describe Resourceful::Resource do
92
108
  @redirect_response = mock('redirect_response',
93
109
  :header => {'Location' => [@redirected_uri]},
94
110
  :is_redirect? => true,
95
- :is_permanent_redirect? => true)
111
+ :is_permanent_redirect? => true,
112
+ :is_not_modified? => false)
96
113
 
97
114
  @request.stub!(:response).and_return(@redirect_response, @response)
98
115
 
@@ -182,17 +199,54 @@ describe Resourceful::Resource do
182
199
  end
183
200
 
184
201
  it 'should re-make the request only once if it was not authorized the first time' do
185
- Resourceful::Request.should_receive(:new).with(:some_method, @resource).twice.and_return(@request)
202
+ Resourceful::Request.should_receive(:new).with(:some_method, @resource, nil, {}).twice.and_return(@request)
186
203
  @response.stub!(:is_not_authorized?).and_return(true)
187
204
  make_request
188
205
  end
189
206
 
190
207
  end
191
208
 
209
+ describe 'with caching' do
210
+ before do
211
+ @cached_response = mock('cached response', :is_redirect? => false,
212
+ :is_not_authorized? => false,
213
+ :is_success? => true,
214
+ :stale? => false)
215
+ @cache_manager.stub!(:lookup).and_return(@cached_response)
216
+ end
217
+
218
+ it 'should lookup the request in the cache' do
219
+ @cache_manager.should_receive(:lookup).with(@request)
220
+ make_request
221
+ end
222
+
223
+ it 'should check if the cached response is stale' do
224
+ @cached_response.should_receive(:stale?).and_return(false)
225
+ make_request
226
+ end
227
+
228
+ describe 'in cache' do
229
+
230
+ end
231
+
232
+ describe 'in cache but stale' do
233
+
234
+ end
235
+
236
+ describe 'not in cache' do
237
+
238
+ end
239
+
240
+ end
241
+
192
242
  end
193
243
 
194
244
  describe '#do_write_request' do
195
245
 
246
+ def make_request
247
+ @resource.do_write_request(:some_method, "data", {})
248
+ end
249
+
196
250
  it 'should make a new request object from the method' do
197
251
  Resourceful::Request.should_receive(:new).with(:some_method, @resource, "data", anything).and_return(@request)
198
252
  @resource.do_write_request(:some_method, "data")
@@ -244,10 +298,6 @@ describe Resourceful::Resource do
244
298
 
245
299
  end
246
300
 
247
- def make_request
248
- @resource.do_write_request(:some_method, "data", {})
249
- end
250
-
251
301
  it 'should check if the response was a redirect' do
252
302
  @redirect_response.should_receive(:is_redirect?).and_return(true)
253
303
  make_request
@@ -311,15 +361,47 @@ describe Resourceful::Resource do
311
361
  end
312
362
 
313
363
  it 'should redirect to the new location with a GET request, regardless of the original method' do
314
- @new_resource.should_receive(:do_read_request).with(:get).and_return(@response)
364
+ @new_resource.should_receive(:do_read_request).with(:get, {}).and_return(@response)
315
365
  make_request
316
366
  end
317
367
  end
318
- end
319
368
 
369
+ end
320
370
 
321
371
  end # write with redirection
322
372
 
373
+ describe 'with authorization' do
374
+ before do
375
+ @authmgr = mock('auth_manager')
376
+ @authmgr.stub!(:add_credentials)
377
+ @authmgr.stub!(:associate_auth_info).and_return(true)
378
+
379
+ @accessor.stub!(:auth_manager).and_return(@authmgr)
380
+ end
381
+
382
+ it 'should attempt to add credentials to the request' do
383
+ @authmgr.should_receive(:add_credentials).with(@request)
384
+ make_request
385
+ end
386
+
387
+ it 'should check if the response was not authorized' do
388
+ @response.should_receive(:is_not_authorized?).and_return(false)
389
+ make_request
390
+ end
391
+
392
+ it 'should associate the auth info in the response if it was not authorized' do
393
+ @authmgr.should_receive(:associate_auth_info).with(@response).and_return(true)
394
+ @response.stub!(:is_not_authorized?).and_return(true)
395
+ make_request
396
+ end
397
+
398
+ it 'should re-make the request only once if it was not authorized the first time' do
399
+ Resourceful::Request.should_receive(:new).with(:some_method, @resource, "data", {}).twice.and_return(@request)
400
+ @response.stub!(:is_not_authorized?).and_return(true)
401
+ make_request
402
+ end
403
+ end
404
+
323
405
  end
324
406
 
325
407
  describe 'callback registration' do
@@ -352,7 +434,7 @@ describe Resourceful::Resource do
352
434
  end
353
435
 
354
436
  it 'should pass :get to the #do_read_request method' do
355
- @resource.should_receive(:do_read_request).with(:get)
437
+ @resource.should_receive(:do_read_request).with(:get, {}).and_return(@response)
356
438
  @resource.get
357
439
  end
358
440
 
@@ -374,17 +456,10 @@ describe Resourceful::Resource do
374
456
 
375
457
  end
376
458
 
377
- end
378
-
379
- describe Resourceful::Resource do
380
-
381
459
  describe "#post(body_data, :content_type => content-type)" do
382
460
  before do
383
- @auth_manager = mock('auth_manager', :add_credentials => nil)
384
- @cache_manager = mock('cache_manager', :lookup => nil, :store => nil)
385
- @accessor = mock('accessor', :auth_manager => @auth_manager, :cache_manager => @cache_manager)
386
461
  @resource = Resourceful::Resource.new(@accessor, 'http://foo.invalid/')
387
- @response = mock('response', :is_redirect? => false, :is_success? => true)
462
+ @response = mock('response', :is_redirect? => false, :is_success? => true, :is_not_authorized? => false, :code => 200)
388
463
  @request = mock('request', :response => @response)
389
464
  Resourceful::Request.stub!(:new).and_return(@request)
390
465
  end
@@ -397,7 +472,10 @@ describe Resourceful::Resource do
397
472
 
398
473
  it 'should put the content type in the header' do
399
474
  Resourceful::Request.should_receive(:new).
400
- with(anything,anything, anything, hash_including('Content-Type' =>'text/plain')).
475
+ with(anything,
476
+ anything,
477
+ anything,
478
+ hash_including(:content_type =>'text/plain')).
401
479
  and_return(@request)
402
480
 
403
481
  @resource.post("a body", :content_type => 'text/plain')
@@ -430,11 +508,8 @@ describe Resourceful::Resource do
430
508
 
431
509
  describe "#put(body_data, :content_type => content_type)" do
432
510
  before do
433
- @auth_manager = mock('auth_manager', :add_credentials => nil)
434
- @cache_manager = mock('cache_manager', :lookup => nil, :store => nil)
435
- @accessor = mock('accessor', :auth_manager => @auth_manager, :cache_manager => @cache_manager)
436
511
  @resource = Resourceful::Resource.new(@accessor, 'http://foo.invalid/')
437
- @response = mock('response', :is_redirect? => false, :is_success? => true)
512
+ @response = mock('response', :is_redirect? => false, :is_success? => true, :is_not_authorized? => false, :code => 200)
438
513
  @request = mock('request', :response => @response)
439
514
  Resourceful::Request.stub!(:new).and_return(@request)
440
515
  end
@@ -447,7 +522,10 @@ describe Resourceful::Resource do
447
522
 
448
523
  it 'should put the content type in the header' do
449
524
  Resourceful::Request.should_receive(:new).
450
- with(anything,anything, anything, hash_including('Content-Type' =>'text/plain')).
525
+ with(anything,
526
+ anything,
527
+ anything,
528
+ hash_including(:content_type =>'text/plain')).
451
529
  and_return(@request)
452
530
 
453
531
  @resource.put("a body", :content_type => 'text/plain')
@@ -58,6 +58,45 @@ describe Resourceful::Response do
58
58
  end
59
59
  end
60
60
 
61
+ describe '#is_unsuccesful?' do
62
+ it 'should be true for a 4xx series response code' do
63
+ Resourceful::Response.new(@uri, 404, {}, "").is_unsuccesful?.should == true
64
+ end
65
+
66
+ it 'should be true for a 5xx series response code' do
67
+ Resourceful::Response.new(@uri, 500, {}, "").is_unsuccesful?.should == true
68
+ end
69
+
70
+ it 'should be not true for a 2xx series response code' do
71
+ Resourceful::Response.new(@uri, 200, {}, "").is_unsuccesful?.should == false
72
+ end
73
+
74
+ it 'should be true for a 3xx series response code' do
75
+ Resourceful::Response.new(@uri, 302, {}, "").is_unsuccesful?.should == true
76
+ end
77
+ end
78
+
79
+ describe '#is_client_error?' do
80
+ it 'be true for a 4xx series response code' do
81
+ Resourceful::Response.new(@uri, 404, {}, "").is_client_error?.should == true
82
+ end
83
+
84
+ it 'be false for anything else' do
85
+ Resourceful::Response.new(@uri, 200, {}, "").is_client_error?.should == false
86
+ end
87
+ end
88
+
89
+ describe '#is_server_error?' do
90
+ it 'be true for a 5xx series response code' do
91
+ Resourceful::Response.new(@uri, 500, {}, "").is_server_error?.should == true
92
+ end
93
+
94
+ it 'be false for anything else' do
95
+ Resourceful::Response.new(@uri, 200, {}, "").is_server_error?.should == false
96
+ end
97
+ end
98
+
99
+
61
100
  it 'should know if it is a redirect' do
62
101
  Resourceful::Response.new(@uri, 301, {}, "").is_redirect?.should == true
63
102
  Resourceful::Response.new(@uri, 302, {}, "").is_redirect?.should == true
@@ -35,7 +35,7 @@ CodeResponder = lambda do |env|
35
35
  [ code, {'Content-Type' => 'text/plain', 'Content-Length' => body.join.size.to_s}, body ]
36
36
  end unless defined? CodeResponder
37
37
 
38
- # YAML-parses the quesy string (expected hash) and sets the header to that
38
+ # YAML-parses the query string (expected hash) and sets the header to that
39
39
  HeaderResponder = lambda do |env|
40
40
  header = YAML.load(URI.unescape(env['QUERY_STRING']))
41
41
  body = [header.inspect]
@@ -48,6 +48,18 @@ HeaderResponder = lambda do |env|
48
48
  [ 200, header, body ]
49
49
  end unless defined? HeaderResponder
50
50
 
51
+ # Echos the request header in the response body
52
+ EchoHeaderResponder = lambda do |env|
53
+ body = [env.inspect]
54
+
55
+ header = {
56
+ 'Content-Type' => 'text/plain',
57
+ 'Content-Length' => body.join.size.to_s
58
+ }
59
+
60
+ [ 200, header, body ]
61
+ end unless defined? EchoHeaderResponder
62
+
51
63
  # redirect. /redirect/{301|302}?{url}
52
64
  Redirector = lambda do |env|
53
65
  code = env['PATH_INFO'] =~ /([\d]+)/ ? Integer($1) : 404
@@ -114,7 +126,6 @@ describe 'simple http server', :shared => true do
114
126
  #setup a thin http server we can connect to
115
127
  require 'thin'
116
128
  require 'rack'
117
- require 'rack/lobster'
118
129
 
119
130
  app = Rack::Builder.new do |env|
120
131
  use Rack::ShowExceptions
@@ -128,6 +139,7 @@ describe 'simple http server', :shared => true do
128
139
  map( '/code' ){ run CodeResponder }
129
140
  map( '/redirect' ){ run Redirector }
130
141
  map( '/header' ){ run HeaderResponder }
142
+ map( '/echo_header' ){ run EchoHeaderResponder }
131
143
  map( '/modified' ){ run ModifiedResponder }
132
144
  map( '/auth' ){ run AuthorizationResponder }
133
145
  end
@@ -65,6 +65,14 @@ describe 'http server' do
65
65
  resp[1]['Expire'].first.should_not =~ /%/
66
66
  end
67
67
 
68
+ it 'should echo the request header in the response body' do
69
+ uri = URI.escape("http://localhost:3000/echo_header")
70
+
71
+ resp = Resourceful::NetHttpAdapter.make_request(:get, uri)
72
+
73
+ resp[2].should =~ /HTTP_HOST/
74
+ end
75
+
68
76
  describe '/modified' do
69
77
  it 'should be 200 if no I-M-S header' do
70
78
  uri = URI.escape("http://localhost:3000/modified?#{(Time.now + 3600).httpdate}")
data/spec/spec.opts ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --format progress
3
+
data/spec/spec_helper.rb CHANGED
@@ -4,8 +4,11 @@ require 'spec'
4
4
  require 'pp'
5
5
  require 'facets'
6
6
 
7
- $LOAD_PATH << Pathname(__FILE__).dirname + "../lib"
7
+ #$LOAD_PATH << Pathname(__FILE__).dirname + "../lib"
8
+ $LOAD_PATH << File.dirname(__FILE__) + "../lib"
8
9
  require 'resourceful/util'
10
+ require 'resourceful'
11
+ require 'resourceful/http_accessor'
9
12
 
10
13
  require Pathname(__FILE__).dirname + 'simple_http_server_shared_spec'
11
14
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: resourceful
3
3
  version: !ruby/object:Gem::Version
4
- version: "0.2"
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Sadauskas & Peter Williams
@@ -9,11 +9,12 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-06-30 00:00:00 -06:00
12
+ date: 2008-07-31 00:00:00 -06:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: addressable
17
+ type: :runtime
17
18
  version_requirement:
18
19
  version_requirements: !ruby/object:Gem::Requirement
19
20
  requirements:
@@ -23,6 +24,7 @@ dependencies:
23
24
  version:
24
25
  - !ruby/object:Gem::Dependency
25
26
  name: httpauth
27
+ type: :runtime
26
28
  version_requirement:
27
29
  version_requirements: !ruby/object:Gem::Requirement
28
30
  requirements:
@@ -32,15 +34,7 @@ dependencies:
32
34
  version:
33
35
  - !ruby/object:Gem::Dependency
34
36
  name: rspec
35
- version_requirement:
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: "0"
41
- version:
42
- - !ruby/object:Gem::Dependency
43
- name: thin
37
+ type: :runtime
44
38
  version_requirement:
45
39
  version_requirements: !ruby/object:Gem::Requirement
46
40
  requirements:
@@ -50,6 +44,7 @@ dependencies:
50
44
  version:
51
45
  - !ruby/object:Gem::Dependency
52
46
  name: facets
47
+ type: :runtime
53
48
  version_requirement:
54
49
  version_requirements: !ruby/object:Gem::Requirement
55
50
  requirements:
@@ -70,6 +65,7 @@ files:
70
65
  - README.markdown
71
66
  - Rakefile
72
67
  - spec/acceptance_shared_specs.rb
68
+ - spec/spec.opts
73
69
  - spec/acceptance_spec.rb
74
70
  - spec/simple_http_server_shared_spec_spec.rb
75
71
  - spec/spec_helper.rb
@@ -121,7 +117,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
121
117
  requirements: []
122
118
 
123
119
  rubyforge_project: resourceful
124
- rubygems_version: 1.1.1
120
+ rubygems_version: 1.2.0
125
121
  signing_key:
126
122
  specification_version: 2
127
123
  summary: Resourceful provides a convenient Ruby API for making HTTP requests.