resourceful 0.2 → 0.2.1

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/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.