hyperclient 0.0.1 → 0.0.2

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.
@@ -0,0 +1,80 @@
1
+ require_relative '../test_helper'
2
+ require 'hyperclient/resource'
3
+
4
+ module Hyperclient
5
+ describe Resource do
6
+ let(:response) do
7
+ File.read('test/fixtures/element.json')
8
+ end
9
+
10
+ let(:parsed_response) do
11
+ JSON.parse(response)
12
+ end
13
+
14
+ before do
15
+ Resource.entry_point = 'http://api.example.org'
16
+ end
17
+
18
+ describe 'url' do
19
+ it 'merges the resource url with the entry point' do
20
+ resource = Resource.new('/path/to/resource')
21
+ resource.url.to_s.must_equal 'http://api.example.org/path/to/resource'
22
+ end
23
+
24
+ it 'returns the given url if it cannot merge it' do
25
+ resource = Resource.new('/search={terms}')
26
+ resource.url.to_s.must_equal '/search={terms}'
27
+ end
28
+ end
29
+
30
+ describe 'initialize' do
31
+ before do
32
+ stub_request(:get, 'http://api.example.org')
33
+ end
34
+
35
+ it 'initializes the response when one is given' do
36
+ resource = Resource.new('/', {response: JSON.parse(response)})
37
+
38
+ assert_not_requested(:get, 'http://api.example.org/')
39
+ end
40
+
41
+ it 'updates the resource URL if the response has one' do
42
+ resource = Resource.new('/', {response: JSON.parse(response)})
43
+
44
+ resource.url.must_include '/productions/1'
45
+ end
46
+
47
+ it 'does no update the resource URL if the response does not have one' do
48
+ resource = Resource.new('/', {})
49
+
50
+ resource.url.wont_include '/productions/1'
51
+ end
52
+
53
+ it 'sets the resource name' do
54
+ resource = Resource.new('/', {name: 'posts'})
55
+
56
+ resource.name.must_equal 'posts'
57
+ end
58
+ end
59
+
60
+ describe 'reload' do
61
+ before do
62
+ stub_request(:get, "http://api.example.org/productions/1").
63
+ to_return(:status => 200, :body => response, headers: {content_type: 'application/json'})
64
+ end
65
+
66
+ it 'retrives itself from the API' do
67
+ resource = Resource.new('/productions/1')
68
+ resource.reload
69
+
70
+ assert_requested(:get, 'http://api.example.org/productions/1', times: 1)
71
+ end
72
+
73
+ it 'returns itself' do
74
+ resource = Resource.new('/productions/1')
75
+
76
+ resource.reload.must_equal resource
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,50 @@
1
+ require_relative '../test_helper'
2
+ require 'hyperclient/response'
3
+
4
+ module Hyperclient
5
+ describe Response do
6
+ let (:response) do
7
+ Response.new JSON.parse(File.read('test/fixtures/element.json'))
8
+ end
9
+
10
+ describe 'attributes' do
11
+ it 'returns the resource attributes' do
12
+ response.attributes['title'].must_equal 'Real World ASP.NET MVC3'
13
+ end
14
+
15
+ it 'does not include _links as attributes' do
16
+ response.attributes.wont_include '_links'
17
+ end
18
+
19
+ it 'does not include _embedded as attributes' do
20
+ response.attributes.wont_include '_embedded'
21
+ end
22
+ end
23
+
24
+ describe 'links' do
25
+ it 'returns resources included in the _links section' do
26
+ response.links.filter.must_be_kind_of Resource
27
+ end
28
+ end
29
+
30
+ describe 'resources' do
31
+ it 'returns resources included in the _embedded section' do
32
+ response.resources.author.must_be_kind_of Resource
33
+ response.resources.episodes.first.must_be_kind_of Resource
34
+ response.resources.episodes.last.must_be_kind_of Resource
35
+ end
36
+ end
37
+
38
+ describe 'url' do
39
+ it 'returns the url of the resource grabbed from the response' do
40
+ response.url.must_equal '/productions/1'
41
+ end
42
+
43
+ it 'returns nil when the response does not include the resource url' do
44
+ response = Response.new({_links: {media: {href: '/media/1'}}})
45
+
46
+ response.url.must_equal nil
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,63 @@
1
+ require_relative 'test_helper'
2
+ require 'hyperclient'
3
+
4
+ describe Hyperclient do
5
+ let(:api) do
6
+ Class.new do
7
+ include Hyperclient
8
+ end
9
+ end
10
+
11
+ describe 'entry point' do
12
+ it 'sets the entry point for Hyperclient::Resource' do
13
+ api.entry_point 'http://my.api.org'
14
+
15
+ Hyperclient::Resource.new('/').url.must_include 'http://my.api.org'
16
+ end
17
+ end
18
+
19
+ describe 'entry' do
20
+ before do
21
+ api.entry_point 'http://my.api.org'
22
+ end
23
+
24
+ it 'initializes a Resource at the entry point' do
25
+ api.new.entry.url.must_equal 'http://my.api.org/'
26
+ end
27
+
28
+ it 'sets the Resource name' do
29
+ api.new.name.must_equal 'Entry point'
30
+ end
31
+ end
32
+
33
+ describe 'auth' do
34
+ it 'sets authentication type' do
35
+ api.auth(:digest, nil, nil)
36
+
37
+ api.http_options[:http][:auth][:type].must_equal :digest
38
+ end
39
+
40
+ it 'sets the authentication credentials' do
41
+ api.auth(:digest, 'user', 'secret')
42
+
43
+ api.http_options[:http][:auth][:credentials].must_include 'user'
44
+ api.http_options[:http][:auth][:credentials].must_include 'secret'
45
+ end
46
+ end
47
+
48
+ describe 'method missing' do
49
+ class Hyperclient::Resource
50
+ def foo
51
+ 'foo'
52
+ end
53
+ end
54
+
55
+ it 'delegates undefined methods to the API when they exist' do
56
+ api.new.foo.must_equal 'foo'
57
+ end
58
+
59
+ it 'raises an error when the method does not exist in the API' do
60
+ lambda { api.new.this_method_does_not_exist }.must_raise(NoMethodError)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,7 @@
1
+ gem 'minitest'
2
+
3
+ require 'minitest/spec'
4
+ require 'minitest/autorun'
5
+ require 'turn'
6
+ require 'webmock/minitest'
7
+ require 'json'
metadata CHANGED
@@ -1,32 +1,115 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hyperclient
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
8
- - Mike Subelsky
8
+ - Oriol Gual
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-03-06 00:00:00.000000000Z
13
- dependencies: []
14
- description: Proof of concept for interacting with a hypermedia API
12
+ date: 2012-05-29 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: httparty
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: minitest
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: turn
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: webmock
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ description: HyperClient is a Ruby Hypermedia API client.
15
79
  email:
16
- - mike@subelsky.com
80
+ - oriol.gual@gmail.com
17
81
  executables: []
18
82
  extensions: []
19
83
  extra_rdoc_files: []
20
84
  files:
85
+ - .gitignore
21
86
  - .rvmrc
87
+ - .travis.yml
88
+ - .yardopts
22
89
  - Gemfile
90
+ - Guardfile
23
91
  - LICENSE
24
- - README.md
92
+ - MIT-LICENSE
25
93
  - Rakefile
94
+ - Readme.md
95
+ - examples/hal_shop.rb
26
96
  - hyperclient.gemspec
27
97
  - lib/hyperclient.rb
98
+ - lib/hyperclient/discoverer.rb
99
+ - lib/hyperclient/http.rb
100
+ - lib/hyperclient/resource.rb
101
+ - lib/hyperclient/response.rb
28
102
  - lib/hyperclient/version.rb
29
- homepage: https://github.com/subelsky/hyperclient
103
+ - test/fixtures/collection.json
104
+ - test/fixtures/element.json
105
+ - test/fixtures/root.json
106
+ - test/hyperclient/discoverer_test.rb
107
+ - test/hyperclient/http_test.rb
108
+ - test/hyperclient/resource_test.rb
109
+ - test/hyperclient/response_test.rb
110
+ - test/hyperclient_test.rb
111
+ - test/test_helper.rb
112
+ homepage: http://codegram.github.com/hyperclient/
30
113
  licenses: []
31
114
  post_install_message:
32
115
  rdoc_options: []
@@ -38,17 +121,32 @@ required_ruby_version: !ruby/object:Gem::Requirement
38
121
  - - ! '>='
39
122
  - !ruby/object:Gem::Version
40
123
  version: '0'
124
+ segments:
125
+ - 0
126
+ hash: -2437981689318086472
41
127
  required_rubygems_version: !ruby/object:Gem::Requirement
42
128
  none: false
43
129
  requirements:
44
130
  - - ! '>='
45
131
  - !ruby/object:Gem::Version
46
132
  version: '0'
133
+ segments:
134
+ - 0
135
+ hash: -2437981689318086472
47
136
  requirements: []
48
137
  rubyforge_project:
49
- rubygems_version: 1.8.15
138
+ rubygems_version: 1.8.23
50
139
  signing_key:
51
140
  specification_version: 3
52
- summary: This client is capable of interacting with hypermedia APIs as described in
53
- http://www.subbu.org/blog/2008/09/on-linking-part-1 and elsewhere
54
- test_files: []
141
+ summary: ''
142
+ test_files:
143
+ - test/fixtures/collection.json
144
+ - test/fixtures/element.json
145
+ - test/fixtures/root.json
146
+ - test/hyperclient/discoverer_test.rb
147
+ - test/hyperclient/http_test.rb
148
+ - test/hyperclient/resource_test.rb
149
+ - test/hyperclient/response_test.rb
150
+ - test/hyperclient_test.rb
151
+ - test/test_helper.rb
152
+ has_rdoc:
data/README.md DELETED
@@ -1,71 +0,0 @@
1
- # Hyperclient
2
-
3
- This gem aims to explore and demonstrate how to write a client for [hypermedia APIs](http://blog.steveklabnik.com/posts/2012-02-23-rest-is-over), formerly
4
- known as REST interfaces that respect the [HATEOAS constraint](http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven).
5
-
6
- Many people have demonstrated how the server should respond. I'm investigating how the client should behave when interacting with a true hypermedia server.
7
-
8
- The gem is being developed against the [Hypertext Application Language](http://stateless.co/hal_specification.html) and [Atompub](http://bitworking.org/projects/atom/rfc5023.html) specifications.
9
-
10
- Contributors welcome!
11
-
12
- ## Installation
13
-
14
- Add this line to your application's Gemfile:
15
-
16
- gem 'hyperclient'
17
-
18
- And then execute:
19
-
20
- $ bundle
21
-
22
- Or install it yourself as:
23
-
24
- $ gem install hyperclient
25
-
26
- ## Usage
27
-
28
- ```ruby
29
- require 'hyperclient'
30
-
31
- # NOTE this is the only URI you ever need to specify yourself. The server will provide all future links.
32
- resource = Hyperclient::Resource.new("http://api.example.com")
33
-
34
- resource.links.each { |l| puts(l.relation => l.uri) }
35
- # {:self => "https://api.example.com"}
36
- # {:orders => "https://api.example.com/orders"}
37
- # {:customers => "https://api.example.com/customers"}
38
-
39
- # since we're at the root level of this API we haven't drilled into any objects yet
40
- pp resource.objects
41
- # []
42
-
43
- orders_resource = resource[:orders].get
44
- pp orders_resource.links
45
- # {:self => "https://api.example.com/orders",
46
- # :next => "https://api.example.com/orders/page/2"}
47
-
48
- # some servers may return embedded objects
49
- orders_resource.objects.each { |l| puts l.class => l.attributes }
50
- # [Hyperclient::Resource => {:id => 50, :item_name => "R2 Motivator", :created_at => "2012-02-03 12:15:02 -0400"},
51
- # Hyperclient::Resource => {:id => 51, :item_name => "Hydrospanner", :created_at => "2012-02-04 13:18:12 -0500"}]
52
-
53
- order_resource = orders_resource.post({ item_name: "Droid Coolant" })
54
- pp order_resource.location
55
- # "https://api.example.com/orders/52"
56
-
57
- pp order_resource.attributes
58
- # {:id => 52, :item_name => "Droid Coolant", :created_at => "2012-03-05 21:31:04 -0500"}
59
- ```
60
-
61
- ## Contributing
62
-
63
- 1. Fork it
64
- 2. Create your feature branch (`git checkout -b my-new-feature`)
65
- 3. Commit your changes (`git commit -am 'Added some feature'`)
66
- 4. Push to the branch (`git push origin my-new-feature`)
67
- 5. Create new Pull Request
68
-
69
- ## Questions?
70
-
71
- Contact me on [Twitter](https://twitter/subelsky) or [email](mike@subelsky.com).