rest-client 0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

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
+