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 CHANGED
@@ -2,3 +2,7 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in nestful.gemspec
4
4
  gemspec
5
+
6
+ group :test do
7
+ gem 'webmock'
8
+ end
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 taken from ActiveResource
104
+ Parts of the connection code were inspired from ActiveResource.
data/Rakefile CHANGED
@@ -1 +1,8 @@
1
- require "bundler/gem_tasks"
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << 'test'
6
+ t.test_files = FileList['test/**/test*.rb']
7
+ t.verbose = true
8
+ end
data/examples/resource.rb CHANGED
@@ -24,4 +24,8 @@ class Charge < Base
24
24
  def refund
25
25
  post(:refund)
26
26
  end
27
+ end
28
+
29
+ class Token < Base
30
+ path '/v1/tokens'
27
31
  end
@@ -32,7 +32,7 @@ module Nestful
32
32
  end
33
33
 
34
34
  def delete(path, headers = {}, &block)
35
- request(:delete, path, header, &block)
35
+ request(:delete, path, headers, &block)
36
36
  end
37
37
 
38
38
  def head(path, headers = {}, &block)
@@ -2,6 +2,10 @@ require 'cgi'
2
2
 
3
3
  module Nestful
4
4
  module Helpers extend self
5
+ def to_path(*params)
6
+ params.map(&:to_s).reject(&:empty?) * '/'
7
+ end
8
+
5
9
  def to_param(value, key = nil)
6
10
  case value
7
11
  when Hash then value.map { |k,v| to_param(v, append_key(key,k)) }.join('&')
@@ -23,7 +23,7 @@ module Nestful
23
23
 
24
24
  def format=(mime_or_format)
25
25
  @format = mime_or_format.is_a?(Symbol) ?
26
- Formats[mime_or_format] : mime_or_format
26
+ Formats[mime_or_format].new : mime_or_format
27
27
  end
28
28
 
29
29
  def url=(value)
@@ -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 : nil
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
- parts.unshift(path)
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(uri(action), *args)
75
+ self.class.get(path(action), *args)
78
76
  end
79
77
 
80
78
  def put(action = '', *args)
81
- self.class.put(uri(action), *args)
79
+ self.class.put(path(action), *args)
82
80
  end
83
81
 
84
82
  def post(action = '', *args)
85
- self.class.post(uri(action), *args)
83
+ self.class.post(path(action), *args)
86
84
  end
87
85
 
88
86
  def delete(action = '', *args)
89
- self.class.delete(uri(action), *args)
87
+ self.class.delete(path(action), *args)
90
88
  end
91
89
 
92
- def uri(*parts)
93
- self.class.uri(self.id, *parts)
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, include_priv = false)
128
+ def respond_to?(method)
131
129
  method_name = method.to_s
132
130
  if attributes.nil?
133
131
  super
@@ -22,6 +22,8 @@ module Nestful
22
22
  response.code.to_i
23
23
  end
24
24
 
25
+ alias_method :status, :code
26
+
25
27
  def decoded
26
28
  @decoded ||= parser ? parser.decode(body) : body
27
29
  end
@@ -1,3 +1,3 @@
1
1
  module Nestful
2
- VERSION = "1.0.0.rc1"
2
+ VERSION = "1.0.0.rc2"
3
3
  end
@@ -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.rc1
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-05 00:00:00.000000000 Z
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.24
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