acfs 1.4.0 → 1.5.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +7 -21
- data/acfs.gemspec +4 -8
- data/lib/acfs/adapter/typhoeus.rb +5 -5
- data/lib/acfs/collections/paginatable.rb +2 -2
- data/lib/acfs/errors.rb +32 -12
- data/lib/acfs/location.rb +3 -3
- data/lib/acfs/middleware/json.rb +3 -3
- data/lib/acfs/operation.rb +15 -0
- data/lib/acfs/request.rb +2 -1
- data/lib/acfs/request/callbacks.rb +3 -3
- data/lib/acfs/resource/attributes.rb +2 -0
- data/lib/acfs/resource/persistence.rb +0 -2
- data/lib/acfs/resource/query_methods.rb +1 -1
- data/lib/acfs/service.rb +19 -14
- data/lib/acfs/stub.rb +3 -4
- data/lib/acfs/version.rb +1 -1
- data/spec/acfs/global_spec.rb +2 -2
- data/spec/acfs/middleware/json_spec.rb +1 -1
- data/spec/acfs/resource/attributes/float_spec.rb +1 -1
- data/spec/acfs/resource/attributes_spec.rb +3 -5
- metadata +9 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 53acc88297d3217a5d01db2ce713f935835b05438471fd2b69918029b5480954
|
4
|
+
data.tar.gz: d61a2f4e5014dab37d4e1a857d548df8dfb42afcaba219005556f203ea68da65
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 35f66d3569256b183cb7c78fed7c41f0ce916f41ec081e60696693af8b869d47e797a53474942c4847cefb621e58d3d52ddf629168c63b7b2d558d1db23cf74a
|
7
|
+
data.tar.gz: 5e03be0b16cb469061b55a3c4467a4fa71496925caa086ed5d024ed79aaefdcc568afd970d526c284b08b8db06593f51886d8642f035f78f2ed7f89bd1b8f311
|
data/CHANGELOG.md
CHANGED
@@ -14,6 +14,16 @@
|
|
14
14
|
### Breaks
|
15
15
|
|
16
16
|
|
17
|
+
## 1.5.0 - (2020-06-19)
|
18
|
+
---
|
19
|
+
|
20
|
+
### New
|
21
|
+
* Error classes for more HTTP error responses: `400`, `401`, `403`, `500`, `502`, `503`, `504`.
|
22
|
+
|
23
|
+
### Changes
|
24
|
+
* Replace deprecated MultiJson with core JSON module
|
25
|
+
|
26
|
+
|
17
27
|
## 1.4.0 - (2020-06-12)
|
18
28
|
---
|
19
29
|
|
data/README.md
CHANGED
@@ -10,6 +10,7 @@ Acfs is a library to develop API client libraries for single services within a l
|
|
10
10
|
|
11
11
|
Acfs covers model and service abstraction, convenient query and filter methods, full middleware stack for pre-processing requests and responses on a per service level and automatic request queuing and parallel processing. See Usage for more.
|
12
12
|
|
13
|
+
|
13
14
|
## Installation
|
14
15
|
|
15
16
|
Add this line to your application's Gemfile:
|
@@ -24,6 +25,7 @@ Or install it yourself as:
|
|
24
25
|
|
25
26
|
> gem install acfs
|
26
27
|
|
28
|
+
|
27
29
|
## Usage
|
28
30
|
|
29
31
|
First you need to define your service(s):
|
@@ -145,6 +147,7 @@ Acfs has basic update support using `PUT` requests:
|
|
145
147
|
@user.persisted? # => true
|
146
148
|
```
|
147
149
|
|
150
|
+
|
148
151
|
## Singleton resources
|
149
152
|
|
150
153
|
Singletons can be used in Acfs by creating a new resource which inherits from `SingletonResource`:
|
@@ -183,6 +186,7 @@ my_single = Single.find name: 'Max'
|
|
183
186
|
Acfs.run # sends GET request with param to /single?name=Max
|
184
187
|
```
|
185
188
|
|
189
|
+
|
186
190
|
## Resource Inheritance
|
187
191
|
|
188
192
|
Acfs provides a resource inheritance similar to ActiveRecord Single Table Inheritance. If a
|
@@ -219,6 +223,7 @@ Acfs.run
|
|
219
223
|
@computer[2].class # => Pc
|
220
224
|
```
|
221
225
|
|
226
|
+
|
222
227
|
## Stubbing
|
223
228
|
|
224
229
|
You can stub resources in applications using an Acfs service client:
|
@@ -279,6 +284,7 @@ it 'should find user number one' do
|
|
279
284
|
end
|
280
285
|
```
|
281
286
|
|
287
|
+
|
282
288
|
## Instrumentation
|
283
289
|
|
284
290
|
Acfs supports [instrumentation via active support][1].
|
@@ -296,21 +302,6 @@ Read [official guide][2] to see to to subscribe.
|
|
296
302
|
[1]: http://guides.rubyonrails.org/active_support_instrumentation.html
|
297
303
|
[2]: http://guides.rubyonrails.org/active_support_instrumentation.html#subscribing-to-an-event
|
298
304
|
|
299
|
-
## Roadmap
|
300
|
-
|
301
|
-
* Update
|
302
|
-
* Better new? detection eg. storing ETag from request resources.
|
303
|
-
* Use PATCH for with only changed attributes and `If-Unmodifed-Since`
|
304
|
-
and `If-Match` header fields if resource was surly loaded from service
|
305
|
-
and not created with an id (e.g `User.new id: 5, name: "john"`).
|
306
|
-
* Conflict detection (ETag / If-Unmodified-Since)
|
307
|
-
* High level features
|
308
|
-
* Support for custom mime types on client and server side. (`application/vnd.myservice.user.v2+msgpack`)
|
309
|
-
* Server side components
|
310
|
-
* Reusing model definitions for generating responses?
|
311
|
-
* Rails responders providing REST operations with integrated ETag,
|
312
|
-
Modified Headers, conflict detection, ...
|
313
|
-
* Documentation
|
314
305
|
|
315
306
|
## Contributing
|
316
307
|
|
@@ -322,14 +313,9 @@ Read [official guide][2] to see to to subscribe.
|
|
322
313
|
7. Push to the branch (`git push origin my-new-feature`)
|
323
314
|
8. Create new Pull Request
|
324
315
|
|
325
|
-
## Contributors
|
326
|
-
|
327
|
-
* [Nicolas Fricke](https://github.com/nicolas-fricke)
|
328
|
-
* [Tino Junge](https://github.com/tino-junge)
|
329
|
-
* [Malte Swart](https://github.com/mswart)
|
330
316
|
|
331
317
|
## License
|
332
318
|
|
333
319
|
MIT License
|
334
320
|
|
335
|
-
Copyright (c) 2013 Jan Graichen. MIT license, see LICENSE for more details.
|
321
|
+
Copyright (c) 2013-2020 Jan Graichen. MIT license, see LICENSE for more details.
|
data/acfs.gemspec
CHANGED
@@ -25,15 +25,11 @@ Gem::Specification.new do |spec|
|
|
25
25
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
26
26
|
spec.require_paths = %w[lib]
|
27
27
|
|
28
|
-
spec.add_runtime_dependency 'actionpack', '>=
|
29
|
-
spec.add_runtime_dependency 'activemodel', '>=
|
30
|
-
spec.add_runtime_dependency 'activesupport', '>=
|
31
|
-
spec.add_runtime_dependency 'multi_json'
|
32
|
-
|
33
|
-
# Bundle update w/o version resolves to 0.3.3 ...
|
34
|
-
spec.add_runtime_dependency 'typhoeus', '~> 1.0'
|
35
|
-
|
28
|
+
spec.add_runtime_dependency 'actionpack', '>= 5.2'
|
29
|
+
spec.add_runtime_dependency 'activemodel', '>= 5.2'
|
30
|
+
spec.add_runtime_dependency 'activesupport', '>= 5.2'
|
36
31
|
spec.add_runtime_dependency 'rack'
|
32
|
+
spec.add_runtime_dependency 'typhoeus', '~> 1.0'
|
37
33
|
|
38
34
|
spec.add_development_dependency 'bundler'
|
39
35
|
|
@@ -55,14 +55,14 @@ module Acfs
|
|
55
55
|
request = ::Typhoeus::Request.new(req.url, **@opts.merge(opts))
|
56
56
|
|
57
57
|
request.on_complete do |response|
|
58
|
-
if response.timed_out?
|
59
|
-
|
60
|
-
|
58
|
+
raise ::Acfs::TimeoutError.new(req) if response.timed_out?
|
59
|
+
|
60
|
+
if response.code.zero?
|
61
61
|
# Failed to get HTTP response
|
62
62
|
raise ::Acfs::RequestError.new(req, response.return_message)
|
63
|
-
else
|
64
|
-
req.complete! convert_response(req, response)
|
65
63
|
end
|
64
|
+
|
65
|
+
req.complete! convert_response(req, response)
|
66
66
|
end
|
67
67
|
|
68
68
|
request
|
data/lib/acfs/errors.rb
CHANGED
@@ -26,7 +26,7 @@ module Acfs
|
|
26
26
|
|
27
27
|
class TimeoutError < RequestError
|
28
28
|
def initialize(request)
|
29
|
-
super(request,
|
29
|
+
super(request, 'Timeout reached')
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
@@ -38,13 +38,13 @@ module Acfs
|
|
38
38
|
def initialize(opts = {})
|
39
39
|
@response = opts[:response]
|
40
40
|
|
41
|
-
if response
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
41
|
+
message = if response
|
42
|
+
(opts[:message] ? opts[:message] + ':' : 'Received') +
|
43
|
+
" #{response.code} for #{response.request.method.upcase}" \
|
44
|
+
" #{response.request.url} #{response.request.format}"
|
45
|
+
else
|
46
|
+
opts[:message] || 'Received erroneous response'
|
47
|
+
end
|
48
48
|
|
49
49
|
super opts, message
|
50
50
|
end
|
@@ -67,11 +67,19 @@ module Acfs
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
|
-
#
|
71
|
-
|
72
|
-
|
73
|
-
|
70
|
+
# 400
|
71
|
+
class BadRequest < ErroneousResponse; end
|
72
|
+
|
73
|
+
# 401
|
74
|
+
class Unauthorized < ErroneousResponse; end
|
75
|
+
|
76
|
+
# 403
|
77
|
+
class Forbidden < ErroneousResponse; end
|
74
78
|
|
79
|
+
# 404
|
80
|
+
class ResourceNotFound < ErroneousResponse; end
|
81
|
+
|
82
|
+
# 422
|
75
83
|
class InvalidResource < ErroneousResponse
|
76
84
|
attr_reader :errors, :resource
|
77
85
|
|
@@ -91,6 +99,18 @@ module Acfs
|
|
91
99
|
end
|
92
100
|
end
|
93
101
|
|
102
|
+
# 500
|
103
|
+
class ServerError < ErroneousResponse; end
|
104
|
+
|
105
|
+
# 502
|
106
|
+
class BadGateway < ErroneousResponse; end
|
107
|
+
|
108
|
+
# 503
|
109
|
+
class ServiceUnavailable < ErroneousResponse; end
|
110
|
+
|
111
|
+
# 504
|
112
|
+
class GatewayTimeout < ErroneousResponse; end
|
113
|
+
|
94
114
|
# A ResourceNotLoaded error will be thrown when calling some
|
95
115
|
# modifing methods on not loaded resources as it is usally
|
96
116
|
# unwanted to call e.g. `update_attributes` on a not loaded
|
data/lib/acfs/location.rb
CHANGED
@@ -49,7 +49,7 @@ module Acfs
|
|
49
49
|
def extract_arg(key, hashes)
|
50
50
|
hashes.each_with_index do |hash, index|
|
51
51
|
if hash.key?(key)
|
52
|
-
return (index
|
52
|
+
return (index.zero? ? hash.delete(key) : hash.fetch(key))
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
@@ -72,9 +72,9 @@ module Acfs
|
|
72
72
|
args.fetch(sym) do
|
73
73
|
if args[:raise].nil? || args[:raise]
|
74
74
|
raise ArgumentError.new "URI path argument `#{sym}' missing on `#{self}'. Given: `#{args}.inspect'"
|
75
|
-
else
|
76
|
-
":#{sym}"
|
77
75
|
end
|
76
|
+
|
77
|
+
":#{sym}"
|
78
78
|
end
|
79
79
|
end
|
80
80
|
end
|
data/lib/acfs/middleware/json.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'json'
|
4
4
|
|
5
5
|
module Acfs
|
6
6
|
module Middleware
|
@@ -12,11 +12,11 @@ module Acfs
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def encode(data)
|
15
|
-
::
|
15
|
+
::JSON.dump data
|
16
16
|
end
|
17
17
|
|
18
18
|
def decode(body)
|
19
|
-
::
|
19
|
+
::JSON.load body
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
data/lib/acfs/operation.rb
CHANGED
@@ -8,6 +8,7 @@ module Acfs
|
|
8
8
|
#
|
9
9
|
class Operation
|
10
10
|
attr_reader :action, :params, :resource, :data, :callback, :location, :url
|
11
|
+
|
11
12
|
delegate :service, to: :resource
|
12
13
|
delegate :call, to: :callback
|
13
14
|
|
@@ -71,10 +72,24 @@ module Acfs
|
|
71
72
|
|
72
73
|
def handle_failure(response)
|
73
74
|
case response.code
|
75
|
+
when 400
|
76
|
+
raise ::Acfs::BadRequest.new response: response
|
77
|
+
when 401
|
78
|
+
raise ::Acfs::Unauthorized.new response: response
|
79
|
+
when 403
|
80
|
+
raise ::Acfs::Forbidden.new response: response
|
74
81
|
when 404
|
75
82
|
raise ::Acfs::ResourceNotFound.new response: response
|
76
83
|
when 422
|
77
84
|
raise ::Acfs::InvalidResource.new response: response, errors: response.data.try(:[], 'errors')
|
85
|
+
when 500
|
86
|
+
raise ::Acfs::ServerError.new response: response
|
87
|
+
when 502
|
88
|
+
raise ::Acfs::BadGateway.new response: response
|
89
|
+
when 503
|
90
|
+
raise ::Acfs::ServiceUnavailable.new response: response
|
91
|
+
when 504
|
92
|
+
raise ::Acfs::GatewayTimeout.new response: response
|
78
93
|
else
|
79
94
|
raise ::Acfs::ErroneousResponse.new response: response
|
80
95
|
end
|
data/lib/acfs/request.rb
CHANGED
@@ -11,7 +11,6 @@ module Acfs
|
|
11
11
|
attr_reader :url, :headers, :params, :data, :method, :operation
|
12
12
|
|
13
13
|
include Request::Callbacks
|
14
|
-
|
15
14
|
def initialize(url, options = {}, &block)
|
16
15
|
@url = URI.parse(url.to_s).tap do |_url|
|
17
16
|
@data = options.delete(:data) || nil
|
@@ -20,7 +19,9 @@ module Acfs
|
|
20
19
|
@params = options.delete(:params) || {}
|
21
20
|
@method = options.delete(:method) || :get
|
22
21
|
end.to_s
|
22
|
+
|
23
23
|
@operation = options.delete(:operation) || nil
|
24
|
+
|
24
25
|
on_complete(&block) if block_given?
|
25
26
|
end
|
26
27
|
|
@@ -45,9 +45,9 @@ module Acfs
|
|
45
45
|
private
|
46
46
|
|
47
47
|
def call_callback(res, index)
|
48
|
-
if index
|
49
|
-
|
50
|
-
|
48
|
+
return if index >= callbacks.size
|
49
|
+
|
50
|
+
callbacks[index].call(res, proc {|bres| call_callback bres, index + 1 })
|
51
51
|
end
|
52
52
|
end
|
53
53
|
end
|
@@ -48,9 +48,11 @@ class Acfs::Resource
|
|
48
48
|
# @return [HashWithIndifferentAccess{Symbol => Object}]
|
49
49
|
# Attributes and their values.
|
50
50
|
#
|
51
|
+
# rubocop:disable Naming/MemoizedInstanceVariableName
|
51
52
|
def attributes
|
52
53
|
@_attrs ||= HashWithIndifferentAccess.new
|
53
54
|
end
|
55
|
+
# rubocop:enable Naming/MemoizedInstanceVariableName
|
54
56
|
|
55
57
|
# @api public
|
56
58
|
#
|
data/lib/acfs/service.rb
CHANGED
@@ -40,21 +40,23 @@ module Acfs
|
|
40
40
|
|
41
41
|
action = opts[:action] || :list
|
42
42
|
|
43
|
-
path =
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
43
|
+
path = begin
|
44
|
+
if opts[:path].is_a?(Hash) && opts[:path].key?(action)
|
45
|
+
opts[:path].fetch(action)
|
46
|
+
else
|
47
|
+
path = if opts[:path].is_a?(Hash)
|
48
|
+
opts[:path][:all].to_s
|
49
|
+
else
|
50
|
+
opts[:path].to_s
|
51
|
+
end
|
51
52
|
|
52
|
-
|
53
|
-
|
54
|
-
|
53
|
+
if path.blank?
|
54
|
+
path = (resource_class.name || 'class').pluralize.underscore
|
55
|
+
end
|
55
56
|
|
56
|
-
|
57
|
-
|
57
|
+
resource_class.location_default_path(action, path.strip)
|
58
|
+
end
|
59
|
+
end
|
58
60
|
|
59
61
|
if path.nil?
|
60
62
|
raise ArgumentError.new "Location for `#{action}' explicit disabled by set to nil."
|
@@ -87,7 +89,10 @@ module Acfs
|
|
87
89
|
#
|
88
90
|
def base_url
|
89
91
|
unless (base = Acfs::Configuration.current.locate identity)
|
90
|
-
raise ArgumentError.new
|
92
|
+
raise ArgumentError.new \
|
93
|
+
"#{identity} not configured. Add `locate '" \
|
94
|
+
"#{identity.to_s.underscore}', 'http://service.url/'` " \
|
95
|
+
'to your configuration.'
|
91
96
|
end
|
92
97
|
|
93
98
|
base.to_s
|
data/lib/acfs/stub.rb
CHANGED
@@ -16,7 +16,7 @@ module Acfs
|
|
16
16
|
@opts[:with].stringify_keys! if @opts[:with].is_a? Hash
|
17
17
|
@opts[:return].stringify_keys! if @opts[:return].is_a? Hash
|
18
18
|
|
19
|
-
if @opts[:return].is_a?
|
19
|
+
if @opts[:return].is_a?(Array) # rubocop:disable Style/GuardClause
|
20
20
|
@opts[:return].map! {|h| h.stringify_keys! if h.is_a? Hash }
|
21
21
|
end
|
22
22
|
end
|
@@ -53,9 +53,8 @@ module Acfs
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def called?(count = nil)
|
56
|
-
if count.respond_to?
|
57
|
-
|
58
|
-
end # For `5.times` Enumerators
|
56
|
+
count = count.count if count.respond_to?(:count)
|
57
|
+
|
59
58
|
count.nil? ? calls.any? : calls.size == count
|
60
59
|
end
|
61
60
|
|
data/lib/acfs/version.rb
CHANGED
data/spec/acfs/global_spec.rb
CHANGED
@@ -122,8 +122,8 @@ describe ::Acfs::Global do
|
|
122
122
|
|
123
123
|
describe '#runner' do
|
124
124
|
it 'returns per-thread runner' do
|
125
|
-
runner1 = Thread.new { acfs.runner }
|
126
|
-
runner2 = Thread.new { acfs.runner }
|
125
|
+
runner1 = Thread.new { acfs.runner }.value
|
126
|
+
runner2 = Thread.new { acfs.runner }.value
|
127
127
|
|
128
128
|
expect(runner1).to_not equal runner2
|
129
129
|
end
|
@@ -47,7 +47,7 @@ describe Acfs::Middleware::JSON do
|
|
47
47
|
let(:body) { data.to_json[4..-4] }
|
48
48
|
|
49
49
|
it 'should raise an error' do
|
50
|
-
expect { request.complete! response }.to raise_error(
|
50
|
+
expect { request.complete! response }.to raise_error(::JSON::ParserError)
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: acfs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jan Graichen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-06-
|
11
|
+
date: 2020-06-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: actionpack
|
@@ -16,44 +16,44 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '5.2'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '5.2'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: activemodel
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '5.2'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '5.2'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: activesupport
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '5.2'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '5.2'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: rack
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - ">="
|
@@ -80,20 +80,6 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '1.0'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: rack
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - ">="
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '0'
|
90
|
-
type: :runtime
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - ">="
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '0'
|
97
83
|
- !ruby/object:Gem::Dependency
|
98
84
|
name: bundler
|
99
85
|
requirement: !ruby/object:Gem::Requirement
|