nestful 1.0.0.rc1 → 1.0.0.rc2
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.
- data/Gemfile +4 -0
- data/README.markdown +31 -3
- data/Rakefile +8 -1
- data/examples/resource.rb +4 -0
- data/lib/nestful/connection.rb +1 -1
- data/lib/nestful/helpers.rb +4 -0
- data/lib/nestful/request.rb +1 -1
- data/lib/nestful/resource.rb +9 -11
- data/lib/nestful/response.rb +2 -0
- data/lib/nestful/version.rb +1 -1
- data/test/nestful/test_endpoint.rb +24 -0
- data/test/nestful/test_request.rb +71 -0
- data/test/nestful/test_resource.rb +45 -0
- data/test/nestful/test_response.rb +61 -0
- metadata +12 -4
data/Gemfile
CHANGED
data/README.markdown
CHANGED
@@ -20,18 +20,22 @@ Nestful is a simple Ruby HTTP/REST client with a sane API.
|
|
20
20
|
|
21
21
|
### POST request
|
22
22
|
|
23
|
+
# url-encoded form POST
|
23
24
|
Nestful.post 'http://example.com', :foo => 'bar'
|
25
|
+
|
26
|
+
# JSON POST
|
24
27
|
Nestful.post 'http://example.com', {:foo => 'bar'}, :format => :json
|
25
28
|
|
26
29
|
### Parameters
|
27
30
|
|
31
|
+
# You can also provide nestled params
|
28
32
|
Nestful.get 'http://example.com', :nestled => {:vars => 1}
|
29
33
|
|
30
34
|
## Request
|
31
35
|
|
32
36
|
`Request` is the base class for making HTTP requests - everthing else is just an abstraction upon it.
|
33
37
|
|
34
|
-
Request.new(url, options
|
38
|
+
Nestful::Request.new(url, options).execute #=> <Nestful::Response>
|
35
39
|
|
36
40
|
Valid `Request` options are:
|
37
41
|
|
@@ -45,11 +49,13 @@ Valid `Request` options are:
|
|
45
49
|
* timeout
|
46
50
|
* ssl_options
|
47
51
|
|
52
|
+
Requests are run via the `execute` method.
|
53
|
+
|
48
54
|
## Endpoint
|
49
55
|
|
50
56
|
The `Endpoint` class provides a single object to work with restful services. The following example does a GET request to the URL; http://example.com/assets/1/
|
51
57
|
|
52
|
-
Nestful::Endpoint.new('http://example.com')['assets'][1].get
|
58
|
+
Nestful::Endpoint.new('http://example.com')['assets'][1].get #=> Nestful::Response
|
53
59
|
|
54
60
|
## Resource
|
55
61
|
|
@@ -57,6 +63,7 @@ If you're building a binding for a REST API, then you should consider using the
|
|
57
63
|
|
58
64
|
class Charge < Nestful::Resource
|
59
65
|
url 'https://api.stripe.com/v1/charges'
|
66
|
+
options :auth_type => :bearer, :password => 'sk_bar'
|
60
67
|
|
61
68
|
def self.all
|
62
69
|
self.new(get)
|
@@ -71,6 +78,27 @@ If you're building a binding for a REST API, then you should consider using the
|
|
71
78
|
end
|
72
79
|
end
|
73
80
|
|
81
|
+
Charge.all #=> []
|
82
|
+
Charge.find('ch_bar').amount
|
83
|
+
|
84
|
+
## Response
|
85
|
+
|
86
|
+
All HTTP responses are in the form of a `Nestful::Response` instance. This contains the raw HTTP response, body, headers and a few helper methods:
|
87
|
+
|
88
|
+
response = Nestful.get('http://www.google.com')
|
89
|
+
response.body #=> '<html>...'
|
90
|
+
response.headers #=> {'Content-Type' => 'text/html'}
|
91
|
+
response.status #=> 200
|
92
|
+
|
93
|
+
You can also access the decoded body if available, such as for JSON responses:
|
94
|
+
|
95
|
+
response = Nestful.get('http://api.stripe.com/v1/charges')
|
96
|
+
charges = response.decoded
|
97
|
+
|
98
|
+
All calls are proxied to the decoded body, so you can access JSON properties like this:
|
99
|
+
|
100
|
+
charges = Nestful.get('http://api.stripe.com/v1/charges')['data']
|
101
|
+
|
74
102
|
## Credits
|
75
103
|
|
76
|
-
Parts of the connection code were
|
104
|
+
Parts of the connection code were inspired from ActiveResource.
|
data/Rakefile
CHANGED
data/examples/resource.rb
CHANGED
data/lib/nestful/connection.rb
CHANGED
data/lib/nestful/helpers.rb
CHANGED
data/lib/nestful/request.rb
CHANGED
data/lib/nestful/resource.rb
CHANGED
@@ -17,7 +17,7 @@ module Nestful
|
|
17
17
|
def self.options(value = nil)
|
18
18
|
@options = value if value
|
19
19
|
return @options if @options
|
20
|
-
superclass.respond_to?(:options) ? superclass.options :
|
20
|
+
superclass.respond_to?(:options) ? superclass.options : {}
|
21
21
|
end
|
22
22
|
|
23
23
|
def self.url
|
@@ -25,9 +25,7 @@ module Nestful
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def self.uri(*parts)
|
28
|
-
|
29
|
-
parts.unshift(endpoint)
|
30
|
-
URI.join(*parts.compact.map(&:to_s))
|
28
|
+
URI.parse(Helpers.to_path(url, *parts))
|
31
29
|
end
|
32
30
|
|
33
31
|
def self.get(action = '', params = {}, options = {})
|
@@ -74,23 +72,23 @@ module Nestful
|
|
74
72
|
end
|
75
73
|
|
76
74
|
def get(action = '', *args)
|
77
|
-
self.class.get(
|
75
|
+
self.class.get(path(action), *args)
|
78
76
|
end
|
79
77
|
|
80
78
|
def put(action = '', *args)
|
81
|
-
self.class.put(
|
79
|
+
self.class.put(path(action), *args)
|
82
80
|
end
|
83
81
|
|
84
82
|
def post(action = '', *args)
|
85
|
-
self.class.post(
|
83
|
+
self.class.post(path(action), *args)
|
86
84
|
end
|
87
85
|
|
88
86
|
def delete(action = '', *args)
|
89
|
-
self.class.delete(
|
87
|
+
self.class.delete(path(action), *args)
|
90
88
|
end
|
91
89
|
|
92
|
-
def
|
93
|
-
|
90
|
+
def path(*parts)
|
91
|
+
Helpers.to_path(self.id, *parts)
|
94
92
|
end
|
95
93
|
|
96
94
|
def id #:nodoc:
|
@@ -127,7 +125,7 @@ module Nestful
|
|
127
125
|
|
128
126
|
alias_method :respond_to_without_attributes?, :respond_to?
|
129
127
|
|
130
|
-
def respond_to?(method
|
128
|
+
def respond_to?(method)
|
131
129
|
method_name = method.to_s
|
132
130
|
if attributes.nil?
|
133
131
|
super
|
data/lib/nestful/response.rb
CHANGED
data/lib/nestful/version.rb
CHANGED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'webmock/minitest'
|
3
|
+
require 'nestful'
|
4
|
+
|
5
|
+
WebMock.disable_net_connect!
|
6
|
+
|
7
|
+
class TestEndpoint < MiniTest::Unit::TestCase
|
8
|
+
def test_join
|
9
|
+
endpoint = Nestful::Endpoint['http://example.com']['charges'][1]
|
10
|
+
assert_equal 'http://example.com/charges/1', endpoint.url
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_get
|
14
|
+
stub_request(:any, 'http://example.com/charges?limit=10')
|
15
|
+
endpoint = Nestful::Endpoint['http://example.com']['charges'].get(:limit => 10)
|
16
|
+
assert_requested(:get, 'http://example.com/charges?limit=10')
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_post
|
20
|
+
stub_request(:any, 'http://example.com/charges')
|
21
|
+
endpoint = Nestful::Endpoint['http://example.com']['charges'].post
|
22
|
+
assert_requested(:post, 'http://example.com/charges')
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'webmock/minitest'
|
3
|
+
require 'nestful'
|
4
|
+
|
5
|
+
WebMock.disable_net_connect!
|
6
|
+
|
7
|
+
class TestRequest < MiniTest::Unit::TestCase
|
8
|
+
def test_get
|
9
|
+
stub_request(:any, 'http://example.com/v1/tokens')
|
10
|
+
Nestful::Request.new('http://example.com/v1/tokens', :method => :get).execute
|
11
|
+
assert_requested(:get, 'http://example.com/v1/tokens')
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_post
|
15
|
+
stub_request(:any, 'http://example.com/v1/tokens')
|
16
|
+
Nestful::Request.new('http://example.com/v1/tokens', :method => :post).execute
|
17
|
+
assert_requested(:post, 'http://example.com/v1/tokens')
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_delete
|
21
|
+
stub_request(:any, 'http://example.com/v1/tokens')
|
22
|
+
Nestful::Request.new('http://example.com/v1/tokens', :method => :delete).execute
|
23
|
+
assert_requested(:delete, 'http://example.com/v1/tokens')
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_put
|
27
|
+
stub_request(:any, 'http://example.com/v1/tokens')
|
28
|
+
Nestful::Request.new('http://example.com/v1/tokens', :method => :put).execute
|
29
|
+
assert_requested(:put, 'http://example.com/v1/tokens')
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_head
|
33
|
+
stub_request(:any, 'http://example.com/v1/tokens')
|
34
|
+
Nestful::Request.new('http://example.com/v1/tokens', :method => :head).execute
|
35
|
+
assert_requested(:head, 'http://example.com/v1/tokens')
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_query_params
|
39
|
+
stub_request(:any, 'http://example.com/v1/tokens?card=1')
|
40
|
+
Nestful::Request.new('http://example.com/v1/tokens', :method => :get, :params => {:card => 1}).execute
|
41
|
+
assert_requested(:get, 'http://example.com/v1/tokens?card=1')
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_form_params
|
45
|
+
stub_request(:any, 'http://example.com/v1/tokens')
|
46
|
+
Nestful::Request.new('http://example.com/v1/tokens', :method => :post, :params => {:number => 4242, :exp_month => 12}).execute
|
47
|
+
assert_requested(:post, 'http://example.com/v1/tokens', :body => 'number=4242&exp_month=12')
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_nestled_form_params
|
51
|
+
stub_request(:any, 'http://example.com/v1/tokens')
|
52
|
+
Nestful::Request.new('http://example.com/v1/tokens', :method => :post, :params => {:card => {:number => 4242, :exp_month => 12}}).execute
|
53
|
+
assert_requested(:post, 'http://example.com/v1/tokens', :body => 'card[number]=4242&card[exp_month]=12')
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_json_params
|
57
|
+
stub_request(:any, 'http://example.com/v1/tokens')
|
58
|
+
Nestful::Request.new('http://example.com/v1/tokens', :method => :post, :format => :json, :params => {:card => {:number => 4242, :exp_month => 12}}).execute
|
59
|
+
assert_requested(:post, 'http://example.com/v1/tokens', :body => '{"card":{"number":4242,"exp_month":12}}', :headers => {'Content-Type' => 'application/json'})
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_timeout
|
63
|
+
skip # TODO
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_auth
|
67
|
+
stub_request(:any, 'http://example.com/v1/tokens')
|
68
|
+
Nestful::Request.new('http://example.com/v1/tokens', :auth_type => :bearer, :password => 'password1').execute
|
69
|
+
assert_requested(:get, 'http://example.com/v1/tokens', :headers => {'Authorization' => 'Bearer password1'})
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'webmock/minitest'
|
3
|
+
require 'nestful'
|
4
|
+
|
5
|
+
WebMock.disable_net_connect!
|
6
|
+
|
7
|
+
class TestResource < MiniTest::Unit::TestCase
|
8
|
+
class Charge < Nestful::Resource
|
9
|
+
endpoint 'http://example.com'
|
10
|
+
path '/v1/charges'
|
11
|
+
end
|
12
|
+
|
13
|
+
def setup
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_get
|
17
|
+
stub_request(:any, 'http://example.com/v1/charges').to_return(:body => '')
|
18
|
+
Charge.get
|
19
|
+
assert_requested(:get, 'http://example.com/v1/charges')
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_post
|
23
|
+
stub_request(:any, 'http://example.com/v1/charges/unknown').to_return(:body => '')
|
24
|
+
Charge.post 'unknown'
|
25
|
+
assert_requested(:post, 'http://example.com/v1/charges/unknown')
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_get_json
|
29
|
+
stub_request(:any, 'http://example.com/v1/charges/1').to_return(
|
30
|
+
:body => '{"id": 1, "amount": 2000}',
|
31
|
+
:headers => {'Content-Type' => 'application/json'}
|
32
|
+
)
|
33
|
+
charge = Charge.find(1)
|
34
|
+
assert_requested(:get, 'http://example.com/v1/charges/1')
|
35
|
+
assert_equal 1, charge.id
|
36
|
+
assert_equal 2000, charge.amount
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_instance_put
|
40
|
+
stub_request(:any, 'http://example.com/v1/charges/1/capture')
|
41
|
+
charge = Charge.new({:id => 1})
|
42
|
+
charge.put(:capture)
|
43
|
+
assert_requested(:put, 'http://example.com/v1/charges/1/capture')
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'webmock/minitest'
|
3
|
+
require 'nestful'
|
4
|
+
|
5
|
+
WebMock.disable_net_connect!
|
6
|
+
|
7
|
+
class TestResponse < MiniTest::Unit::TestCase
|
8
|
+
def test_headers
|
9
|
+
stub_request(:any, 'http://example.com/v1/charges').to_return(:headers => {'X-TEST' => 'BAR'})
|
10
|
+
response = Nestful.get('http://example.com/v1/charges')
|
11
|
+
assert_equal 'BAR', response.headers['X-TEST']
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_content_type
|
15
|
+
stub_request(:any, 'http://example.com/v1/charges').to_return(:headers => {'Content-Type' => 'application/json'})
|
16
|
+
response = Nestful.get('http://example.com/v1/charges')
|
17
|
+
assert_equal 'application/json', response.headers.content_type
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_body
|
21
|
+
stub_request(:any, 'http://example.com/v1/charges').to_return(:body => 'ok')
|
22
|
+
response = Nestful.get('http://example.com/v1/charges')
|
23
|
+
assert_equal 'ok', response.body
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_parse_json
|
27
|
+
stub_request(:any, 'http://example.com/v1/charges').to_return(:headers => {'Content-Type' => 'application/json'}, :body => '{"result":true}')
|
28
|
+
response = Nestful.get('http://example.com/v1/charges')
|
29
|
+
assert_equal({'result' => true}, response.decoded)
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_status
|
33
|
+
stub_request(:any, 'http://example.com/v1/charges').to_return(:status => 201)
|
34
|
+
response = Nestful.get('http://example.com/v1/charges')
|
35
|
+
assert_equal 201, response.status
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_raises_404
|
39
|
+
stub_request(:any, 'http://example.com/v1/charges').to_return(:status => 404)
|
40
|
+
|
41
|
+
assert_raises Nestful::ResourceNotFound do
|
42
|
+
Nestful.get('http://example.com/v1/charges')
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_raises_400
|
47
|
+
stub_request(:any, 'http://example.com/v1/charges').to_return(:status => 400)
|
48
|
+
|
49
|
+
assert_raises Nestful::BadRequest do
|
50
|
+
Nestful.get('http://example.com/v1/charges')
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_delegation
|
55
|
+
stub_request(:any, 'http://example.com/v1/charges').to_return(:headers => {'Content-Type' => 'application/json'}, :body => '{"result":true}')
|
56
|
+
response = Nestful.get('http://example.com/v1/charges')
|
57
|
+
|
58
|
+
assert response.respond_to?(:fetch)
|
59
|
+
assert response.fetch('result')
|
60
|
+
end
|
61
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nestful
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.
|
4
|
+
version: 1.0.0.rc2
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-04-
|
12
|
+
date: 2013-04-10 00:00:00.000000000Z
|
13
13
|
dependencies: []
|
14
14
|
description:
|
15
15
|
email:
|
@@ -39,6 +39,10 @@ files:
|
|
39
39
|
- lib/nestful/response/headers.rb
|
40
40
|
- lib/nestful/version.rb
|
41
41
|
- nestful.gemspec
|
42
|
+
- test/nestful/test_endpoint.rb
|
43
|
+
- test/nestful/test_request.rb
|
44
|
+
- test/nestful/test_resource.rb
|
45
|
+
- test/nestful/test_response.rb
|
42
46
|
homepage: https://github.com/maccman/nestful
|
43
47
|
licenses: []
|
44
48
|
post_install_message:
|
@@ -59,8 +63,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
59
63
|
version: 1.3.1
|
60
64
|
requirements: []
|
61
65
|
rubyforge_project:
|
62
|
-
rubygems_version: 1.8.
|
66
|
+
rubygems_version: 1.8.15
|
63
67
|
signing_key:
|
64
68
|
specification_version: 3
|
65
69
|
summary: Simple Ruby HTTP/REST client with a sane API
|
66
|
-
test_files:
|
70
|
+
test_files:
|
71
|
+
- test/nestful/test_endpoint.rb
|
72
|
+
- test/nestful/test_request.rb
|
73
|
+
- test/nestful/test_resource.rb
|
74
|
+
- test/nestful/test_response.rb
|