rg-service 1.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/.gitignore +12 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/README.md +65 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/rg/clock.rb +48 -0
- data/lib/rg/service.rb +65 -0
- data/lib/rg/service/convenience_constructors.rb +36 -0
- data/lib/rg/service/exception_formatting.rb +35 -0
- data/lib/rg/service/kill_switch.rb +53 -0
- data/lib/rg/service/result.rb +53 -0
- data/lib/rg/service/version.rb +5 -0
- data/rg-service.gemspec +29 -0
- metadata +129 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0a58613378aa4c5e5c7f81d3e794d2f84f497ec0
|
4
|
+
data.tar.gz: e320b6f211d831070672102127e52f694414e6b3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4ebed8ba8c2616db4eafe30f3e67a536b188b769d181fea4bb02031b6e28f2885efb2fb0f9d2a679b3e671d63d24a5278ddaa1ee73e938ad569f1978585f24f7
|
7
|
+
data.tar.gz: f656f405ea84b26a2284fd1a3c3fb73d3367a1d0e771e5b0ace8242bc21827879f247755a38b6b9a587018326015d42f610d2df43d7f818b17fd4ca5499a05c9
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
# RG::Service
|
2
|
+
|
3
|
+
This is a basic service object framework for use in Rails applications
|
4
|
+
at Real Geeks.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem 'rg-service', git: "git@github.com:RealGeeks/rg-service.git", tag: "v1.0.0"
|
12
|
+
```
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
$ bundle
|
17
|
+
|
18
|
+
Or install it yourself as:
|
19
|
+
|
20
|
+
$ gem install rg-service
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
TODO: Write usage instructions here
|
25
|
+
|
26
|
+
## Development
|
27
|
+
|
28
|
+
After checking out the repo, run `bin/setup` to install dependencies.
|
29
|
+
Then, run `rake spec` to run the tests. You can also run `bin/console`
|
30
|
+
for an interactive prompt that will allow you to experiment.
|
31
|
+
|
32
|
+
To install this gem onto your local machine, run `bundle exec rake
|
33
|
+
install`. To release a new version, update the version number in
|
34
|
+
`version.rb`, and then run `bundle exec rake release`, which will create
|
35
|
+
a git tag for the version, push git commits and tags, and push the
|
36
|
+
`.gem` file to [rubygems.org](https://rubygems.org).
|
37
|
+
|
38
|
+
## Contributing
|
39
|
+
|
40
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/realgeeks/rg-service.
|
41
|
+
|
42
|
+
## License
|
43
|
+
|
44
|
+
The MIT License (MIT)
|
45
|
+
|
46
|
+
Copyright (c) 2017 Real Geeks, LLC
|
47
|
+
|
48
|
+
Permission is hereby granted, free of charge, to any person obtaining a
|
49
|
+
copy of this software and associated documentation files (the
|
50
|
+
"Software"), to deal in the Software without restriction, including
|
51
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
52
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
53
|
+
permit persons to whom the Software is furnished to do so, subject to
|
54
|
+
the following conditions:
|
55
|
+
|
56
|
+
The above copyright notice and this permission notice shall be included
|
57
|
+
in all copies or substantial portions of the Software.
|
58
|
+
|
59
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
60
|
+
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
61
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
62
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
63
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
64
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
65
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "rg/service"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/lib/rg/clock.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
module RG
|
2
|
+
class Clock
|
3
|
+
SUBSECOND_PRECISION_DIGITS = 6 # microseconds are Quite Good Enough, Thank You(tm)
|
4
|
+
|
5
|
+
# Convenience constructor for use in specs.
|
6
|
+
# Example use: Clock.as_of( 1.hour.from_now )
|
7
|
+
def self.as_of(time)
|
8
|
+
new(time)
|
9
|
+
end
|
10
|
+
|
11
|
+
# Apparently stubbing .new doesn't work so well, so we'll go with
|
12
|
+
# Clock.for_current_time instead.
|
13
|
+
def self.for_current_time
|
14
|
+
new( Time.now )
|
15
|
+
end
|
16
|
+
|
17
|
+
# Another quick convenience method
|
18
|
+
def self.current_time
|
19
|
+
for_current_time.to_time
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(time)
|
23
|
+
@time = time.utc
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_time
|
27
|
+
time.round(SUBSECOND_PRECISION_DIGITS)
|
28
|
+
end
|
29
|
+
|
30
|
+
def plus( duration )
|
31
|
+
Clock.as_of( time + duration )
|
32
|
+
end
|
33
|
+
|
34
|
+
def minus( duration )
|
35
|
+
Clock.as_of( time - duration )
|
36
|
+
end
|
37
|
+
|
38
|
+
# This is here to facilitate tests of sleep-based behavior.
|
39
|
+
# (Obviously, this should be stubbed in tests.)
|
40
|
+
def sleep(duration)
|
41
|
+
super # invoke Kernel#sleep
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
attr_reader :time
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
data/lib/rg/service.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require "active_support"
|
2
|
+
require "virtus"
|
3
|
+
|
4
|
+
require_relative "service/version"
|
5
|
+
require_relative "service/kill_switch"
|
6
|
+
require_relative "service/result"
|
7
|
+
require_relative "service/convenience_constructors"
|
8
|
+
require_relative "service/exception_formatting"
|
9
|
+
require_relative "clock"
|
10
|
+
|
11
|
+
module RG
|
12
|
+
class Service
|
13
|
+
extend ConvenienceConstructors
|
14
|
+
extend ExceptionFormatting
|
15
|
+
|
16
|
+
# This allows us to declare attributes at the top of a service file
|
17
|
+
# (which should help us notice when a given service starts having too
|
18
|
+
# many dependencies), and it also allows us to support named
|
19
|
+
# parameters when invoking a service.
|
20
|
+
#
|
21
|
+
# As of this writing, I haven't been able to get Virtus' default
|
22
|
+
# attributes to work as described, so be sure to check that you got
|
23
|
+
# any required parameters before proceeding...
|
24
|
+
include Virtus.model
|
25
|
+
|
26
|
+
# All services have a :clock attribute that can be passed on construction.
|
27
|
+
attribute :clock, Clock, default: :default_clock
|
28
|
+
|
29
|
+
# If not provided, this will default to Clock.for_current_time.
|
30
|
+
private def default_clock
|
31
|
+
Clock.for_current_time
|
32
|
+
end
|
33
|
+
|
34
|
+
# Services are performed by instances, but this provides a more
|
35
|
+
# convenient way of invoking them.
|
36
|
+
def self.perform(**kwargs)
|
37
|
+
|
38
|
+
result = new(**kwargs).perform
|
39
|
+
|
40
|
+
unless result.is_a?(Service::Result)
|
41
|
+
raise TypeError, "Expected #{self.name} to return a Service::Result, but got:\n#{result.inspect}"
|
42
|
+
end
|
43
|
+
|
44
|
+
return result
|
45
|
+
|
46
|
+
rescue StandardError => e
|
47
|
+
handle_exception e
|
48
|
+
end
|
49
|
+
|
50
|
+
def perform
|
51
|
+
raise NotImplementedError, "Subclass must implement!"
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
# NOTE: subclasses may override
|
57
|
+
def self.handle_exception(e)
|
58
|
+
if defined?(Raven)
|
59
|
+
Raven.capture_exception e
|
60
|
+
end
|
61
|
+
|
62
|
+
raise e
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module RG
|
2
|
+
class Service
|
3
|
+
|
4
|
+
module ConvenienceConstructors
|
5
|
+
def success(message: nil, object: nil, data: {}, errors: [])
|
6
|
+
::RG::Service::Result.new( status: :success, message: message, object: object, data: data, errors: errors )
|
7
|
+
end
|
8
|
+
|
9
|
+
def disabled
|
10
|
+
RG::Service::Result.new( status: :success )
|
11
|
+
end
|
12
|
+
|
13
|
+
def nothingtodohere(message=nil)
|
14
|
+
RG::Service::Result.new( status: :success, message: message )
|
15
|
+
end
|
16
|
+
|
17
|
+
def failure(message: nil, object: nil, data: {}, errors: [])
|
18
|
+
RG::Service::Result.new( status: :failure, message: message, object: object, data: data, errors: errors )
|
19
|
+
end
|
20
|
+
|
21
|
+
def result_from_exception(e)
|
22
|
+
message = format_exception(e)
|
23
|
+
data = {
|
24
|
+
error: {
|
25
|
+
class: e.class.name,
|
26
|
+
msg: e.message,
|
27
|
+
backtrace: e.backtrace,
|
28
|
+
},
|
29
|
+
exception: e,
|
30
|
+
}
|
31
|
+
RG::Service::Result.new( status: :failure, message: message, data: data )
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module RG
|
2
|
+
class Service
|
3
|
+
|
4
|
+
module ExceptionFormatting
|
5
|
+
EXCEPTION_TEMPLATE = <<-EOF
|
6
|
+
Exception: %<err_class>s
|
7
|
+
Message: %<err_msg>s
|
8
|
+
|
9
|
+
Backtrace:
|
10
|
+
%<err_backtrace>s"
|
11
|
+
EOF
|
12
|
+
|
13
|
+
def format_exception(e, originating_file: nil)
|
14
|
+
EXCEPTION_TEMPLATE % {
|
15
|
+
err_class: e.class.name,
|
16
|
+
err_msg: e.message,
|
17
|
+
err_backtrace: format_backtrace( e, originating_file: originating_file ),
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
def format_backtrace(e, originating_file: nil)
|
22
|
+
if originating_file.present?
|
23
|
+
truncate_below = e.backtrace.index {|line|
|
24
|
+
line.include?(originating_file)
|
25
|
+
}
|
26
|
+
range = (0..truncate_below)
|
27
|
+
e.backtrace[range].join("\n")
|
28
|
+
else
|
29
|
+
e.backtrace.join("\n")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module RG
|
2
|
+
class Service
|
3
|
+
|
4
|
+
# Some services may need to be enabled or disabled for testing.
|
5
|
+
# DRY up the boilerplate that makes this happen, so that service
|
6
|
+
# classes may choose when to self-terminate as follows:
|
7
|
+
#
|
8
|
+
# def perform
|
9
|
+
# return if disabled?
|
10
|
+
# # side-effect-having code
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# To turn a service on or off, call .enable! or .disable! on the
|
14
|
+
# service class. Including services will be enabled by default.
|
15
|
+
module KillSwitch
|
16
|
+
INCLUDING_CLASSES = []
|
17
|
+
|
18
|
+
mattr_accessor :all_enabled
|
19
|
+
self.all_enabled = true
|
20
|
+
|
21
|
+
def self.included(receiver)
|
22
|
+
receiver.mattr_accessor :enabled
|
23
|
+
|
24
|
+
receiver.extend ClassMethods
|
25
|
+
receiver.extend Predicates
|
26
|
+
receiver.include Predicates
|
27
|
+
INCLUDING_CLASSES << receiver
|
28
|
+
end
|
29
|
+
|
30
|
+
module ClassMethods
|
31
|
+
def enable! ; self.enabled = true ; end
|
32
|
+
def disable! ; self.enabled = false ; end
|
33
|
+
end
|
34
|
+
|
35
|
+
module Predicates
|
36
|
+
def enabled?
|
37
|
+
if self.enabled.nil?
|
38
|
+
self.enabled = ::Service::KillSwitch.all_enabled
|
39
|
+
end
|
40
|
+
|
41
|
+
!!self.enabled
|
42
|
+
end
|
43
|
+
|
44
|
+
def disabled? ; !enabled? ; end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Set the global flag Set all the services that have been loaded so far
|
49
|
+
def self.disable_all! ; KillSwitch.all_enabled = false ; KillSwitch::INCLUDING_CLASSES.each(&:disable!) ; end
|
50
|
+
def self.enable_all! ; KillSwitch.all_enabled = true ; KillSwitch::INCLUDING_CLASSES.each(&:enable!) ; end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module RG
|
2
|
+
class Service
|
3
|
+
|
4
|
+
# Some services may need to return success/failure results with
|
5
|
+
# additional information. They may use this to do so.
|
6
|
+
class Result
|
7
|
+
include Virtus.model
|
8
|
+
attribute :status, Symbol
|
9
|
+
attribute :message, String
|
10
|
+
attribute :object
|
11
|
+
attribute :data, Hash
|
12
|
+
attribute :errors, Array[String]
|
13
|
+
|
14
|
+
VALID_STATUSES = [
|
15
|
+
:success,
|
16
|
+
:failure,
|
17
|
+
]
|
18
|
+
|
19
|
+
def initialize(**kwargs)
|
20
|
+
unless VALID_STATUSES.include?(kwargs[:status])
|
21
|
+
fail ArgumentError, "The :status attribute must be one of: #{VALID_STATUSES.inspect}"
|
22
|
+
end
|
23
|
+
|
24
|
+
super # hey, don't overlook this ;)
|
25
|
+
|
26
|
+
# If given a (non-nil) object: arg, put it in #data[:object]
|
27
|
+
if object.present?
|
28
|
+
data[:object] ||= object
|
29
|
+
end
|
30
|
+
|
31
|
+
# Always make sure there's a :status field in #data
|
32
|
+
data[:status] ||= friendly_status
|
33
|
+
end
|
34
|
+
|
35
|
+
def success? ; :success == status ; end
|
36
|
+
def failure? ; :failure == status ; end
|
37
|
+
|
38
|
+
def description
|
39
|
+
"%<status>s:\n%<message>s" % {
|
40
|
+
status: friendly_status,
|
41
|
+
message: message,
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def friendly_status
|
48
|
+
status.to_s.capitalize
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
data/rg-service.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'rg/service/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "rg-service"
|
8
|
+
spec.version = Rg::Service::VERSION
|
9
|
+
spec.authors = ["Sam Livingston-Gray"]
|
10
|
+
spec.email = ["geeksam@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Service framework for Real Geeks}
|
13
|
+
spec.description = %q{Service framework for Real Geeks}
|
14
|
+
spec.homepage = "https://github.com/realgeeks/rg-service"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
17
|
+
f.match(%r{^(test|spec|features)/})
|
18
|
+
end
|
19
|
+
spec.bindir = "exe"
|
20
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.14"
|
24
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
25
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
26
|
+
|
27
|
+
spec.add_runtime_dependency "activesupport", ">= 4.0"
|
28
|
+
spec.add_runtime_dependency "virtus", ">= 1.0.5"
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rg-service
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sam Livingston-Gray
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-11-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.14'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.14'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: activesupport
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '4.0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '4.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: virtus
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 1.0.5
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 1.0.5
|
83
|
+
description: Service framework for Real Geeks
|
84
|
+
email:
|
85
|
+
- geeksam@gmail.com
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- ".gitignore"
|
91
|
+
- ".rspec"
|
92
|
+
- ".travis.yml"
|
93
|
+
- Gemfile
|
94
|
+
- README.md
|
95
|
+
- Rakefile
|
96
|
+
- bin/console
|
97
|
+
- bin/setup
|
98
|
+
- lib/rg/clock.rb
|
99
|
+
- lib/rg/service.rb
|
100
|
+
- lib/rg/service/convenience_constructors.rb
|
101
|
+
- lib/rg/service/exception_formatting.rb
|
102
|
+
- lib/rg/service/kill_switch.rb
|
103
|
+
- lib/rg/service/result.rb
|
104
|
+
- lib/rg/service/version.rb
|
105
|
+
- rg-service.gemspec
|
106
|
+
homepage: https://github.com/realgeeks/rg-service
|
107
|
+
licenses: []
|
108
|
+
metadata: {}
|
109
|
+
post_install_message:
|
110
|
+
rdoc_options: []
|
111
|
+
require_paths:
|
112
|
+
- lib
|
113
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '0'
|
123
|
+
requirements: []
|
124
|
+
rubyforge_project:
|
125
|
+
rubygems_version: 2.6.11
|
126
|
+
signing_key:
|
127
|
+
specification_version: 4
|
128
|
+
summary: Service framework for Real Geeks
|
129
|
+
test_files: []
|