paul-resourceful 0.5.4 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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