braque 0.1.4 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +36 -5
- data/lib/braque/model.rb +10 -5
- data/lib/braque/version.rb +1 -1
- data/spec/braque/client_headers_spec.rb +19 -3
- data/spec/braque/helpers/hypermedia_responses_helper_spec.rb +1 -1
- data/spec/braque/model_spec.rb +17 -17
- data/spec/braque/multiple_model_spec.rb +5 -5
- data/spec/braque/subclassed_model_spec.rb +7 -7
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a4c1ebc21906dfa95cf2c91d86d5280cb674798e
|
4
|
+
data.tar.gz: 21240b5b4080d20712490a9be9f2f8785e2a7fd3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e75f45268a9392bbaf483483d779e9e7f25467cf9bb18f70cd7da537e76cb10c176be63c82d87f8e80863be1d442a5b013d532ea87f9de96ea3bbcee0517f54c
|
7
|
+
data.tar.gz: 50a7a00106e3e8c6b5b723aee03ec9f3060ac619442d2a891de756a67d2ce6cdbd66cd6f8f39e2e6c822676837f3edd97bd8b686487cf823fcdd709350b01d03
|
data/README.md
CHANGED
@@ -2,19 +2,18 @@
|
|
2
2
|
|
3
3
|
Braque aims to provide a simple and familiar interface for setting up clients to interact with [Hypermedia (hal+json)](http://stateless.co/hal_specification.html) API services. It is a lightweight wrapper around [Hyperclient](https://github.com/codegram/hyperclient) and [ActiveAttr](https://github.com/cgriego/active_attr).
|
4
4
|
|
5
|
-
Braque is an early-stage and exploratory project.
|
5
|
+
Braque is an early-stage and exploratory project. That said, at [Artsy](https://www.artsy.net), we've used Braque to consume [Gris](https://github.com/artsy/gris) APIs with great benefit.
|
6
6
|
|
7
7
|
[![Build Status](https://semaphoreci.com/api/v1/projects/c557a59e-1c1a-4719-a41a-6462a424ddfa/381676/badge.png)](https://semaphoreci.com/dylanfareed/braque)
|
8
8
|
|
9
9
|
### Model setup
|
10
10
|
|
11
|
-
```Braque::Model``` is ActiveSupport concern. You can use Braque::Model to map a remote resource to a class in your application. Do so by including Braque::Model in the class, defining the API service's root url
|
11
|
+
```Braque::Model``` is ActiveSupport concern. You can use Braque::Model to map a remote resource to a class in your application. Do so by including Braque::Model in the class, defining the API service's root url, and listing attributes which we expect to receive from the API.
|
12
12
|
|
13
13
|
```ruby
|
14
14
|
class Article
|
15
15
|
include Braque::Model
|
16
|
-
self.api_root = Rails.application.config_for(:
|
17
|
-
self.api_token = Rails.application.config_for(:article_service)['token']
|
16
|
+
self.api_root = Rails.application.config_for(:articles_service)['url']
|
18
17
|
|
19
18
|
attribute :id
|
20
19
|
attribute :title
|
@@ -25,7 +24,39 @@ class Article
|
|
25
24
|
end
|
26
25
|
```
|
27
26
|
|
28
|
-
|
27
|
+
### Credentials
|
28
|
+
|
29
|
+
```Braque::Model``` also supports multiple API authentication strategies. Defining `http_authorization_header` or `accept_header` with the model will pass those credentials to the provider API with each request.
|
30
|
+
|
31
|
+
For example, `http_authorization_header` credentials defined here are added to the request's `Http-Authorization` headers.
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
class Article
|
35
|
+
include Braque::Model
|
36
|
+
self.api_root = Rails.application.config_for(:articles_service)['url']
|
37
|
+
self.http_authorization_header = Rails.application.config_for(:articles_service)['token']
|
38
|
+
|
39
|
+
attribute :id
|
40
|
+
attribute :title
|
41
|
+
end
|
42
|
+
```
|
43
|
+
|
44
|
+
Defining an `accept_header` credential will replace Hyperclient's default `Accept` header with the value you provide.
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
class Article
|
48
|
+
include Braque::Model
|
49
|
+
self.api_root = Rails.application.config_for(:articles_service)['url']
|
50
|
+
self.accept_header = Rails.application.config_for(:articles_service)['accept_header']
|
51
|
+
|
52
|
+
attribute :id
|
53
|
+
attribute :title
|
54
|
+
end
|
55
|
+
```
|
56
|
+
|
57
|
+
### Controllers
|
58
|
+
|
59
|
+
In a Rails app, once you've set up your model, you can use the following familiar syntax to query the remote API:
|
29
60
|
|
30
61
|
```ruby
|
31
62
|
class ArticlesController < ApplicationController
|
data/lib/braque/model.rb
CHANGED
@@ -4,9 +4,12 @@ module Braque
|
|
4
4
|
include ::ActiveAttr::Model
|
5
5
|
|
6
6
|
included do
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
# NOTE: This adds class attributes to Braque::Model that will be
|
8
|
+
# used to set up Hyperclient in the client method.
|
9
|
+
#
|
10
|
+
[:api_root, :accept_header, :authorization_header, :http_authorization_header].each do |sym|
|
11
|
+
class_attribute sym
|
12
|
+
end
|
10
13
|
|
11
14
|
# NOTE: This assumes that the related API uses an ID attribute to
|
12
15
|
# define the resource. Rails will use this field to construct
|
@@ -31,7 +34,8 @@ module Braque
|
|
31
34
|
end
|
32
35
|
|
33
36
|
def save(params = {})
|
34
|
-
response = self.class.client.method(self.class.instance_method_name).call(resource_find_options)
|
37
|
+
response = self.class.client.method(self.class.instance_method_name).call(resource_find_options)
|
38
|
+
._patch("#{self.class.instance_method_name}" => params)
|
35
39
|
self.class.new response
|
36
40
|
end
|
37
41
|
|
@@ -87,7 +91,8 @@ module Braque
|
|
87
91
|
|
88
92
|
def client
|
89
93
|
Hyperclient.new(api_root) do |client|
|
90
|
-
client.headers['Http-Authorization'] =
|
94
|
+
client.headers['Http-Authorization'] = http_authorization_header if http_authorization_header
|
95
|
+
client.headers['Authorization'] = authorization_header if authorization_header
|
91
96
|
client.headers['Accept'] = accept_header if accept_header
|
92
97
|
end
|
93
98
|
end
|
data/lib/braque/version.rb
CHANGED
@@ -11,14 +11,14 @@ RSpec.describe 'Hyperclient header configuration' do
|
|
11
11
|
class Mantle
|
12
12
|
include ::Braque::Model
|
13
13
|
self.api_root = 'http://localhost:9292'
|
14
|
-
self.
|
14
|
+
self.http_authorization_header = 'replace-me'
|
15
15
|
end
|
16
16
|
|
17
|
-
it 'passes
|
17
|
+
it 'passes http_authorization_header via Http-Authorization headers with requests' do
|
18
18
|
Mantle.client._get
|
19
19
|
expect(
|
20
20
|
root_request
|
21
|
-
.with(headers: { 'Http-Authorization' => Mantle.
|
21
|
+
.with(headers: { 'Http-Authorization' => Mantle.http_authorization_header })
|
22
22
|
).to have_been_requested
|
23
23
|
end
|
24
24
|
|
@@ -46,4 +46,20 @@ RSpec.describe 'Hyperclient header configuration' do
|
|
46
46
|
).to have_been_requested
|
47
47
|
end
|
48
48
|
end
|
49
|
+
|
50
|
+
context 'with a Braque::Model class that defines an authorization header' do
|
51
|
+
class Lithoshpere
|
52
|
+
include ::Braque::Model
|
53
|
+
self.api_root = 'http://localhost:9292'
|
54
|
+
self.authorization_header = 'Farallon Plate'
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'includes correct Authorization header with request headers' do
|
58
|
+
Lithoshpere.client._get
|
59
|
+
expect(
|
60
|
+
root_request
|
61
|
+
.with(headers: { 'Authorization' => Lithoshpere.authorization_header })
|
62
|
+
).to have_been_requested
|
63
|
+
end
|
64
|
+
end
|
49
65
|
end
|
@@ -11,7 +11,7 @@ RSpec.describe Braque::Helpers::HypermediaResponsesHelper do
|
|
11
11
|
class Article
|
12
12
|
include ::Braque::Model
|
13
13
|
self.api_root = 'http://localhost:9292'
|
14
|
-
self.
|
14
|
+
self.http_authorization_header = 'replace-me'
|
15
15
|
attribute :id
|
16
16
|
attribute :title
|
17
17
|
attribute :key
|
data/spec/braque/model_spec.rb
CHANGED
@@ -5,7 +5,7 @@ RSpec.describe Braque::Model, type: :model do
|
|
5
5
|
class Breeze
|
6
6
|
include ::Braque::Model
|
7
7
|
self.api_root = 'http://localhost:9292'
|
8
|
-
self.
|
8
|
+
self.http_authorization_header = 'replace-me'
|
9
9
|
self.accept_header = 'application/vnd.el-nino-v1+json'
|
10
10
|
attribute :id
|
11
11
|
attribute :title
|
@@ -20,14 +20,14 @@ RSpec.describe Braque::Model, type: :model do
|
|
20
20
|
|
21
21
|
let(:root_request) do
|
22
22
|
WebMock.stub_request(:get, "#{Breeze.api_root}/")
|
23
|
-
.with(headers: { 'Http-Authorization' => Breeze.
|
23
|
+
.with(headers: { 'Http-Authorization' => Breeze.http_authorization_header })
|
24
24
|
.with(headers: { 'Accept' => Breeze.accept_header })
|
25
25
|
.to_return(status: 200, body: root_response)
|
26
26
|
end
|
27
27
|
|
28
28
|
let(:root_request_with_token_resource_path) do
|
29
29
|
WebMock.stub_request(:get, "#{Breeze.api_root}/")
|
30
|
-
.with(headers: { 'Http-Authorization' => Breeze.
|
30
|
+
.with(headers: { 'Http-Authorization' => Breeze.http_authorization_header })
|
31
31
|
.with(headers: { 'Accept' => Breeze.accept_header })
|
32
32
|
.to_return(status: 200, body: root_response_with_token_resource_path)
|
33
33
|
end
|
@@ -50,7 +50,7 @@ RSpec.describe Braque::Model, type: :model do
|
|
50
50
|
before(:each) do
|
51
51
|
root_request
|
52
52
|
@collection_request = WebMock.stub_request(:get, "#{Breeze.api_root}/breezes")
|
53
|
-
.with(headers: { 'Http-Authorization' => Breeze.
|
53
|
+
.with(headers: { 'Http-Authorization' => Breeze.http_authorization_header })
|
54
54
|
.with(headers: { 'Accept' => Breeze.accept_header })
|
55
55
|
.to_return(status: 200, body: collection_response)
|
56
56
|
@breezes = Breeze.list
|
@@ -80,7 +80,7 @@ RSpec.describe Braque::Model, type: :model do
|
|
80
80
|
before(:each) do
|
81
81
|
root_request
|
82
82
|
@collection_request = WebMock.stub_request(:get, "#{Breeze.api_root}/breezes")
|
83
|
-
.with(headers: { 'Http-Authorization' => Breeze.
|
83
|
+
.with(headers: { 'Http-Authorization' => Breeze.http_authorization_header })
|
84
84
|
.with(headers: { 'Accept' => Breeze.accept_header })
|
85
85
|
.to_return(status: 500)
|
86
86
|
end
|
@@ -96,7 +96,7 @@ RSpec.describe Braque::Model, type: :model do
|
|
96
96
|
before(:each) do
|
97
97
|
root_request
|
98
98
|
@collection_request = WebMock.stub_request(:get, "#{Breeze.api_root}/breezes")
|
99
|
-
.with(headers: { 'Http-Authorization' => Breeze.
|
99
|
+
.with(headers: { 'Http-Authorization' => Breeze.http_authorization_header })
|
100
100
|
.with(headers: { 'Accept' => Breeze.accept_header })
|
101
101
|
.with(query: 'ids%5B0%5D=1&ids%5B1%5D=2')
|
102
102
|
.to_return(status: 200, body: collection_response)
|
@@ -113,7 +113,7 @@ RSpec.describe Braque::Model, type: :model do
|
|
113
113
|
before(:each) do
|
114
114
|
root_request
|
115
115
|
@resource_request = WebMock.stub_request(:get, "#{Breeze.api_root}/breezes/1")
|
116
|
-
.with(headers: { 'Http-Authorization' => Breeze.
|
116
|
+
.with(headers: { 'Http-Authorization' => Breeze.http_authorization_header })
|
117
117
|
.with(headers: { 'Accept' => Breeze.accept_header })
|
118
118
|
.to_return(status: 200, body: resource_response)
|
119
119
|
@breeze = Breeze.find(id: 1)
|
@@ -136,7 +136,7 @@ RSpec.describe Braque::Model, type: :model do
|
|
136
136
|
before(:each) do
|
137
137
|
root_request
|
138
138
|
@resource_request = WebMock.stub_request(:get, "#{Breeze.api_root}/breezes/1")
|
139
|
-
.with(headers: { 'Http-Authorization' => Breeze.
|
139
|
+
.with(headers: { 'Http-Authorization' => Breeze.http_authorization_header })
|
140
140
|
.with(headers: { 'Accept' => Breeze.accept_header })
|
141
141
|
.to_return(status: 500)
|
142
142
|
end
|
@@ -158,7 +158,7 @@ RSpec.describe Braque::Model, type: :model do
|
|
158
158
|
|
159
159
|
root_request_with_token_resource_path
|
160
160
|
@resource_request = WebMock.stub_request(:get, "#{Breeze.api_root}/breezes/1?token=123")
|
161
|
-
.with(headers: { 'Http-Authorization' => Breeze.
|
161
|
+
.with(headers: { 'Http-Authorization' => Breeze.http_authorization_header })
|
162
162
|
.with(headers: { 'Accept' => Breeze.accept_header })
|
163
163
|
.to_return(status: 200, body: resource_response)
|
164
164
|
@breeze = Breeze.find(id: 1, token: 123)
|
@@ -185,7 +185,7 @@ RSpec.describe Braque::Model, type: :model do
|
|
185
185
|
before(:each) do
|
186
186
|
root_request
|
187
187
|
@create_request = WebMock.stub_request(:post, "#{Breeze.api_root}/breezes")
|
188
|
-
.with(headers: { 'Http-Authorization' => Breeze.
|
188
|
+
.with(headers: { 'Http-Authorization' => Breeze.http_authorization_header })
|
189
189
|
.with(headers: { 'Accept' => Breeze.accept_header })
|
190
190
|
.to_return(status: 201, body: resource_response)
|
191
191
|
@params = { title: 'What a nice breeze.' }
|
@@ -210,7 +210,7 @@ RSpec.describe Braque::Model, type: :model do
|
|
210
210
|
before(:each) do
|
211
211
|
root_request
|
212
212
|
@create_request = WebMock.stub_request(:post, "#{Breeze.api_root}/breezes")
|
213
|
-
.with(headers: { 'Http-Authorization' => Breeze.
|
213
|
+
.with(headers: { 'Http-Authorization' => Breeze.http_authorization_header })
|
214
214
|
.with(headers: { 'Accept' => Breeze.accept_header })
|
215
215
|
.to_return(status: 500)
|
216
216
|
end
|
@@ -233,7 +233,7 @@ RSpec.describe Braque::Model, type: :model do
|
|
233
233
|
before(:each) do
|
234
234
|
root_request
|
235
235
|
@save_request = WebMock.stub_request(:patch, "#{Breeze.api_root}/breezes/1")
|
236
|
-
.with(headers: { 'Http-Authorization' => Breeze.
|
236
|
+
.with(headers: { 'Http-Authorization' => Breeze.http_authorization_header })
|
237
237
|
.with(headers: { 'Accept' => Breeze.accept_header })
|
238
238
|
.to_return(status: 200, body: resource_response)
|
239
239
|
@params = { title: 'What a nice breeze.' }
|
@@ -258,7 +258,7 @@ RSpec.describe Braque::Model, type: :model do
|
|
258
258
|
before(:each) do
|
259
259
|
root_request
|
260
260
|
@save_request = WebMock.stub_request(:patch, "#{Breeze.api_root}/breezes/1")
|
261
|
-
.with(headers: { 'Http-Authorization' => Breeze.
|
261
|
+
.with(headers: { 'Http-Authorization' => Breeze.http_authorization_header })
|
262
262
|
.with(headers: { 'Accept' => Breeze.accept_header })
|
263
263
|
.to_return(status: 500)
|
264
264
|
end
|
@@ -281,7 +281,7 @@ RSpec.describe Braque::Model, type: :model do
|
|
281
281
|
|
282
282
|
root_request_with_token_resource_path
|
283
283
|
@save_request = WebMock.stub_request(:patch, "#{Breeze.api_root}/breezes/1?token=123")
|
284
|
-
.with(headers: { 'Http-Authorization' => Breeze.
|
284
|
+
.with(headers: { 'Http-Authorization' => Breeze.http_authorization_header })
|
285
285
|
.with(headers: { 'Accept' => Breeze.accept_header })
|
286
286
|
.to_return(status: 200, body: resource_response)
|
287
287
|
@params = { title: 'What a nice breeze.' }
|
@@ -312,7 +312,7 @@ RSpec.describe Braque::Model, type: :model do
|
|
312
312
|
before(:each) do
|
313
313
|
root_request
|
314
314
|
@destroy_request = WebMock.stub_request(:delete, "#{Breeze.api_root}/breezes/1")
|
315
|
-
.with(headers: { 'Http-Authorization' => Breeze.
|
315
|
+
.with(headers: { 'Http-Authorization' => Breeze.http_authorization_header })
|
316
316
|
.with(headers: { 'Accept' => Breeze.accept_header })
|
317
317
|
.to_return(status: 200)
|
318
318
|
@breeze = Breeze.new(id: 1).destroy
|
@@ -329,7 +329,7 @@ RSpec.describe Braque::Model, type: :model do
|
|
329
329
|
before(:each) do
|
330
330
|
root_request
|
331
331
|
@destroy_request = WebMock.stub_request(:delete, "#{Breeze.api_root}/breezes/1")
|
332
|
-
.with(headers: { 'Http-Authorization' => Breeze.
|
332
|
+
.with(headers: { 'Http-Authorization' => Breeze.http_authorization_header })
|
333
333
|
.with(headers: { 'Accept' => Breeze.accept_header })
|
334
334
|
.to_return(status: 500)
|
335
335
|
end
|
@@ -352,7 +352,7 @@ RSpec.describe Braque::Model, type: :model do
|
|
352
352
|
|
353
353
|
root_request_with_token_resource_path
|
354
354
|
@destroy_request = WebMock.stub_request(:delete, "#{Breeze.api_root}/breezes/1?token=123")
|
355
|
-
.with(headers: { 'Http-Authorization' => Breeze.
|
355
|
+
.with(headers: { 'Http-Authorization' => Breeze.http_authorization_header })
|
356
356
|
.with(headers: { 'Accept' => Breeze.accept_header })
|
357
357
|
.to_return(status: 200)
|
358
358
|
@breeze = Breeze.new(id: 1, token: 123).destroy
|
@@ -6,21 +6,21 @@ RSpec.describe Braque::Model, type: :model do
|
|
6
6
|
class Wind
|
7
7
|
include ::Braque::Model
|
8
8
|
self.api_root = 'http://localhost:9292'
|
9
|
-
self.
|
9
|
+
self.http_authorization_header = 'replace-me'
|
10
10
|
end
|
11
11
|
|
12
12
|
class Tide
|
13
13
|
include ::Braque::Model
|
14
14
|
self.api_root = 'http://localhost:9393'
|
15
|
-
self.
|
15
|
+
self.http_authorization_header = 'do-replace-me-as-well'
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
it 'sets the correct api_root and
|
19
|
+
it 'sets the correct api_root and http_authorization_header for each class' do
|
20
20
|
expect(Tide.api_root).to eq 'http://localhost:9393'
|
21
|
-
expect(Tide.
|
21
|
+
expect(Tide.http_authorization_header).to eq 'do-replace-me-as-well'
|
22
22
|
expect(Wind.api_root).to eq 'http://localhost:9292'
|
23
|
-
expect(Wind.
|
23
|
+
expect(Wind.http_authorization_header).to eq 'replace-me'
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
@@ -6,7 +6,7 @@ RSpec.describe Braque::Model, type: :model do
|
|
6
6
|
class GeologicModel
|
7
7
|
include ::Braque::Model
|
8
8
|
self.api_root = 'http://localhost:9292'
|
9
|
-
self.
|
9
|
+
self.http_authorization_header = 'replace-me'
|
10
10
|
end
|
11
11
|
|
12
12
|
class ContinentalDrift < GeologicModel
|
@@ -14,32 +14,32 @@ RSpec.describe Braque::Model, type: :model do
|
|
14
14
|
|
15
15
|
class Convection < GeologicModel
|
16
16
|
self.api_root = 'http://localhost:9595'
|
17
|
-
self.
|
17
|
+
self.http_authorization_header = 'ok-another-one-to-replace'
|
18
18
|
end
|
19
19
|
|
20
20
|
class SeafloorSpreading
|
21
21
|
include ::Braque::Model
|
22
22
|
self.api_root = 'http://localhost:9393'
|
23
|
-
self.
|
23
|
+
self.http_authorization_header = 'do-replace-me-as-well'
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
27
|
context 'api configuration' do
|
28
28
|
it 'sets the correct api_root and api_token for the base class' do
|
29
29
|
expect(GeologicModel.api_root).to eq 'http://localhost:9292'
|
30
|
-
expect(GeologicModel.
|
30
|
+
expect(GeologicModel.http_authorization_header).to eq 'replace-me'
|
31
31
|
end
|
32
32
|
it 'sets the correct api_root and api_token for a subclassed class' do
|
33
33
|
expect(ContinentalDrift.api_root).to eq 'http://localhost:9292'
|
34
|
-
expect(ContinentalDrift.
|
34
|
+
expect(ContinentalDrift.http_authorization_header).to eq 'replace-me'
|
35
35
|
end
|
36
36
|
it 'sets the correct api_root and api_token for a subclassed class with variable overrides' do
|
37
37
|
expect(Convection.api_root).to eq 'http://localhost:9595'
|
38
|
-
expect(Convection.
|
38
|
+
expect(Convection.http_authorization_header).to eq 'ok-another-one-to-replace'
|
39
39
|
end
|
40
40
|
it 'sets the correct api_root and api_token for a new Braque::Model class' do
|
41
41
|
expect(SeafloorSpreading.api_root).to eq 'http://localhost:9393'
|
42
|
-
expect(SeafloorSpreading.
|
42
|
+
expect(SeafloorSpreading.http_authorization_header).to eq 'do-replace-me-as-well'
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: braque
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dylan Fareed
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-09-
|
11
|
+
date: 2015-09-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: hyperclient
|
@@ -99,7 +99,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
99
99
|
version: '0'
|
100
100
|
requirements: []
|
101
101
|
rubyforge_project:
|
102
|
-
rubygems_version: 2.4.
|
102
|
+
rubygems_version: 2.4.3
|
103
103
|
signing_key:
|
104
104
|
specification_version: 4
|
105
105
|
summary: Braque provides a simple interface for interacting with Hypermedia API services
|