mu-ruby 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8f0ec48050129702f841631856f087e9ed43a400
4
+ data.tar.gz: 3d8d6b2b0203ca56f1a1e1595841d3bb115a9467
5
+ SHA512:
6
+ metadata.gz: 17064e9306c060115a9f0868073aefba580fcc7fb3e52101c82e0895b358670dee8292653eb28628dd229d169f6b2339ed1bdb847137e585a0ce0010d5333af3
7
+ data.tar.gz: e1fff4414f7edf36b71da219d39c99d64d60779c9899fd6d392d8adf99cf3879a9f3e096d5125cee1e01cfe1fd9317c06ce3d5840a1621c295d0dd6b817238cf
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1,31 @@
1
+ AllCops:
2
+ Exclude:
3
+ - 'tmp/**/*'
4
+ - 'vendor/**/*'
5
+ - 'bin/**/*'
6
+ - 'log/**/*'
7
+ - 'lib/mu/logger/version.rb'
8
+ - '*.gemspec'
9
+
10
+ #Metrics/ClassLength:
11
+ # Max: 110
12
+ #
13
+ Metrics/AbcSize:
14
+ Max: 20
15
+
16
+ Metrics/LineLength:
17
+ Max: 130
18
+ Metrics/MethodLength:
19
+ Max: 30
20
+
21
+ #Metrics/ModuleLength:
22
+ # Max: 300
23
+ #
24
+ #Metrics/CyclomaticComplexity:
25
+ # Max: 15
26
+ #
27
+ #Metrics/PerceivedComplexity:
28
+ # Max: 15
29
+ #
30
+ Documentation:
31
+ Enabled: false
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.3.1
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.3
4
+ before_install: gem install bundler -v 1.10.6
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in mu.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,104 @@
1
+ # Mu (µ)
2
+
3
+ Welcome to the Ruby edition of ___Microservices Unbound___!
4
+
5
+ This gem serves as the base component for building Ruby microservices. It will eventually provide a full
6
+ complement of straightforward and easy to use APIs that will serve as a "running start" for building a distributed
7
+ service-oriented architecture of small services.
8
+
9
+ ## Features
10
+
11
+ From experience, I have discovered that there is a small but essential set of behaviors that microservices must
12
+ implement for this architecture to succeed. The fundamental reason for this is that increasing the number of moving
13
+ parts in a system does, by its very definition, increase complexity. This complexity is manageable, but only if steps
14
+ are taken to insure that all services can be viewed, scaled, monitored and maintained in a similar fashion.
15
+
16
+ ### Logging
17
+
18
+ Provide a simple, easy-to-understand API that will:
19
+
20
+ * Capture key-value sets for all log events rather than simple strings
21
+ * Uniformly include discriminating attributes in all events (service name, host, instance)
22
+ * Provide easy to read formatting for local use by developers
23
+ * Provide formatting as JSON for subsequent filtering, processing, and/or indexing by a log aggregator
24
+ * Cross-service session identification
25
+
26
+ ### Configuration
27
+
28
+ * Make it easy to specify configuration across a multiple dimensions: service, environment, local overrides.
29
+ * Log all configuration data when a service starts up
30
+
31
+ ### Inter-Service Communication
32
+
33
+ * Simple data marshalling
34
+ * Synchronous Communication via REST utilizing JSON API
35
+ * REST-ful endpoint implementation skeletons
36
+ * Middleware to handle logging and security
37
+ * REST client abstraction for JSON API compliant services (e.g. other Mu-enabled services)
38
+ * Generic HTTP client abstraction for external and other non-standard REST APIs
39
+ * Asynchronous Communication via AMQP
40
+ * Broadcast (event bus)
41
+ * Service-to-Service (psuedo-synchronous messaging)
42
+ * Backchannel (control bus)
43
+
44
+ ### Authentication / Authorization
45
+
46
+ * Authenticate all incoming requests
47
+ * Provide role-based authorization requirements by endpoint
48
+ * Pass credentials of incoming requests on with subsequent requests
49
+
50
+ ### Storage
51
+
52
+ * RDBMS
53
+ * Key-Value Stores (e.g. Riak, Redis)
54
+ * File/Bulk Storage (e.g. S3)
55
+
56
+ ## Additional Components
57
+
58
+ The converse of these simple APIs for services is to provide components that enable these capabilities across a
59
+ distributed system. For example, a good logging API needs a centralized log aggregator. Here are some of the
60
+ infrastructure components that I have in mind to provide as starting points:
61
+
62
+ * Log Aggregator: Elasticsearch/Logstash/Kibana (ELK stack)
63
+ * Basic admin/monitoring service
64
+ * Serves as an example implementation service using the mu-ruby gem.
65
+ * Monitors service availability using the AMQP backchannel
66
+ * Provides visibility of the configuration in use for any given service
67
+ * Sample deployment template for AWS using Terraform and Ansible
68
+ * Sample single-machine development environment using Docker
69
+ * Sample cross-service integration tests using Cucumber
70
+
71
+
72
+
73
+
74
+ ## Installation
75
+
76
+ **None of this is valid yet, this gem has not been pushed to Rubygems.**
77
+
78
+ Add this line to your application's Gemfile:
79
+
80
+ ```ruby
81
+ gem 'mu'
82
+ ```
83
+
84
+ And then execute:
85
+
86
+ $ bundle
87
+
88
+ Or install it yourself as:
89
+
90
+ $ gem install mu
91
+
92
+ ## Usage
93
+
94
+ TODO: Write usage instructions here
95
+
96
+ ## Development
97
+
98
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
99
+
100
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
101
+
102
+ ## Contributing
103
+
104
+ Bug reports and pull requests are welcome on GitHub at https://github.com/goneflyin/mu-ruby.
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "mu"
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
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
data/lib/mu/logger.rb ADDED
@@ -0,0 +1,114 @@
1
+ require 'json'
2
+ require 'logger'
3
+ require 'socket'
4
+ require 'mu/logging/colored_log_formatter'
5
+ require 'mu/logging/json_log_formatter'
6
+
7
+ VALID_RUBY_CONST = /\A[A-Z][a-zA-Z_]*\Z/
8
+
9
+ module Mu
10
+ class Logger
11
+ LEVELS = %w(debug info warn error fatal).freeze
12
+
13
+ LEVELS.each do |method|
14
+ define_method(method.to_sym) do |event, data = {}, &block|
15
+ log_event(method.to_sym, event, data, &block)
16
+ end
17
+ end
18
+
19
+ def initialize(*args)
20
+ @logger = create_logger(args)
21
+
22
+ @logger.formatter =
23
+ if ['colored'].include?(ENV['LOG_FORMAT'])
24
+ then Mu::Logging::Formatting.colored_format
25
+ else Mu::Logging::Formatting.json_format
26
+ end
27
+
28
+ self.level = LEVELS.index(ENV['LOG_LEVEL']) || ::Logger::INFO
29
+ end
30
+
31
+ def for_event(event)
32
+ RubyCompatibleLogger.new(event, @logger)
33
+ end
34
+
35
+ private
36
+
37
+ def create_logger(args)
38
+ return ::Logger.new(STDOUT) if args.empty? # Default to STDOUT
39
+ return args[0] if logger?(args[0])
40
+ return ::Logger.new(Kernel.const_get(args[0])) if const_io_stream?(args[0])
41
+
42
+ ::Logger.new(*args)
43
+ end
44
+
45
+ def logger?(logger_param)
46
+ # Allow use of pre-existing Logger
47
+ logger_param.is_a?(::Logger)
48
+ end
49
+
50
+ # Allow STDOUT or STDERR to be explicitly specified
51
+ def const_io_stream?(logger_param)
52
+ logger_param.is_a?(String) &&
53
+ logger_param =~ VALID_RUBY_CONST &&
54
+ Kernel.const_defined?(logger_param)
55
+ end
56
+
57
+ def log_event(method, event, data = {})
58
+ extra = { 'event' => event }
59
+ data.is_a?(Hash) ? extra.merge!(data) : extra['message'] = data
60
+
61
+ if block_given?
62
+ t0 = now
63
+ begin
64
+ yield(extra)
65
+ rescue Exception => e
66
+ extra['exception'] = [e.class.name, e.message]
67
+ raise
68
+ ensure
69
+ extra['duration'] = (now - t0)
70
+ @logger.send(method, prefix_and_flatten_hash(extra))
71
+ end
72
+ else
73
+ @logger.send(method, prefix_and_flatten_hash(extra))
74
+ end
75
+ end
76
+
77
+ def method_missing(meth, *args, &block)
78
+ @logger.send(meth, *args, &block)
79
+ end
80
+
81
+ def now
82
+ Time.now.to_f * 1000
83
+ end
84
+
85
+ MAX_NESTED_LEVELS = 7
86
+
87
+ def prefix_and_flatten_hash(hash, prefix = '', level = 1)
88
+ if level > MAX_NESTED_LEVELS
89
+ return { "#{prefix}TRUNCATED" => "data nested deeper than #{MAX_NESTED_LEVELS} levels has been truncated" }
90
+ end
91
+
92
+ hash.inject({}) do |ret, (k, v)|
93
+ key = prefix + k.to_s
94
+ if v && v.is_a?(Hash)
95
+ then ret.merge(prefix_and_flatten_hash(v, key + '.', level + 1))
96
+ else ret.merge(key => v)
97
+ end
98
+ end
99
+ end
100
+
101
+ class RubyCompatibleLogger < Mu::Logger
102
+ LEVELS.each do |method|
103
+ define_method(method.to_sym) do |data = {}, &block|
104
+ log_event(method.to_sym, @event, data, &block)
105
+ end
106
+ end
107
+
108
+ def initialize(event, logger)
109
+ @event = event
110
+ super logger
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,26 @@
1
+ module Mu
2
+ module Logging
3
+ module Formatting
4
+ def self.colored_format
5
+ ColoredLogFormatter.method(:format_log)
6
+ end
7
+ end
8
+
9
+ class ColoredLogFormatter
10
+ def self.format_log(_severity, datetime, _progname, data)
11
+ event = data.delete('event') || data.delete(:event)
12
+ duration = data.delete('duration') || data.delete(:duration)
13
+ sql = data.delete('sql') || data.delete(:sql)
14
+
15
+ str = [
16
+ "\e[35m[#{datetime.strftime('%T.%L')}]\e[0m", # magenta
17
+ "\e[32m#{event}\e[0m", # green
18
+ data.map { |k, v| ["\e[34m#{k}\e[0m", v].join('=') }.join(' ') # blue=white
19
+ ].join(' ')
20
+ str << " \e[31m(#{duration.to_f.round(2)}ms)\e[0m" if duration # red
21
+ str << "\n" << sql if sql
22
+ str << "\n"
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ module Mu
2
+ module Logging
3
+ module Formatting
4
+ def self.json_format
5
+ JsonLogFormatter.method(:format_log)
6
+ end
7
+ end
8
+
9
+ class JsonLogFormatter
10
+ def self.format_log(_severity, datetime, _progname, data)
11
+ json = {
12
+ '@timestamp' => datetime.iso8601(3),
13
+ app: Mu.app,
14
+ environment: Mu.env,
15
+ host: hostname,
16
+ event: data.delete('event') || data.delete(:event)
17
+ }.merge(data)
18
+ JSON.generate(json) + "\n"
19
+ end
20
+
21
+ def self.hostname
22
+ @hostname ||= Socket.gethostname
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,17 @@
1
+ require 'mu/logger'
2
+
3
+ module Mu
4
+ module Logging
5
+ class RubyCompatibleLogger < Mu::Logger
6
+ LEVELS.each do |method|
7
+ define_method(method.to_sym) do |data = {}, &block|
8
+ log_event(method.to_sym, @event, data, &block)
9
+ end
10
+ end
11
+ def initialize(event, logger)
12
+ @event = event
13
+ super logger
14
+ end
15
+ end
16
+ end
17
+ end
data/lib/mu/version.rb ADDED
@@ -0,0 +1,3 @@
1
+ module Mu
2
+ VERSION = '0.1.0'.freeze
3
+ end
data/lib/mu.rb ADDED
@@ -0,0 +1,48 @@
1
+ require 'mu/version'
2
+ require 'mu/logger'
3
+ require 'dotenv'
4
+
5
+ module Mu
6
+ def self.app
7
+ @_app ||= 'application'
8
+ end
9
+
10
+ def self.app=(application_name)
11
+ @_app = application_name
12
+ end
13
+
14
+ def self.env
15
+ @_env ||= ENV['RACK_ENV'] || 'development'
16
+ end
17
+
18
+ def self.env=(environment)
19
+ @_env = environment
20
+ end
21
+
22
+ def self.logger
23
+ @_logger ||= Mu::Logger.new(STDOUT)
24
+ end
25
+
26
+ def self.logger=(logger)
27
+ @_logger = logger
28
+ end
29
+
30
+ def self.report_error(_e)
31
+ # TODO: Add call to abstraction for reporting service
32
+ raise NotImplementedError, 'Abstraction for reporting errors not yet implemented.'
33
+ end
34
+
35
+ def self.report_error!(_e)
36
+ # TODO: Add call to abstraction for reporting service
37
+ raise NotImplementedError, 'Abstraction for reporting errors not yet implemented.'
38
+ end
39
+
40
+ def self.init(app = nil)
41
+ self.app = app if app
42
+
43
+ # Dotenv gives precedence to files loaded earlier in the list
44
+ Dotenv.load("#{Mu.env}.env", '.env')
45
+ end
46
+ end
47
+
48
+ MU = Mu unless defined?(MU)
data/mu-ruby.gemspec ADDED
@@ -0,0 +1,38 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'mu/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'mu-ruby'
8
+ spec.version = Mu::VERSION
9
+ spec.authors = ['Scott Pfister']
10
+ spec.email = ['scott.pfister@gmail.com']
11
+
12
+ spec.summary = 'A library that provides simple, generic behavior that greatly increase success with µ-services.'
13
+ spec.description = 'A library that provides simple, generic behavior that greatly increase success with µ-services.'
14
+ spec.homepage = 'http://github.com/goneflyin/mu-ruby'
15
+ spec.license = 'MIT'
16
+
17
+ # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
18
+ # delete this section to allow pushing this gem to any host.
19
+ if spec.respond_to?(:metadata)
20
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
21
+ else
22
+ raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.'
23
+ end
24
+
25
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
26
+ spec.bindir = 'exe'
27
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ['lib']
29
+
30
+ spec.add_dependency 'dotenv', '~> 2.1', '>= 2.1.0'
31
+
32
+ spec.add_development_dependency 'bundler', '~> 1.10'
33
+ spec.add_development_dependency 'rake', '~> 10.0'
34
+ spec.add_development_dependency 'rspec', '~> 3.5', '>= 3.5.0'
35
+ spec.add_development_dependency 'rubocop', '~> 0.43', '>= 0.43.0'
36
+ spec.add_development_dependency 'pry', '~> 0.10', '>= 0.10.4'
37
+ spec.add_development_dependency 'pry-nav', '~> 0.2', '>= 0.2.4'
38
+ end
metadata ADDED
@@ -0,0 +1,192 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mu-ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Scott Pfister
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-09-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: dotenv
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.1'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 2.1.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '2.1'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 2.1.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: bundler
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.10'
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.10'
47
+ - !ruby/object:Gem::Dependency
48
+ name: rake
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '10.0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '10.0'
61
+ - !ruby/object:Gem::Dependency
62
+ name: rspec
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '3.5'
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: 3.5.0
71
+ type: :development
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - "~>"
76
+ - !ruby/object:Gem::Version
77
+ version: '3.5'
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: 3.5.0
81
+ - !ruby/object:Gem::Dependency
82
+ name: rubocop
83
+ requirement: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - "~>"
86
+ - !ruby/object:Gem::Version
87
+ version: '0.43'
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: 0.43.0
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - "~>"
96
+ - !ruby/object:Gem::Version
97
+ version: '0.43'
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: 0.43.0
101
+ - !ruby/object:Gem::Dependency
102
+ name: pry
103
+ requirement: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - "~>"
106
+ - !ruby/object:Gem::Version
107
+ version: '0.10'
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: 0.10.4
111
+ type: :development
112
+ prerelease: false
113
+ version_requirements: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.10'
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: 0.10.4
121
+ - !ruby/object:Gem::Dependency
122
+ name: pry-nav
123
+ requirement: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - "~>"
126
+ - !ruby/object:Gem::Version
127
+ version: '0.2'
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: 0.2.4
131
+ type: :development
132
+ prerelease: false
133
+ version_requirements: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - "~>"
136
+ - !ruby/object:Gem::Version
137
+ version: '0.2'
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ version: 0.2.4
141
+ description: A library that provides simple, generic behavior that greatly increase
142
+ success with µ-services.
143
+ email:
144
+ - scott.pfister@gmail.com
145
+ executables: []
146
+ extensions: []
147
+ extra_rdoc_files: []
148
+ files:
149
+ - ".gitignore"
150
+ - ".rspec"
151
+ - ".rubocop.yml"
152
+ - ".ruby-version"
153
+ - ".travis.yml"
154
+ - Gemfile
155
+ - README.md
156
+ - Rakefile
157
+ - bin/console
158
+ - bin/setup
159
+ - lib/mu.rb
160
+ - lib/mu/logger.rb
161
+ - lib/mu/logging/colored_log_formatter.rb
162
+ - lib/mu/logging/json_log_formatter.rb
163
+ - lib/mu/logging/ruby_compatible_logger.rb
164
+ - lib/mu/version.rb
165
+ - mu-ruby.gemspec
166
+ homepage: http://github.com/goneflyin/mu-ruby
167
+ licenses:
168
+ - MIT
169
+ metadata:
170
+ allowed_push_host: https://rubygems.org
171
+ post_install_message:
172
+ rdoc_options: []
173
+ require_paths:
174
+ - lib
175
+ required_ruby_version: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - ">="
178
+ - !ruby/object:Gem::Version
179
+ version: '0'
180
+ required_rubygems_version: !ruby/object:Gem::Requirement
181
+ requirements:
182
+ - - ">="
183
+ - !ruby/object:Gem::Version
184
+ version: '0'
185
+ requirements: []
186
+ rubyforge_project:
187
+ rubygems_version: 2.5.1
188
+ signing_key:
189
+ specification_version: 4
190
+ summary: A library that provides simple, generic behavior that greatly increase success
191
+ with µ-services.
192
+ test_files: []