hyperclient 0.0.8 → 0.1.0

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/test/test_helper.rb CHANGED
@@ -1,7 +1,16 @@
1
+ if ENV['COVERAGE']
2
+ require 'simplecov'
3
+ SimpleCov.start do
4
+ add_filter '/test/'
5
+ end
6
+ end
7
+
1
8
  gem 'minitest'
2
9
 
3
10
  require 'minitest/spec'
4
11
  require 'minitest/autorun'
12
+ require 'mocha'
5
13
  require 'turn'
6
14
  require 'webmock/minitest'
7
- require 'json'
15
+ require 'json'
16
+ require 'pry'
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.8
4
+ version: 0.1.0
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-08-24 00:00:00.000000000 Z
12
+ date: 2012-09-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: httparty
@@ -27,6 +27,22 @@ dependencies:
27
27
  - - ! '>='
28
28
  - !ruby/object:Gem::Version
29
29
  version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: uri_template
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
30
46
  - !ruby/object:Gem::Dependency
31
47
  name: minitest
32
48
  requirement: !ruby/object:Gem::Requirement
@@ -75,6 +91,22 @@ dependencies:
75
91
  - - ! '>='
76
92
  - !ruby/object:Gem::Version
77
93
  version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: mocha
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
78
110
  description: HyperClient is a Ruby Hypermedia API client.
79
111
  email:
80
112
  - oriol.gual@gmail.com
@@ -96,21 +128,26 @@ files:
96
128
  - examples/hal_shop.rb
97
129
  - hyperclient.gemspec
98
130
  - lib/hyperclient.rb
99
- - lib/hyperclient/discoverer.rb
131
+ - lib/hyperclient/attributes.rb
132
+ - lib/hyperclient/collection.rb
133
+ - lib/hyperclient/entry_point.rb
100
134
  - lib/hyperclient/http.rb
101
- - lib/hyperclient/representation.rb
135
+ - lib/hyperclient/link.rb
136
+ - lib/hyperclient/link_collection.rb
102
137
  - lib/hyperclient/resource.rb
103
- - lib/hyperclient/resource_factory.rb
138
+ - lib/hyperclient/resource_collection.rb
104
139
  - lib/hyperclient/version.rb
105
140
  - test/fixtures/collection.json
106
141
  - test/fixtures/element.json
107
142
  - test/fixtures/root.json
108
- - test/hyperclient/discoverer_test.rb
143
+ - test/hyperclient/attributes_test.rb
144
+ - test/hyperclient/collection_test.rb
145
+ - test/hyperclient/entry_point_test.rb
109
146
  - test/hyperclient/http_test.rb
110
- - test/hyperclient/representation_test.rb
111
- - test/hyperclient/resource_factory_test.rb
147
+ - test/hyperclient/link_collection_test.rb
148
+ - test/hyperclient/link_test.rb
149
+ - test/hyperclient/resource_collection_test.rb
112
150
  - test/hyperclient/resource_test.rb
113
- - test/hyperclient_test.rb
114
151
  - test/test_helper.rb
115
152
  homepage: http://codegram.github.com/hyperclient/
116
153
  licenses: []
@@ -126,7 +163,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
126
163
  version: '0'
127
164
  segments:
128
165
  - 0
129
- hash: 3332679930856512053
166
+ hash: -1184667501328950554
130
167
  required_rubygems_version: !ruby/object:Gem::Requirement
131
168
  none: false
132
169
  requirements:
@@ -135,10 +172,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
135
172
  version: '0'
136
173
  segments:
137
174
  - 0
138
- hash: 3332679930856512053
175
+ hash: -1184667501328950554
139
176
  requirements: []
140
177
  rubyforge_project:
141
- rubygems_version: 1.8.19
178
+ rubygems_version: 1.8.23
142
179
  signing_key:
143
180
  specification_version: 3
144
181
  summary: ''
@@ -146,11 +183,13 @@ test_files:
146
183
  - test/fixtures/collection.json
147
184
  - test/fixtures/element.json
148
185
  - test/fixtures/root.json
149
- - test/hyperclient/discoverer_test.rb
186
+ - test/hyperclient/attributes_test.rb
187
+ - test/hyperclient/collection_test.rb
188
+ - test/hyperclient/entry_point_test.rb
150
189
  - test/hyperclient/http_test.rb
151
- - test/hyperclient/representation_test.rb
152
- - test/hyperclient/resource_factory_test.rb
190
+ - test/hyperclient/link_collection_test.rb
191
+ - test/hyperclient/link_test.rb
192
+ - test/hyperclient/resource_collection_test.rb
153
193
  - test/hyperclient/resource_test.rb
154
- - test/hyperclient_test.rb
155
194
  - test/test_helper.rb
156
195
  has_rdoc:
@@ -1,84 +0,0 @@
1
- module Hyperclient
2
- # Public: Discovers resources from a Representation.
3
- class Discoverer
4
- # Include goodness of Enumerable.
5
- include Enumerable
6
-
7
- # Public: Initializes a Discoverer.
8
- #
9
- # representation - A Hash representing some resources.
10
- def initialize(representation)
11
- @representation = representation
12
- end
13
-
14
- # Public: Fetch a Resource with the given name. It is useful when
15
- # resources don't have a friendly name and you can't call a method on the
16
- # Discoverer.
17
- #
18
- # name - A String representing the resource name.
19
- #
20
- # Returns a Resource
21
- def [](name)
22
- resources[name.to_s]
23
- end
24
-
25
- # Public: Iterates over the discovered resources so one can navigate easily
26
- # between them.
27
- #
28
- # block - A block to pass to each.
29
- #
30
- # Returns an Enumerable.
31
- def each(&block)
32
- resources.values.each(&block)
33
- end
34
-
35
- # Public: Returns a Resource with the name of the method when exists.
36
- def method_missing(method, *args, &block)
37
- resources.fetch(method.to_s) { super }
38
- end
39
-
40
- private
41
- # Internal: Returns a Hash with the resources of the representation.
42
- def resources
43
- return {} unless @representation.respond_to?(:inject)
44
-
45
- @resources ||= @representation.inject({}) do |memo, (name, representation)|
46
- next memo if name == 'self'
47
- memo.update(name => build_resource(representation, name))
48
- end
49
- end
50
-
51
- # Internal: Returns a Resource (or a collection of Resources).
52
- #
53
- # representation - A Hash representing the resource representation.
54
- # name - An optional String with the name of the resource.
55
- def build_resource(representation, name = nil)
56
- return representation.map(&method(:build_resource)) if representation.is_a?(Array)
57
-
58
- url = URLExtractor.new(representation).url
59
- ResourceFactory.resource(url, {representation: representation, name: name})
60
- end
61
-
62
- # Internal: Extract the url from a HAL representation.
63
- class URLExtractor
64
- # Public: Initializes a URLExtractor.
65
- #
66
- # representation - A Hash with the representation of a Resource.
67
- def initialize(representation)
68
- @representation = representation
69
- end
70
-
71
- # Public: Returns a String with the resource URL
72
- def url
73
- return @representation.delete('href') if @representation.include?('href')
74
-
75
- if @representation && @representation['_links'] && @representation['_links']['self'] &&
76
- (url = @representation['_links']['self']['href'])
77
- return url
78
- end
79
- end
80
- end
81
- end
82
- end
83
-
84
- require 'hyperclient/resource_factory'
@@ -1,43 +0,0 @@
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 embedded
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
- end
41
- end
42
-
43
- require 'json'
@@ -1,53 +0,0 @@
1
- module Hyperclient
2
- # Public: This class acts as an interface to build Resources. It has a simple
3
- # identity map so a user can save HTTP calls when interacting with the same
4
- # resource.
5
- #
6
- # Examples
7
- #
8
- # ResourceFactory.resource('http://myapi.org/resource/1')
9
- # => #<Hyperclient::Resource url: 'http://myapi.org/resource/1'>
10
- #
11
- class ResourceFactory
12
- # Public: A factory method to build Resources. It will try to find a
13
- # Resource in the identity map or build a new one if does not exist.
14
- #
15
- # url - A String to identify the Resource
16
- # args - An Array to pass other arguments to the Resource initialization.
17
- #
18
- # Raises MissingURLException if no url given.
19
- # Returns a Resource.
20
- def self.resource(url, *args)
21
- raise MissingURLException.new(args) unless url
22
-
23
- identity_map.fetch(url) do |url|
24
- resource = Resource.new(url, *args)
25
- identity_map.update(url => resource)
26
- resource
27
- end
28
- end
29
-
30
- private
31
- # Internal: Returns a Hash that acts as identity map.
32
- def self.identity_map
33
- @identity_map ||= {}
34
- end
35
- end
36
-
37
- # Public: Exception that is raised when building a Resource without a URL.
38
- class MissingURLException < StandardError
39
- # Public: Initializes a MissingURLException
40
- #
41
- # args - An Array of the args the were to be used to build the Resource.
42
- def initialize(args)
43
- @args = args
44
- end
45
-
46
- # Public: Returns a String with the exception message.
47
- def message
48
- "Cannot build Resource without a URL, given args were: #{@args.inspect}"
49
- end
50
- end
51
- end
52
-
53
- require 'hyperclient/resource'
@@ -1,101 +0,0 @@
1
- require_relative '../test_helper'
2
- require 'hyperclient/representation'
3
-
4
- module Hyperclient
5
- describe Discoverer do
6
- before do
7
- Resource.entry_point = 'http://api.myexample.org/'
8
- end
9
-
10
- let (:representation) do
11
- JSON.parse(File.read('test/fixtures/element.json'))
12
- end
13
-
14
- describe 'each' do
15
- it 'iterates between resources' do
16
- discoverer = Discoverer.new(representation['_links'])
17
-
18
- discoverer.each do |resource|
19
- resource.must_be_kind_of Resource
20
- end
21
- end
22
- end
23
-
24
- describe '[]' do
25
- it 'fetches a resource' do
26
- discoverer = Discoverer.new(representation['_links'])
27
-
28
- discoverer['filter'].must_be_kind_of Resource
29
- end
30
- end
31
-
32
- describe 'resources' do
33
- it 'does not include self as a resource' do
34
- discoverer = Discoverer.new(representation['_links'])
35
-
36
- lambda { discoverer.self }.must_raise NoMethodError
37
- end
38
-
39
- it 'builds single resources' do
40
- discoverer = Discoverer.new(representation['_links'])
41
-
42
- discoverer.filter.must_be_kind_of Resource
43
- end
44
-
45
- it 'builds collection resources' do
46
- discoverer = Discoverer.new(representation['_embedded'])
47
-
48
- discoverer.episodes.must_be_kind_of Array
49
- end
50
-
51
- it 'also builds elements in collection resources' do
52
- discoverer = Discoverer.new(representation['_embedded'])
53
-
54
- discoverer.episodes.first.must_be_kind_of Resource
55
- end
56
-
57
- it 'initializes resources with its URL' do
58
- discoverer = Discoverer.new(representation['_links'])
59
-
60
- discoverer.filter.url.wont_be_empty
61
- end
62
-
63
- it 'initializes resources with the representation' do
64
- discoverer = Discoverer.new(representation['_embedded'])
65
-
66
- discoverer.author.attributes.wont_be_empty
67
- end
68
-
69
- it 'initializes resources with its name' do
70
- discoverer = Discoverer.new(representation['_links'])
71
-
72
- discoverer.filter.name.wont_be_empty
73
- end
74
- end
75
-
76
- describe Discoverer::URLExtractor do
77
- describe 'url' do
78
- it 'extracts the url from embedded resources' do
79
- hal = {'_links' => {'self' => {'href' => '/path/to/resource'}}}
80
- extractor = Discoverer::URLExtractor.new(hal)
81
-
82
- extractor.url.must_equal '/path/to/resource'
83
- end
84
-
85
- it 'extracts the url from linked resources' do
86
- hal = {'href' => '/path/to/resource'}
87
- extractor = Discoverer::URLExtractor.new(hal)
88
-
89
- extractor.url.must_equal '/path/to/resource'
90
- end
91
-
92
- it 'deletes the url from linked resources to prevent empty representations' do
93
- hal = {'href' => '/path/to/resource'}
94
- Discoverer::URLExtractor.new(hal).url
95
-
96
- hal.include?('href').must_equal false
97
- end
98
- end
99
- end
100
- end
101
- end
@@ -1,52 +0,0 @@
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 '{"title": "Hello world"}'
13
-
14
- representation.attributes['title'].must_equal 'Hello world'
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.attributes.must_equal({})
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 'embedded' do
45
- it 'returns resources included in the _embedded section' do
46
- representation.embedded.author.must_be_kind_of Resource
47
- representation.embedded.episodes.first.must_be_kind_of Resource
48
- representation.embedded.episodes.last.must_be_kind_of Resource
49
- end
50
- end
51
- end
52
- end