paul-resourceful 0.5.4 → 0.6.0

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.
@@ -23,17 +23,31 @@ module Resourceful
23
23
  # Make an HTTP request using the standard library net/http.
24
24
  #
25
25
  # Will use a proxy defined in the http_proxy environment variable, if set.
26
- def self.make_request(method, uri, body = nil, header = nil)
26
+ #
27
+ # @param [#read] body
28
+ # An IO-ish thing containing the body of the request
29
+ #
30
+ def make_request(method, uri, body = nil, header = nil)
27
31
  uri = uri.is_a?(Addressable::URI) ? uri : Addressable::URI.parse(uri)
28
32
 
33
+ if [:put, :post].include? method
34
+ body = body ? body.read : ""
35
+ header[:content_length] = body.size
36
+ end
37
+
29
38
  req = net_http_request_class(method).new(uri.absolute_path)
30
39
  header.each_field { |k,v| req[k] = v } if header
31
40
  https = ("https" == uri.scheme)
32
- conn = Net::HTTP.Proxy(*proxy_details).new(uri.host, uri.port || (https ? 443 : 80))
41
+ conn_class = proxy_details ? Net::HTTP.Proxy(*proxy_details) : Net::HTTP
42
+ conn = conn_class.new(uri.host, uri.port || (https ? 443 : 80))
33
43
  conn.use_ssl = https
34
44
  begin
35
45
  conn.start
36
- res = conn.request(req, body)
46
+ res = if body
47
+ conn.request(req, body)
48
+ else
49
+ conn.request(req)
50
+ end
37
51
  ensure
38
52
  conn.finish if conn.started?
39
53
  end
@@ -49,12 +63,12 @@ module Resourceful
49
63
  private
50
64
 
51
65
  # Parse proxy details from http_proxy environment variable
52
- def self.proxy_details
66
+ def proxy_details
53
67
  proxy = Addressable::URI.parse(ENV["http_proxy"])
54
68
  [proxy.host, proxy.port, proxy.user, proxy.password] if proxy
55
69
  end
56
70
 
57
- def self.net_http_request_class(method)
71
+ def net_http_request_class(method)
58
72
  case method
59
73
  when :get then Net::HTTP::Get
60
74
  when :head then Net::HTTP::Head
@@ -0,0 +1,72 @@
1
+ module Resourceful
2
+ # Declarative way of interpreting options hashes
3
+ #
4
+ # include OptionsInterpretion
5
+ # def my_method(opts = {})
6
+ # extract_opts(opts) do |opts|
7
+ # host = opts.extract(:host)
8
+ # port = opts.extract(:port, :default => 80) {|p| Integer(p)}
9
+ # end
10
+ # end
11
+ #
12
+ module OptionsInterpretation
13
+ # Interpret an options hash
14
+ #
15
+ # @param [Hash] opts
16
+ # The options to interpret.
17
+ #
18
+ # @yield block that used to interpreter options hash
19
+ #
20
+ # @yieldparam [Resourceful::OptionsInterpretion::OptionsInterpreter] interpeter
21
+ # An interpreter that can be used to extract option information from the options hash.
22
+ def extract_opts(opts, &blk)
23
+ opts = opts.clone
24
+ yield OptionsInterpreter.new(opts)
25
+
26
+ unless opts.empty?
27
+ raise ArgumentError, "Unrecognized options: #{opts.keys.join(", ")}"
28
+ end
29
+
30
+ end
31
+
32
+ class OptionsInterpreter
33
+ def initialize(options_hash)
34
+ @options_hash = options_hash
35
+ end
36
+
37
+ # Extract a particular option.
38
+ #
39
+ # @param [String] name
40
+ # Name of option to extract
41
+ # @param [Hash] interpreter_opts
42
+ # ':default'
43
+ # :: The default value, or an object that responds to #call
44
+ # with the default value.
45
+ # ':required'
46
+ # :: Boolean indicating if this option is required. Default:
47
+ # false if a default is provided; otherwise true.
48
+ def extract(name, interpreter_opts = {}, &blk)
49
+ option_required = !interpreter_opts.has_key?(:default)
50
+ option_required = interpreter_opts[:required] if interpreter_opts.has_key?(:required)
51
+
52
+ raise ArgumentError, "Required option #{name} not provided" if option_required && !@options_hash.has_key?(name)
53
+ # We have the option we need
54
+
55
+ orig_val = @options_hash.delete(name)
56
+
57
+ if block_given?
58
+ yield orig_val
59
+
60
+ elsif orig_val
61
+ orig_val
62
+
63
+ elsif interpreter_opts[:default] && interpreter_opts[:default].respond_to?(:call)
64
+ interpreter_opts[:default].call()
65
+
66
+ elsif interpreter_opts[:default]
67
+ interpreter_opts[:default]
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -163,7 +163,7 @@ module Resourceful
163
163
  def perform!
164
164
  @request_time = Time.now
165
165
 
166
- http_resp = NetHttpAdapter.make_request(@method, @resource.uri, @body, @header)
166
+ http_resp = adapter.make_request(@method, @resource.uri, @body, @header)
167
167
  @response = Resourceful::Response.new(uri, *http_resp)
168
168
  @response.request_time = @request_time
169
169
  @response.authoritative = true
@@ -205,7 +205,7 @@ module Resourceful
205
205
 
206
206
  # Does this request force us to revalidate the cache?
207
207
  def forces_revalidation?
208
- if max_age == 0 || header.cache_control && cc.include?('no-cache')
208
+ if max_age == 0 || skip_cache?
209
209
  logger.info(" Client forced revalidation")
210
210
  true
211
211
  else
@@ -225,6 +225,10 @@ module Resourceful
225
225
  def logger
226
226
  resource.logger
227
227
  end
228
+
229
+ def adapter
230
+ accessor.http_adapter
231
+ end
228
232
  end
229
233
 
230
234
  end
@@ -5,7 +5,6 @@ module Resourceful
5
5
 
6
6
  class Resource
7
7
  attr_reader :accessor
8
- attr_accessor :default_header
9
8
 
10
9
  # Build a new resource for a uri
11
10
  #
@@ -30,6 +29,10 @@ module Resourceful
30
29
  end
31
30
  alias uri effective_uri
32
31
 
32
+ def default_header(temp_defaults = {})
33
+ @default_header.merge(temp_defaults)
34
+ end
35
+
33
36
  # Returns the host for this Resource's current uri
34
37
  def host
35
38
  Addressable::URI.parse(uri).host
@@ -95,7 +98,6 @@ module Resourceful
95
98
  # @raise [UnsuccessfulHttpRequestError] unless the request is a
96
99
  # success, ie the final request returned a 2xx response code
97
100
  def post(data = nil, header = {})
98
- check_content_type_exists(data, header)
99
101
  request(:post, data, header)
100
102
  end
101
103
 
@@ -116,7 +118,6 @@ module Resourceful
116
118
  # @raise [UnsuccessfulHttpRequestError] unless the request is a
117
119
  # success, ie the final request returned a 2xx response code
118
120
  def put(data, header = {})
119
- check_content_type_exists(data, header)
120
121
  request(:put, data, header)
121
122
  end
122
123
 
@@ -137,17 +138,32 @@ module Resourceful
137
138
  private
138
139
 
139
140
  # Ensures that the request has a content type header
140
- # TODO Move this to request
141
- def check_content_type_exists(body, header)
142
- if body
143
- raise MissingContentType unless header.has_key?(:content_type) or default_header.has_key?(:content_type)
141
+ def ensure_content_type(body, header)
142
+ return if header.has_key?('Content-Type')
143
+
144
+ if body.respond_to?(:content_type)
145
+ header['Content-Type'] = body.content_type
146
+ return
144
147
  end
148
+
149
+ return if default_header.has_key?('Content-Type')
150
+
151
+ # could not figure it out
152
+ raise MissingContentType
145
153
  end
146
154
 
147
155
  # Actually make the request
148
156
  def request(method, data, header)
149
- log_request_with_time "#{method.to_s.upcase} [#{uri}]" do
150
- request = Request.new(method, self, data, default_header.merge(header))
157
+ header = default_header.merge(header)
158
+ ensure_content_type(data, header) if data
159
+
160
+ data = StringIO.new(data) if data.kind_of?(String)
161
+
162
+ logger.debug { header.map {|k,v| "#{k}: #{v}"}.join("\n\t\t") }
163
+ logger.debug { data = StringIO.new(data.read); data.string } if data
164
+
165
+ log_request_with_time "#{method.to_s.upcase} [#{uri}]" do
166
+ request = Request.new(method, self, data, header)
151
167
  request.fetch_response
152
168
  end
153
169
  end
@@ -26,8 +26,8 @@ module Resourceful
26
26
  if header['Cache-Control'] and header['Cache-Control'].first.include?('max-age')
27
27
  max_age = header['Cache-Control'].first.split(',').grep(/max-age/).first.split('=').last.to_i
28
28
  return true if current_age > max_age
29
- elsif header['Expire']
30
- return true if Time.httpdate(header['Expire'].first) < Time.now
29
+ elsif header['Expires']
30
+ return true if Time.httpdate(header['Expires']) < Time.now
31
31
  end
32
32
 
33
33
  false
@@ -75,8 +75,8 @@ module Resourceful
75
75
 
76
76
  # Algorithm taken from RCF2616#13.2.3
77
77
  def current_age
78
- age_value = header['Age'] ? header['Age'].first.to_i : 0
79
- date_value = Time.httpdate(header['Date'].first)
78
+ age_value = header['Age'] || 0
79
+ date_value = Time.httpdate(header['Date'])
80
80
  now = Time.now
81
81
 
82
82
  apparent_age = [0, response_time - date_value].max
@@ -85,7 +85,7 @@ module Resourceful
85
85
  end
86
86
 
87
87
  def body
88
- encoding = header['Content-Encoding'] && header['Content-Encoding'].first
88
+ encoding = header['Content-Encoding']
89
89
  case encoding
90
90
  when nil
91
91
  # body is identity encoded; just return it
@@ -0,0 +1,17 @@
1
+ require 'resourceful/abstract_form_data'
2
+ require 'cgi'
3
+
4
+ module Resourceful
5
+ class UrlencodedFormData < AbstractFormData
6
+
7
+ def content_type
8
+ "application/x-www-form-urlencoded"
9
+ end
10
+
11
+ def read
12
+ @form_data.map do |k,v|
13
+ CGI.escape(k) + '=' + CGI.escape(v)
14
+ end.join('&')
15
+ end
16
+ end
17
+ end
data/lib/resourceful.rb CHANGED
@@ -10,9 +10,13 @@ require 'resourceful/util'
10
10
  require 'resourceful/header'
11
11
  require 'resourceful/http_accessor'
12
12
 
13
+ module Resourceful
14
+ autoload :MultipartFormData, 'resourceful/multipart_form_data'
15
+ autoload :UrlencodedFormData, 'resourceful/urlencoded_form_data'
16
+ end
17
+
13
18
  # Resourceful is a library that provides a high level HTTP interface.
14
19
  module Resourceful
15
- VERSION = "0.5.4"
20
+ VERSION = "0.6.0"
16
21
  RESOURCEFUL_USER_AGENT_TOKEN = "Resourceful/#{VERSION}(Ruby/#{RUBY_VERSION})"
17
-
18
22
  end
data/resourceful.gemspec CHANGED
@@ -2,20 +2,20 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{resourceful}
5
- s.version = "0.5.4"
5
+ s.version = "0.6.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Paul Sadauskas"]
9
- s.date = %q{2009-07-28}
9
+ s.date = %q{2009-08-14}
10
10
  s.description = %q{An HTTP library for Ruby that takes advantage of everything HTTP has to offer.}
11
11
  s.email = %q{psadauskas@gmail.com}
12
- s.extra_rdoc_files = ["lib/resourceful.rb", "lib/resourceful/net_http_adapter.rb", "lib/resourceful/stubbed_resource_proxy.rb", "lib/resourceful/header.rb", "lib/resourceful/memcache_cache_manager.rb", "lib/resourceful/response.rb", "lib/resourceful/util.rb", "lib/resourceful/options_interpreter.rb", "lib/resourceful/cache_manager.rb", "lib/resourceful/request.rb", "lib/resourceful/resource.rb", "lib/resourceful/exceptions.rb", "lib/resourceful/http_accessor.rb", "lib/resourceful/authentication_manager.rb", "README.markdown"]
13
- s.files = ["lib/resourceful.rb", "lib/resourceful/net_http_adapter.rb", "lib/resourceful/stubbed_resource_proxy.rb", "lib/resourceful/header.rb", "lib/resourceful/memcache_cache_manager.rb", "lib/resourceful/response.rb", "lib/resourceful/util.rb", "lib/resourceful/options_interpreter.rb", "lib/resourceful/cache_manager.rb", "lib/resourceful/request.rb", "lib/resourceful/resource.rb", "lib/resourceful/exceptions.rb", "lib/resourceful/http_accessor.rb", "lib/resourceful/authentication_manager.rb", "README.markdown", "MIT-LICENSE", "Rakefile", "Manifest", "spec/simple_sinatra_server_spec.rb", "spec/old_acceptance_specs.rb", "spec/acceptance_shared_specs.rb", "spec/spec_helper.rb", "spec/simple_sinatra_server.rb", "spec/acceptance/authorization_spec.rb", "spec/acceptance/header_spec.rb", "spec/acceptance/resource_spec.rb", "spec/acceptance/caching_spec.rb", "spec/acceptance/redirecting_spec.rb", "spec/spec.opts", "resourceful.gemspec"]
12
+ s.extra_rdoc_files = ["lib/resourceful.rb", "lib/resourceful/net_http_adapter.rb", "lib/resourceful/options_interpretation.rb", "lib/resourceful/stubbed_resource_proxy.rb", "lib/resourceful/urlencoded_form_data.rb", "lib/resourceful/header.rb", "lib/resourceful/memcache_cache_manager.rb", "lib/resourceful/response.rb", "lib/resourceful/util.rb", "lib/resourceful/abstract_form_data.rb", "lib/resourceful/cache_manager.rb", "lib/resourceful/request.rb", "lib/resourceful/resource.rb", "lib/resourceful/exceptions.rb", "lib/resourceful/multipart_form_data.rb", "lib/resourceful/http_accessor.rb", "lib/resourceful/authentication_manager.rb", "README.markdown"]
13
+ s.files = ["lib/resourceful.rb", "lib/resourceful/net_http_adapter.rb", "lib/resourceful/options_interpretation.rb", "lib/resourceful/stubbed_resource_proxy.rb", "lib/resourceful/urlencoded_form_data.rb", "lib/resourceful/header.rb", "lib/resourceful/memcache_cache_manager.rb", "lib/resourceful/response.rb", "lib/resourceful/util.rb", "lib/resourceful/abstract_form_data.rb", "lib/resourceful/cache_manager.rb", "lib/resourceful/request.rb", "lib/resourceful/resource.rb", "lib/resourceful/exceptions.rb", "lib/resourceful/multipart_form_data.rb", "lib/resourceful/http_accessor.rb", "lib/resourceful/authentication_manager.rb", "History.txt", "resourceful.gemspec", "README.markdown", "MIT-LICENSE", "Rakefile", "Manifest", "spec/simple_sinatra_server_spec.rb", "spec/old_acceptance_specs.rb", "spec/acceptance_shared_specs.rb", "spec/spec_helper.rb", "spec/simple_sinatra_server.rb", "spec/acceptance/authorization_spec.rb", "spec/acceptance/header_spec.rb", "spec/acceptance/resource_spec.rb", "spec/acceptance/caching_spec.rb", "spec/acceptance/redirecting_spec.rb", "spec/resourceful/multipart_form_data_spec.rb", "spec/resourceful/header_spec.rb", "spec/resourceful/resource_spec.rb", "spec/resourceful/urlencoded_form_data_spec.rb", "spec/caching_spec.rb", "spec/spec.opts"]
14
14
  s.homepage = %q{http://github.com/paul/resourceful}
15
15
  s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Resourceful", "--main", "README.markdown"]
16
16
  s.require_paths = ["lib"]
17
17
  s.rubyforge_project = %q{resourceful}
18
- s.rubygems_version = %q{1.3.3}
18
+ s.rubygems_version = %q{1.3.5}
19
19
  s.summary = %q{An HTTP library for Ruby that takes advantage of everything HTTP has to offer.}
20
20
 
21
21
  if s.respond_to? :specification_version then
@@ -23,14 +23,14 @@ Gem::Specification.new do |s|
23
23
  s.specification_version = 3
24
24
 
25
25
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
26
- s.add_runtime_dependency(%q<addressable>, [">= 0"])
26
+ s.add_runtime_dependency(%q<addressable>, [">= 2.1.0"])
27
27
  s.add_runtime_dependency(%q<httpauth>, [">= 0"])
28
28
  s.add_development_dependency(%q<thin>, [">= 0"])
29
29
  s.add_development_dependency(%q<yard>, [">= 0"])
30
30
  s.add_development_dependency(%q<sinatra>, [">= 0"])
31
31
  s.add_development_dependency(%q<rspec>, [">= 0"])
32
32
  else
33
- s.add_dependency(%q<addressable>, [">= 0"])
33
+ s.add_dependency(%q<addressable>, [">= 2.1.0"])
34
34
  s.add_dependency(%q<httpauth>, [">= 0"])
35
35
  s.add_dependency(%q<thin>, [">= 0"])
36
36
  s.add_dependency(%q<yard>, [">= 0"])
@@ -38,7 +38,7 @@ Gem::Specification.new do |s|
38
38
  s.add_dependency(%q<rspec>, [">= 0"])
39
39
  end
40
40
  else
41
- s.add_dependency(%q<addressable>, [">= 0"])
41
+ s.add_dependency(%q<addressable>, [">= 2.1.0"])
42
42
  s.add_dependency(%q<httpauth>, [">= 0"])
43
43
  s.add_dependency(%q<thin>, [">= 0"])
44
44
  s.add_dependency(%q<yard>, [">= 0"])
@@ -30,9 +30,7 @@ describe Resourceful do
30
30
  end
31
31
 
32
32
  def uri_for_code(code, params = {})
33
- template = Addressable::Template.new("http://localhost:3000/code/{code}")
34
- uri = template.expand("code" => code.to_s)
35
-
33
+ uri = Addressable::Template.new("http://localhost:42682/code/{code}").expand("code" => code.to_s)
36
34
  uri_plus_params(uri, params)
37
35
  end
38
36
 
@@ -106,7 +104,7 @@ describe Resourceful do
106
104
 
107
105
  it 'should revalidate the cached response if the response is expired' do
108
106
  in_the_past = (Time.now - 60).httpdate
109
- resource = @http.resource(uri_for_code(200, "Expire" => in_the_past))
107
+ resource = @http.resource(uri_for_code(200, "Expires" => in_the_past))
110
108
 
111
109
  resp = resource.get
112
110
  resp.should be_expired
@@ -121,7 +119,7 @@ describe Resourceful do
121
119
 
122
120
  it "should be authoritative if the response is directly from the server" do
123
121
  resource = @http.resource(
124
- uri_plus_params('http://localhost:3000/', "Cache-Control" => 'max-age=10')
122
+ uri_plus_params('http://localhost:42682/', "Cache-Control" => 'max-age=10')
125
123
  )
126
124
 
127
125
  response = resource.get
@@ -131,7 +129,7 @@ describe Resourceful do
131
129
  it "should be authoritative if a cached response was revalidated with the server" do
132
130
  now = Time.now.httpdate
133
131
  resource = @http.resource(
134
- uri_plus_params('http://localhost:3000/cached',
132
+ uri_plus_params('http://localhost:42682/cached',
135
133
  "modified" => now,
136
134
  "Cache-Control" => 'max-age=0')
137
135
  )
@@ -144,7 +142,7 @@ describe Resourceful do
144
142
  it "should not be authoritative if the cached response was not revalidated" do
145
143
  now = Time.now.httpdate
146
144
  resource = @http.resource(
147
- uri_plus_params('http://localhost:3000/cached',
145
+ uri_plus_params('http://localhost:42682/cached',
148
146
  "modified" => now,
149
147
  "Cache-Control" => 'max-age=10')
150
148
  )
@@ -162,7 +160,7 @@ describe Resourceful do
162
160
  now = Time.now.httpdate
163
161
 
164
162
  resource = @http.resource(
165
- uri_plus_params('http://localhost:3000/cached',
163
+ uri_plus_params('http://localhost:42682/cached',
166
164
  "modified" => now,
167
165
  "Cache-Control" => 'max-age=0')
168
166
  )
@@ -6,7 +6,7 @@ describe Resourceful do
6
6
  describe 'setting headers' do
7
7
  before do
8
8
  @http = Resourceful::HttpAccessor.new
9
- @resource = @http.resource("http://localhost:3000/header")
9
+ @resource = @http.resource("http://localhost:42682/header")
10
10
  end
11
11
 
12
12
  it 'should handle "Content-Type"' do
@@ -7,12 +7,12 @@ describe Resourceful do
7
7
  describe "working with a resource" do
8
8
  before do
9
9
  @http = Resourceful::HttpAccessor.new
10
- @resource = @http.resource('http://localhost:3000/')
10
+ @resource = @http.resource('http://localhost:42682/')
11
11
  end
12
12
 
13
13
  it 'should make the original uri available' do
14
- @resource.effective_uri.should == 'http://localhost:3000/'
15
- @resource.uri.should == 'http://localhost:3000/'
14
+ @resource.effective_uri.should == 'http://localhost:42682/'
15
+ @resource.uri.should == 'http://localhost:42682/'
16
16
  end
17
17
 
18
18
  it 'should set the user agent string on the default header' do
@@ -0,0 +1,89 @@
1
+
2
+ require 'rubygems'
3
+ require 'fakeweb'
4
+
5
+ $LOAD_PATH << File.join(File.dirname(__FILE__), "..", "lib")
6
+ require 'resourceful'
7
+
8
+ describe "Caching" do
9
+
10
+ before do
11
+ FakeWeb.allow_net_connect = false
12
+ FakeWeb.clean_registry
13
+
14
+ @http = Resourceful::HttpAccessor.new(:cache_manager => Resourceful::InMemoryCacheManager.new)
15
+ if ENV['SPEC_LOGGING']
16
+ @http.logger = Resourceful::StdOutLogger.new
17
+ end
18
+ end
19
+
20
+ describe "should cache" do
21
+
22
+ before do
23
+ FakeWeb.register_uri(:get, "http://example.com/cache",
24
+ [{:body => "Original response", :cache_control => "private,max-age=15"},
25
+ {:body => "Overrode cached response"}]
26
+ )
27
+
28
+ @resource = @http.resource("http://example.com/cache")
29
+ end
30
+
31
+ it "should cache the response" do
32
+ resp = @resource.get
33
+ resp.body.should == "Original response"
34
+
35
+ resp = @resource.get
36
+ resp.body.should == "Original response"
37
+ end
38
+
39
+ end
40
+
41
+ describe "updating headers" do
42
+ before do
43
+ FakeWeb.register_uri(:get, "http://example.com/override",
44
+ [{:body => "Original response", :cache_control => "private,max-age=0", :x_updateme => "foo"},
45
+ {:body => "Overrode cached response", :status => 304, :x_updateme => "bar"} ]
46
+ )
47
+
48
+ @resource = @http.resource("http://example.com/override")
49
+ end
50
+
51
+ it "should update headers from the 304" do
52
+ resp = @resource.get
53
+ resp.headers['X-Updateme'].should == ["foo"]
54
+
55
+ resp = @resource.get
56
+ resp.headers['X-Updateme'].should == ["bar"]
57
+ resp.headers['Cache-Control'].should == ["private,max-age=0"]
58
+ end
59
+
60
+ end
61
+
62
+ describe "updating expiration" do
63
+ before do
64
+ FakeWeb.register_uri(:get, "http://example.com/timeout",
65
+ [{:body => "Original response", :cache_control => "private,max-age=1"},
66
+ {:body => "cached response", :cache_control => "private,max-age=1"}]
67
+ )
68
+
69
+ @resource = @http.resource("http://example.com/timeout")
70
+ end
71
+
72
+ it "should refresh the expiration timer" do
73
+ resp = @resource.get
74
+ resp.should_not be_stale
75
+
76
+ sleep 2
77
+
78
+ resp.should be_stale
79
+
80
+ resp = @resource.get
81
+ resp.should_not be_stale
82
+
83
+ resp = @resource.get
84
+ end
85
+
86
+ end
87
+
88
+
89
+ end
@@ -0,0 +1,8 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper.rb"
2
+
3
+
4
+ describe Resourceful::Header do
5
+ it "should have constants for header names" do
6
+ Resourceful::Header::CONTENT_TYPE.should == 'Content-Type'
7
+ end
8
+ end
@@ -0,0 +1,77 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+ require 'tempfile'
3
+ require "resourceful/multipart_form_data.rb"
4
+
5
+ describe Resourceful::MultipartFormData do
6
+
7
+ before do
8
+ @form_data = Resourceful::MultipartFormData.new
9
+ end
10
+
11
+ it "should know its content-type" do
12
+ @form_data.content_type.should match(/^multipart\/form-data/i)
13
+ end
14
+
15
+ it "should know its boundary string" do
16
+ @form_data.content_type.should match(/; boundary=[0-9A-Za-z]{10,}/i)
17
+ end
18
+
19
+
20
+ describe "with simple parameters" do
21
+
22
+ it "should all simple parameters to be added" do
23
+ @form_data.add(:foo, "testing")
24
+ end
25
+
26
+ it "should render a multipart form-data document when #read is called" do
27
+ @form_data.add('foo', 'bar')
28
+ @form_data.add('baz', 'this')
29
+
30
+ boundary = /boundary=(\w+)/.match(@form_data.content_type)[1]
31
+ @form_data.read.should eql(<<MPFD[0..-2])
32
+ --#{boundary}\r
33
+ Content-Disposition: form-data; name="foo"\r
34
+ \r
35
+ bar\r
36
+ --#{boundary}\r
37
+ Content-Disposition: form-data; name="baz"\r
38
+ \r
39
+ this\r
40
+ --#{boundary}--
41
+ MPFD
42
+
43
+ end
44
+
45
+ describe "with file parameter" do
46
+ it "should add file parameters to be added" do
47
+ Tempfile.open('resourceful-post-file-tests') do |file_to_upload|
48
+ file_to_upload << "This is a test"
49
+ file_to_upload.flush
50
+
51
+ @form_data.add_file(:foo, file_to_upload.path)
52
+ end
53
+ end
54
+
55
+ it "should render a multipart form-data document when #read is called" do
56
+ Tempfile.open('resourceful-post-file-tests') do |file_to_upload|
57
+ file_to_upload << "This is a test"
58
+ file_to_upload.flush
59
+
60
+ @form_data.add_file(:foo, file_to_upload.path)
61
+
62
+ boundary = /boundary=(\w+)/.match(@form_data.content_type)[1]
63
+ @form_data.read.should eql(<<MPFD[0..-2])
64
+ --#{boundary}\r
65
+ Content-Disposition: form-data; name="foo"; filename="#{File.basename(file_to_upload.path)}"\r
66
+ Content-Type: application/octet-stream\r
67
+ \r
68
+ This is a test\r
69
+ --#{boundary}--
70
+ MPFD
71
+
72
+ end
73
+
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,20 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ module Resourceful
4
+ describe Resource do
5
+ before do
6
+ @http_adapter = stub(:http_adapter)
7
+ http = Resourceful::HttpAccessor.new(:http_adapter => @http_adapter)
8
+ @resource = http.resource('http://foo.example')
9
+ end
10
+
11
+ describe "POSTing" do
12
+ it "should use bodies content type as the request content-type if it is known" do
13
+ @http_adapter.should_receive(:make_request).with(anything, anything, anything, hash_including('Content-Type' => 'application/x-special-type')).and_return([200, {}, ""])
14
+ body = stub(:body, :content_type => 'application/x-special-type', :read => "hello there")
15
+ @resource.post(body)
16
+ end
17
+ end
18
+
19
+ end
20
+ end