garage_client 2.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.rspec +1 -0
- data/CHANGELOG.md +40 -0
- data/Gemfile +8 -0
- data/Guardfile +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +196 -0
- data/Rakefile +8 -0
- data/garage_client.gemspec +36 -0
- data/gemfiles/Gemfile.faraday-0.8.x +4 -0
- data/lib/garage_client.rb +33 -0
- data/lib/garage_client/cachers/base.rb +44 -0
- data/lib/garage_client/client.rb +93 -0
- data/lib/garage_client/configuration.rb +51 -0
- data/lib/garage_client/error.rb +37 -0
- data/lib/garage_client/request.rb +38 -0
- data/lib/garage_client/request/json_encoded.rb +59 -0
- data/lib/garage_client/resource.rb +63 -0
- data/lib/garage_client/response.rb +123 -0
- data/lib/garage_client/response/cacheable.rb +27 -0
- data/lib/garage_client/response/raise_http_exception.rb +34 -0
- data/lib/garage_client/version.rb +3 -0
- data/spec/features/configuration_spec.rb +46 -0
- data/spec/fixtures/example.yaml +56 -0
- data/spec/fixtures/examples.yaml +60 -0
- data/spec/fixtures/examples_dictionary.yaml +60 -0
- data/spec/fixtures/examples_without_pagination.yaml +58 -0
- data/spec/garage_client/cacher_spec.rb +55 -0
- data/spec/garage_client/client_spec.rb +228 -0
- data/spec/garage_client/configuration_spec.rb +106 -0
- data/spec/garage_client/error_spec.rb +37 -0
- data/spec/garage_client/request/json_encoded_spec.rb +66 -0
- data/spec/garage_client/resource_spec.rb +102 -0
- data/spec/garage_client/response_spec.rb +450 -0
- data/spec/garage_client_spec.rb +48 -0
- data/spec/spec_helper.rb +56 -0
- metadata +275 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 648321b65499a513c8305e6aac962afb10bf99f6
|
4
|
+
data.tar.gz: 17c99e87555fadc63de66ac384d09a354feeb00b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: dc3e8ea2288e52f6ec2e9d9ef1b9f92318478ea543852cf77706ca53665f20d5d63e6445d88496ad0a415733772241addb8a67ffc4529e54415883ccab20e6d4
|
7
|
+
data.tar.gz: 57c200a989fc68dcd096ced3dc853ca92eb4d03246e2d26afec236c60fd3d06332d284ed642723b8f3e396b3f6fd643f15c0e0c105ba275579009ea347d006a6
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
## 2.1.0
|
2
|
+
- Access token is now embedded in authorization header as a bearer token, instead of embedding in query parameter, to avoid logging and exposing access token value.
|
3
|
+
Before: access token is embedded in both query parameter (`?access_token=XXX`) and in authorization header (`Authorization: Token token="XXX"`).
|
4
|
+
After: access tok is embedded in authorization header as a bearer token (`Authorization: Bearer XXX`).
|
5
|
+
|
6
|
+
## 2.0.0
|
7
|
+
- Remove `user_agent` configuration, use `headers` option instead.
|
8
|
+
|
9
|
+
## 1.3.0
|
10
|
+
- Provide a convenient way to cache HTTP response
|
11
|
+
|
12
|
+
## 1.2.4
|
13
|
+
- Raise GarageClient::InvalidResponseType when receives invalid response (e.g. String)
|
14
|
+
|
15
|
+
## 1.2.3
|
16
|
+
- Fixed response.respond_to?(:name)
|
17
|
+
|
18
|
+
## 1.2.2
|
19
|
+
- GarageClient::Response supports Link header parsing
|
20
|
+
|
21
|
+
## 1.2.1
|
22
|
+
- Set Content-Type with multipart/form-data when multipart params are detected
|
23
|
+
|
24
|
+
## 1.2.0
|
25
|
+
- `:headers` option will overwrite the entire headers
|
26
|
+
- `:default_headers` will be deprecated. Please use `:headers`
|
27
|
+
- `Garage.version` was deprecated. Please use `Garage::VERSION`
|
28
|
+
- `Garage.configuration` was added to configure settings
|
29
|
+
|
30
|
+
## 1.1.2
|
31
|
+
- Remove needless empty module clause (7f5e13)
|
32
|
+
- Change gemspec dependency (`hashie ~> 1.2.0` to `hashie >= 1.2.0`) (632ea1)
|
33
|
+
|
34
|
+
## 1.1.1
|
35
|
+
- GarageClient::Error accepts no argument initialization
|
36
|
+
|
37
|
+
## 1.1.0
|
38
|
+
- Add ``:default_headers`` option
|
39
|
+
- Verbose exception message
|
40
|
+
- Resource#links does not raise error when _links is not existed
|
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Cookpad Inc.
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,196 @@
|
|
1
|
+
# GarageClient
|
2
|
+
GarageClient is a simple Ruby library to provide a primitive client interface to the Garage application API.
|
3
|
+
|
4
|
+
## Install
|
5
|
+
Install from rake command:
|
6
|
+
|
7
|
+
```
|
8
|
+
$ bundle install
|
9
|
+
$ rake install
|
10
|
+
```
|
11
|
+
|
12
|
+
or modify Gemfile in your application and invoke `bundle install`.
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
# Gemfile
|
16
|
+
gem "garage_client"
|
17
|
+
```
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
Here are quick examples.
|
21
|
+
|
22
|
+
### Client initialization
|
23
|
+
```ruby
|
24
|
+
require "garage_client"
|
25
|
+
|
26
|
+
# First, you have to create a GarageClient::Client with an access token.
|
27
|
+
# You can get `YOUR_ACCESS_TOKEN` with OAuth 2.0 flow.
|
28
|
+
client = GarageClient::Client.new(access_token: YOUR_ACCESS_TOKEN)
|
29
|
+
```
|
30
|
+
|
31
|
+
### Read from Garage application
|
32
|
+
```ruby
|
33
|
+
# GET https://garage.example.com/v1/recipes
|
34
|
+
client.get("/recipes")
|
35
|
+
|
36
|
+
# GET https://garage.example.com/v1/recipes?fields=id,name,ingredients
|
37
|
+
client.get("/recipes", fields: "id,name,ingredients")
|
38
|
+
|
39
|
+
# GET https://garage.example.com/v1/me
|
40
|
+
user = client.get("/me")
|
41
|
+
|
42
|
+
# GET https://garage.example.com/v1/users/:user_id/recipes?fields=__default__,user[id,name]
|
43
|
+
client.get("/users/#{user.id}/recipes", fields: "__default__,user[id,name]")
|
44
|
+
```
|
45
|
+
|
46
|
+
### Write to Garage application
|
47
|
+
```ruby
|
48
|
+
# POST https://garage.example.com/v1/suggestions
|
49
|
+
client.post("/suggestions", message: "suggestion message")
|
50
|
+
|
51
|
+
# POST https://garage.example.com/v1/users/:user_id/bookmark_tags with JSON {"name":"tag name"}
|
52
|
+
bookmark_tag = client.post("/users/#{user.id}/bookmark_tags", name: "tag name")
|
53
|
+
|
54
|
+
# PUT https://garage.example.com/v1/bookmark_tags/:id with JSON {"name":"new tag name"}
|
55
|
+
client.put("/bookmark_tags/#{bookmark_tag.id}", name: "new tag name")
|
56
|
+
|
57
|
+
# DELETE https://garage.example.com/v1/bookmark_tags/:id
|
58
|
+
client.delete("/bookmark_tags/#{bookmark_tag.id}")
|
59
|
+
```
|
60
|
+
|
61
|
+
### Response
|
62
|
+
```ruby
|
63
|
+
# `.get` method returns a GarageClient::Response of a resource.
|
64
|
+
user = client.get("/me")
|
65
|
+
user.id
|
66
|
+
user.url
|
67
|
+
user.name
|
68
|
+
|
69
|
+
# `.get` method also returns a GarageClient::Response of an array of resources.
|
70
|
+
# In this case, the response object can respond to `.total_count` method.
|
71
|
+
recipes = client.get("/recipes")
|
72
|
+
recipes.total_count
|
73
|
+
recipes[0].id
|
74
|
+
recipes[0].name
|
75
|
+
|
76
|
+
# While Garage application API returns all default properties, some additional properties are not included in them.
|
77
|
+
# You can specify the returned properties by `?fields=...` URI query parameters.
|
78
|
+
recipes = client.get("/recipes", fields: "__default__,user")
|
79
|
+
recipes[0].id
|
80
|
+
recipes[0].name
|
81
|
+
recipes[0].user.id
|
82
|
+
recipes[0].user.url
|
83
|
+
recipes[0].user.name
|
84
|
+
|
85
|
+
# `.post` method also returns a GarageClient::Response of the newly created resource.
|
86
|
+
suggestion = client.post("/suggestions", message: "suggestion message")
|
87
|
+
suggestion.message
|
88
|
+
```
|
89
|
+
|
90
|
+
## Configuration
|
91
|
+
There are the following options:
|
92
|
+
|
93
|
+
- `adapter` - faraday adapter for http client (default: `:net_http`)
|
94
|
+
- `cacher` - take a cacher class in which caching logic is defined (default: nil)
|
95
|
+
- `headers` - default http headers (default: `{ "Accept" => "application/json", "User-Agent" => "garage_client #{VERSION}" }`)
|
96
|
+
- `endpoint` - Garage application API endpoint (default: nil)
|
97
|
+
- `path_prefix` - API path prefix (default: `'/v1'`)
|
98
|
+
- `verbose` - Enable verbose http log (default: `false`)
|
99
|
+
|
100
|
+
You can configure the global settings:
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
GarageClient.configure do |c|
|
104
|
+
c.endpoint = "http://localhost:3000"
|
105
|
+
c.verbose = true
|
106
|
+
end
|
107
|
+
```
|
108
|
+
|
109
|
+
or each GarageClient::Client settings:
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
client = GarageClient::Client.new(
|
113
|
+
adapter: :test,
|
114
|
+
headers: { "Host" => "garage.example.com" },
|
115
|
+
endpoint: "http://localhost:3000",
|
116
|
+
path_prefix: "/v2",
|
117
|
+
verbose: true,
|
118
|
+
)
|
119
|
+
```
|
120
|
+
|
121
|
+
## Exceptions
|
122
|
+
GarageClient raises one of the following exceptions upon an error.
|
123
|
+
Make sure to always look out for these in your code.
|
124
|
+
|
125
|
+
```ruby
|
126
|
+
GarageClient::Unauthorized
|
127
|
+
GarageClient::Forbidden
|
128
|
+
GarageClient::NotFound
|
129
|
+
GarageClient::NotAcceptable
|
130
|
+
GarageClient::Conflict
|
131
|
+
GarageClient::UnsupportedMediaType
|
132
|
+
GarageClient::UnprocessableEntity
|
133
|
+
GarageClient::InternalServerError
|
134
|
+
GarageClient::ServiceUnavailable
|
135
|
+
```
|
136
|
+
|
137
|
+
## Utility
|
138
|
+
`.properties` returns a list of properties of the resource.
|
139
|
+
|
140
|
+
```ruby
|
141
|
+
user = client.get("/me")
|
142
|
+
user.properties #=> [:id, :url, :name, :_links]
|
143
|
+
```
|
144
|
+
|
145
|
+
`.links` returns a list of link names related to the resource.
|
146
|
+
|
147
|
+
```ruby
|
148
|
+
user = client.get("/me")
|
149
|
+
user.properties #=> [:self, :bookmarks, :recipes, ...]
|
150
|
+
user.links.recipes #=> "https://garage.example.com/v1/users/:user_id/recipes"
|
151
|
+
```
|
152
|
+
|
153
|
+
## Caching
|
154
|
+
Define a cacher class with your custom caching logic to let it cache response, inheriting GarageClient::Cachers::Base.
|
155
|
+
It must override `read_from_cache?`, `written_to_cache?`, `key`, and `store` to compose your caching logic.
|
156
|
+
|
157
|
+
```ruby
|
158
|
+
class MyCacher < GarageClient::Cachers::Base
|
159
|
+
private
|
160
|
+
|
161
|
+
def read_from_cache?
|
162
|
+
has_get_method? && has_cached_path?
|
163
|
+
end
|
164
|
+
|
165
|
+
def written_to_cache?
|
166
|
+
read_from_cache?
|
167
|
+
end
|
168
|
+
|
169
|
+
def key
|
170
|
+
@env[:url].to_s
|
171
|
+
end
|
172
|
+
|
173
|
+
def store
|
174
|
+
Rails.cache
|
175
|
+
end
|
176
|
+
|
177
|
+
def options
|
178
|
+
{ expires_in: 5.minutes }
|
179
|
+
end
|
180
|
+
|
181
|
+
def has_get_method?
|
182
|
+
@env[:method] == :get
|
183
|
+
end
|
184
|
+
|
185
|
+
def has_cached_path?
|
186
|
+
case @env[:url].path
|
187
|
+
when %r<^/v1/searches>
|
188
|
+
true
|
189
|
+
when %r<^/v1/recipes/\d+>
|
190
|
+
true
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
GarageClient::Client.new(cacher: MyCacher)
|
196
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.unshift File.expand_path("../lib", __FILE__)
|
3
|
+
require 'garage_client/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.version = GarageClient::VERSION
|
7
|
+
s.name = "garage_client"
|
8
|
+
s.homepage = "https://github.com/cookpad/garage_client"
|
9
|
+
s.summary = "Ruby client library for the Garage API"
|
10
|
+
s.description = s.summary
|
11
|
+
|
12
|
+
s.files = `git ls-files`.split($\)
|
13
|
+
s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
14
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
15
|
+
s.require_paths = ['lib']
|
16
|
+
s.authors = ['Cookpad Inc.']
|
17
|
+
s.email = ['kaihatsu@cookpad.com']
|
18
|
+
|
19
|
+
s.add_dependency 'activesupport', '> 3.2.0'
|
20
|
+
s.add_dependency 'faraday', '>= 0.8.0'
|
21
|
+
s.add_dependency 'faraday_middleware'
|
22
|
+
s.add_dependency 'hashie', '>= 1.2.0'
|
23
|
+
s.add_dependency 'link_header'
|
24
|
+
s.add_dependency 'mime-types', '~> 1.16'
|
25
|
+
|
26
|
+
s.add_dependency 'system_timer' if RUBY_VERSION < '1.9'
|
27
|
+
|
28
|
+
s.add_development_dependency "rake", ">= 0.9.2"
|
29
|
+
s.add_development_dependency "rspec"
|
30
|
+
s.add_development_dependency "json"
|
31
|
+
s.add_development_dependency "guard-rspec"
|
32
|
+
s.add_development_dependency "webmock"
|
33
|
+
s.add_development_dependency "pry"
|
34
|
+
# Until bug fixed: https://github.com/colszowka/simplecov/issues/281
|
35
|
+
s.add_development_dependency "simplecov", "~> 0.7.1"
|
36
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'active_support/all'
|
2
|
+
require 'faraday'
|
3
|
+
require 'faraday_middleware'
|
4
|
+
|
5
|
+
require 'garage_client/version'
|
6
|
+
require 'garage_client/cachers/base'
|
7
|
+
require 'garage_client/configuration'
|
8
|
+
require 'garage_client/error'
|
9
|
+
require 'garage_client/request'
|
10
|
+
require 'garage_client/request/json_encoded'
|
11
|
+
require 'garage_client/response'
|
12
|
+
require 'garage_client/response/cacheable'
|
13
|
+
require 'garage_client/response/raise_http_exception'
|
14
|
+
require 'garage_client/resource'
|
15
|
+
require 'garage_client/client'
|
16
|
+
|
17
|
+
module GarageClient
|
18
|
+
class << self
|
19
|
+
GarageClient::Configuration.keys.each do |key|
|
20
|
+
delegate key, "#{key}=", to: :configuration
|
21
|
+
end
|
22
|
+
|
23
|
+
delegate 'default_headers', 'default_headers=', to: :configuration
|
24
|
+
|
25
|
+
def configuration
|
26
|
+
@configuration ||= GarageClient::Configuration.new
|
27
|
+
end
|
28
|
+
|
29
|
+
def configure(&block)
|
30
|
+
configuration.instance_eval(&block)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# Inherit this abstract class and pass it to garage_client client to cache its responses.
|
2
|
+
module GarageClient
|
3
|
+
module Cachers
|
4
|
+
class Base
|
5
|
+
def initialize(env)
|
6
|
+
@env = env
|
7
|
+
end
|
8
|
+
|
9
|
+
def call
|
10
|
+
response = read_from_cache? && store.read(key, options) || yield
|
11
|
+
store.write(key, response, options) if written_to_cache?
|
12
|
+
response
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
# Return boolean to tell if we need to cache the response or not.
|
18
|
+
def allowed_to_read_cache?
|
19
|
+
raise NotImplementedError, "You must implement #{self.class}##{__method__}"
|
20
|
+
end
|
21
|
+
|
22
|
+
# Return boolean to tell if we can try to check cache or not.
|
23
|
+
def allowed_to_write_cache?
|
24
|
+
raise NotImplementedError, "You must implement #{self.class}##{__method__}"
|
25
|
+
end
|
26
|
+
|
27
|
+
# Return string to cache key to store a given HTTP response.
|
28
|
+
def key
|
29
|
+
raise NotImplementedError, "You must implement #{self.class}##{__method__}"
|
30
|
+
end
|
31
|
+
|
32
|
+
# Return store-object to get or write response (e.g. Rails.cache).
|
33
|
+
# This store-object must respond to `fetch(key, options)` method signature.
|
34
|
+
def store
|
35
|
+
raise NotImplementedError, "You must implement #{self.class}##{__method__}"
|
36
|
+
end
|
37
|
+
|
38
|
+
# Return hash table to be used as store's options.
|
39
|
+
def options
|
40
|
+
{}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module GarageClient
|
2
|
+
class Client
|
3
|
+
include GarageClient::Request
|
4
|
+
|
5
|
+
def self.property(key)
|
6
|
+
define_method(key) do
|
7
|
+
options.fetch(key, GarageClient.configuration.send(key))
|
8
|
+
end
|
9
|
+
|
10
|
+
define_method("#{key}=") do |value|
|
11
|
+
options[key] = value
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :options
|
16
|
+
|
17
|
+
property :adapter
|
18
|
+
property :cacher
|
19
|
+
property :endpoint
|
20
|
+
property :path_prefix
|
21
|
+
property :verbose
|
22
|
+
|
23
|
+
def initialize(options = {})
|
24
|
+
require_necessaries(options)
|
25
|
+
@options = options
|
26
|
+
end
|
27
|
+
|
28
|
+
def headers
|
29
|
+
@headers ||= GarageClient.configuration.headers.merge(given_headers.stringify_keys)
|
30
|
+
end
|
31
|
+
alias :default_headers :headers
|
32
|
+
|
33
|
+
def headers=(value)
|
34
|
+
@headers = value
|
35
|
+
end
|
36
|
+
alias :default_headers= :headers=
|
37
|
+
|
38
|
+
def access_token
|
39
|
+
options[:access_token]
|
40
|
+
end
|
41
|
+
|
42
|
+
def access_token=(value)
|
43
|
+
options[:access_token] = value
|
44
|
+
end
|
45
|
+
|
46
|
+
def me(params = {}, options = {})
|
47
|
+
get('/me', params, options)
|
48
|
+
end
|
49
|
+
|
50
|
+
def conn
|
51
|
+
@conn ||= connection
|
52
|
+
end
|
53
|
+
|
54
|
+
def apply_auth_middleware(faraday_builder)
|
55
|
+
faraday_builder.authorization :Bearer, access_token if access_token
|
56
|
+
end
|
57
|
+
|
58
|
+
def connection
|
59
|
+
Faraday.new(headers: headers, url: endpoint) do |builder|
|
60
|
+
# Response Middlewares
|
61
|
+
builder.use Faraday::Response::Logger if verbose
|
62
|
+
builder.use FaradayMiddleware::Mashify
|
63
|
+
builder.use Faraday::Response::ParseJson, :content_type => /\bjson$/
|
64
|
+
builder.use GarageClient::Response::Cacheable, cacher: cacher if cacher
|
65
|
+
builder.use GarageClient::Response::RaiseHttpException
|
66
|
+
|
67
|
+
# Request Middlewares
|
68
|
+
builder.use Faraday::Request::Multipart
|
69
|
+
builder.use GarageClient::Request::JsonEncoded
|
70
|
+
|
71
|
+
# Low-level Middlewares
|
72
|
+
apply_auth_middleware builder
|
73
|
+
builder.adapter(*adapter)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def given_headers
|
80
|
+
options[:headers] || options[:default_headers] || {}
|
81
|
+
end
|
82
|
+
|
83
|
+
def require_necessaries(options)
|
84
|
+
if !options[:endpoint] && !default_options.endpoint
|
85
|
+
raise "Missing endpoint configuration"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def default_options
|
90
|
+
GarageClient.configuration
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|