hyperclient 0.0.3 → 0.0.4

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
@@ -3,6 +3,7 @@ source 'https://rubygems.org'
3
3
  gemspec
4
4
 
5
5
  gem 'rake'
6
+ gem 'growl'
6
7
  gem 'guard'
7
8
  gem 'guard-minitest'
8
9
  gem 'pry'
data/examples/cs.rb ADDED
@@ -0,0 +1,44 @@
1
+ require 'hyperclient'
2
+
3
+ class HalShop
4
+ include Hyperclient
5
+
6
+ entry_point 'http://cs-api.heroku.com/api/'
7
+ end
8
+
9
+ def print_resources(resources)
10
+ resources.each do |resource|
11
+ if resource.is_a?(Array)
12
+ print_resources(resource)
13
+ else
14
+ puts %{Found "#{resource.name}" at "#{resource.url}" }
15
+ end
16
+ end
17
+ end
18
+
19
+ def print_games(games)
20
+ games.each do |game|
21
+ puts %{Found "#{game.attributes['name']}" at "#{game.url}" }
22
+ end
23
+ end
24
+
25
+
26
+ api = HalShop.new
27
+
28
+ puts "Let's inspect the API:"
29
+ puts "\n"
30
+
31
+ puts 'Links from the entry point:'
32
+ print_resources(api.links)
33
+ puts "\n"
34
+
35
+ puts 'How is the server feeling today?'
36
+ puts api.attributes['motd']
37
+ puts "\n"
38
+
39
+ puts "Let's read the feeds:"
40
+ print_resources(api.links.feeds.links)
41
+ puts "\n"
42
+
43
+ puts "I like games!"
44
+ print_games(api.links.feeds.links.games.resources.games)
data/lib/hyperclient.rb CHANGED
@@ -17,7 +17,7 @@ module Hyperclient
17
17
 
18
18
  # Public: Initializes the API with the entry point.
19
19
  def entry
20
- @entry ||= Resource.new('/', resource_options)
20
+ @entry ||= Resource.new('', resource_options)
21
21
  end
22
22
 
23
23
  # Internal: Delegate the method to the API if it exists.
@@ -1,14 +1,14 @@
1
1
  module Hyperclient
2
- # Public: Discovers resources from an HTTP response.
2
+ # Public: Discovers resources from a Representation.
3
3
  class Discoverer
4
4
  # Include goodness of Enumerable.
5
5
  include Enumerable
6
6
 
7
7
  # Public: Initializes a Discoverer.
8
8
  #
9
- # response - A Hash representing some resources.
10
- def initialize(response)
11
- @response = response
9
+ # representation - A Hash representing some resources.
10
+ def initialize(representation)
11
+ @representation = representation
12
12
  end
13
13
 
14
14
  # Public: Fetch a Resource with the given name. It is useful when
@@ -38,24 +38,24 @@ module Hyperclient
38
38
  end
39
39
 
40
40
  private
41
- # Internal: Returns a Hash with the resources of the response.
41
+ # Internal: Returns a Hash with the resources of the representation.
42
42
  def resources
43
- return {} unless @response.respond_to?(:inject)
43
+ return {} unless @representation.respond_to?(:inject)
44
44
 
45
- @resources ||= @response.inject({}) do |memo, (name, response)|
45
+ @resources ||= @representation.inject({}) do |memo, (name, representation)|
46
46
  next memo if name == 'self'
47
- memo.update(name => build_resource(response, name))
47
+ memo.update(name => build_resource(representation, name))
48
48
  end
49
49
  end
50
50
 
51
51
  # Internal: Returns a Resource (or a collection of Resources).
52
52
  #
53
- # response - A Hash representing the resource response.
53
+ # representation - A Hash representing the resource representation.
54
54
  # name - An optional String with the name of the resource.
55
- def build_resource(response, name = nil)
56
- return response.map(&method(:build_resource)) if response.is_a?(Array)
55
+ def build_resource(representation, name = nil)
56
+ return representation.map(&method(:build_resource)) if representation.is_a?(Array)
57
57
 
58
- ResourceFactory.resource(response.delete('href'), {response: response, name: name})
58
+ ResourceFactory.resource(representation.delete('href'), {representation: representation, name: name})
59
59
  end
60
60
  end
61
61
  end
@@ -29,7 +29,7 @@ module Hyperclient
29
29
 
30
30
  # Public: Sends a GET request the the resource url.
31
31
  #
32
- # Returns: The response parsed response.
32
+ # Returns: The parsed response.
33
33
  def get
34
34
  self.class.get(url).parsed_response
35
35
  end
@@ -0,0 +1,52 @@
1
+ require 'hyperclient/discoverer'
2
+
3
+ module Hyperclient
4
+ # Public: This class is responsible for parsing a representation from the API
5
+ # and exposing some methods to access its values.
6
+ #
7
+ # It is mainly used by Hyperclient::Resource.
8
+ class Representation
9
+ # Public: Initializes a Representation.
10
+ #
11
+ # representation - A Hash containing a representation from the API. If the
12
+ # representation is not a Hash it will try to parse it as JSON.
13
+ def initialize(representation)
14
+ begin
15
+ representation = JSON.parse(representation) unless representation.is_a? Hash
16
+ rescue JSON::ParserError
17
+ warn 'WARNING Hyperclient::Representation: JSON representation was not valid:'
18
+ puts representation
19
+ representation = {}
20
+ end
21
+ @representation = representation
22
+ end
23
+
24
+ # Public: Returns a Discoverer for the _links section of the representation. It
25
+ # can be used later to use the resources from this section.
26
+ def links
27
+ @links ||= Discoverer.new(@representation['_links'])
28
+ end
29
+
30
+ # Public: Returns a Discoverer for the _embedded section of the representation.
31
+ # It can be used later to use the resources from this section.
32
+ def resources
33
+ @embedded ||= Discoverer.new(@representation['_embedded'])
34
+ end
35
+
36
+ # Public: Returns a Hash with the attributes of the resource.
37
+ def attributes
38
+ @attributes ||= @representation.dup.delete_if {|key, value| key =~ /^_/}
39
+ end
40
+
41
+ # Public: Returns a String with the resource URL or nil of it does not have
42
+ # one.
43
+ def url
44
+ if @representation && @representation['_links'] && @representation['_links']['self'] &&
45
+ (url = @representation['_links']['self']['href'])
46
+ return url
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ require 'json'
@@ -1,4 +1,4 @@
1
- require 'hyperclient/response'
1
+ require 'hyperclient/representation'
2
2
  require 'hyperclient/http'
3
3
 
4
4
  module Hyperclient
@@ -7,8 +7,8 @@ module Hyperclient
7
7
  # resource's attributes, links and embedded resources.
8
8
  class Resource
9
9
  extend Forwardable
10
- # Public: Delegate attributes and resources to the response.
11
- def_delegators :response, :attributes, :resources, :links
10
+ # Public: Delegate attributes and resources to the representation.
11
+ def_delegators :representation, :attributes, :resources, :links
12
12
 
13
13
  # Public: Delegate all HTTP methods (get, post, put, delete, options and
14
14
  # head) to Hyperclient::HTTP.
@@ -24,14 +24,14 @@ module Hyperclient
24
24
  #
25
25
  # options - An options Hash to initialize different values:
26
26
  # :name - The String name of the resource.
27
- # :response - An optional Hash representation of the resource's
28
- # HTTP response.
27
+ # :representation - An optional Hash representation of the resource's
28
+ # HTTP representation.
29
29
  # :http - An optional Hash to pass to the HTTP class.
30
30
  def initialize(url, options = {})
31
31
  @url = url
32
32
  @name = options[:name]
33
33
  @http = HTTP.new(self, options[:http])
34
- initialize_response(options[:response])
34
+ initialize_representation(options[:representation])
35
35
  end
36
36
 
37
37
  # Public: Sets the entry point for all the resources in your API client.
@@ -52,31 +52,31 @@ module Hyperclient
52
52
  end
53
53
  end
54
54
 
55
- # Public: Gets a fresh response from the resource representation.
55
+ # Public: Gets a fresh representation from the resource representation.
56
56
  #
57
57
  # Returns itself (this way you can chain method calls).
58
58
  def reload
59
- initialize_response(get)
59
+ initialize_representation(get)
60
60
  self
61
61
  end
62
62
 
63
63
  private
64
- # Internal: Initializes a Response
64
+ # Internal: Initializes a Representation
65
65
  #
66
- # raw_response - A Hash representing the HTTP response for the resource.
66
+ # raw_representation - A Hash representing the HTTP representation for the resource.
67
67
  #
68
68
  # Return nothing.
69
- def initialize_response(raw_response)
70
- if raw_response && raw_response.is_a?(Hash) && !raw_response.empty?
71
- @response = Response.new(raw_response)
72
- @url = @response.url if @response.url
69
+ def initialize_representation(raw_representation)
70
+ if raw_representation && !raw_representation.empty?
71
+ @representation = Representation.new(raw_representation)
72
+ @url = @representation.url if @representation.url
73
73
  end
74
74
  end
75
75
 
76
- # Internal: Returns the resource response.
77
- def response
78
- reload unless @response
79
- @response
76
+ # Internal: Returns the resource representation.
77
+ def representation
78
+ reload unless @representation
79
+ @representation
80
80
  end
81
81
  end
82
82
  end
@@ -1,3 +1,3 @@
1
1
  module Hyperclient
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -1,5 +1,5 @@
1
1
  require_relative '../test_helper'
2
- require 'hyperclient/response'
2
+ require 'hyperclient/representation'
3
3
 
4
4
  module Hyperclient
5
5
  describe Discoverer do
@@ -7,13 +7,13 @@ module Hyperclient
7
7
  Resource.entry_point = 'http://api.myexample.org/'
8
8
  end
9
9
 
10
- let (:response) do
10
+ let (:representation) do
11
11
  JSON.parse(File.read('test/fixtures/element.json'))
12
12
  end
13
13
 
14
14
  describe 'each' do
15
15
  it 'iterates between resources' do
16
- discoverer = Discoverer.new(response['_links'])
16
+ discoverer = Discoverer.new(representation['_links'])
17
17
 
18
18
  discoverer.each do |resource|
19
19
  resource.must_be_kind_of Resource
@@ -23,7 +23,7 @@ module Hyperclient
23
23
 
24
24
  describe '[]' do
25
25
  it 'fetches a resource' do
26
- discoverer = Discoverer.new(response['_links'])
26
+ discoverer = Discoverer.new(representation['_links'])
27
27
 
28
28
  discoverer['filter'].must_be_kind_of Resource
29
29
  end
@@ -31,43 +31,43 @@ module Hyperclient
31
31
 
32
32
  describe 'resources' do
33
33
  it 'does not include self as a resource' do
34
- discoverer = Discoverer.new(response['_links'])
34
+ discoverer = Discoverer.new(representation['_links'])
35
35
 
36
36
  lambda { discoverer.self }.must_raise NoMethodError
37
37
  end
38
38
 
39
39
  it 'builds single resources' do
40
- discoverer = Discoverer.new(response['_links'])
40
+ discoverer = Discoverer.new(representation['_links'])
41
41
 
42
42
  discoverer.filter.must_be_kind_of Resource
43
43
  end
44
44
 
45
45
  it 'builds collection resources' do
46
- discoverer = Discoverer.new(response['_embedded'])
46
+ discoverer = Discoverer.new(representation['_embedded'])
47
47
 
48
48
  discoverer.episodes.must_be_kind_of Array
49
49
  end
50
50
 
51
51
  it 'also builds elements in collection resources' do
52
- discoverer = Discoverer.new(response['_embedded'])
52
+ discoverer = Discoverer.new(representation['_embedded'])
53
53
 
54
54
  discoverer.episodes.first.must_be_kind_of Resource
55
55
  end
56
56
 
57
57
  it 'initializes resources with its URL' do
58
- discoverer = Discoverer.new(response['_links'])
58
+ discoverer = Discoverer.new(representation['_links'])
59
59
 
60
60
  discoverer.filter.url.wont_be_empty
61
61
  end
62
62
 
63
- it 'initializes resources with the response' do
64
- discoverer = Discoverer.new(response['_embedded'])
63
+ it 'initializes resources with the representation' do
64
+ discoverer = Discoverer.new(representation['_embedded'])
65
65
 
66
66
  discoverer.author.attributes.wont_be_empty
67
67
  end
68
68
 
69
69
  it 'initializes resources with its name' do
70
- discoverer = Discoverer.new(response['_links'])
70
+ discoverer = Discoverer.new(representation['_links'])
71
71
 
72
72
  discoverer.filter.name.wont_be_empty
73
73
  end
@@ -0,0 +1,64 @@
1
+ require_relative '../test_helper'
2
+ require 'hyperclient/representation'
3
+
4
+ module Hyperclient
5
+ describe Representation do
6
+ let (:representation) do
7
+ Representation.new JSON.parse(File.read('test/fixtures/element.json'))
8
+ end
9
+
10
+ describe 'intialize' do
11
+ it 'handles non-hash representations' do
12
+ representation = Representation.new '{"_links": {"self": {"href": "/productions/1"}}}'
13
+
14
+ representation.url.must_equal '/productions/1'
15
+ end
16
+
17
+ it 'does not raise when non-JSON response is given' do
18
+ representation = Representation.new 'This is not JSON'
19
+
20
+ representation.url.must_equal nil
21
+ end
22
+ end
23
+
24
+ describe 'attributes' do
25
+ it 'returns the resource attributes' do
26
+ representation.attributes['title'].must_equal 'Real World ASP.NET MVC3'
27
+ end
28
+
29
+ it 'does not include _links as attributes' do
30
+ representation.attributes.wont_include '_links'
31
+ end
32
+
33
+ it 'does not include _embedded as attributes' do
34
+ representation.attributes.wont_include '_embedded'
35
+ end
36
+ end
37
+
38
+ describe 'links' do
39
+ it 'returns resources included in the _links section' do
40
+ representation.links.filter.must_be_kind_of Resource
41
+ end
42
+ end
43
+
44
+ describe 'resources' do
45
+ it 'returns resources included in the _embedded section' do
46
+ representation.resources.author.must_be_kind_of Resource
47
+ representation.resources.episodes.first.must_be_kind_of Resource
48
+ representation.resources.episodes.last.must_be_kind_of Resource
49
+ end
50
+ end
51
+
52
+ describe 'url' do
53
+ it 'returns the url of the resource grabbed from the representation' do
54
+ representation.url.must_equal '/productions/1'
55
+ end
56
+
57
+ it 'returns nil when the representation does not include the resource url' do
58
+ representation = Representation.new({_links: {media: {href: '/media/1'}}})
59
+
60
+ representation.url.must_equal nil
61
+ end
62
+ end
63
+ end
64
+ end
@@ -3,12 +3,12 @@ require 'hyperclient/resource'
3
3
 
4
4
  module Hyperclient
5
5
  describe Resource do
6
- let(:response) do
6
+ let(:representation) do
7
7
  File.read('test/fixtures/element.json')
8
8
  end
9
9
 
10
- let(:parsed_response) do
11
- JSON.parse(response)
10
+ let(:parsed_representation) do
11
+ JSON.parse(representation)
12
12
  end
13
13
 
14
14
  before do
@@ -32,19 +32,19 @@ module Hyperclient
32
32
  stub_request(:get, 'http://api.example.org')
33
33
  end
34
34
 
35
- it 'initializes the response when one is given' do
36
- resource = Resource.new('/', {response: JSON.parse(response)})
35
+ it 'initializes the representation when one is given' do
36
+ resource = Resource.new('/', {representation: JSON.parse(representation)})
37
37
 
38
38
  assert_not_requested(:get, 'http://api.example.org/')
39
39
  end
40
40
 
41
- it 'updates the resource URL if the response has one' do
42
- resource = Resource.new('/', {response: JSON.parse(response)})
41
+ it 'updates the resource URL if the representation has one' do
42
+ resource = Resource.new('/', {representation: JSON.parse(representation)})
43
43
 
44
44
  resource.url.must_include '/productions/1'
45
45
  end
46
46
 
47
- it 'does no update the resource URL if the response does not have one' do
47
+ it 'does no update the resource URL if the representation does not have one' do
48
48
  resource = Resource.new('/', {})
49
49
 
50
50
  resource.url.wont_include '/productions/1'
@@ -60,7 +60,7 @@ module Hyperclient
60
60
  describe 'reload' do
61
61
  before do
62
62
  stub_request(:get, "http://api.example.org/productions/1").
63
- to_return(:status => 200, :body => response, headers: {content_type: 'application/json'})
63
+ to_return(:status => 200, :body => representation, headers: {content_type: 'application/json'})
64
64
  end
65
65
 
66
66
  it 'retrives itself from the API' do
@@ -22,7 +22,12 @@ describe Hyperclient do
22
22
  end
23
23
 
24
24
  it 'initializes a Resource at the entry point' do
25
- api.new.entry.url.must_equal 'http://my.api.org/'
25
+ api.new.entry.url.must_equal 'http://my.api.org'
26
+ end
27
+
28
+ it 'also works with entry points that are not in the root' do
29
+ api.entry_point 'http://my.api.org/api'
30
+ api.new.entry.url.must_equal 'http://my.api.org/api'
26
31
  end
27
32
 
28
33
  it 'sets the Resource name' do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hyperclient
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
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: 2012-05-31 00:00:00.000000000 Z
12
+ date: 2012-06-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: httparty
@@ -92,23 +92,24 @@ files:
92
92
  - MIT-LICENSE
93
93
  - Rakefile
94
94
  - Readme.md
95
+ - examples/cs.rb
95
96
  - examples/hal_shop.rb
96
97
  - hyperclient.gemspec
97
98
  - lib/hyperclient.rb
98
99
  - lib/hyperclient/discoverer.rb
99
100
  - lib/hyperclient/http.rb
101
+ - lib/hyperclient/representation.rb
100
102
  - lib/hyperclient/resource.rb
101
103
  - lib/hyperclient/resource_factory.rb
102
- - lib/hyperclient/response.rb
103
104
  - lib/hyperclient/version.rb
104
105
  - test/fixtures/collection.json
105
106
  - test/fixtures/element.json
106
107
  - test/fixtures/root.json
107
108
  - test/hyperclient/discoverer_test.rb
108
109
  - test/hyperclient/http_test.rb
110
+ - test/hyperclient/representation_test.rb
109
111
  - test/hyperclient/resource_factory_test.rb
110
112
  - test/hyperclient/resource_test.rb
111
- - test/hyperclient/response_test.rb
112
113
  - test/hyperclient_test.rb
113
114
  - test/test_helper.rb
114
115
  homepage: http://codegram.github.com/hyperclient/
@@ -125,7 +126,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
125
126
  version: '0'
126
127
  segments:
127
128
  - 0
128
- hash: 2448296263010756108
129
+ hash: 12208377733581260
129
130
  required_rubygems_version: !ruby/object:Gem::Requirement
130
131
  none: false
131
132
  requirements:
@@ -134,7 +135,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
134
135
  version: '0'
135
136
  segments:
136
137
  - 0
137
- hash: 2448296263010756108
138
+ hash: 12208377733581260
138
139
  requirements: []
139
140
  rubyforge_project:
140
141
  rubygems_version: 1.8.23
@@ -147,9 +148,9 @@ test_files:
147
148
  - test/fixtures/root.json
148
149
  - test/hyperclient/discoverer_test.rb
149
150
  - test/hyperclient/http_test.rb
151
+ - test/hyperclient/representation_test.rb
150
152
  - test/hyperclient/resource_factory_test.rb
151
153
  - test/hyperclient/resource_test.rb
152
- - test/hyperclient/response_test.rb
153
154
  - test/hyperclient_test.rb
154
155
  - test/test_helper.rb
155
156
  has_rdoc:
@@ -1,42 +0,0 @@
1
- require 'hyperclient/discoverer'
2
-
3
- module Hyperclient
4
- # Public: This class is responsible for parsing a response from the API
5
- # and exposing some methods to access its values.
6
- #
7
- # It is mainly used by Hyperclient::Resource.
8
- class Response
9
- # Public: Initializes a Response.
10
- #
11
- # response - A Hash representing the response from the API.
12
- def initialize(response)
13
- @response = response
14
- end
15
-
16
- # Public: Returns a Discoverer for the _links section of the response. It
17
- # can be used later to use the resources from this section.
18
- def links
19
- @links ||= Discoverer.new(@response['_links'])
20
- end
21
-
22
- # Public: Returns a Discoverer for the _embedded section of the response.
23
- # It can be used later to use the resources from this section.
24
- def resources
25
- @embedded ||= Discoverer.new(@response['_embedded'])
26
- end
27
-
28
- # Public: Returns a Hash with the attributes of the resource.
29
- def attributes
30
- @attributes ||= @response.dup.delete_if {|key, value| key =~ /^_/}
31
- end
32
-
33
- # Public: Returns a String with the resource URL or nil of it does not have
34
- # one.
35
- def url
36
- if @response && @response['_links'] && @response['_links']['self'] &&
37
- (url = @response['_links']['self']['href'])
38
- return url
39
- end
40
- end
41
- end
42
- end
@@ -1,50 +0,0 @@
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