aptible-resource 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,90 @@
1
+ module HyperResource::Modules
2
+ module InternalAttributes
3
+
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+
7
+ base._hr_class_attributes.each do |attr|
8
+ base._hr_class_attribute attr
9
+ end
10
+
11
+ (base._hr_attributes - base._hr_class_attributes).each do |attr|
12
+ base.send(:attr_accessor, attr)
13
+ end
14
+
15
+ ## Fallback attributes fall back from instance to class.
16
+ (base._hr_attributes & base._hr_class_attributes).each do |attr|
17
+ base._hr_fallback_attribute attr
18
+ end
19
+ end
20
+
21
+ module ClassMethods
22
+
23
+ def _hr_class_attributes # @private
24
+ [ :root, ## e.g. 'https://example.com/api/v1'
25
+ :auth, ## e.g. {:basic => ['username', 'password']}
26
+ :headers, ## e.g. {'Accept' => 'application/vnd.example+json'}
27
+ :namespace, ## e.g. 'ExampleAPI', or the class ExampleAPI itself
28
+ :adapter, ## subclass of HR::Adapter
29
+ :faraday_options ## e.g. {:request => {:timeout => 30}}
30
+ ]
31
+ end
32
+
33
+ def _hr_attributes # @private
34
+ [ :root,
35
+ :href,
36
+ :auth,
37
+ :headers,
38
+ :namespace,
39
+ :adapter,
40
+ :faraday_options,
41
+
42
+ :request,
43
+ :response,
44
+ :body,
45
+
46
+ :attributes,
47
+ :links,
48
+ :objects,
49
+
50
+ :loaded
51
+ ]
52
+ end
53
+
54
+ ## Inheritable class attribute, kinda like in Rails.
55
+ def _hr_class_attribute(*names)
56
+ names.map(&:to_sym).each do |name|
57
+ instance_eval <<-EOT
58
+ def #{name}=(val)
59
+ @#{name} = val
60
+ end
61
+ def #{name}
62
+ return @#{name} if defined?(@#{name})
63
+ return superclass.#{name} if superclass.respond_to?(:#{name})
64
+ nil
65
+ end
66
+ EOT
67
+ end
68
+ end
69
+
70
+ ## Instance attributes which fall back to class attributes.
71
+ def _hr_fallback_attribute(*names)
72
+ names.map(&:to_sym).each do |name|
73
+ class_eval <<-EOT
74
+ def #{name}=(val)
75
+ @#{name} = val
76
+ end
77
+ def #{name}
78
+ return @#{name} if defined?(@#{name})
79
+ return self.class.#{name} if self.class.respond_to?(:#{name})
80
+ nil
81
+ end
82
+ EOT
83
+ end
84
+ end
85
+
86
+ end # ClassMethods
87
+
88
+ end
89
+ end
90
+
@@ -0,0 +1,60 @@
1
+ class HyperResource
2
+ class Objects < Hash
3
+ attr_accessor :_resource
4
+
5
+ def initialize(resource=nil)
6
+ self._resource = resource || HyperResource.new
7
+ end
8
+
9
+ ## Creates accessor methods in self.class and self._resource.class.
10
+ ## Protects against method creation into HyperResource::Objects and
11
+ ## HyperResource classes. Just subclasses, please!
12
+ def _hr_create_methods!(opts={}) # @private
13
+ return if self.class.to_s == 'HyperResource::Objects'
14
+ return if self._resource.class.to_s == 'HyperResource'
15
+ return if self.class.send(
16
+ :class_variable_defined?, :@@_hr_created_objects_methods)
17
+
18
+ self.keys.each do |attr|
19
+ attr_sym = attr.to_sym
20
+
21
+ self.class.send(:define_method, attr_sym) do
22
+ self[attr]
23
+ end
24
+
25
+ ## Don't stomp on _resource's methods
26
+ unless _resource.respond_to?(attr_sym)
27
+ _resource.class.send(:define_method, attr_sym) do
28
+ objects.send(attr_sym)
29
+ end
30
+ end
31
+ end
32
+
33
+ self.class.send(:class_variable_set, :@@_hr_created_objects_methods, true)
34
+ end
35
+
36
+ def []=(attr, value) # @private
37
+ super(attr.to_s, value)
38
+ end
39
+
40
+ ## When +key+ is a string, returns the array of objects under that name.
41
+ ## When +key+ is a number, returns +ith(key)+. Returns nil on lookup
42
+ ## failure.
43
+ def [](key)
44
+ case key
45
+ when String, Symbol
46
+ return super(key.to_s) if self.has_key?(key.to_s)
47
+ return super(key.to_sym) if self.has_key?(key.to_sym)
48
+ when Fixnum
49
+ return ith(key)
50
+ end
51
+ nil
52
+ end
53
+
54
+ def method_missing(method, *args) # @private
55
+ return self[method] if self[method]
56
+ raise NoMethodError, "undefined method `#{method}' for #{self.inspect}"
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,2 @@
1
+ class HyperResource::Response < Hash
2
+ end
@@ -0,0 +1,4 @@
1
+ class HyperResource
2
+ VERSION = '0.2.4'
3
+ VERSION_DATE = '2014-04-02'
4
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ describe Aptible::Resource::Base do
4
+ subject { Api.new }
5
+
6
+ describe '#initialize' do
7
+ it 'should be a HyperResource instance' do
8
+ expect(subject).to be_a HyperResource
9
+ end
10
+
11
+ it 'should require root_url to be defined' do
12
+ expect { described_class.new }.to raise_error
13
+ end
14
+ end
15
+
16
+ describe '#bearer_token' do
17
+ it 'should accept an Aptible::Resource::Token' do
18
+ token = Api::Token.new
19
+ token.stub(:access_token) { 'aptible_auth_token' }
20
+ subject.stub(:token) { token }
21
+ expect(subject.bearer_token).to eq token.access_token
22
+ end
23
+
24
+ it 'should accept a Fridge::AccessToken' do
25
+ token = Fridge::AccessToken.new
26
+ token.stub(:to_s) { 'fridge_access_token' }
27
+ subject.stub(:token) { token }
28
+ expect(subject.bearer_token).to eq token.to_s
29
+ end
30
+
31
+ it 'should accept a String' do
32
+ subject.stub(:token) { 'token' }
33
+ expect(subject.bearer_token).to eq 'token'
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ describe Aptible::Resource::Model do
4
+ subject { Api.new }
5
+
6
+ describe '.collection_href' do
7
+ it 'should use the pluralized resource name' do
8
+ url = Api::Mainframe.collection_href
9
+ expect(url).to eq '/mainframes'
10
+ end
11
+ end
12
+
13
+ describe '.find' do
14
+ it 'should call find_by_url' do
15
+ url = '/mainframes/42'
16
+ expect(Api::Mainframe).to receive(:find_by_url).with url, {}
17
+ Api::Mainframe.find(42)
18
+ end
19
+ end
20
+
21
+ describe '.all' do
22
+ let(:mainframe) { double 'Mainframe' }
23
+ let(:collection) { double 'Api' }
24
+
25
+ before do
26
+ collection.stub(:mainframes) { [mainframe] }
27
+ Api::Mainframe.any_instance.stub(:find_by_url) { collection }
28
+ end
29
+
30
+ it 'should be an array' do
31
+ expect(Api::Mainframe.all).to be_a Array
32
+ end
33
+
34
+ it 'should return the root collection' do
35
+ expect(Api::Mainframe.all).to eq [mainframe]
36
+ end
37
+
38
+ it 'should pass options to the HyperResource initializer' do
39
+ klass = Api::Mainframe
40
+ options = { token: 'token' }
41
+ expect(klass).to receive(:new).with(options).and_return klass.new
42
+ Api::Mainframe.all(options)
43
+ end
44
+ end
45
+
46
+ describe '.create' do
47
+ it 'should create a new top-level resource' do
48
+ mainframes = double 'Api'
49
+ Api.stub_chain(:new, :mainframes) { mainframes }
50
+ expect(mainframes).to receive(:create).with(foo: 'bar')
51
+ Api::Mainframe.create(foo: 'bar')
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,11 @@
1
+ require 'aptible/resource'
2
+
3
+ class Api < Aptible::Resource::Base
4
+ def namespace
5
+ 'Api'
6
+ end
7
+
8
+ def root_url
9
+ 'https://resource.example.com'
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ require_relative 'api'
2
+
3
+ # rubocop:disable ClassAndModuleChildren
4
+ class Api::Mainframe < Api
5
+ end
@@ -0,0 +1,5 @@
1
+ require_relative 'api'
2
+
3
+ # rubocop:disable ClassAndModuleChildren
4
+ class Api::Token < Api
5
+ end
@@ -0,0 +1,10 @@
1
+ def set_env(*args, &block)
2
+ hash = args.first.is_a?(Hash) ? args.first : Hash[*args]
3
+ old_values = Hash[hash.map { |k, v| [k, ENV[k]] }]
4
+ begin
5
+ hash.each { |k, v| ENV[k] = v }
6
+ yield
7
+ ensure
8
+ old_values.each { |k, v| ENV[k] = v }
9
+ end
10
+ end
@@ -0,0 +1,14 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+
4
+ # Load shared spec files
5
+ Dir["#{File.dirname(__FILE__)}/shared/**/*.rb"].each do |file|
6
+ require file
7
+ end
8
+ # Load spec fixtures
9
+ Dir["#{File.dirname(__FILE__)}/fixtures/**/*.rb"].each do |file|
10
+ require file
11
+ end
12
+
13
+ # Require library up front
14
+ require 'aptible/resource'
metadata ADDED
@@ -0,0 +1,225 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: aptible-resource
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Frank Macreery
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-04-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: uri_template
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 0.5.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 0.5.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: faraday
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: 0.8.6
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: 0.8.6
41
+ - !ruby/object:Gem::Dependency
42
+ name: json
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: fridge
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: activesupport
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: bundler
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: '1.6'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: '1.6'
97
+ - !ruby/object:Gem::Dependency
98
+ name: aptible-tasks
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rake
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rspec
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ~>
130
+ - !ruby/object:Gem::Version
131
+ version: '2.0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ~>
137
+ - !ruby/object:Gem::Version
138
+ version: '2.0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: pry
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - '>='
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - '>='
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ description: Foundation classes for Aptible resource server gems
154
+ email:
155
+ - frank@macreery.com
156
+ executables: []
157
+ extensions: []
158
+ extra_rdoc_files: []
159
+ files:
160
+ - .gitignore
161
+ - .rspec
162
+ - .rubocop.yml
163
+ - .travis.yml
164
+ - Gemfile
165
+ - LICENSE.md
166
+ - README.md
167
+ - Rakefile
168
+ - aptible-resource.gemspec
169
+ - lib/aptible/resource.rb
170
+ - lib/aptible/resource/adapter.rb
171
+ - lib/aptible/resource/base.rb
172
+ - lib/aptible/resource/model.rb
173
+ - lib/aptible/resource/token.rb
174
+ - lib/aptible/resource/version.rb
175
+ - lib/hyper_resource.rb
176
+ - lib/hyper_resource/adapter.rb
177
+ - lib/hyper_resource/adapter/hal_json.rb
178
+ - lib/hyper_resource/attributes.rb
179
+ - lib/hyper_resource/exceptions.rb
180
+ - lib/hyper_resource/link.rb
181
+ - lib/hyper_resource/links.rb
182
+ - lib/hyper_resource/modules/http.rb
183
+ - lib/hyper_resource/modules/internal_attributes.rb
184
+ - lib/hyper_resource/objects.rb
185
+ - lib/hyper_resource/response.rb
186
+ - lib/hyper_resource/version.rb
187
+ - spec/aptible/resource/base_spec.rb
188
+ - spec/aptible/resource/model_spec.rb
189
+ - spec/fixtures/api.rb
190
+ - spec/fixtures/mainframe.rb
191
+ - spec/fixtures/token.rb
192
+ - spec/shared/set_env.rb
193
+ - spec/spec_helper.rb
194
+ homepage: https://github.com/aptible/aptible-resource
195
+ licenses:
196
+ - MIT
197
+ metadata: {}
198
+ post_install_message:
199
+ rdoc_options: []
200
+ require_paths:
201
+ - lib
202
+ required_ruby_version: !ruby/object:Gem::Requirement
203
+ requirements:
204
+ - - '>='
205
+ - !ruby/object:Gem::Version
206
+ version: '0'
207
+ required_rubygems_version: !ruby/object:Gem::Requirement
208
+ requirements:
209
+ - - '>='
210
+ - !ruby/object:Gem::Version
211
+ version: '0'
212
+ requirements: []
213
+ rubyforge_project:
214
+ rubygems_version: 2.2.2
215
+ signing_key:
216
+ specification_version: 4
217
+ summary: Foundation classes for Aptible resource server gems
218
+ test_files:
219
+ - spec/aptible/resource/base_spec.rb
220
+ - spec/aptible/resource/model_spec.rb
221
+ - spec/fixtures/api.rb
222
+ - spec/fixtures/mainframe.rb
223
+ - spec/fixtures/token.rb
224
+ - spec/shared/set_env.rb
225
+ - spec/spec_helper.rb