grape_cache 0.0.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 +7 -0
- data/.travis.yml +5 -0
- data/Dockerfile +17 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +86 -0
- data/README.md +50 -0
- data/grape_cache.gemspec +32 -0
- data/lib/grape_cache/middleware.rb +140 -0
- data/lib/grape_cache/version.rb +7 -0
- data/lib/grape_cache.rb +13 -0
- data/spec/grape_cache/middleware_spec.rb +86 -0
- data/spec/spec_helper.rb +37 -0
- metadata +109 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0aff7faeba22650387a9a0f10bdc1fada4349666
|
4
|
+
data.tar.gz: cead8b6f22a977484ecfbd8dae9a9776b50ca5f5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e07e1a92ed8a8d513dbef1cc678ea871767e03851d12dd2a40ce93c5e96e38344eb5d2926b897f7a0fb04d55837c452e75f961e528b5a7fca3b292198793a017
|
7
|
+
data.tar.gz: 0d678a2010d84859870d6da9995c97b7210aef3753990c1a705c3f8d9b2c39886ba02f4bd431ed40f1a5258bfd7da069686ce8873f04b2bb78f1b80eb943dbe4
|
data/.travis.yml
ADDED
data/Dockerfile
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
grape_cache (0.0.0)
|
5
|
+
grape (~> 0.16)
|
6
|
+
multi_json
|
7
|
+
oj
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: https://rubygems.org/
|
11
|
+
specs:
|
12
|
+
activesupport (4.2.6)
|
13
|
+
i18n (~> 0.7)
|
14
|
+
json (~> 1.7, >= 1.7.7)
|
15
|
+
minitest (~> 5.1)
|
16
|
+
thread_safe (~> 0.3, >= 0.3.4)
|
17
|
+
tzinfo (~> 1.1)
|
18
|
+
axiom-types (0.1.1)
|
19
|
+
descendants_tracker (~> 0.0.4)
|
20
|
+
ice_nine (~> 0.11.0)
|
21
|
+
thread_safe (~> 0.3, >= 0.3.1)
|
22
|
+
builder (3.2.2)
|
23
|
+
coercible (1.0.0)
|
24
|
+
descendants_tracker (~> 0.0.1)
|
25
|
+
descendants_tracker (0.0.4)
|
26
|
+
thread_safe (~> 0.3, >= 0.3.1)
|
27
|
+
diff-lcs (1.2.5)
|
28
|
+
enumerable-lazy (0.0.1)
|
29
|
+
equalizer (0.0.11)
|
30
|
+
grape (0.16.2)
|
31
|
+
activesupport
|
32
|
+
builder
|
33
|
+
hashie (>= 2.1.0)
|
34
|
+
multi_json (>= 1.3.2)
|
35
|
+
multi_xml (>= 0.5.2)
|
36
|
+
mustermann19 (~> 0.4.3)
|
37
|
+
rack (>= 1.3.0)
|
38
|
+
rack-accept
|
39
|
+
virtus (>= 1.0.0)
|
40
|
+
hashie (3.4.4)
|
41
|
+
i18n (0.7.0)
|
42
|
+
ice_nine (0.11.2)
|
43
|
+
json (1.8.3)
|
44
|
+
minitest (5.9.0)
|
45
|
+
multi_json (1.12.1)
|
46
|
+
multi_xml (0.5.5)
|
47
|
+
mustermann19 (0.4.3)
|
48
|
+
enumerable-lazy
|
49
|
+
oj (2.15.0)
|
50
|
+
rack (1.6.4)
|
51
|
+
rack-accept (0.4.5)
|
52
|
+
rack (>= 0.4)
|
53
|
+
rack-test (0.6.3)
|
54
|
+
rack (>= 1.0)
|
55
|
+
rspec (3.4.0)
|
56
|
+
rspec-core (~> 3.4.0)
|
57
|
+
rspec-expectations (~> 3.4.0)
|
58
|
+
rspec-mocks (~> 3.4.0)
|
59
|
+
rspec-core (3.4.4)
|
60
|
+
rspec-support (~> 3.4.0)
|
61
|
+
rspec-expectations (3.4.0)
|
62
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
63
|
+
rspec-support (~> 3.4.0)
|
64
|
+
rspec-mocks (3.4.1)
|
65
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
66
|
+
rspec-support (~> 3.4.0)
|
67
|
+
rspec-support (3.4.1)
|
68
|
+
thread_safe (0.3.5)
|
69
|
+
tzinfo (1.2.2)
|
70
|
+
thread_safe (~> 0.1)
|
71
|
+
virtus (1.0.5)
|
72
|
+
axiom-types (~> 0.1)
|
73
|
+
coercible (~> 1.0)
|
74
|
+
descendants_tracker (~> 0.0, >= 0.0.3)
|
75
|
+
equalizer (~> 0.0, >= 0.0.9)
|
76
|
+
|
77
|
+
PLATFORMS
|
78
|
+
ruby
|
79
|
+
|
80
|
+
DEPENDENCIES
|
81
|
+
grape_cache!
|
82
|
+
rack-test
|
83
|
+
rspec (~> 3.0)
|
84
|
+
|
85
|
+
BUNDLED WITH
|
86
|
+
1.12.4
|
data/README.md
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# Grape Cache [](https://travis-ci.org/gabrielcorado/grape_cache) [](https://badge.fury.io/rb/grape_cache)
|
2
|
+
```
|
3
|
+
+-----------+ Cached?
|
4
|
+
| Request +------------------+
|
5
|
+
+-----------+ |
|
6
|
+
|
|
7
|
+
|
|
8
|
+
v
|
9
|
+
+-----------+ No +-----+-----+
|
10
|
+
| API Call +<-----------+ Cache |
|
11
|
+
+-----+-----+ +-----+-----+
|
12
|
+
| |
|
13
|
+
| |
|
14
|
+
v |
|
15
|
+
+-----+-----+ Yes |
|
16
|
+
| Response +<-----------------+
|
17
|
+
+-----------+
|
18
|
+
```
|
19
|
+
|
20
|
+
## How it works
|
21
|
+
The module generates a key based on the Grape Route(METHOD + PATH) and the current params
|
22
|
+
(HTTP BODY + QUERY STRINGS) and set the result of the API Call to this key.
|
23
|
+
When another request with exacly same attributes that will generate the same key again,
|
24
|
+
it does not call the API again, it just return the last response.
|
25
|
+
|
26
|
+
## Usage
|
27
|
+
```ruby
|
28
|
+
# Add the Middleware into your API class
|
29
|
+
# In the middleware definition you have to specify the
|
30
|
+
# store used by the middleware, also you could pass the
|
31
|
+
# params for this store like `:expires_in`
|
32
|
+
class Application < Grape::API
|
33
|
+
use GrapeCache, store: Rails.cache, options: { expires_in: 1.hour }
|
34
|
+
end
|
35
|
+
|
36
|
+
# After this just simply set your routes with a cache flag
|
37
|
+
get '/hello/cache', cache: true do
|
38
|
+
{ hello: 'From cache' }
|
39
|
+
end
|
40
|
+
|
41
|
+
# To use it with a shared cache env you could use the flag `:namespace`
|
42
|
+
# to define it. In this case I'll use the Apartment as example.
|
43
|
+
use GrapeCache, store: Rails.cache, namespace: -> { Apartment::Tenant.current }
|
44
|
+
```
|
45
|
+
|
46
|
+
## Development
|
47
|
+
* Building the docker container: `docker build -t grape-cache .`
|
48
|
+
* Running the tests:
|
49
|
+
* With volume: `docker run --rm -it -v (PWD):/app grape-cache bundle exec rspec`
|
50
|
+
* Without volume: `docker run --rm -it grape-cache bundle exec rspec`
|
data/grape_cache.gemspec
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
#
|
2
|
+
require './lib/grape_cache/version'
|
3
|
+
|
4
|
+
#
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
#
|
7
|
+
s.name = 'grape_cache'
|
8
|
+
s.version = GrapeCache.version
|
9
|
+
|
10
|
+
#
|
11
|
+
s.summary = ''
|
12
|
+
s.description = ''
|
13
|
+
|
14
|
+
#
|
15
|
+
s.author = 'Gabriel Corado'
|
16
|
+
s.email = 'gabrielcorado@mail.com'
|
17
|
+
s.homepage = 'http://github.com/gabrielcorado/venduitz'
|
18
|
+
|
19
|
+
#
|
20
|
+
s.files = `git ls-files`.strip.split("\n")
|
21
|
+
s.executables = Dir["bin/*"].map { |f| File.basename(f) }
|
22
|
+
|
23
|
+
# Dependencies
|
24
|
+
# s.add_dependency 'concurrent-ruby', '~> 1.0'
|
25
|
+
# s.add_dependency 'docker-api', '~> 1.26'
|
26
|
+
s.add_dependency 'multi_json'
|
27
|
+
s.add_dependency 'oj'
|
28
|
+
s.add_dependency 'grape', '~> 0.16'
|
29
|
+
|
30
|
+
# Development depencies
|
31
|
+
s.add_development_dependency 'rspec', '~> 3.0'
|
32
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
#
|
2
|
+
module GrapeCache
|
3
|
+
# Middleware Class
|
4
|
+
class Middleware < Grape::Middleware::Base
|
5
|
+
# Overwriting the method call! from Grape::Middleware::Base
|
6
|
+
# Reason: Make the :before call to return the whole stack
|
7
|
+
def call!(env)
|
8
|
+
@env = env
|
9
|
+
# Just here is moving!
|
10
|
+
before_res = before
|
11
|
+
return before_res unless before_res.nil?
|
12
|
+
# end the overwrite
|
13
|
+
begin
|
14
|
+
@app_response = @app.call(@env)
|
15
|
+
ensure
|
16
|
+
begin
|
17
|
+
after_response = after
|
18
|
+
rescue StandardError => e
|
19
|
+
warn "caught error of type #{e.class} in after callback inside #{self.class.name} : #{e.message}"
|
20
|
+
raise e
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
response = after_response || @app_response
|
25
|
+
merge_headers response
|
26
|
+
response
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
def after
|
31
|
+
# Check if cache is enabled in this route
|
32
|
+
return unless cache?
|
33
|
+
|
34
|
+
# Cache its output
|
35
|
+
store.write key(@params), response, @options.fetch(:options, {}).merge(endpoint.options.fetch(:options, {}))
|
36
|
+
|
37
|
+
# Do not change the return
|
38
|
+
return
|
39
|
+
end
|
40
|
+
|
41
|
+
# Generate the cache if its necessary
|
42
|
+
def before
|
43
|
+
# Check if cache is enabled in this route
|
44
|
+
return unless cache?
|
45
|
+
|
46
|
+
# Generate the cache key
|
47
|
+
k = key(params)
|
48
|
+
|
49
|
+
# Check the current key exists in the cache
|
50
|
+
return unless store.exist?(k)
|
51
|
+
|
52
|
+
# Get to the response it
|
53
|
+
res = MultiJson.load store.read(k)
|
54
|
+
|
55
|
+
# Return in the Rack Formatt
|
56
|
+
[res['status'], res['headers'], res['body']]
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
# Check if the current route has cache
|
62
|
+
def cache?
|
63
|
+
endpoint.options.fetch(:route_options, {}).fetch(:cache, false)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Cache store
|
67
|
+
def store
|
68
|
+
# Check if Store was defined
|
69
|
+
raise 'Cache Store have to be defined' if @options[:store].nil?
|
70
|
+
|
71
|
+
# Return it
|
72
|
+
@options[:store]
|
73
|
+
end
|
74
|
+
|
75
|
+
# Cache key
|
76
|
+
def key(opts)
|
77
|
+
# Get the namespace
|
78
|
+
ns = namespace
|
79
|
+
|
80
|
+
# Default prefix: `grape_cache`
|
81
|
+
res = "grape_cache/#{digest(route)}/#{digest(opts)}"
|
82
|
+
|
83
|
+
# Add the namespace (if its necessary)
|
84
|
+
"#{ns}/#{res}" if ns.nil?
|
85
|
+
|
86
|
+
# Return the result
|
87
|
+
res
|
88
|
+
end
|
89
|
+
|
90
|
+
# Get the namespace
|
91
|
+
def namespace
|
92
|
+
# Check if its nil
|
93
|
+
return nil if @options[:namespace].nil?
|
94
|
+
|
95
|
+
# Call it if it's a Proc
|
96
|
+
@options[:namespace].proc? ? @options[:namespace].call : @options[:namespace]
|
97
|
+
end
|
98
|
+
|
99
|
+
# Route
|
100
|
+
def route
|
101
|
+
"#{endpoint.route.options[:method]} #{endpoint.route.pattern.path}"
|
102
|
+
end
|
103
|
+
|
104
|
+
# Transform the reponse into JSON
|
105
|
+
def response
|
106
|
+
# Dump it to JSON
|
107
|
+
MultiJson.dump({
|
108
|
+
status: @app_response.status,
|
109
|
+
headers: @app_response.headers,
|
110
|
+
body: @app_response.body
|
111
|
+
})
|
112
|
+
end
|
113
|
+
|
114
|
+
# Digest the params
|
115
|
+
def digest(params)
|
116
|
+
# Dump the params
|
117
|
+
dump = Marshal::dump(params)
|
118
|
+
|
119
|
+
# Disgest the params
|
120
|
+
Digest::MD5.hexdigest dump
|
121
|
+
end
|
122
|
+
|
123
|
+
# Endpoint params
|
124
|
+
# Get the input passed and the QueryString
|
125
|
+
def params
|
126
|
+
# endpoint.declared(endpoint.params)
|
127
|
+
@params = "#{env['QUERY_STRING']}_#{env[Grape::Env::RACK_INPUT].read}"
|
128
|
+
end
|
129
|
+
|
130
|
+
# Request
|
131
|
+
def request
|
132
|
+
@request ||= Rack::Request.new(env)
|
133
|
+
end
|
134
|
+
|
135
|
+
# Access the endpoint
|
136
|
+
def endpoint
|
137
|
+
env['api.endpoint']
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
data/lib/grape_cache.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
# Helper
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
# Create a Grape API application
|
5
|
+
class Application < Grape::API
|
6
|
+
# Add the Middleware
|
7
|
+
# insert_after Grape::Middleware::Formatter, GrapeCache::Middleware, store: CacheStore.new
|
8
|
+
use GrapeCache::Middleware, store: CacheStore.new
|
9
|
+
|
10
|
+
# Set the format
|
11
|
+
format :json
|
12
|
+
|
13
|
+
# Simple Route
|
14
|
+
params do
|
15
|
+
optional :break, default: true
|
16
|
+
end
|
17
|
+
get '/simple', cache: true do
|
18
|
+
{ hello: 'Route', time: Time.now }
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
resource :sub do
|
23
|
+
get '/simple', cache: true do
|
24
|
+
{ hello: 'Sub', time: Time.now }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Post request
|
29
|
+
post '/post', cache: true do
|
30
|
+
{ hello: 'Sub', time: Time.now }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Class test
|
35
|
+
describe GrapeCache::Middleware do
|
36
|
+
# Create a Grape app
|
37
|
+
let(:app) { Application.new }
|
38
|
+
|
39
|
+
#
|
40
|
+
it 'should generate the cache for a simple text view' do
|
41
|
+
# Execute the route
|
42
|
+
get '/simple'
|
43
|
+
|
44
|
+
# Get it infos
|
45
|
+
first = MultiJson.load last_response.body
|
46
|
+
expect(first['time']).to eq(Time.now.to_s)
|
47
|
+
|
48
|
+
# Sleep...
|
49
|
+
sleep 2
|
50
|
+
|
51
|
+
# Sub Route
|
52
|
+
get '/sub/simple', hello: 'Test'
|
53
|
+
expect(MultiJson.load(last_response.body)['time']).to eq(Time.now.to_s)
|
54
|
+
|
55
|
+
# Sleep...
|
56
|
+
sleep 2
|
57
|
+
|
58
|
+
# Cached response
|
59
|
+
get '/simple'
|
60
|
+
expect(MultiJson.load(last_response.body)['time']).to eq(first['time'])
|
61
|
+
|
62
|
+
# Sleep...
|
63
|
+
sleep 2
|
64
|
+
|
65
|
+
# Test a Post request
|
66
|
+
post '/post', {hello: 'Test'}.to_json, 'CONTENT_TYPE' => 'application/json'
|
67
|
+
first_post = MultiJson.load(last_response.body)
|
68
|
+
expect(first_post['time']).to eq(Time.now.to_s)
|
69
|
+
|
70
|
+
# Sleep...
|
71
|
+
sleep 2
|
72
|
+
|
73
|
+
# Test a Post request
|
74
|
+
post '/post', {hello: 'Test'}.to_json, 'CONTENT_TYPE' => 'application/json'
|
75
|
+
expect(MultiJson.load(last_response.body)['time']).to eq(first_post['time'])
|
76
|
+
|
77
|
+
# Sleep...
|
78
|
+
sleep 2
|
79
|
+
|
80
|
+
# Execute the route
|
81
|
+
get '/simple', break: true
|
82
|
+
|
83
|
+
# Get it infos
|
84
|
+
expect(MultiJson.load(last_response.body)['time']).to eq(Time.now.to_s)
|
85
|
+
end
|
86
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# Spec dependencies
|
2
|
+
require 'grape_cache'
|
3
|
+
require 'grape'
|
4
|
+
require 'rack/test'
|
5
|
+
|
6
|
+
# Configure the RSpec
|
7
|
+
RSpec.configure do |config|
|
8
|
+
config.order = 'random'
|
9
|
+
config.seed = '12345'
|
10
|
+
config.include Rack::Test::Methods
|
11
|
+
end
|
12
|
+
|
13
|
+
# Define a Store
|
14
|
+
class CacheStore
|
15
|
+
# Storage
|
16
|
+
attr_reader :storage
|
17
|
+
|
18
|
+
# Initialize
|
19
|
+
def initialize
|
20
|
+
@storage = {}
|
21
|
+
end
|
22
|
+
|
23
|
+
#
|
24
|
+
def write(key, value, options)
|
25
|
+
@storage[key] = value
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
def read(key)
|
30
|
+
@storage[key]
|
31
|
+
end
|
32
|
+
|
33
|
+
# Exist?
|
34
|
+
def exist?(key)
|
35
|
+
@storage.key?(key)
|
36
|
+
end
|
37
|
+
end
|
metadata
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: grape_cache
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Gabriel Corado
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-05-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: multi_json
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: oj
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: grape
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.16'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.16'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.0'
|
69
|
+
description: ''
|
70
|
+
email: gabrielcorado@mail.com
|
71
|
+
executables: []
|
72
|
+
extensions: []
|
73
|
+
extra_rdoc_files: []
|
74
|
+
files:
|
75
|
+
- ".travis.yml"
|
76
|
+
- Dockerfile
|
77
|
+
- Gemfile
|
78
|
+
- Gemfile.lock
|
79
|
+
- README.md
|
80
|
+
- grape_cache.gemspec
|
81
|
+
- lib/grape_cache.rb
|
82
|
+
- lib/grape_cache/middleware.rb
|
83
|
+
- lib/grape_cache/version.rb
|
84
|
+
- spec/grape_cache/middleware_spec.rb
|
85
|
+
- spec/spec_helper.rb
|
86
|
+
homepage: http://github.com/gabrielcorado/venduitz
|
87
|
+
licenses: []
|
88
|
+
metadata: {}
|
89
|
+
post_install_message:
|
90
|
+
rdoc_options: []
|
91
|
+
require_paths:
|
92
|
+
- lib
|
93
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
requirements: []
|
104
|
+
rubyforge_project:
|
105
|
+
rubygems_version: 2.4.5.1
|
106
|
+
signing_key:
|
107
|
+
specification_version: 4
|
108
|
+
summary: ''
|
109
|
+
test_files: []
|