activecrew 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a45d0ac6c7ba04c2eee3d07464b4a33eb8929527
4
+ data.tar.gz: d451a7a7ada0b52d1cab74db53f5545f0b48f1bc
5
+ SHA512:
6
+ metadata.gz: fdea905f162d86ff05391ed80582cbfaa5c092f2a2741847a65f0dc73273d63bfb61f987f614cba8b43d0466374ec0ebbffe09ea56d0939723a29669bcf51af7
7
+ data.tar.gz: 487f78c9e5cc76199a3f0841ad956f4c38aaa7170cc2a6cda9aed1e0dc6ccbd656e66dcd437afe897ab71201fa3e1b45c7f57c6f4c215ab9c8dedf983ffac01c
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /.idea
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.3.1
4
+ before_install: gem install bundler -v 1.13.6
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in activecommand.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Max Kazarin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,41 @@
1
+ # ActiveCrew
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/activecrew.svg)](https://badge.fury.io/rb/activecrew)
4
+ [![Code Climate](https://codeclimate.com/github/maxkazar/activecrew/badges/gpa.svg)](https://codeclimate.com/github/maxkazar/activecrew)
5
+ [![Build Status](https://travis-ci.org/maxkazar/activecrew.svg)](https://travis-ci.org/maxkazar/activecrew)
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'activecrew'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install activecrew
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ 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.
30
+
31
+ 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).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/maxkazar/activecrew.
36
+
37
+
38
+ ## License
39
+
40
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
41
+
@@ -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
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'active_crew/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'activecrew'
8
+ spec.version = ActiveCrew::VERSION
9
+ spec.authors = ['Max Kazarin']
10
+ spec.email = ['maxkazargm@gmail.com']
11
+
12
+ spec.summary = %q{Steroid command pattern.}
13
+ spec.description = %q{Steroid command pattern.}
14
+ spec.homepage = 'https://github.com/maxkazar/activecrew'
15
+ spec.license = 'MIT'
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(spec)/}) }
18
+ spec.require_paths = ['lib']
19
+
20
+ spec.add_development_dependency 'bundler', '~> 1.10'
21
+ spec.add_development_dependency 'rake', '~> 10.0'
22
+ spec.add_development_dependency 'rspec'
23
+ spec.add_development_dependency 'actionpack', '~> 4.0'
24
+
25
+ spec.add_dependency 'activesupport', '~> 4.0'
26
+ end
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "activecrew"
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
@@ -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
@@ -0,0 +1,46 @@
1
+ require 'rubygems'
2
+
3
+ require 'active_support/all'
4
+ require 'active_crew/version'
5
+ require 'active_crew/configuration'
6
+ require 'active_crew/concerns/authorizable'
7
+ require 'active_crew/concerns/chainable'
8
+ require 'active_crew/concerns/commandable'
9
+ require 'active_crew/concerns/combinable'
10
+ require 'active_crew/concerns/respondable'
11
+ require 'active_crew/concerns/measurable'
12
+ require 'active_crew/concerns/validatable'
13
+ require 'active_crew/base'
14
+ require 'active_crew/backends'
15
+ require 'active_crew/responders'
16
+
17
+ require 'active_crew/extender' if defined? ActionController
18
+
19
+ module ActiveCrew
20
+ class << self
21
+ # Getter for shared global objects
22
+ attr_reader :configuration
23
+
24
+ # Returns the global [Configuration](ActiveCrew/Configuration) object.
25
+ #
26
+ # @example
27
+ # ActiveCrew.configuration.responder = :pusher
28
+ def configuration
29
+ @configuration ||= ActiveCrew::Configuration.new
30
+ end
31
+
32
+ # Yields the global configuration to a block.
33
+ # @yield [Configuration] global configuration
34
+ #
35
+ # @example
36
+ # ActiveCrew.configure do |config|
37
+ # config.responder = :fayer
38
+ # end
39
+ def configure
40
+ yield configuration if block_given?
41
+
42
+ Backends.create
43
+ Responders.create
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,45 @@
1
+ module ActiveCrew
2
+ module Backends
3
+ autoload :InlineBackend, 'active_crew/backends/inline_backend'
4
+ autoload :SidekiqBackend, 'active_crew/backends/sidekiq_backend'
5
+
6
+ class << self
7
+ attr_reader :default
8
+
9
+ def create
10
+ @default = "ActiveCrew::Backends::#{backend.to_s.classify}Backend".constantize
11
+ rescue NameError
12
+ raise ArgumentError, "Unsupported backend #{backend} for active command."
13
+ end
14
+
15
+ def enqueue(name, invoker, *args)
16
+ default.enqueue name, serialize(invoker), *args
17
+ end
18
+
19
+ def dequeue(name, invoker, *args)
20
+ command = create_command name, deserialize(invoker), *args
21
+ command.execute if command.can_execute?
22
+ end
23
+
24
+ private
25
+
26
+ def backend
27
+ ActiveCrew.configuration.backend
28
+ end
29
+
30
+ def serialize(invoker)
31
+ [invoker.class.name, invoker.id.to_s]
32
+ end
33
+
34
+ def deserialize(invoker)
35
+ invoker[0].constantize.find invoker[1]
36
+ end
37
+
38
+ def create_command(name, invoker, *args)
39
+ "#{name.classify}Command".constantize.new invoker, *args
40
+ rescue NameError
41
+ raise ArgumentError, "Unsupported command #{name} for active command."
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,19 @@
1
+ module ActiveCrew
2
+ module Backends
3
+ class InlineBackend
4
+ class Queue
5
+ def size
6
+ 0
7
+ end
8
+ end
9
+
10
+ def self.enqueue(*args)
11
+ ActiveCrew::Backends.dequeue *args
12
+ end
13
+
14
+ def self.queue(command_name)
15
+ Queue.new
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,27 @@
1
+ module ActiveCrew
2
+ module Backends
3
+ class SidekiqBackend
4
+ include Sidekiq::Worker
5
+
6
+ class << self
7
+ def enqueue(*args)
8
+ Sidekiq::Client.push 'class' => self,
9
+ 'queue' => queue_name(args.first),
10
+ 'args' => args
11
+ end
12
+
13
+ def queue_name(command_name)
14
+ command_name[/^(.*)\/[^\/]*$/, 1].underscore.gsub(/\//, '_')
15
+ end
16
+
17
+ def queue(command_name)
18
+ Sidekiq::Queue.new queue_name command_name
19
+ end
20
+ end
21
+
22
+ def perform(*args)
23
+ ActiveCrew::Backends.dequeue *args
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,50 @@
1
+ module ActiveCrew
2
+
3
+ # Sidekiq Command class. Implements command pattern for Sidekiq.
4
+ # Helps to deconstruct application into micro services with command interface.
5
+ #
6
+ # Command class file structure with two micro services (mailer and users):
7
+ #
8
+ # app
9
+ # commands
10
+ # mailer
11
+ # deliver_command.rb
12
+ # users
13
+ # create_command.rb
14
+ #
15
+ # Command queues will be the following:
16
+ #
17
+ # mailer
18
+ # users
19
+ #
20
+ class Base
21
+ prepend Chainable
22
+ prepend Combinable
23
+ prepend Validatable
24
+ prepend Measurable
25
+ prepend Respondable
26
+ prepend Authorizable
27
+
28
+ include Commandable
29
+
30
+ attr_reader :invoker, :options, :context
31
+
32
+ def initialize(invoker, context = {})
33
+ @invoker = invoker
34
+ # Should only symbolize key for
35
+ @context = ActiveSupport::HashWithIndifferentAccess.new context
36
+ @options = @context[:options] || {}
37
+ end
38
+
39
+ def name
40
+ @name ||= self.class.name.underscore.gsub(/_command/, '')
41
+ end
42
+
43
+ def execute
44
+ perform
45
+ end
46
+
47
+ def perform
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,17 @@
1
+ module ActiveCrew
2
+ class AuthorizationError < Exception; end
3
+
4
+ module Authorizable
5
+ extend ActiveSupport::Concern
6
+
7
+ def execute
8
+ raise AuthorizationError unless can_execute?
9
+
10
+ super
11
+ end
12
+
13
+ def can_execute?
14
+ invoker.can? name, options
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,35 @@
1
+ module ActiveCrew
2
+ module Chainable
3
+ def chain
4
+ @chain ||= @context[:chain] || []
5
+ end
6
+
7
+ def commands(*args)
8
+ options = args.extract_options!
9
+ add_to_chain args
10
+ execute_chain options
11
+ end
12
+
13
+ def execute
14
+ super
15
+ execute_chain
16
+ end
17
+
18
+ private
19
+
20
+ def add_to_chain(commands)
21
+ chain.concat commands
22
+ end
23
+
24
+ def execute_chain(options = nil)
25
+ return unless chain.present?
26
+
27
+ name = chain.shift
28
+ if name.is_a? Array
29
+ name.each { |name| command name, options }
30
+ else
31
+ command name, options, chain: chain
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,27 @@
1
+ module ActiveCrew
2
+ # Combinable behavior helps to combine command executions into one command execution
3
+ module Combinable
4
+ def execute
5
+ super
6
+ execute_combine_commands
7
+ end
8
+
9
+ def combine_command(name, options = {})
10
+ combine_command_options = combine_commands[name] ||= {}
11
+ options.each do |key, value|
12
+ combine_command_value = combine_command_options[key] ||= []
13
+ combine_command_value << value unless combine_command_value.include? value
14
+ end
15
+ end
16
+
17
+ def combine_commands
18
+ @combine_commands ||= {}
19
+ end
20
+
21
+ private
22
+
23
+ def execute_combine_commands
24
+ combine_commands.each { |name, options| command name, options }
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,11 @@
1
+ module ActiveCrew
2
+ module Commandable
3
+ def command(name, options = {}, context = {})
4
+ Backends.enqueue name, invoker, @context.merge(options: options).merge(context)
5
+ end
6
+
7
+ def backend
8
+ Backends.default
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,30 @@
1
+ module ActiveCrew
2
+ class MeasurerError < Exception; end
3
+
4
+ module Measurable
5
+ extend ActiveSupport::Concern
6
+
7
+ private
8
+
9
+ def execute
10
+ started_at = Time.current
11
+
12
+ super
13
+
14
+ measurer.measure self, Time.current - started_at if measurer
15
+ end
16
+
17
+ def has_measurer?
18
+ measurer.present?
19
+ end
20
+
21
+ def measurer
22
+ return @measurer if defined? @measurer
23
+
24
+ measurer_name = ActiveCrew.configuration.measurer
25
+ @measurer = measurer_name && measurer_name.to_s.classify.constantize
26
+ rescue NameError
27
+ raise MeasurerError, "Unsupported measurer #{measurer_name} for active command."
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,21 @@
1
+ module ActiveCrew
2
+ class CommandError < Exception; end
3
+
4
+ module Respondable
5
+ def respond_with(model)
6
+ Responders.respond_with name, invoker, context, model
7
+ end
8
+
9
+ def respond_fail(*args)
10
+ fail CommandError, I18n.t(*args)
11
+ end
12
+
13
+ def execute
14
+ super
15
+ rescue Interrupt
16
+ raise
17
+ rescue CommandError
18
+ respond_with $ERROR_INFO
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ module ActiveCrew
2
+ module Validatable
3
+ extend ActiveSupport::Concern
4
+
5
+ def validate!
6
+
7
+ end
8
+
9
+ def execute
10
+ validate!
11
+
12
+ super
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,10 @@
1
+ module ActiveCrew
2
+ class Configuration
3
+ attr_accessor :responder, :backend, :measurer
4
+
5
+ def initialize
6
+ @responder = :inline
7
+ @backend = :inline
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ module ActiveCrew
2
+ module Extender
3
+ def command(name, options)
4
+ context = { options: options }
5
+
6
+ ActiveCrew::Responders.init context, request
7
+ ActiveCrew::Backends.enqueue name, current_user, context
8
+ end
9
+ end
10
+ end
11
+
12
+ ActionController::Base.include ActiveCrew::Extender
@@ -0,0 +1,30 @@
1
+ module ActiveCrew
2
+ module Responders
3
+ autoload :InlineResponder, 'active_crew/responders/inline_responder'
4
+ autoload :FayeResponder, 'active_crew/responders/faye_responder'
5
+
6
+ class << self
7
+ attr_reader :default
8
+
9
+ def create
10
+ @default = "ActiveCrew::Responders::#{responder.to_s.classify}Responder".constantize
11
+ rescue NameError
12
+ raise ArgumentError, "Unsupported responder #{responder} for active command."
13
+ end
14
+
15
+ def init(context, request)
16
+ default.init(context, request) if default.respond_to? :init
17
+ end
18
+
19
+ def respond_with(name, invoker, context, model)
20
+ default.respond name, invoker, context, model
21
+ end
22
+
23
+ private
24
+
25
+ def responder
26
+ ActiveCrew.configuration.responder
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,109 @@
1
+ module ActiveCrew
2
+ module Responders
3
+ # FayeResponderError class.
4
+ class FayeResponderError < Exception; end
5
+
6
+ # FayeConnectionError class.
7
+ class FayeConnectionError < Exception; end
8
+
9
+ # ActiveCrew Faye responder.
10
+ module FayeResponder
11
+ module_function
12
+
13
+ MAX_RETRIES = 5
14
+
15
+ def init(context, request)
16
+ context[:session] = request.headers['x-session-token']
17
+ end
18
+
19
+ # Respond with faye
20
+ def respond(name, invoker, context, model)
21
+ request channel: channel(invoker),
22
+ data: payload(name, invoker, context, model),
23
+ ext: { publish_key: config[:publish_key] }
24
+ end
25
+
26
+ def request(message)
27
+ retries = 0
28
+
29
+ begin
30
+ validate RestClient.post url, message.to_json, header
31
+ rescue FayeResponderError
32
+ retries += 1
33
+ raise FayeConnectionError $ERROR_INFO unless retries < MAX_RETRIES
34
+
35
+ retry
36
+ rescue FayeConnectionError
37
+ Rails.logger.fatal $ERROR_INFO.message
38
+ end
39
+ end
40
+
41
+ # @return Invoker channel name
42
+ def channel(invoker)
43
+ "/#{invoker.class.to_s.underscore}/#{invoker.id}"
44
+ end
45
+
46
+ # @return Faye request payload
47
+ def payload(name, invoker, context, model)
48
+ {
49
+ invoker: serialize_invoker(invoker),
50
+ session: context[:session],
51
+ command: name,
52
+ status: status(model),
53
+ response: serialize(model)
54
+ }
55
+ end
56
+
57
+ def serialize_invoker(invoker)
58
+ serialize invoker, serializer: "#{invoker.class}::InvokerSerializer".constantize
59
+ end
60
+
61
+ # Serialize payload
62
+ def serialize(model, options = {})
63
+ return { base: model.message } if model.is_a? CommandError
64
+
65
+ if model.is_a?(Array) || model.errors.empty?
66
+ ActiveModelSerializers::SerializableResource.new(model, options).serializable_hash
67
+ else
68
+ ActiveModelSerializers::SerializableResource.new(model.errors, options.merge(root: 'errors')).serializable_hash[:errors]
69
+ end
70
+ end
71
+
72
+ def status(model)
73
+ model.is_a?(Array) || !model.is_a?(CommandError) && model.valid? ? :success : :failure
74
+ end
75
+
76
+ # @return Faye request header
77
+ def header
78
+ {
79
+ 'Content-Type' => 'application/json',
80
+ 'Pragma' => 'no-cache',
81
+ 'X-Requested-With' => 'XMLHttpRequest'
82
+ }
83
+ end
84
+
85
+ # Validate faye response
86
+ def validate(response)
87
+ fail FayeResponderError, response.code unless response.code == 200
88
+
89
+ response = JSON.parse(response)[0].symbolize_keys
90
+ fail FayeResponderError, response[:error] unless response[:successful]
91
+ end
92
+
93
+ def url
94
+ "http://#{config[:host]}/faye"
95
+ end
96
+
97
+ def config
98
+ return @config if defined? @config
99
+
100
+ @config = YAML.load(ERB.new(File.new(config_path).read).result)[Rails.env]
101
+ @config = (@config || {}).symbolize_keys
102
+ end
103
+
104
+ def config_path
105
+ File.join(Rails.root, 'config', 'faye.yml')
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,9 @@
1
+ module ActiveCrew
2
+ module Responders
3
+ module InlineResponder
4
+ def self.respond(*, model)
5
+ model
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ module ActiveCrew
2
+ VERSION = '0.1.4'
3
+ end
@@ -0,0 +1 @@
1
+ require 'active_crew'
metadata ADDED
@@ -0,0 +1,142 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: activecrew
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.4
5
+ platform: ruby
6
+ authors:
7
+ - Max Kazarin
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-11-17 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.10'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.10'
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: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: actionpack
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '4.0'
62
+ type: :development
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: activesupport
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '4.0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '4.0'
83
+ description: Steroid command pattern.
84
+ email:
85
+ - maxkazargm@gmail.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - ".travis.yml"
92
+ - Gemfile
93
+ - LICENSE.txt
94
+ - README.md
95
+ - Rakefile
96
+ - activecrew.gemspec
97
+ - bin/console
98
+ - bin/setup
99
+ - lib/active_crew.rb
100
+ - lib/active_crew/backends.rb
101
+ - lib/active_crew/backends/inline_backend.rb
102
+ - lib/active_crew/backends/sidekiq_backend.rb
103
+ - lib/active_crew/base.rb
104
+ - lib/active_crew/concerns/authorizable.rb
105
+ - lib/active_crew/concerns/chainable.rb
106
+ - lib/active_crew/concerns/combinable.rb
107
+ - lib/active_crew/concerns/commandable.rb
108
+ - lib/active_crew/concerns/measurable.rb
109
+ - lib/active_crew/concerns/respondable.rb
110
+ - lib/active_crew/concerns/validatable.rb
111
+ - lib/active_crew/configuration.rb
112
+ - lib/active_crew/extender.rb
113
+ - lib/active_crew/responders.rb
114
+ - lib/active_crew/responders/faye_responder.rb
115
+ - lib/active_crew/responders/inline_responder.rb
116
+ - lib/active_crew/version.rb
117
+ - lib/activecrew.rb
118
+ homepage: https://github.com/maxkazar/activecrew
119
+ licenses:
120
+ - MIT
121
+ metadata: {}
122
+ post_install_message:
123
+ rdoc_options: []
124
+ require_paths:
125
+ - lib
126
+ required_ruby_version: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ required_rubygems_version: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - ">="
134
+ - !ruby/object:Gem::Version
135
+ version: '0'
136
+ requirements: []
137
+ rubyforge_project:
138
+ rubygems_version: 2.6.7
139
+ signing_key:
140
+ specification_version: 4
141
+ summary: Steroid command pattern.
142
+ test_files: []