[DRE-commits] r4441 - in branches/upstream: . librestclient-ruby librestclient-ruby/current librestclient-ruby/current/bin librestclient-ruby/current/lib librestclient-ruby/current/lib/restclient librestclient-ruby/current/lib/restclient/mixin librestclient-ruby/current/spec librestclient-ruby/current/spec/mixin
Lucas Nussbaum
lucas at alioth.debian.org
Sat Dec 12 16:52:10 UTC 2009
Author: lucas
Date: 2009-12-12 16:52:10 +0000 (Sat, 12 Dec 2009)
New Revision: 4441
Added:
branches/upstream/librestclient-ruby/
branches/upstream/librestclient-ruby/current/
branches/upstream/librestclient-ruby/current/.gitignore
branches/upstream/librestclient-ruby/current/README.rdoc
branches/upstream/librestclient-ruby/current/Rakefile
branches/upstream/librestclient-ruby/current/VERSION
branches/upstream/librestclient-ruby/current/bin/
branches/upstream/librestclient-ruby/current/bin/restclient
branches/upstream/librestclient-ruby/current/lib/
branches/upstream/librestclient-ruby/current/lib/rest_client.rb
branches/upstream/librestclient-ruby/current/lib/restclient.rb
branches/upstream/librestclient-ruby/current/lib/restclient/
branches/upstream/librestclient-ruby/current/lib/restclient/exceptions.rb
branches/upstream/librestclient-ruby/current/lib/restclient/mixin/
branches/upstream/librestclient-ruby/current/lib/restclient/mixin/response.rb
branches/upstream/librestclient-ruby/current/lib/restclient/net_http_ext.rb
branches/upstream/librestclient-ruby/current/lib/restclient/payload.rb
branches/upstream/librestclient-ruby/current/lib/restclient/raw_response.rb
branches/upstream/librestclient-ruby/current/lib/restclient/request.rb
branches/upstream/librestclient-ruby/current/lib/restclient/resource.rb
branches/upstream/librestclient-ruby/current/lib/restclient/response.rb
branches/upstream/librestclient-ruby/current/rest-client.gemspec
branches/upstream/librestclient-ruby/current/spec/
branches/upstream/librestclient-ruby/current/spec/base.rb
branches/upstream/librestclient-ruby/current/spec/exceptions_spec.rb
branches/upstream/librestclient-ruby/current/spec/master_shake.jpg
branches/upstream/librestclient-ruby/current/spec/mixin/
branches/upstream/librestclient-ruby/current/spec/mixin/response_spec.rb
branches/upstream/librestclient-ruby/current/spec/payload_spec.rb
branches/upstream/librestclient-ruby/current/spec/raw_response_spec.rb
branches/upstream/librestclient-ruby/current/spec/request_spec.rb
branches/upstream/librestclient-ruby/current/spec/resource_spec.rb
branches/upstream/librestclient-ruby/current/spec/response_spec.rb
branches/upstream/librestclient-ruby/current/spec/restclient_spec.rb
Log:
[svn-inject] Installing original source of librestclient-ruby
Added: branches/upstream/librestclient-ruby/current/.gitignore
===================================================================
--- branches/upstream/librestclient-ruby/current/.gitignore (rev 0)
+++ branches/upstream/librestclient-ruby/current/.gitignore 2009-12-12 16:52:10 UTC (rev 4441)
@@ -0,0 +1,2 @@
+rdoc
+pkg
Added: branches/upstream/librestclient-ruby/current/README.rdoc
===================================================================
--- branches/upstream/librestclient-ruby/current/README.rdoc (rev 0)
+++ branches/upstream/librestclient-ruby/current/README.rdoc 2009-12-12 16:52:10 UTC (rev 4441)
@@ -0,0 +1,104 @@
+= REST Client -- simple DSL for accessing REST resources
+
+A simple REST client for Ruby, inspired by the Sinatra's microframework style
+of specifying actions: get, put, post, delete.
+
+== Usage: Raw URL
+
+ require 'rest_client'
+
+ RestClient.get 'http://example.com/resource'
+ RestClient.get 'https://user:password@example.com/private/resource'
+
+ RestClient.post 'http://example.com/resource', :param1 => 'one', :nested => { :param2 => 'two' }
+
+ RestClient.delete 'http://example.com/resource'
+
+== Multipart
+
+Yeah, that's right! This does multipart sends for you!
+
+ RestClient.post '/data', :myfile => File.new("/path/to/image.jpg")
+
+This does two things for you:
+
+* Auto-detects that you have a File value sends it as multipart
+* Auto-detects the mime of the file and sets it in the HEAD of the payload for each entry
+
+If you are sending params that do not contain a File object but the payload needs to be multipart then:
+
+ RestClient.post '/data', :foo => 'bar', :multipart => true
+
+== Streaming downloads
+
+RestClient.get('http://some/resource/lotsofdata') do |res|
+ res.read_body do |chunk|
+ .. do something with chunk ..
+ end
+end
+
+See RestClient module docs for more details.
+
+== Usage: ActiveResource-Style
+
+ resource = RestClient::Resource.new 'http://example.com/resource'
+ resource.get
+
+ private_resource = RestClient::Resource.new 'https://example.com/private/resource', 'user', 'pass'
+ private_resource.put File.read('pic.jpg'), :content_type => 'image/jpg'
+
+See RestClient::Resource module docs for details.
+
+== Usage: Resource Nesting
+
+ site = RestClient::Resource.new('http://example.com')
+ site['posts/1/comments'].post 'Good article.', :content_type => 'text/plain'
+
+See RestClient::Resource docs for details.
+
+== Shell
+
+The restclient shell command gives an IRB session with RestClient already loaded:
+
+ $ restclient
+ >> RestClient.get 'http://example.com'
+
+Specify a URL argument for get/post/put/delete on that resource:
+
+ $ restclient http://example.com
+ >> put '/resource', 'data'
+
+Add a user and password for authenticated resources:
+
+ $ restclient https://example.com user pass
+ >> delete '/private/resource'
+
+Create ~/.restclient for named sessions:
+
+ sinatra:
+ url: http://localhost:4567
+ rack:
+ url: http://localhost:9292
+ private_site:
+ url: http://example.com
+ username: user
+ password: pass
+
+Then invoke:
+
+ $ restclient private_site
+
+== Meta
+
+Written by Adam Wiggins (adam at heroku dot com)
+
+Major modifications by Blake Mizerany
+
+Patches contributed by: Chris Anderson, Greg Borenstein, Ardekantur, Pedro Belo, Rafael Souza, Rick Olson, and Aman Gupta
+
+Released under the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+http://rest-client.heroku.com
+
+http://github.com/adamwiggins/rest-client
+
Added: branches/upstream/librestclient-ruby/current/Rakefile
===================================================================
--- branches/upstream/librestclient-ruby/current/Rakefile (rev 0)
+++ branches/upstream/librestclient-ruby/current/Rakefile 2009-12-12 16:52:10 UTC (rev 4441)
@@ -0,0 +1,57 @@
+require 'rake'
+
+require 'jeweler'
+
+Jeweler::Tasks.new do |s|
+ s.name = "rest-client"
+ s.description = "A simple REST client for Ruby, inspired by the Sinatra microframework style of specifying actions: get, put, post, delete."
+ s.summary = "Simple REST client for Ruby, inspired by microframework syntax for specifying actions."
+ s.author = "Adam Wiggins"
+ s.email = "adam at heroku.com"
+ s.homepage = "http://rest-client.heroku.com/"
+ s.rubyforge_project = "rest-client"
+ s.has_rdoc = true
+ s.files = FileList["[A-Z]*", "{bin,lib,spec}/**/*"]
+ s.executables = %w(restclient)
+end
+
+Jeweler::RubyforgeTasks.new
+
+############################
+
+require 'spec/rake/spectask'
+
+desc "Run all specs"
+Spec::Rake::SpecTask.new('spec') do |t|
+ t.spec_opts = ['--colour --format progress --loadby mtime --reverse']
+ t.spec_files = FileList['spec/*_spec.rb']
+end
+
+desc "Print specdocs"
+Spec::Rake::SpecTask.new(:doc) do |t|
+ t.spec_opts = ["--format", "specdoc", "--dry-run"]
+ t.spec_files = FileList['spec/*_spec.rb']
+end
+
+desc "Run all examples with RCov"
+Spec::Rake::SpecTask.new('rcov') do |t|
+ t.spec_files = FileList['spec/*_spec.rb']
+ t.rcov = true
+ t.rcov_opts = ['--exclude', 'examples']
+end
+
+task :default => :spec
+
+############################
+
+require 'rake/rdoctask'
+
+Rake::RDocTask.new do |t|
+ t.rdoc_dir = 'rdoc'
+ t.title = "rest-client, fetch RESTful resources effortlessly"
+ t.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
+ t.options << '--charset' << 'utf-8'
+ t.rdoc_files.include('README.rdoc')
+ t.rdoc_files.include('lib/*.rb')
+end
+
Added: branches/upstream/librestclient-ruby/current/VERSION
===================================================================
--- branches/upstream/librestclient-ruby/current/VERSION (rev 0)
+++ branches/upstream/librestclient-ruby/current/VERSION 2009-12-12 16:52:10 UTC (rev 4441)
@@ -0,0 +1 @@
+1.1.5
Added: branches/upstream/librestclient-ruby/current/bin/restclient
===================================================================
--- branches/upstream/librestclient-ruby/current/bin/restclient (rev 0)
+++ branches/upstream/librestclient-ruby/current/bin/restclient 2009-12-12 16:52:10 UTC (rev 4441)
@@ -0,0 +1,87 @@
+#!/usr/bin/env ruby
+
+$:.unshift File.dirname(__FILE__) + "/../lib"
+require 'restclient'
+
+require "yaml"
+
+def usage(why = nil)
+ puts "failed for reason: #{why}" if why
+ puts "usage: restclient [get|put|post|delete] url|name [username] [password]"
+ puts " The verb is optional, if you leave it off you'll get an interactive shell."
+ puts " put and post both take the input body on stdin."
+ exit(1)
+end
+
+if %w(get put post delete).include? ARGV.first
+ @verb = ARGV.shift
+else
+ @verb = nil
+end
+
+ at url = ARGV.shift || 'http://localhost:4567'
+
+config = YAML.load(File.read(ENV['HOME'] + "/.restclient")) rescue {}
+
+ at url, @username, @password = if c = config[@url]
+ [c['url'], c['username'], c['password']]
+else
+ [@url, *ARGV]
+end
+
+usage("invalid url '#{@url}") unless @url =~ /^https?/
+usage("too few args") unless ARGV.size < 3
+
+def r
+ @r ||= RestClient::Resource.new(@url, @username, @password)
+end
+
+r # force rc to load
+
+if @verb
+ begin
+ if %w(put post).include? @verb
+ puts r.send(@verb, STDIN.read)
+ else
+ puts r.send(@verb)
+ end
+ exit 0
+ rescue RestClient::Exception => e
+ puts e.response.body if e.respond_to? :response
+ raise
+ end
+end
+
+%w(get post put delete).each do |m|
+ eval <<-end_eval
+def #{m}(path, *args, &b)
+ r[path].#{m}(*args, &b)
+end
+ end_eval
+end
+
+def method_missing(s, *args, &b)
+ super unless r.respond_to?(s)
+ begin
+ r.send(s, *args, &b)
+ rescue RestClient::RequestFailed => e
+ print STDERR, e.response.body
+ raise e
+ end
+end
+
+require 'irb'
+require 'irb/completion'
+
+if File.exists? ".irbrc"
+ ENV['IRBRC'] = ".irbrc"
+end
+
+if File.exists?(rcfile = "~/.restclientrc")
+ load(rcfile)
+end
+
+ARGV.clear
+
+IRB.start
+exit!
Property changes on: branches/upstream/librestclient-ruby/current/bin/restclient
___________________________________________________________________
Added: svn:executable
+
Added: branches/upstream/librestclient-ruby/current/lib/rest_client.rb
===================================================================
--- branches/upstream/librestclient-ruby/current/lib/rest_client.rb (rev 0)
+++ branches/upstream/librestclient-ruby/current/lib/rest_client.rb 2009-12-12 16:52:10 UTC (rev 4441)
@@ -0,0 +1,2 @@
+# This file exists for backward compatbility with require 'rest_client'
+require File.dirname(__FILE__) + '/restclient'
Added: branches/upstream/librestclient-ruby/current/lib/restclient/exceptions.rb
===================================================================
--- branches/upstream/librestclient-ruby/current/lib/restclient/exceptions.rb (rev 0)
+++ branches/upstream/librestclient-ruby/current/lib/restclient/exceptions.rb 2009-12-12 16:52:10 UTC (rev 4441)
@@ -0,0 +1,88 @@
+module RestClient
+ # This is the base RestClient exception class. Rescue it if you want to
+ # catch any exception that your request might raise
+ class Exception < RuntimeError
+ def message(default=nil)
+ self.class::ErrorMessage
+ end
+ end
+
+ # Base RestClient exception when there's a response available
+ class ExceptionWithResponse < Exception
+ attr_accessor :response
+
+ def initialize(response=nil)
+ @response = response
+ end
+
+ def http_code
+ @response.code.to_i if @response
+ end
+
+ def http_body
+ RestClient::Request.decode(@response['content-encoding'], @response.body) if @response
+ end
+ end
+
+ # A redirect was encountered; caught by execute to retry with the new url.
+ class Redirect < Exception
+ ErrorMessage = "Redirect"
+
+ attr_accessor :url
+ def initialize(url)
+ @url = url
+ end
+ end
+
+ class NotModified < ExceptionWithResponse
+ ErrorMessage = 'NotModified'
+ end
+
+ # Authorization is required to access the resource specified.
+ class Unauthorized < ExceptionWithResponse
+ ErrorMessage = 'Unauthorized'
+ end
+
+ # No resource was found at the given URL.
+ class ResourceNotFound < ExceptionWithResponse
+ ErrorMessage = 'Resource not found'
+ end
+
+ # The server broke the connection prior to the request completing. Usually
+ # this means it crashed, or sometimes that your network connection was
+ # severed before it could complete.
+ class ServerBrokeConnection < Exception
+ ErrorMessage = 'Server broke connection'
+ end
+
+ # The server took too long to respond.
+ class RequestTimeout < Exception
+ ErrorMessage = 'Request timed out'
+ end
+
+ # The request failed, meaning the remote HTTP server returned a code other
+ # than success, unauthorized, or redirect.
+ #
+ # The exception message attempts to extract the error from the XML, using
+ # format returned by Rails: <errors><error>some message</error></errors>
+ #
+ # You can get the status code by e.http_code, or see anything about the
+ # response via e.response. For example, the entire result body (which is
+ # probably an HTML error page) is e.response.body.
+ class RequestFailed < ExceptionWithResponse
+ def message
+ "HTTP status code #{http_code}"
+ end
+
+ def to_s
+ message
+ end
+ end
+end
+
+# backwards compatibility
+class RestClient::Request
+ Redirect = RestClient::Redirect
+ Unauthorized = RestClient::Unauthorized
+ RequestFailed = RestClient::RequestFailed
+end
Added: branches/upstream/librestclient-ruby/current/lib/restclient/mixin/response.rb
===================================================================
--- branches/upstream/librestclient-ruby/current/lib/restclient/mixin/response.rb (rev 0)
+++ branches/upstream/librestclient-ruby/current/lib/restclient/mixin/response.rb 2009-12-12 16:52:10 UTC (rev 4441)
@@ -0,0 +1,43 @@
+module RestClient
+ module Mixin
+ module Response
+ attr_reader :net_http_res
+
+ # HTTP status code, always 200 since RestClient throws exceptions for
+ # other codes.
+ def code
+ @code ||= @net_http_res.code.to_i
+ end
+
+ # A hash of the headers, beautified with symbols and underscores.
+ # e.g. "Content-type" will become :content_type.
+ def headers
+ @headers ||= self.class.beautify_headers(@net_http_res.to_hash)
+ end
+
+ # Hash of cookies extracted from response headers
+ def cookies
+ @cookies ||= (self.headers[:set_cookie] || "").split('; ').inject({}) do |out, raw_c|
+ key, val = raw_c.split('=')
+ unless %w(expires domain path secure).member?(key)
+ out[key] = val
+ end
+ out
+ end
+ end
+
+ def self.included(receiver)
+ receiver.extend(RestClient::Mixin::Response::ClassMethods)
+ end
+
+ module ClassMethods
+ def beautify_headers(headers)
+ headers.inject({}) do |out, (key, value)|
+ out[key.gsub(/-/, '_').to_sym] = value.first
+ out
+ end
+ end
+ end
+ end
+ end
+end
Added: branches/upstream/librestclient-ruby/current/lib/restclient/net_http_ext.rb
===================================================================
--- branches/upstream/librestclient-ruby/current/lib/restclient/net_http_ext.rb (rev 0)
+++ branches/upstream/librestclient-ruby/current/lib/restclient/net_http_ext.rb 2009-12-12 16:52:10 UTC (rev 4441)
@@ -0,0 +1,21 @@
+#
+# Replace the request method in Net::HTTP to sniff the body type
+# and set the stream if appropriate
+#
+# Taken from:
+# http://www.missiondata.com/blog/ruby/29/streaming-data-to-s3-with-ruby/
+
+module Net
+ class HTTP
+ alias __request__ request
+
+ def request(req, body=nil, &block)
+ if body != nil && body.respond_to?(:read)
+ req.body_stream = body
+ return __request__(req, nil, &block)
+ else
+ return __request__(req, body, &block)
+ end
+ end
+ end
+end
Added: branches/upstream/librestclient-ruby/current/lib/restclient/payload.rb
===================================================================
--- branches/upstream/librestclient-ruby/current/lib/restclient/payload.rb (rev 0)
+++ branches/upstream/librestclient-ruby/current/lib/restclient/payload.rb 2009-12-12 16:52:10 UTC (rev 4441)
@@ -0,0 +1,206 @@
+require "tempfile"
+require "stringio"
+
+module RestClient
+ module Payload
+ extend self
+
+ def generate(params)
+ if params.is_a?(String)
+ Base.new(params)
+ elsif params
+ if params.delete(:multipart) == true || has_file?(params)
+ Multipart.new(params)
+ else
+ UrlEncoded.new(params)
+ end
+ else
+ nil
+ end
+ end
+
+ def has_file?(params)
+ params.any? do |_, v|
+ case v
+ when Hash
+ has_file?(v)
+ else
+ v.respond_to?(:path) && v.respond_to?(:read)
+ end
+ end
+ end
+
+ class Base
+ def initialize(params)
+ build_stream(params)
+ end
+
+ def build_stream(params)
+ @stream = StringIO.new(params)
+ @stream.seek(0)
+ end
+
+ def read(bytes=nil)
+ @stream.read(bytes)
+ end
+ alias :to_s :read
+
+ def escape(v)
+ URI.escape(v.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
+ end
+
+ def headers
+ { 'Content-Length' => size.to_s }
+ end
+
+ def size
+ @stream.size
+ end
+ alias :length :size
+
+ def close
+ @stream.close
+ end
+
+ def inspect
+ to_s.inspect
+ end
+ end
+
+ class UrlEncoded < Base
+ def build_stream(params)
+ @stream = StringIO.new(params.map do |k,v|
+ "#{escape(k)}=#{escape(v)}"
+ end.join("&"))
+ @stream.seek(0)
+ end
+
+ def headers
+ super.merge({ 'Content-Type' => 'application/x-www-form-urlencoded' })
+ end
+ end
+
+ class Multipart < Base
+ EOL = "\r\n"
+
+ def build_stream(params)
+ b = "--#{boundary}"
+
+ @stream = Tempfile.new("RESTClient.Stream.#{rand(1000)}")
+ @stream.write(b + EOL)
+ x = params.to_a
+ last_index = x.length - 1
+ x.each_with_index do |a, index|
+ k, v = *a
+ if v.respond_to?(:read) && v.respond_to?(:path)
+ create_file_field(@stream, k,v)
+ else
+ create_regular_field(@stream, k,v)
+ end
+ @stream.write(EOL + b)
+ @stream.write(EOL) unless last_index == index
+ end
+ @stream.write('--')
+ @stream.write(EOL)
+ @stream.seek(0)
+ end
+
+ def create_regular_field(s, k, v)
+ s.write("Content-Disposition: multipart/form-data; name=\"#{k}\"")
+ s.write(EOL)
+ s.write(EOL)
+ s.write(v)
+ end
+
+ def create_file_field(s, k, v)
+ begin
+ s.write("Content-Disposition: multipart/form-data; name=\"#{k}\"; filename=\"#{File.basename(v.path)}\"#{EOL}")
+ s.write("Content-Type: #{mime_for(v.path)}#{EOL}")
+ s.write(EOL)
+ while data = v.read(8124)
+ s.write(data)
+ end
+ ensure
+ v.close
+ end
+ end
+
+ def mime_for(path)
+ ext = File.extname(path)[1..-1]
+ MIME_TYPES[ext] || 'text/plain'
+ end
+
+ def boundary
+ @boundary ||= rand(1_000_000).to_s
+ end
+
+ def headers
+ super.merge({'Content-Type' => %Q{multipart/form-data; boundary="#{boundary}"}})
+ end
+
+ def close
+ @stream.close
+ end
+ end
+
+ # :stopdoc:
+ # From WEBrick.
+ MIME_TYPES = {
+ "ai" => "application/postscript",
+ "asc" => "text/plain",
+ "avi" => "video/x-msvideo",
+ "bin" => "application/octet-stream",
+ "bmp" => "image/bmp",
+ "class" => "application/octet-stream",
+ "cer" => "application/pkix-cert",
+ "crl" => "application/pkix-crl",
+ "crt" => "application/x-x509-ca-cert",
+ "css" => "text/css",
+ "dms" => "application/octet-stream",
+ "doc" => "application/msword",
+ "dvi" => "application/x-dvi",
+ "eps" => "application/postscript",
+ "etx" => "text/x-setext",
+ "exe" => "application/octet-stream",
+ "gif" => "image/gif",
+ "gz" => "application/x-gzip",
+ "htm" => "text/html",
+ "html" => "text/html",
+ "jpe" => "image/jpeg",
+ "jpeg" => "image/jpeg",
+ "jpg" => "image/jpeg",
+ "js" => "text/javascript",
+ "lha" => "application/octet-stream",
+ "lzh" => "application/octet-stream",
+ "mov" => "video/quicktime",
+ "mpe" => "video/mpeg",
+ "mpeg" => "video/mpeg",
+ "mpg" => "video/mpeg",
+ "pbm" => "image/x-portable-bitmap",
+ "pdf" => "application/pdf",
+ "pgm" => "image/x-portable-graymap",
+ "png" => "image/png",
+ "pnm" => "image/x-portable-anymap",
+ "ppm" => "image/x-portable-pixmap",
+ "ppt" => "application/vnd.ms-powerpoint",
+ "ps" => "application/postscript",
+ "qt" => "video/quicktime",
+ "ras" => "image/x-cmu-raster",
+ "rb" => "text/plain",
+ "rd" => "text/plain",
+ "rtf" => "application/rtf",
+ "sgm" => "text/sgml",
+ "sgml" => "text/sgml",
+ "tif" => "image/tiff",
+ "tiff" => "image/tiff",
+ "txt" => "text/plain",
+ "xbm" => "image/x-xbitmap",
+ "xls" => "application/vnd.ms-excel",
+ "xml" => "text/xml",
+ "xpm" => "image/x-xpixmap",
+ "xwd" => "image/x-xwindowdump",
+ "zip" => "application/zip",
+ }
+ # :startdoc:
+ end
+end
Added: branches/upstream/librestclient-ruby/current/lib/restclient/raw_response.rb
===================================================================
--- branches/upstream/librestclient-ruby/current/lib/restclient/raw_response.rb (rev 0)
+++ branches/upstream/librestclient-ruby/current/lib/restclient/raw_response.rb 2009-12-12 16:52:10 UTC (rev 4441)
@@ -0,0 +1,30 @@
+require File.dirname(__FILE__) + '/mixin/response'
+
+module RestClient
+ # The response from RestClient on a raw request looks like a string, but is
+ # actually one of these. 99% of the time you're making a rest call all you
+ # care about is the body, but on the occassion you want to fetch the
+ # headers you can:
+ #
+ # RestClient.get('http://example.com').headers[:content_type]
+ #
+ # In addition, if you do not use the response as a string, you can access
+ # a Tempfile object at res.file, which contains the path to the raw
+ # downloaded request body.
+ class RawResponse
+ include RestClient::Mixin::Response
+
+ attr_reader :file
+
+ def initialize(tempfile, net_http_res)
+ @net_http_res = net_http_res
+ @file = tempfile
+ end
+
+ def to_s
+ @file.open
+ @file.read
+ end
+
+ end
+end
Added: branches/upstream/librestclient-ruby/current/lib/restclient/request.rb
===================================================================
--- branches/upstream/librestclient-ruby/current/lib/restclient/request.rb (rev 0)
+++ branches/upstream/librestclient-ruby/current/lib/restclient/request.rb 2009-12-12 16:52:10 UTC (rev 4441)
@@ -0,0 +1,241 @@
+require 'tempfile'
+
+module RestClient
+ # This class is used internally by RestClient to send the request, but you can also
+ # access it internally if you'd like to use a method not directly supported by the
+ # main API. For example:
+ #
+ # RestClient::Request.execute(:method => :head, :url => 'http://example.com')
+ #
+ class Request
+ attr_reader :method, :url, :payload, :headers,
+ :cookies, :user, :password, :timeout, :open_timeout,
+ :verify_ssl, :ssl_client_cert, :ssl_client_key, :ssl_ca_file,
+ :raw_response
+
+ def self.execute(args)
+ new(args).execute
+ end
+
+ def initialize(args)
+ @method = args[:method] or raise ArgumentError, "must pass :method"
+ @url = args[:url] or raise ArgumentError, "must pass :url"
+ @headers = args[:headers] || {}
+ @cookies = @headers.delete(:cookies) || args[:cookies] || {}
+ @payload = Payload.generate(args[:payload])
+ @user = args[:user]
+ @password = args[:password]
+ @timeout = args[:timeout]
+ @open_timeout = args[:open_timeout]
+ @raw_response = args[:raw_response] || false
+ @verify_ssl = args[:verify_ssl] || false
+ @ssl_client_cert = args[:ssl_client_cert] || nil
+ @ssl_client_key = args[:ssl_client_key] || nil
+ @ssl_ca_file = args[:ssl_ca_file] || nil
+ @tf = nil # If you are a raw request, this is your tempfile
+ end
+
+ def execute
+ execute_inner
+ rescue Redirect => e
+ @url = e.url
+ @method = :get
+ @payload = nil
+ execute
+ end
+
+ def execute_inner
+ uri = parse_url_with_auth(url)
+ transmit uri, net_http_request_class(method).new(uri.request_uri, make_headers(headers)), payload
+ end
+
+ def make_headers(user_headers)
+ unless @cookies.empty?
+ user_headers[:cookie] = @cookies.map {|key, val| "#{key.to_s}=#{val}" }.join('; ')
+ end
+
+ headers = default_headers.merge(user_headers).inject({}) do |final, (key, value)|
+ final[key.to_s.gsub(/_/, '-').capitalize] = value.to_s
+ final
+ end
+
+ headers.merge!(@payload.headers) if @payload
+ headers
+ end
+
+ def net_http_class
+ if RestClient.proxy
+ proxy_uri = URI.parse(RestClient.proxy)
+ Net::HTTP::Proxy(proxy_uri.host, proxy_uri.port, proxy_uri.user, proxy_uri.password)
+ else
+ Net::HTTP
+ end
+ end
+
+ def net_http_request_class(method)
+ Net::HTTP.const_get(method.to_s.capitalize)
+ end
+
+ def parse_url(url)
+ url = "http://#{url}" unless url.match(/^http/)
+ URI.parse(url)
+ end
+
+ def parse_url_with_auth(url)
+ uri = parse_url(url)
+ @user = uri.user if uri.user
+ @password = uri.password if uri.password
+ uri
+ end
+
+ def process_payload(p=nil, parent_key=nil)
+ unless p.is_a?(Hash)
+ p
+ else
+ @headers[:content_type] ||= 'application/x-www-form-urlencoded'
+ p.keys.map do |k|
+ key = parent_key ? "#{parent_key}[#{k}]" : k
+ if p[k].is_a? Hash
+ process_payload(p[k], key)
+ else
+ value = URI.escape(p[k].to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
+ "#{key}=#{value}"
+ end
+ end.join("&")
+ end
+ end
+
+ def transmit(uri, req, payload)
+ setup_credentials(req)
+
+ net = net_http_class.new(uri.host, uri.port)
+ net.use_ssl = uri.is_a?(URI::HTTPS)
+ if @verify_ssl == false
+ net.verify_mode = OpenSSL::SSL::VERIFY_NONE
+ elsif @verify_ssl.is_a? Integer
+ net.verify_mode = @verify_ssl
+ end
+ net.cert = @ssl_client_cert if @ssl_client_cert
+ net.key = @ssl_client_key if @ssl_client_key
+ net.ca_file = @ssl_ca_file if @ssl_ca_file
+ net.read_timeout = @timeout if @timeout
+ net.open_timeout = @open_timeout if @open_timeout
+
+ display_log request_log
+
+ net.start do |http|
+ res = http.request(req, payload) { |http_response| fetch_body(http_response) }
+ result = process_result(res)
+ display_log response_log(res)
+
+ if result.kind_of?(String) or @method == :head
+ Response.new(result, res)
+ elsif @raw_response
+ RawResponse.new(@tf, res)
+ else
+ nil
+ end
+ end
+ rescue EOFError
+ raise RestClient::ServerBrokeConnection
+ rescue Timeout::Error
+ raise RestClient::RequestTimeout
+ end
+
+ def setup_credentials(req)
+ req.basic_auth(user, password) if user
+ end
+
+ def fetch_body(http_response)
+ if @raw_response
+ # Taken from Chef, which as in turn...
+ # Stolen from http://www.ruby-forum.com/topic/166423
+ # Kudos to _why!
+ @tf = Tempfile.new("rest-client")
+ size, total = 0, http_response.header['Content-Length'].to_i
+ http_response.read_body do |chunk|
+ @tf.write(chunk)
+ size += chunk.size
+ if size == 0
+ display_log("#{@method} #{@url} done (0 length file)")
+ elsif total == 0
+ display_log("#{@method} #{@url} (zero content length)")
+ else
+ display_log("#{@method} #{@url} %d%% done (%d of %d)" % [(size * 100) / total, size, total])
+ end
+ end
+ @tf.close
+ @tf
+ else
+ http_response.read_body
+ end
+ http_response
+ end
+
+ def process_result(res)
+ if res.code =~ /\A2\d{2}\z/
+ # We don't decode raw requests
+ unless @raw_response
+ self.class.decode res['content-encoding'], res.body if res.body
+ end
+ elsif %w(301 302 303).include? res.code
+ url = res.header['Location']
+
+ if url !~ /^http/
+ uri = URI.parse(@url)
+ uri.path = "/#{url}".squeeze('/')
+ url = uri.to_s
+ end
+
+ raise Redirect, url
+ elsif res.code == "304"
+ raise NotModified, res
+ elsif res.code == "401"
+ raise Unauthorized, res
+ elsif res.code == "404"
+ raise ResourceNotFound, res
+ else
+ raise RequestFailed, res
+ end
+ end
+
+ def self.decode(content_encoding, body)
+ if content_encoding == 'gzip' and not body.empty?
+ Zlib::GzipReader.new(StringIO.new(body)).read
+ elsif content_encoding == 'deflate'
+ Zlib::Inflate.new.inflate(body)
+ else
+ body
+ end
+ end
+
+ def request_log
+ out = []
+ out << "RestClient.#{method} #{url.inspect}"
+ out << (payload.size > 100 ? "(#{payload.size} byte payload)".inspect : payload.inspect) if payload
+ out << headers.inspect.gsub(/^\{/, '').gsub(/\}$/, '') unless headers.empty?
+ out.join(', ')
+ end
+
+ def response_log(res)
+ size = @raw_response ? File.size(@tf.path) : (res.body.nil? ? 0 : res.body.size)
+ "# => #{res.code} #{res.class.to_s.gsub(/^Net::HTTP/, '')} | #{(res['Content-type'] || '').gsub(/;.*$/, '')} #{size} bytes"
+ end
+
+ def display_log(msg)
+ return unless log_to = RestClient.log
+
+ if log_to == 'stdout'
+ STDOUT.puts msg
+ elsif log_to == 'stderr'
+ STDERR.puts msg
+ else
+ File.open(log_to, 'a') { |f| f.puts msg }
+ end
+ end
+
+ def default_headers
+ { :accept => '*/*; q=0.5, application/xml', :accept_encoding => 'gzip, deflate' }
+ end
+ end
+end
Added: branches/upstream/librestclient-ruby/current/lib/restclient/resource.rb
===================================================================
--- branches/upstream/librestclient-ruby/current/lib/restclient/resource.rb (rev 0)
+++ branches/upstream/librestclient-ruby/current/lib/restclient/resource.rb 2009-12-12 16:52:10 UTC (rev 4441)
@@ -0,0 +1,146 @@
+module RestClient
+ # A class that can be instantiated for access to a RESTful resource,
+ # including authentication.
+ #
+ # Example:
+ #
+ # resource = RestClient::Resource.new('http://some/resource')
+ # jpg = resource.get(:accept => 'image/jpg')
+ #
+ # With HTTP basic authentication:
+ #
+ # resource = RestClient::Resource.new('http://protected/resource', :user => 'user', :password => 'password')
+ # resource.delete
+ #
+ # With a timeout (seconds):
+ #
+ # RestClient::Resource.new('http://slow', :timeout => 10)
+ #
+ # With an open timeout (seconds):
+ #
+ # RestClient::Resource.new('http://behindfirewall', :open_timeout => 10)
+ #
+ # You can also use resources to share common headers. For headers keys,
+ # symbols are converted to strings. Example:
+ #
+ # resource = RestClient::Resource.new('http://some/resource', :headers => { :client_version => 1 })
+ #
+ # This header will be transported as X-Client-Version (notice the X prefix,
+ # capitalization and hyphens)
+ #
+ # Use the [] syntax to allocate subresources:
+ #
+ # site = RestClient::Resource.new('http://example.com', :user => 'adam', :password => 'mypasswd')
+ # site['posts/1/comments'].post 'Good article.', :content_type => 'text/plain'
+ #
+ class Resource
+ attr_reader :url, :options
+
+ def initialize(url, options={}, backwards_compatibility=nil)
+ @url = url
+ if options.class == Hash
+ @options = options
+ else # compatibility with previous versions
+ @options = { :user => options, :password => backwards_compatibility }
+ end
+ end
+
+ def get(additional_headers={}, &b)
+ headers = (options[:headers] || {}).merge(additional_headers)
+ Request.execute(options.merge(
+ :method => :get,
+ :url => url,
+ :headers => headers), &b)
+ end
+
+ def post(payload, additional_headers={}, &b)
+ headers = (options[:headers] || {}).merge(additional_headers)
+ Request.execute(options.merge(
+ :method => :post,
+ :url => url,
+ :payload => payload,
+ :headers => headers), &b)
+ end
+
+ def put(payload, additional_headers={}, &b)
+ headers = (options[:headers] || {}).merge(additional_headers)
+ Request.execute(options.merge(
+ :method => :put,
+ :url => url,
+ :payload => payload,
+ :headers => headers), &b)
+ end
+
+ def delete(additional_headers={}, &b)
+ headers = (options[:headers] || {}).merge(additional_headers)
+ Request.execute(options.merge(
+ :method => :delete,
+ :url => url,
+ :headers => headers), &b)
+ end
+
+ def to_s
+ url
+ end
+
+ def user
+ options[:user]
+ end
+
+ def password
+ options[:password]
+ end
+
+ def headers
+ options[:headers] || {}
+ end
+
+ def timeout
+ options[:timeout]
+ end
+
+ def open_timeout
+ options[:open_timeout]
+ end
+
+ # Construct a subresource, preserving authentication.
+ #
+ # Example:
+ #
+ # site = RestClient::Resource.new('http://example.com', 'adam', 'mypasswd')
+ # site['posts/1/comments'].post 'Good article.', :content_type => 'text/plain'
+ #
+ # This is especially useful if you wish to define your site in one place and
+ # call it in multiple locations:
+ #
+ # def orders
+ # RestClient::Resource.new('http://example.com/orders', 'admin', 'mypasswd')
+ # end
+ #
+ # orders.get # GET http://example.com/orders
+ # orders['1'].get # GET http://example.com/orders/1
+ # orders['1/items'].delete # DELETE http://example.com/orders/1/items
+ #
+ # Nest resources as far as you want:
+ #
+ # site = RestClient::Resource.new('http://example.com')
+ # posts = site['posts']
+ # first_post = posts['1']
+ # comments = first_post['comments']
+ # comments.post 'Hello', :content_type => 'text/plain'
+ #
+ def [](suburl)
+ self.class.new(concat_urls(url, suburl), options)
+ end
+
+ def concat_urls(url, suburl) # :nodoc:
+ url = url.to_s
+ suburl = suburl.to_s
+ if url.slice(-1, 1) == '/' or suburl.slice(0, 1) == '/'
+ url + suburl
+ else
+ "#{url}/#{suburl}"
+ end
+ end
+ end
+end
Added: branches/upstream/librestclient-ruby/current/lib/restclient/response.rb
===================================================================
--- branches/upstream/librestclient-ruby/current/lib/restclient/response.rb (rev 0)
+++ branches/upstream/librestclient-ruby/current/lib/restclient/response.rb 2009-12-12 16:52:10 UTC (rev 4441)
@@ -0,0 +1,20 @@
+require File.dirname(__FILE__) + '/mixin/response'
+
+module RestClient
+ # The response from RestClient looks like a string, but is actually one of
+ # these. 99% of the time you're making a rest call all you care about is
+ # the body, but on the occassion you want to fetch the headers you can:
+ #
+ # RestClient.get('http://example.com').headers[:content_type]
+ #
+ class Response < String
+
+ include RestClient::Mixin::Response
+
+ def initialize(string, net_http_res)
+ @net_http_res = net_http_res
+ super(string || "")
+ end
+
+ end
+end
Added: branches/upstream/librestclient-ruby/current/lib/restclient.rb
===================================================================
--- branches/upstream/librestclient-ruby/current/lib/restclient.rb (rev 0)
+++ branches/upstream/librestclient-ruby/current/lib/restclient.rb 2009-12-12 16:52:10 UTC (rev 4441)
@@ -0,0 +1,107 @@
+require 'uri'
+require 'zlib'
+require 'stringio'
+
+begin
+ require 'net/https'
+rescue LoadError => e
+ raise e unless RUBY_PLATFORM =~ /linux/
+ raise LoadError, "no such file to load -- net/https. Try running apt-get install libopenssl-ruby"
+end
+
+require File.dirname(__FILE__) + '/restclient/request'
+require File.dirname(__FILE__) + '/restclient/mixin/response'
+require File.dirname(__FILE__) + '/restclient/response'
+require File.dirname(__FILE__) + '/restclient/raw_response'
+require File.dirname(__FILE__) + '/restclient/resource'
+require File.dirname(__FILE__) + '/restclient/exceptions'
+require File.dirname(__FILE__) + '/restclient/payload'
+require File.dirname(__FILE__) + '/restclient/net_http_ext'
+
+# This module's static methods are the entry point for using the REST client.
+#
+# # GET
+# xml = RestClient.get 'http://example.com/resource'
+# jpg = RestClient.get 'http://example.com/resource', :accept => 'image/jpg'
+#
+# # authentication and SSL
+# RestClient.get 'https://user:password@example.com/private/resource'
+#
+# # POST or PUT with a hash sends parameters as a urlencoded form body
+# RestClient.post 'http://example.com/resource', :param1 => 'one'
+#
+# # nest hash parameters
+# RestClient.post 'http://example.com/resource', :nested => { :param1 => 'one' }
+#
+# # POST and PUT with raw payloads
+# RestClient.post 'http://example.com/resource', 'the post body', :content_type => 'text/plain'
+# RestClient.post 'http://example.com/resource.xml', xml_doc
+# RestClient.put 'http://example.com/resource.pdf', File.read('my.pdf'), :content_type => 'application/pdf'
+#
+# # DELETE
+# RestClient.delete 'http://example.com/resource'
+#
+# # retreive the response http code and headers
+# res = RestClient.get 'http://example.com/some.jpg'
+# res.code # => 200
+# res.headers[:content_type] # => 'image/jpg'
+#
+# # HEAD
+# RestClient.head('http://example.com').headers
+#
+# To use with a proxy, just set RestClient.proxy to the proper http proxy:
+#
+# RestClient.proxy = "http://proxy.example.com/"
+#
+# Or inherit the proxy from the environment:
+#
+# RestClient.proxy = ENV['http_proxy']
+#
+# For live tests of RestClient, try using http://rest-test.heroku.com, which echoes back information about the rest call:
+#
+# >> RestClient.put 'http://rest-test.heroku.com/resource', :foo => 'baz'
+# => "PUT http://rest-test.heroku.com/resource with a 7 byte payload, content type application/x-www-form-urlencoded {\"foo\"=>\"baz\"}"
+#
+module RestClient
+ def self.get(url, headers={})
+ Request.execute(:method => :get, :url => url, :headers => headers)
+ end
+
+ def self.post(url, payload, headers={})
+ Request.execute(:method => :post, :url => url, :payload => payload, :headers => headers)
+ end
+
+ def self.put(url, payload, headers={})
+ Request.execute(:method => :put, :url => url, :payload => payload, :headers => headers)
+ end
+
+ def self.delete(url, headers={})
+ Request.execute(:method => :delete, :url => url, :headers => headers)
+ end
+
+ def self.head(url, headers={})
+ Request.execute(:method => :head, :url => url, :headers => headers)
+ end
+
+ class << self
+ attr_accessor :proxy
+ end
+
+ # Print log of RestClient calls. Value can be stdout, stderr, or a filename.
+ # You can also configure logging by the environment variable RESTCLIENT_LOG.
+ def self.log=(log)
+ @@log = log
+ end
+
+ def self.log # :nodoc:
+ return ENV['RESTCLIENT_LOG'] if ENV['RESTCLIENT_LOG']
+ return @@log if defined? @@log
+ nil
+ end
+
+ def self.version
+ version_path = File.dirname(__FILE__) + "/../VERSION"
+ return File.read(version_path).chomp if File.file?(version_path)
+ "0.0.0"
+ end
+end
Added: branches/upstream/librestclient-ruby/current/rest-client.gemspec
===================================================================
--- branches/upstream/librestclient-ruby/current/rest-client.gemspec (rev 0)
+++ branches/upstream/librestclient-ruby/current/rest-client.gemspec 2009-12-12 16:52:10 UTC (rev 4441)
@@ -0,0 +1,70 @@
+# -*- encoding: utf-8 -*-
+
+Gem::Specification.new do |s|
+ s.name = %q{rest-client}
+ s.version = "1.1.5"
+
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
+ s.authors = ["Adam Wiggins"]
+ s.date = %q{2009-08-12}
+ s.default_executable = %q{restclient}
+ s.description = %q{A simple REST client for Ruby, inspired by the Sinatra microframework style of specifying actions: get, put, post, delete.}
+ s.email = %q{adam at heroku.com}
+ s.executables = ["restclient"]
+ s.extra_rdoc_files = [
+ "README.rdoc"
+ ]
+ s.files = [
+ "README.rdoc",
+ "Rakefile",
+ "VERSION",
+ "bin/restclient",
+ "lib/rest_client.rb",
+ "lib/restclient.rb",
+ "lib/restclient/exceptions.rb",
+ "lib/restclient/mixin/response.rb",
+ "lib/restclient/net_http_ext.rb",
+ "lib/restclient/payload.rb",
+ "lib/restclient/raw_response.rb",
+ "lib/restclient/request.rb",
+ "lib/restclient/resource.rb",
+ "lib/restclient/response.rb",
+ "spec/base.rb",
+ "spec/exceptions_spec.rb",
+ "spec/master_shake.jpg",
+ "spec/mixin/response_spec.rb",
+ "spec/payload_spec.rb",
+ "spec/raw_response_spec.rb",
+ "spec/request_spec.rb",
+ "spec/resource_spec.rb",
+ "spec/response_spec.rb",
+ "spec/restclient_spec.rb"
+ ]
+ s.homepage = %q{http://rest-client.heroku.com/}
+ s.rdoc_options = ["--charset=UTF-8"]
+ s.require_paths = ["lib"]
+ s.rubyforge_project = %q{rest-client}
+ s.rubygems_version = %q{1.3.5}
+ s.summary = %q{Simple REST client for Ruby, inspired by microframework syntax for specifying actions.}
+ s.test_files = [
+ "spec/base.rb",
+ "spec/exceptions_spec.rb",
+ "spec/mixin/response_spec.rb",
+ "spec/payload_spec.rb",
+ "spec/raw_response_spec.rb",
+ "spec/request_spec.rb",
+ "spec/resource_spec.rb",
+ "spec/response_spec.rb",
+ "spec/restclient_spec.rb"
+ ]
+
+ if s.respond_to? :specification_version then
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
+ s.specification_version = 3
+
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
+ else
+ end
+ else
+ end
+end
Added: branches/upstream/librestclient-ruby/current/spec/base.rb
===================================================================
--- branches/upstream/librestclient-ruby/current/spec/base.rb (rev 0)
+++ branches/upstream/librestclient-ruby/current/spec/base.rb 2009-12-12 16:52:10 UTC (rev 4441)
@@ -0,0 +1,10 @@
+require 'rubygems'
+require 'spec'
+
+begin
+ require "ruby-debug"
+rescue LoadError
+ # NOP, ignore
+end
+
+require File.dirname(__FILE__) + '/../lib/restclient'
Added: branches/upstream/librestclient-ruby/current/spec/exceptions_spec.rb
===================================================================
--- branches/upstream/librestclient-ruby/current/spec/exceptions_spec.rb (rev 0)
+++ branches/upstream/librestclient-ruby/current/spec/exceptions_spec.rb 2009-12-12 16:52:10 UTC (rev 4441)
@@ -0,0 +1,65 @@
+require File.dirname(__FILE__) + '/base'
+
+describe RestClient::Exception do
+ it "sets the exception message to ErrorMessage" do
+ RestClient::ResourceNotFound.new.message.should == 'Resource not found'
+ end
+
+ it "contains exceptions in RestClient" do
+ RestClient::Unauthorized.new.should be_a_kind_of(RestClient::Exception)
+ RestClient::ServerBrokeConnection.new.should be_a_kind_of(RestClient::Exception)
+ end
+end
+
+describe RestClient::RequestFailed do
+ before do
+ @response = mock('HTTP Response', :code => '502')
+ end
+
+ it "stores the http response on the exception" do
+ begin
+ raise RestClient::RequestFailed, :response
+ rescue RestClient::RequestFailed => e
+ e.response.should == :response
+ end
+ end
+
+ it "http_code convenience method for fetching the code as an integer" do
+ RestClient::RequestFailed.new(@response).http_code.should == 502
+ end
+
+ it "http_body convenience method for fetching the body (decoding when necessary)" do
+ @response.stub!(:[]).with('content-encoding').and_return('gzip')
+ @response.stub!(:body).and_return('compressed body')
+ RestClient::Request.should_receive(:decode).with('gzip', 'compressed body').and_return('plain body')
+ RestClient::RequestFailed.new(@response).http_body.should == 'plain body'
+ end
+
+ it "shows the status code in the message" do
+ RestClient::RequestFailed.new(@response).to_s.should match(/502/)
+ end
+end
+
+describe RestClient::ResourceNotFound do
+ it "also has the http response attached" do
+ begin
+ raise RestClient::ResourceNotFound, :response
+ rescue RestClient::ResourceNotFound => e
+ e.response.should == :response
+ end
+ end
+end
+
+describe "backwards compatibility" do
+ it "alias RestClient::Request::Redirect to RestClient::Redirect" do
+ RestClient::Request::Redirect.should == RestClient::Redirect
+ end
+
+ it "alias RestClient::Request::Unauthorized to RestClient::Unauthorized" do
+ RestClient::Request::Unauthorized.should == RestClient::Unauthorized
+ end
+
+ it "alias RestClient::Request::RequestFailed to RestClient::RequestFailed" do
+ RestClient::Request::RequestFailed.should == RestClient::RequestFailed
+ end
+end
Added: branches/upstream/librestclient-ruby/current/spec/master_shake.jpg
===================================================================
(Binary files differ)
Property changes on: branches/upstream/librestclient-ruby/current/spec/master_shake.jpg
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: branches/upstream/librestclient-ruby/current/spec/mixin/response_spec.rb
===================================================================
--- branches/upstream/librestclient-ruby/current/spec/mixin/response_spec.rb (rev 0)
+++ branches/upstream/librestclient-ruby/current/spec/mixin/response_spec.rb 2009-12-12 16:52:10 UTC (rev 4441)
@@ -0,0 +1,46 @@
+require File.dirname(__FILE__) + '/../base'
+
+class MockResponse
+ include RestClient::Mixin::Response
+
+ def initialize(body, res)
+ @net_http_res = res
+ @body = @body
+ end
+end
+
+describe RestClient::Mixin::Response do
+ before do
+ @net_http_res = mock('net http response')
+ @response = MockResponse.new('abc', @net_http_res)
+ end
+
+ it "fetches the numeric response code" do
+ @net_http_res.should_receive(:code).and_return('200')
+ @response.code.should == 200
+ end
+
+ it "beautifies the headers by turning the keys to symbols" do
+ h = RestClient::Response.beautify_headers('content-type' => [ 'x' ])
+ h.keys.first.should == :content_type
+ end
+
+ it "beautifies the headers by turning the values to strings instead of one-element arrays" do
+ h = RestClient::Response.beautify_headers('x' => [ 'text/html' ] )
+ h.values.first.should == 'text/html'
+ end
+
+ it "fetches the headers" do
+ @net_http_res.should_receive(:to_hash).and_return('content-type' => [ 'text/html' ])
+ @response.headers.should == { :content_type => 'text/html' }
+ end
+
+ it "extracts cookies from response headers" do
+ @net_http_res.should_receive(:to_hash).and_return('set-cookie' => ['session_id=1; path=/'])
+ @response.cookies.should == { 'session_id' => '1' }
+ end
+
+ it "can access the net http result directly" do
+ @response.net_http_res.should == @net_http_res
+ end
+end
Added: branches/upstream/librestclient-ruby/current/spec/payload_spec.rb
===================================================================
--- branches/upstream/librestclient-ruby/current/spec/payload_spec.rb (rev 0)
+++ branches/upstream/librestclient-ruby/current/spec/payload_spec.rb 2009-12-12 16:52:10 UTC (rev 4441)
@@ -0,0 +1,76 @@
+require File.dirname(__FILE__) + "/base"
+
+describe RestClient::Payload do
+ context "A regular Payload" do
+ it "should should default content-type to standard enctype" do
+ RestClient::Payload::UrlEncoded.new({}).headers['Content-Type'].
+ should == 'application/x-www-form-urlencoded'
+ end
+
+ it "should form properly encoded params" do
+ RestClient::Payload::UrlEncoded.new({:foo => 'bar'}).to_s.
+ should == "foo=bar"
+ end
+ end
+
+ context "A multipart Payload" do
+ it "should should default content-type to standard enctype" do
+ m = RestClient::Payload::Multipart.new({})
+ m.stub!(:boundary).and_return(123)
+ m.headers['Content-Type'].should == 'multipart/form-data; boundary="123"'
+ end
+
+ it "should form properly seperated multipart data" do
+ m = RestClient::Payload::Multipart.new({:foo => "bar", :bar => "baz"})
+ m.to_s.should == <<-EOS
+--#{m.boundary}\r
+Content-Disposition: multipart/form-data; name="bar"\r
+\r
+baz\r
+--#{m.boundary}\r
+Content-Disposition: multipart/form-data; name="foo"\r
+\r
+bar\r
+--#{m.boundary}--\r
+EOS
+ end
+
+ it "should form properly seperated multipart data" do
+ f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
+ m = RestClient::Payload::Multipart.new({:foo => f})
+ m.to_s.should == <<-EOS
+--#{m.boundary}\r
+Content-Disposition: multipart/form-data; name="foo"; filename="master_shake.jpg"\r
+Content-Type: image/jpeg\r
+\r
+#{IO.read(f.path)}\r
+--#{m.boundary}--\r
+EOS
+ end
+ end
+
+ context "Payload generation" do
+ it "should recognize standard urlencoded params" do
+ RestClient::Payload.generate({"foo" => 'bar'}).should be_kind_of(RestClient::Payload::UrlEncoded)
+ end
+
+ it "should recognize multipart params" do
+ f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
+
+ RestClient::Payload.generate({"foo" => f}).should be_kind_of(RestClient::Payload::Multipart)
+ end
+
+ it "should be multipart if forced" do
+ RestClient::Payload.generate({"foo" => "bar", :multipart => true}).should be_kind_of(RestClient::Payload::Multipart)
+ end
+
+ it "should return data if no of the above" do
+ RestClient::Payload.generate("data").should be_kind_of(RestClient::Payload::Base)
+ end
+
+ it "should recognize nested multipart payloads" do
+ f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
+ RestClient::Payload.generate({"foo" => {"file" => f}}).should be_kind_of(RestClient::Payload::Multipart)
+ end
+ end
+end
Added: branches/upstream/librestclient-ruby/current/spec/raw_response_spec.rb
===================================================================
--- branches/upstream/librestclient-ruby/current/spec/raw_response_spec.rb (rev 0)
+++ branches/upstream/librestclient-ruby/current/spec/raw_response_spec.rb 2009-12-12 16:52:10 UTC (rev 4441)
@@ -0,0 +1,17 @@
+require File.dirname(__FILE__) + '/base'
+
+describe RestClient::RawResponse do
+ before do
+ @tf = mock("Tempfile", :read => "the answer is 42", :open => true)
+ @net_http_res = mock('net http response')
+ @response = RestClient::RawResponse.new(@tf, @net_http_res)
+ end
+
+ it "behaves like string" do
+ @response.to_s.should == 'the answer is 42'
+ end
+
+ it "exposes a Tempfile" do
+ @response.file.should == @tf
+ end
+end
Added: branches/upstream/librestclient-ruby/current/spec/request_spec.rb
===================================================================
--- branches/upstream/librestclient-ruby/current/spec/request_spec.rb (rev 0)
+++ branches/upstream/librestclient-ruby/current/spec/request_spec.rb 2009-12-12 16:52:10 UTC (rev 4441)
@@ -0,0 +1,484 @@
+require File.dirname(__FILE__) + '/base'
+
+describe RestClient::Request do
+ before do
+ @request = RestClient::Request.new(:method => :put, :url => 'http://some/resource', :payload => 'payload')
+
+ @uri = mock("uri")
+ @uri.stub!(:request_uri).and_return('/resource')
+ @uri.stub!(:host).and_return('some')
+ @uri.stub!(:port).and_return(80)
+
+ @net = mock("net::http base")
+ @http = mock("net::http connection")
+ Net::HTTP.stub!(:new).and_return(@net)
+ @net.stub!(:start).and_yield(@http)
+ @net.stub!(:use_ssl=)
+ @net.stub!(:verify_mode=)
+ end
+
+ it "accept */* mimetype, preferring xml" do
+ @request.default_headers[:accept].should == '*/*; q=0.5, application/xml'
+ end
+
+ it "decodes an uncompressed result body by passing it straight through" do
+ RestClient::Request.decode(nil, 'xyz').should == 'xyz'
+ end
+
+ it "decodes a gzip body" do
+ RestClient::Request.decode('gzip', "\037\213\b\b\006'\252H\000\003t\000\313T\317UH\257\312,HM\341\002\000G\242(\r\v\000\000\000").should == "i'm gziped\n"
+ end
+
+ it "ingores gzip for empty bodies" do
+ RestClient::Request.decode('gzip', '').should be_empty
+ end
+
+ it "decodes a deflated body" do
+ RestClient::Request.decode('deflate', "x\234+\316\317MUHIM\313I,IMQ(I\255(\001\000A\223\006\363").should == "some deflated text"
+ end
+
+ it "processes a successful result" do
+ res = mock("result")
+ res.stub!(:code).and_return("200")
+ res.stub!(:body).and_return('body')
+ res.stub!(:[]).with('content-encoding').and_return(nil)
+ @request.process_result(res).should == 'body'
+ end
+
+ it "doesn't classify successful requests as failed" do
+ 203.upto(206) do |code|
+ res = mock("result")
+ res.stub!(:code).and_return(code.to_s)
+ res.stub!(:body).and_return("")
+ res.stub!(:[]).with('content-encoding').and_return(nil)
+ @request.process_result(res).should be_empty
+ end
+ end
+
+ it "parses a url into a URI object" do
+ URI.should_receive(:parse).with('http://example.com/resource')
+ @request.parse_url('http://example.com/resource')
+ end
+
+ it "adds http:// to the front of resources specified in the syntax example.com/resource" do
+ URI.should_receive(:parse).with('http://example.com/resource')
+ @request.parse_url('example.com/resource')
+ end
+
+ it "extracts the username and password when parsing http://user:password@example.com/" do
+ URI.stub!(:parse).and_return(mock('uri', :user => 'joe', :password => 'pass1'))
+ @request.parse_url_with_auth('http://joe:pass1@example.com/resource')
+ @request.user.should == 'joe'
+ @request.password.should == 'pass1'
+ end
+
+ it "doesn't overwrite user and password (which may have already been set by the Resource constructor) if there is no user/password in the url" do
+ URI.stub!(:parse).and_return(mock('uri', :user => nil, :password => nil))
+ @request = RestClient::Request.new(:method => 'get', :url => 'example.com', :user => 'beth', :password => 'pass2')
+ @request.parse_url_with_auth('http://example.com/resource')
+ @request.user.should == 'beth'
+ @request.password.should == 'pass2'
+ end
+
+ it "correctly formats cookies provided to the constructor" do
+ URI.stub!(:parse).and_return(mock('uri', :user => nil, :password => nil))
+ @request = RestClient::Request.new(:method => 'get', :url => 'example.com', :cookies => {:session_id => '1' })
+ @request.should_receive(:default_headers).and_return({'foo' => 'bar'})
+ headers = @request.make_headers({}).should == { 'Foo' => 'bar', 'Cookie' => 'session_id=1'}
+ end
+
+ it "determines the Net::HTTP class to instantiate by the method name" do
+ @request.net_http_request_class(:put).should == Net::HTTP::Put
+ end
+
+ it "merges user headers with the default headers" do
+ @request.should_receive(:default_headers).and_return({ '1' => '2' })
+ headers = @request.make_headers('3' => '4')
+ headers.should have_key('1')
+ headers['1'].should == '2'
+ headers.should have_key('3')
+ headers['3'].should == '4'
+ end
+
+ it "prefers the user header when the same header exists in the defaults" do
+ @request.should_receive(:default_headers).and_return({ '1' => '2' })
+ headers = @request.make_headers('1' => '3')
+ headers.should have_key('1')
+ headers['1'].should == '3'
+ end
+
+ it "converts header symbols from :content_type to 'Content-type'" do
+ @request.should_receive(:default_headers).and_return({})
+ headers = @request.make_headers(:content_type => 'abc')
+ headers.should have_key('Content-type')
+ headers['Content-type'].should == 'abc'
+ end
+
+ it "converts header values to strings" do
+ @request.make_headers('A' => 1)['A'].should == '1'
+ end
+
+ it "executes by constructing the Net::HTTP object, headers, and payload and calling transmit" do
+ @request.should_receive(:parse_url_with_auth).with('http://some/resource').and_return(@uri)
+ klass = mock("net:http class")
+ @request.should_receive(:net_http_request_class).with(:put).and_return(klass)
+ klass.should_receive(:new).and_return('result')
+ @request.should_receive(:transmit).with(@uri, 'result', kind_of(RestClient::Payload::Base))
+ @request.execute_inner
+ end
+
+ it "transmits the request with Net::HTTP" do
+ @http.should_receive(:request).with('req', 'payload')
+ @request.should_receive(:process_result)
+ @request.should_receive(:response_log)
+ @request.transmit(@uri, 'req', 'payload')
+ end
+
+ it "uses SSL when the URI refers to a https address" do
+ @uri.stub!(:is_a?).with(URI::HTTPS).and_return(true)
+ @net.should_receive(:use_ssl=).with(true)
+ @http.stub!(:request)
+ @request.stub!(:process_result)
+ @request.stub!(:response_log)
+ @request.transmit(@uri, 'req', 'payload')
+ end
+
+ it "sends nil payloads" do
+ @http.should_receive(:request).with('req', nil)
+ @request.should_receive(:process_result)
+ @request.stub!(:response_log)
+ @request.transmit(@uri, 'req', nil)
+ end
+
+ it "passes non-hash payloads straight through" do
+ @request.process_payload("x").should == "x"
+ end
+
+ it "converts a hash payload to urlencoded data" do
+ @request.process_payload(:a => 'b c+d').should == "a=b%20c%2Bd"
+ end
+
+ it "accepts nested hashes in payload" do
+ payload = @request.process_payload(:user => { :name => 'joe', :location => { :country => 'USA', :state => 'CA' }})
+ payload.should include('user[name]=joe')
+ payload.should include('user[location][country]=USA')
+ payload.should include('user[location][state]=CA')
+ end
+
+ it "set urlencoded content_type header on hash payloads" do
+ @request.process_payload(:a => 1)
+ @request.headers[:content_type].should == 'application/x-www-form-urlencoded'
+ end
+
+ it "sets up the credentials prior to the request" do
+ @http.stub!(:request)
+ @request.stub!(:process_result)
+ @request.stub!(:response_log)
+
+ @request.stub!(:user).and_return('joe')
+ @request.stub!(:password).and_return('mypass')
+ @request.should_receive(:setup_credentials).with('req')
+
+ @request.transmit(@uri, 'req', nil)
+ end
+
+ it "does not attempt to send any credentials if user is nil" do
+ @request.stub!(:user).and_return(nil)
+ req = mock("request")
+ req.should_not_receive(:basic_auth)
+ @request.setup_credentials(req)
+ end
+
+ it "setup credentials when there's a user" do
+ @request.stub!(:user).and_return('joe')
+ @request.stub!(:password).and_return('mypass')
+ req = mock("request")
+ req.should_receive(:basic_auth).with('joe', 'mypass')
+ @request.setup_credentials(req)
+ end
+
+ it "catches EOFError and shows the more informative ServerBrokeConnection" do
+ @http.stub!(:request).and_raise(EOFError)
+ lambda { @request.transmit(@uri, 'req', nil) }.should raise_error(RestClient::ServerBrokeConnection)
+ end
+
+ it "execute calls execute_inner" do
+ @request.should_receive(:execute_inner)
+ @request.execute
+ end
+
+ it "class method execute wraps constructor" do
+ req = mock("rest request")
+ RestClient::Request.should_receive(:new).with(1 => 2).and_return(req)
+ req.should_receive(:execute)
+ RestClient::Request.execute(1 => 2)
+ end
+
+ it "raises a Redirect with the new location when the response is in the 30x range" do
+ res = mock('response', :code => '301', :header => { 'Location' => 'http://new/resource' })
+ lambda { @request.process_result(res) }.should raise_error(RestClient::Redirect) { |e| e.url.should == 'http://new/resource'}
+ end
+
+ it "handles redirects with relative paths" do
+ res = mock('response', :code => '301', :header => { 'Location' => 'index' })
+ lambda { @request.process_result(res) }.should raise_error(RestClient::Redirect) { |e| e.url.should == 'http://some/index' }
+ end
+
+ it "handles redirects with absolute paths" do
+ @request.instance_variable_set('@url', 'http://some/place/else')
+ res = mock('response', :code => '301', :header => { 'Location' => '/index' })
+ lambda { @request.process_result(res) }.should raise_error(RestClient::Redirect) { |e| e.url.should == 'http://some/index' }
+ end
+
+ it "uses GET and clears payload when following 30x redirects" do
+ url = "http://example.com/redirected"
+
+ @request.should_receive(:execute_inner).once.ordered.and_raise(RestClient::Redirect.new(url))
+
+ @request.should_receive(:execute_inner).once.ordered do
+ @request.url.should == url
+ @request.method.should == :get
+ @request.payload.should be_nil
+ end
+
+ @request.execute
+ end
+
+ it "raises Unauthorized when the response is 401" do
+ res = mock('response', :code => '401')
+ lambda { @request.process_result(res) }.should raise_error(RestClient::Unauthorized)
+ end
+
+ it "raises ResourceNotFound when the response is 404" do
+ res = mock('response', :code => '404')
+ lambda { @request.process_result(res) }.should raise_error(RestClient::ResourceNotFound)
+ end
+
+ it "raises RequestFailed otherwise" do
+ res = mock('response', :code => '500')
+ lambda { @request.process_result(res) }.should raise_error(RestClient::RequestFailed)
+ end
+
+ it "creates a proxy class if a proxy url is given" do
+ RestClient.stub!(:proxy).and_return("http://example.com/")
+ @request.net_http_class.should include(Net::HTTP::ProxyDelta)
+ end
+
+ it "creates a non-proxy class if a proxy url is not given" do
+ @request.net_http_class.should_not include(Net::HTTP::ProxyDelta)
+ end
+
+ it "logs a get request" do
+ RestClient::Request.new(:method => :get, :url => 'http://url').request_log.should ==
+ 'RestClient.get "http://url"'
+ end
+
+ it "logs a post request with a small payload" do
+ RestClient::Request.new(:method => :post, :url => 'http://url', :payload => 'foo').request_log.should ==
+ 'RestClient.post "http://url", "foo"'
+ end
+
+ it "logs a post request with a large payload" do
+ RestClient::Request.new(:method => :post, :url => 'http://url', :payload => ('x' * 1000)).request_log.should ==
+ 'RestClient.post "http://url", "(1000 byte payload)"'
+ end
+
+ it "logs input headers as a hash" do
+ RestClient::Request.new(:method => :get, :url => 'http://url', :headers => { :accept => 'text/plain' }).request_log.should ==
+ 'RestClient.get "http://url", :accept=>"text/plain"'
+ end
+
+ it "logs a response including the status code, content type, and result body size in bytes" do
+ res = mock('result', :code => '200', :class => Net::HTTPOK, :body => 'abcd')
+ res.stub!(:[]).with('Content-type').and_return('text/html')
+ @request.response_log(res).should == "# => 200 OK | text/html 4 bytes"
+ end
+
+ it "logs a response with a nil Content-type" do
+ res = mock('result', :code => '200', :class => Net::HTTPOK, :body => 'abcd')
+ res.stub!(:[]).with('Content-type').and_return(nil)
+ @request.response_log(res).should == "# => 200 OK | 4 bytes"
+ end
+
+ it "logs a response with a nil body" do
+ res = mock('result', :code => '200', :class => Net::HTTPOK, :body => nil)
+ res.stub!(:[]).with('Content-type').and_return('text/html; charset=utf-8')
+ @request.response_log(res).should == "# => 200 OK | text/html 0 bytes"
+ end
+
+ it "strips the charset from the response content type" do
+ res = mock('result', :code => '200', :class => Net::HTTPOK, :body => 'abcd')
+ res.stub!(:[]).with('Content-type').and_return('text/html; charset=utf-8')
+ @request.response_log(res).should == "# => 200 OK | text/html 4 bytes"
+ end
+
+ it "displays the log to stdout" do
+ RestClient.stub!(:log).and_return('stdout')
+ STDOUT.should_receive(:puts).with('xyz')
+ @request.display_log('xyz')
+ end
+
+ it "displays the log to stderr" do
+ RestClient.stub!(:log).and_return('stderr')
+ STDERR.should_receive(:puts).with('xyz')
+ @request.display_log('xyz')
+ end
+
+ it "append the log to the requested filename" do
+ RestClient.stub!(:log).and_return('/tmp/restclient.log')
+ f = mock('file handle')
+ File.should_receive(:open).with('/tmp/restclient.log', 'a').and_yield(f)
+ f.should_receive(:puts).with('xyz')
+ @request.display_log('xyz')
+ end
+
+ it "set read_timeout" do
+ @request = RestClient::Request.new(:method => :put, :url => 'http://some/resource', :payload => 'payload', :timeout => 123)
+ @http.stub!(:request)
+ @request.stub!(:process_result)
+ @request.stub!(:response_log)
+
+ @net.should_receive(:read_timeout=).with(123)
+
+ @request.transmit(@uri, 'req', nil)
+ end
+
+ it "set open_timeout" do
+ @request = RestClient::Request.new(:method => :put, :url => 'http://some/resource', :payload => 'payload', :open_timeout => 123)
+ @http.stub!(:request)
+ @request.stub!(:process_result)
+ @request.stub!(:response_log)
+
+ @net.should_receive(:open_timeout=).with(123)
+
+ @request.transmit(@uri, 'req', nil)
+ end
+
+ it "should default to not verifying ssl certificates" do
+ @request.verify_ssl.should == false
+ end
+
+ it "should set net.verify_mode to OpenSSL::SSL::VERIFY_NONE if verify_ssl is false" do
+ @net.should_receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_NONE)
+ @http.stub!(:request)
+ @request.stub!(:process_result)
+ @request.stub!(:response_log)
+ @request.transmit(@uri, 'req', 'payload')
+ end
+
+ it "should not set net.verify_mode to OpenSSL::SSL::VERIFY_NONE if verify_ssl is true" do
+ @request = RestClient::Request.new(:method => :put, :url => 'https://some/resource', :payload => 'payload', :verify_ssl => true)
+ @net.should_not_receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_NONE)
+ @http.stub!(:request)
+ @request.stub!(:process_result)
+ @request.stub!(:response_log)
+ @request.transmit(@uri, 'req', 'payload')
+ end
+
+ it "should set net.verify_mode to the passed value if verify_ssl is an OpenSSL constant" do
+ mode = OpenSSL::SSL::VERIFY_PEER |
+ OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
+ @request = RestClient::Request.new( :method => :put,
+ :url => 'https://some/resource',
+ :payload => 'payload',
+ :verify_ssl => mode )
+ @net.should_receive(:verify_mode=).with(mode)
+ @http.stub!(:request)
+ @request.stub!(:process_result)
+ @request.stub!(:response_log)
+ @request.transmit(@uri, 'req', 'payload')
+ end
+
+ it "should default to not having an ssl_client_cert" do
+ @request.ssl_client_cert.should be(nil)
+ end
+
+ it "should set the ssl_client_cert if provided" do
+ @request = RestClient::Request.new(
+ :method => :put,
+ :url => 'https://some/resource',
+ :payload => 'payload',
+ :ssl_client_cert => "whatsupdoc!"
+ )
+ @net.should_receive(:cert=).with("whatsupdoc!")
+ @http.stub!(:request)
+ @request.stub!(:process_result)
+ @request.stub!(:response_log)
+ @request.transmit(@uri, 'req', 'payload')
+ end
+
+ it "should not set the ssl_client_cert if it is not provided" do
+ @request = RestClient::Request.new(
+ :method => :put,
+ :url => 'https://some/resource',
+ :payload => 'payload'
+ )
+ @net.should_not_receive(:cert=).with("whatsupdoc!")
+ @http.stub!(:request)
+ @request.stub!(:process_result)
+ @request.stub!(:response_log)
+ @request.transmit(@uri, 'req', 'payload')
+ end
+
+ it "should default to not having an ssl_client_key" do
+ @request.ssl_client_key.should be(nil)
+ end
+
+ it "should set the ssl_client_key if provided" do
+ @request = RestClient::Request.new(
+ :method => :put,
+ :url => 'https://some/resource',
+ :payload => 'payload',
+ :ssl_client_key => "whatsupdoc!"
+ )
+ @net.should_receive(:key=).with("whatsupdoc!")
+ @http.stub!(:request)
+ @request.stub!(:process_result)
+ @request.stub!(:response_log)
+ @request.transmit(@uri, 'req', 'payload')
+ end
+
+ it "should not set the ssl_client_key if it is not provided" do
+ @request = RestClient::Request.new(
+ :method => :put,
+ :url => 'https://some/resource',
+ :payload => 'payload'
+ )
+ @net.should_not_receive(:key=).with("whatsupdoc!")
+ @http.stub!(:request)
+ @request.stub!(:process_result)
+ @request.stub!(:response_log)
+ @request.transmit(@uri, 'req', 'payload')
+ end
+
+ it "should default to not having an ssl_ca_file" do
+ @request.ssl_ca_file.should be(nil)
+ end
+
+ it "should set the ssl_ca_file if provided" do
+ @request = RestClient::Request.new(
+ :method => :put,
+ :url => 'https://some/resource',
+ :payload => 'payload',
+ :ssl_ca_file => "Certificate Authority File"
+ )
+ @net.should_receive(:ca_file=).with("Certificate Authority File")
+ @http.stub!(:request)
+ @request.stub!(:process_result)
+ @request.stub!(:response_log)
+ @request.transmit(@uri, 'req', 'payload')
+ end
+
+ it "should not set the ssl_ca_file if it is not provided" do
+ @request = RestClient::Request.new(
+ :method => :put,
+ :url => 'https://some/resource',
+ :payload => 'payload'
+ )
+ @net.should_not_receive(:ca_file=).with("Certificate Authority File")
+ @http.stub!(:request)
+ @request.stub!(:process_result)
+ @request.stub!(:response_log)
+ @request.transmit(@uri, 'req', 'payload')
+ end
+end
Added: branches/upstream/librestclient-ruby/current/spec/resource_spec.rb
===================================================================
--- branches/upstream/librestclient-ruby/current/spec/resource_spec.rb (rev 0)
+++ branches/upstream/librestclient-ruby/current/spec/resource_spec.rb 2009-12-12 16:52:10 UTC (rev 4441)
@@ -0,0 +1,75 @@
+require File.dirname(__FILE__) + '/base'
+
+describe RestClient::Resource do
+ before do
+ @resource = RestClient::Resource.new('http://some/resource', :user => 'jane', :password => 'mypass', :headers => { 'X-Something' => '1'})
+ end
+
+ context "Resource delegation" do
+ it "GET" do
+ RestClient::Request.should_receive(:execute).with(:method => :get, :url => 'http://some/resource', :headers => { 'X-Something' => '1'}, :user => 'jane', :password => 'mypass')
+ @resource.get
+ end
+
+ it "POST" do
+ RestClient::Request.should_receive(:execute).with(:method => :post, :url => 'http://some/resource', :payload => 'abc', :headers => { :content_type => 'image/jpg', 'X-Something' => '1'}, :user => 'jane', :password => 'mypass')
+ @resource.post 'abc', :content_type => 'image/jpg'
+ end
+
+ it "PUT" do
+ RestClient::Request.should_receive(:execute).with(:method => :put, :url => 'http://some/resource', :payload => 'abc', :headers => { :content_type => 'image/jpg', 'X-Something' => '1'}, :user => 'jane', :password => 'mypass')
+ @resource.put 'abc', :content_type => 'image/jpg'
+ end
+
+ it "DELETE" do
+ RestClient::Request.should_receive(:execute).with(:method => :delete, :url => 'http://some/resource', :headers => { 'X-Something' => '1'}, :user => 'jane', :password => 'mypass')
+ @resource.delete
+ end
+
+ it "overrides resource headers" do
+ RestClient::Request.should_receive(:execute).with(:method => :get, :url => 'http://some/resource', :headers => { 'X-Something' => '2'}, :user => 'jane', :password => 'mypass')
+ @resource.get 'X-Something' => '2'
+ end
+ end
+
+ it "can instantiate with no user/password" do
+ @resource = RestClient::Resource.new('http://some/resource')
+ end
+
+ it "is backwards compatible with previous constructor" do
+ @resource = RestClient::Resource.new('http://some/resource', 'user', 'pass')
+ @resource.user.should == 'user'
+ @resource.password.should == 'pass'
+ end
+
+ it "concatinates urls, inserting a slash when it needs one" do
+ @resource.concat_urls('http://example.com', 'resource').should == 'http://example.com/resource'
+ end
+
+ it "concatinates urls, using no slash if the first url ends with a slash" do
+ @resource.concat_urls('http://example.com/', 'resource').should == 'http://example.com/resource'
+ end
+
+ it "concatinates urls, using no slash if the second url starts with a slash" do
+ @resource.concat_urls('http://example.com', '/resource').should == 'http://example.com/resource'
+ end
+
+ it "concatinates even non-string urls, :posts + 1 => 'posts/1'" do
+ @resource.concat_urls(:posts, 1).should == 'posts/1'
+ end
+
+ it "offers subresources via []" do
+ parent = RestClient::Resource.new('http://example.com')
+ parent['posts'].url.should == 'http://example.com/posts'
+ end
+
+ it "transports options to subresources" do
+ parent = RestClient::Resource.new('http://example.com', :user => 'user', :password => 'password')
+ parent['posts'].user.should == 'user'
+ parent['posts'].password.should == 'password'
+ end
+
+ it "prints its url with to_s" do
+ RestClient::Resource.new('x').to_s.should == 'x'
+ end
+end
Added: branches/upstream/librestclient-ruby/current/spec/response_spec.rb
===================================================================
--- branches/upstream/librestclient-ruby/current/spec/response_spec.rb (rev 0)
+++ branches/upstream/librestclient-ruby/current/spec/response_spec.rb 2009-12-12 16:52:10 UTC (rev 4441)
@@ -0,0 +1,16 @@
+require File.dirname(__FILE__) + '/base'
+
+describe RestClient::Response do
+ before do
+ @net_http_res = mock('net http response')
+ @response = RestClient::Response.new('abc', @net_http_res)
+ end
+
+ it "behaves like string" do
+ @response.should == 'abc'
+ end
+
+ it "accepts nil strings and sets it to empty for the case of HEAD" do
+ RestClient::Response.new(nil, @net_http_res).should == ""
+ end
+end
Added: branches/upstream/librestclient-ruby/current/spec/restclient_spec.rb
===================================================================
--- branches/upstream/librestclient-ruby/current/spec/restclient_spec.rb (rev 0)
+++ branches/upstream/librestclient-ruby/current/spec/restclient_spec.rb 2009-12-12 16:52:10 UTC (rev 4441)
@@ -0,0 +1,53 @@
+require File.dirname(__FILE__) + '/base'
+
+describe RestClient do
+ describe "API" do
+ it "GET" do
+ RestClient::Request.should_receive(:execute).with(:method => :get, :url => 'http://some/resource', :headers => {})
+ RestClient.get('http://some/resource')
+ end
+
+ it "POST" do
+ RestClient::Request.should_receive(:execute).with(:method => :post, :url => 'http://some/resource', :payload => 'payload', :headers => {})
+ RestClient.post('http://some/resource', 'payload')
+ end
+
+ it "PUT" do
+ RestClient::Request.should_receive(:execute).with(:method => :put, :url => 'http://some/resource', :payload => 'payload', :headers => {})
+ RestClient.put('http://some/resource', 'payload')
+ end
+
+ it "DELETE" do
+ RestClient::Request.should_receive(:execute).with(:method => :delete, :url => 'http://some/resource', :headers => {})
+ RestClient.delete('http://some/resource')
+ end
+
+ it "HEAD" do
+ RestClient::Request.should_receive(:execute).with(:method => :head, :url => 'http://some/resource', :headers => {})
+ RestClient.head('http://some/resource')
+ end
+ end
+
+ describe "logging" do
+ after do
+ RestClient.log = nil
+ end
+
+ it "gets the log source from the RESTCLIENT_LOG environment variable" do
+ ENV.stub!(:[]).with('RESTCLIENT_LOG').and_return('from env')
+ RestClient.log = 'from class method'
+ RestClient.log.should == 'from env'
+ end
+
+ it "sets a destination for log output, used if no environment variable is set" do
+ ENV.stub!(:[]).with('RESTCLIENT_LOG').and_return(nil)
+ RestClient.log = 'from class method'
+ RestClient.log.should == 'from class method'
+ end
+
+ it "returns nil (no logging) if neither are set (default)" do
+ ENV.stub!(:[]).with('RESTCLIENT_LOG').and_return(nil)
+ RestClient.log.should == nil
+ end
+ end
+end
More information about the Pkg-ruby-extras-commits
mailing list