rest-client 0.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rest-client might be problematic. Click here for more details.

@@ -0,0 +1,82 @@
1
+ require 'rake'
2
+ require 'spec/rake/spectask'
3
+
4
+ desc "Run all specs"
5
+ Spec::Rake::SpecTask.new('spec') do |t|
6
+ t.spec_files = FileList['spec/*_spec.rb']
7
+ end
8
+
9
+ desc "Print specdocs"
10
+ Spec::Rake::SpecTask.new(:doc) do |t|
11
+ t.spec_opts = ["--format", "specdoc", "--dry-run"]
12
+ t.spec_files = FileList['spec/*_spec.rb']
13
+ end
14
+
15
+ desc "Run all examples with RCov"
16
+ Spec::Rake::SpecTask.new('rcov') do |t|
17
+ t.spec_files = FileList['spec/*_spec.rb']
18
+ t.rcov = true
19
+ t.rcov_opts = ['--exclude', 'examples']
20
+ end
21
+
22
+ task :default => :spec
23
+
24
+ ######################################################
25
+
26
+ require 'rake'
27
+ require 'rake/testtask'
28
+ require 'rake/clean'
29
+ require 'rake/gempackagetask'
30
+ require 'rake/rdoctask'
31
+ require 'fileutils'
32
+
33
+ version = "0.1"
34
+ name = "rest-client"
35
+
36
+ spec = Gem::Specification.new do |s|
37
+ s.name = name
38
+ s.version = version
39
+ s.summary = "Simple REST client for Ruby, inspired by microframework syntax for specifying actions."
40
+ s.description = "A simple REST client for Ruby, inspired by the microframework (Camping, Sinatra...) style of specifying actions: get, put, post, delete."
41
+ s.author = "Adam Wiggins"
42
+ s.email = "adam@heroku.com"
43
+ s.homepage = "http://rest-client.heroku.com/"
44
+ s.rubyforge_project = "rest-client"
45
+
46
+ s.platform = Gem::Platform::RUBY
47
+ s.has_rdoc = true
48
+
49
+ s.files = %w(Rakefile) + Dir.glob("{lib,spec}/**/*")
50
+
51
+ s.require_path = "lib"
52
+ end
53
+
54
+ Rake::GemPackageTask.new(spec) do |p|
55
+ p.need_tar = true if RUBY_PLATFORM !~ /mswin/
56
+ end
57
+
58
+ task :install => [ :package ] do
59
+ sh %{sudo gem install pkg/#{name}-#{version}.gem}
60
+ end
61
+
62
+ task :uninstall => [ :clean ] do
63
+ sh %{sudo gem uninstall #{name}}
64
+ end
65
+
66
+ Rake::TestTask.new do |t|
67
+ t.libs << "spec"
68
+ t.test_files = FileList['spec/*_spec.rb']
69
+ t.verbose = true
70
+ end
71
+
72
+ Rake::RDocTask.new do |t|
73
+ t.rdoc_dir = 'rdoc'
74
+ t.title = "rest-client, fetch RESTful resources effortlessly"
75
+ t.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
76
+ t.options << '--charset' << 'utf-8'
77
+ t.rdoc_files.include('README')
78
+ t.rdoc_files.include('lib/rest_client.rb')
79
+ end
80
+
81
+ CLEAN.include [ 'pkg', '*.gem', '.config' ]
82
+
@@ -0,0 +1,98 @@
1
+ require 'uri'
2
+ require 'net/http'
3
+
4
+ # This module's static methods are the entry point for using the REST client.
5
+ module RestClient
6
+ def self.get(url, headers={})
7
+ Request.new(:get, url, nil, headers).execute
8
+ end
9
+
10
+ def self.post(url, payload=nil, headers={})
11
+ Request.new(:post, url, payload, headers).execute
12
+ end
13
+
14
+ def self.put(url, payload=nil, headers={})
15
+ Request.new(:put, url, payload, headers).execute
16
+ end
17
+
18
+ def self.delete(url, headers={})
19
+ Request.new(:delete, url, nil, headers).execute
20
+ end
21
+
22
+ # Internal class used to build and execute the request.
23
+ class Request
24
+ attr_reader :method, :url, :payload, :headers
25
+
26
+ def initialize(method, url, payload, headers)
27
+ @method = method
28
+ @url = url
29
+ @payload = payload
30
+ @headers = headers
31
+ end
32
+
33
+ def execute
34
+ execute_inner
35
+ rescue Redirect => e
36
+ @url = e.message
37
+ execute
38
+ end
39
+
40
+ def execute_inner
41
+ uri = parse_url(url)
42
+ transmit uri, net_http_class(method).new(uri.path, make_headers(headers)), payload
43
+ end
44
+
45
+ def make_headers(user_headers)
46
+ final = {}
47
+ merged = default_headers.merge(user_headers)
48
+ merged.keys.each do |key|
49
+ final[key.to_s.gsub(/_/, '-').capitalize] = merged[key]
50
+ end
51
+ final
52
+ end
53
+
54
+ def net_http_class(method)
55
+ Object.module_eval "Net::HTTP::#{method.to_s.capitalize}"
56
+ end
57
+
58
+ def parse_url(url)
59
+ url = "http://#{url}" unless url.match(/^http/)
60
+ URI.parse(url)
61
+ end
62
+
63
+ # A redirect was encountered; caught by execute to retry with the new url.
64
+ class Redirect < Exception; end
65
+
66
+ # Request failed with an unhandled http error code.
67
+ class RequestFailed < Exception; end
68
+
69
+ # Authorization is required to access the resource specified.
70
+ class Unauthorized < Exception; end
71
+
72
+ def transmit(uri, req, payload)
73
+ Net::HTTP.start(uri.host, uri.port) do |http|
74
+ process_result http.request(req, payload || "")
75
+ end
76
+ end
77
+
78
+ def process_result(res)
79
+ if %w(200 201 202).include? res.code
80
+ res.body
81
+ elsif %w(301 302 303).include? res.code
82
+ raise Redirect, res.header['Location']
83
+ elsif res.code == "401"
84
+ raise Unauthorized
85
+ else
86
+ raise RequestFailed, error_message(res)
87
+ end
88
+ end
89
+
90
+ def error_message(res)
91
+ "HTTP code #{res.code}: #{res.body}"
92
+ end
93
+
94
+ def default_headers
95
+ { :accept => 'application/xml' }
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,4 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+
4
+ require File.dirname(__FILE__) + '/../lib/rest_client'
@@ -0,0 +1,114 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+
3
+ describe RestClient do
4
+ context "public API" do
5
+ before do
6
+ @request = mock("restclient request")
7
+ end
8
+
9
+ it "GET" do
10
+ RestClient::Request.should_receive(:new).with(:get, 'http://some/resource', nil, {}).and_return(@request)
11
+ @request.should_receive(:execute)
12
+ RestClient.get('http://some/resource')
13
+ end
14
+
15
+ it "POST" do
16
+ RestClient::Request.should_receive(:new).with(:post, 'http://some/resource', 'payload', {}).and_return(@request)
17
+ @request.should_receive(:execute)
18
+ RestClient.post('http://some/resource', 'payload')
19
+ end
20
+
21
+ it "PUT" do
22
+ RestClient::Request.should_receive(:new).with(:put, 'http://some/resource', 'payload', {}).and_return(@request)
23
+ @request.should_receive(:execute)
24
+ RestClient.put('http://some/resource', 'payload')
25
+ end
26
+
27
+ it "DELETE" do
28
+ RestClient::Request.should_receive(:new).with(:delete, 'http://some/resource', nil, {}).and_return(@request)
29
+ @request.should_receive(:execute)
30
+ RestClient.delete('http://some/resource')
31
+ end
32
+ end
33
+
34
+ context RestClient::Request do
35
+ before do
36
+ @request = RestClient::Request.new(:put, 'http://some/resource', 'payload', {})
37
+
38
+ @uri = mock("uri")
39
+ @uri.stub!(:path).and_return('/resource')
40
+ @uri.stub!(:host).and_return('some')
41
+ @uri.stub!(:port).and_return(80)
42
+ end
43
+
44
+ it "requests xml mimetype" do
45
+ @request.default_headers[:accept].should == 'application/xml'
46
+ end
47
+
48
+ it "processes a successful result" do
49
+ res = mock("result")
50
+ res.stub!(:code).and_return("200")
51
+ res.stub!(:body).and_return('body')
52
+ @request.process_result(res).should == 'body'
53
+ end
54
+
55
+ it "parses a url into a URI object" do
56
+ URI.should_receive(:parse).with('http://example.com/resource')
57
+ @request.parse_url('http://example.com/resource')
58
+ end
59
+
60
+ it "adds http:// to the front of resources specified in the syntax example.com/resource" do
61
+ URI.should_receive(:parse).with('http://example.com/resource')
62
+ @request.parse_url('example.com/resource')
63
+ end
64
+
65
+ it "determines the Net::HTTP class to instantiate by the method name" do
66
+ @request.net_http_class(:put).should == Net::HTTP::Put
67
+ end
68
+
69
+ it "merges user headers with the default headers" do
70
+ @request.should_receive(:default_headers).and_return({ '1' => '2' })
71
+ @request.make_headers('3' => '4').should == { '1' => '2', '3' => '4' }
72
+ end
73
+
74
+ it "prefers the user header when the same header exists in the defaults" do
75
+ @request.should_receive(:default_headers).and_return({ '1' => '2' })
76
+ @request.make_headers('1' => '3').should == { '1' => '3' }
77
+ end
78
+
79
+ it "converts header symbols from :content_type to 'Content-type'" do
80
+ @request.should_receive(:default_headers).and_return({})
81
+ @request.make_headers(:content_type => 'abc').should == { 'Content-type' => 'abc' }
82
+ end
83
+
84
+ it "executes by constructing the Net::HTTP object, headers, and payload and calling transmit" do
85
+ @request.should_receive(:parse_url).with('http://some/resource').and_return(@uri)
86
+ klass = mock("net:http class")
87
+ @request.should_receive(:net_http_class).with(:put).and_return(klass)
88
+ klass.should_receive(:new).and_return('result')
89
+ @request.should_receive(:transmit).with(@uri, 'result', 'payload')
90
+ @request.execute_inner
91
+ end
92
+
93
+ it "transmits the request with Net::HTTP" do
94
+ http = mock("net::http connection")
95
+ Net::HTTP.should_receive(:start).and_yield(http)
96
+ http.should_receive(:request).with('req', 'payload')
97
+ @request.should_receive(:process_result)
98
+ @request.transmit(@uri, 'req', 'payload')
99
+ end
100
+
101
+ it "doesn't send nil payloads" do
102
+ http = mock("net::http connection")
103
+ Net::HTTP.should_receive(:start).and_yield(http)
104
+ http.should_receive(:request).with('req', '')
105
+ @request.should_receive(:process_result)
106
+ @request.transmit(@uri, 'req', nil)
107
+ end
108
+
109
+ it "execute calls execute_inner" do
110
+ @request.should_receive(:execute_inner)
111
+ @request.execute
112
+ end
113
+ end
114
+ end
metadata ADDED
@@ -0,0 +1,56 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rest-client
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.1"
5
+ platform: ruby
6
+ authors:
7
+ - Adam Wiggins
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-03-08 23:00:00 -08:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: "A simple REST client for Ruby, inspired by the microframework (Camping, Sinatra...) style of specifying actions: get, put, post, delete."
17
+ email: adam@heroku.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - Rakefile
26
+ - lib/rest_client.rb
27
+ - spec/base.rb
28
+ - spec/rest_client_spec.rb
29
+ has_rdoc: true
30
+ homepage: http://rest-client.heroku.com/
31
+ post_install_message:
32
+ rdoc_options: []
33
+
34
+ require_paths:
35
+ - lib
36
+ required_ruby_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: "0"
41
+ version:
42
+ required_rubygems_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: "0"
47
+ version:
48
+ requirements: []
49
+
50
+ rubyforge_project: rest-client
51
+ rubygems_version: 1.0.1
52
+ signing_key:
53
+ specification_version: 2
54
+ summary: Simple REST client for Ruby, inspired by microframework syntax for specifying actions.
55
+ test_files: []
56
+