bender 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7edca865195b4a76c8dd36e2667ca4e5da3525ec
4
+ data.tar.gz: 0c7a58986b30d1fd58f8e7d160f9b7306d9063c9
5
+ SHA512:
6
+ metadata.gz: 9ed1ea2f3f5f85090aaabc7bead95b69e8191f01dbb5f859a3da65067924b88ff4dbde922c72f51b89a8979a15cfce3cde8aa4fac7bb122280dc9697913aa55e
7
+ data.tar.gz: 2d0c454f83496d3c85951780691577e044e5bc13a97e16d8864d0728961735e0cfcf132eea9bc38718c69705bdd831c3ed2de938bfae2cf0a2d1691306e53abc
data/.env_sample ADDED
@@ -0,0 +1,4 @@
1
+ QUEUE_PREFIX=
2
+ AWS_ACCESS_KEY=
3
+ AWS_SECRET_ACCESS=
4
+ AWS_REGION=
data/.gitignore ADDED
@@ -0,0 +1,35 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /test/tmp/
9
+ /test/version_tmp/
10
+ /tmp/
11
+
12
+ ## Specific to RubyMotion:
13
+ .dat*
14
+ .repl_history
15
+ build/
16
+
17
+ ## Documentation cache and generated files:
18
+ /.yardoc/
19
+ /_yardoc/
20
+ /doc/
21
+ /rdoc/
22
+
23
+ ## Environment normalisation:
24
+ /.bundle/
25
+ /lib/bundler/man/
26
+
27
+ # for a library or gem, you might want to ignore these files since the code is
28
+ # intended to run in multiple environments; otherwise, check them in:
29
+ # Gemfile.lock
30
+ .ruby-version
31
+ .ruby-gemset
32
+
33
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
34
+ .rvmrc
35
+ .env
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,69 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ bender (0.0.1)
5
+ activesupport (~> 4.2)
6
+ aws-sdk-v1 (~> 1.61)
7
+ dotenv (~> 1.0)
8
+ thor (~> 0.19)
9
+
10
+ GEM
11
+ remote: https://rubygems.org/
12
+ specs:
13
+ activesupport (4.2.0)
14
+ i18n (~> 0.7)
15
+ json (~> 1.7, >= 1.7.7)
16
+ minitest (~> 5.1)
17
+ thread_safe (~> 0.3, >= 0.3.4)
18
+ tzinfo (~> 1.1)
19
+ aws-sdk-v1 (1.61.0)
20
+ json (~> 1.4)
21
+ nokogiri (>= 1.4.4)
22
+ byebug (3.5.1)
23
+ columnize (~> 0.8)
24
+ debugger-linecache (~> 1.2)
25
+ slop (~> 3.6)
26
+ coderay (1.1.0)
27
+ columnize (0.9.0)
28
+ debugger-linecache (1.2.0)
29
+ diff-lcs (1.1.3)
30
+ dotenv (1.0.2)
31
+ i18n (0.7.0)
32
+ json (1.8.2)
33
+ method_source (0.8.2)
34
+ mini_portile (0.6.2)
35
+ minitest (5.5.1)
36
+ nokogiri (1.6.6.2)
37
+ mini_portile (~> 0.6.0)
38
+ pry (0.10.1)
39
+ coderay (~> 1.1.0)
40
+ method_source (~> 0.8.1)
41
+ slop (~> 3.4)
42
+ pry-byebug (2.0.0)
43
+ byebug (~> 3.4)
44
+ pry (~> 0.10)
45
+ rake (10.1.0)
46
+ rspec (2.12.0)
47
+ rspec-core (~> 2.12.0)
48
+ rspec-expectations (~> 2.12.0)
49
+ rspec-mocks (~> 2.12.0)
50
+ rspec-core (2.12.2)
51
+ rspec-expectations (2.12.1)
52
+ diff-lcs (~> 1.1.3)
53
+ rspec-mocks (2.12.2)
54
+ slop (3.6.0)
55
+ thor (0.19.1)
56
+ thread_safe (0.3.4)
57
+ tzinfo (1.2.2)
58
+ thread_safe (~> 0.1)
59
+
60
+ PLATFORMS
61
+ ruby
62
+
63
+ DEPENDENCIES
64
+ bender!
65
+ bundler (~> 1.7)
66
+ pry (~> 0.10)
67
+ pry-byebug (~> 2.0)
68
+ rake (~> 10.0)
69
+ rspec (~> 2.12)
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Anthony Leak
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # bender
2
+
3
+ Reason for _bender_:
4
+
5
+ We run [Resque](https://github.com/resque/resque) workers hosted on AWS using auto scaling groups. In order to ensure workers are always running we use the super awesome [God](www.godrb.com) gem.
6
+
7
+ Our issue is when scaling-in we need to inform the resque workers to gracefully shutdown .i.e:
8
+
9
+ * Finish the current job
10
+ * Stop polling for new jobs
11
+ * Terminate the process
12
+
13
+ While we do make use of Resque's remote shutdown - God does what God does best and restarts the process. One solution would be to implement remote pause in Resque - we required additional management of our remote nodes during termination.
14
+
15
+ More to follow.
16
+
17
+ ## Installation
18
+
19
+ Add this line to your application's Gemfile:
20
+
21
+ ```ruby
22
+ gem 'bender'
23
+ ```
24
+
25
+ And then execute:
26
+
27
+ $ bundle
28
+
29
+ Or install it yourself as:
30
+
31
+ $ gem install bender
32
+
33
+ ## Usage
34
+
35
+ TODO: Write usage instructions here
36
+
37
+ ## Contributing
38
+
39
+ 1. Fork it ( https://github.com/aleak/bender/fork )
40
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
41
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
42
+ 4. Push to the branch (`git push origin my-new-feature`)
43
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/bender.gemspec ADDED
@@ -0,0 +1,33 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'bender/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "bender"
8
+ spec.version = Bender::VERSION
9
+ spec.authors = ["Anthony Leak"]
10
+ spec.email = ["anthony.leak@gmail.com"]
11
+ spec.summary = %q{Bender - Just a super guy.}
12
+ spec.description = %q{We all love Bender.}
13
+ spec.homepage = "https://www.github.com/aleak/bender"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+
24
+ spec.add_development_dependency "pry", '~> 0.10'
25
+ spec.add_development_dependency "pry-byebug", '~> 2.0'
26
+ spec.add_development_dependency "rspec", '~> 2.12'
27
+
28
+ spec.add_runtime_dependency 'aws-sdk-v1', '~> 1.61'
29
+ spec.add_runtime_dependency 'activesupport', '~> 4.2'
30
+ spec.add_runtime_dependency 'dotenv', '~> 1.0'
31
+ spec.add_runtime_dependency 'thor', '~> 0.19'
32
+
33
+ end
data/bin/bender ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift(File.join(File.dirname(File.dirname(__FILE__)), 'lib'))
4
+
5
+ require 'bender'
6
+
7
+ Bender::CLI.start(ARGV)
data/lib/bender/cli.rb ADDED
@@ -0,0 +1,69 @@
1
+ require 'yaml'
2
+ require 'thor'
3
+ require 'active_support/core_ext/hash'
4
+ require 'bender/client'
5
+
6
+ module Bender
7
+ class CLI < Thor
8
+ class_option :config, :aliases => ["-c"], :type => :string, :required => true
9
+
10
+ def initialize(args = [], opts = {}, config = {})
11
+ super(args, opts, config)
12
+
13
+ if !File.exists?(options[:config])
14
+ puts "Cannot find #{options[:config]}."
15
+ exit
16
+ end
17
+
18
+ config_options = YAML.load_file(options[:config]).deep_symbolize_keys
19
+ @options = @options.symbolize_keys.merge(config_options)
20
+ end
21
+
22
+ desc "start", "Start processing watchers."
23
+ option :require, :aliases => ["-r"], :type => :string
24
+ option :pid_file, :aliases => ["-p"], :type => :string
25
+ option :interval, :aliases => ["-i"], :type => :numeric
26
+ option :daemon, :aliases => ["-d"], :type => :boolean
27
+ option :timeout, :aliases => ["-t"], :type => :numeric
28
+ option :graceful_term, :aliases => ["-g"], :type => :boolean
29
+
30
+ def start
31
+ load_enviroment(options[:require])
32
+ opts = @options.symbolize_keys.slice(:timeout, :interval, :daemon, :pid_file)
33
+ Bender::Client.new(@options).start_watchers
34
+ end
35
+
36
+ desc "publish", "Publish a message."
37
+ option :watcher, :aliases => ["-w"], :type => :string, :required => true
38
+ option :message, :aliases => ["-m"], :type => :string, :required => true
39
+
40
+ def publish
41
+ load_enviroment(options[:require])
42
+ opts = @options.symbolize_keys.slice(:timeout, :interval, :daemon, :pid_file)
43
+ Bender::Client.new(@options).publish options[:watcher], options[:message]
44
+ end
45
+
46
+ protected
47
+ # Loads the environment from the given configuration file.
48
+ # @api private
49
+ def load_enviroment(file = nil)
50
+ file ||= "."
51
+
52
+ if File.directory?(file) && File.exists?(File.expand_path("#{file}/config/environment.rb"))
53
+ require 'rails'
54
+ require File.expand_path("#{file}/config/environment.rb")
55
+ if defined?(::Rails) && ::Rails.respond_to?(:application)
56
+ # Rails 3
57
+ ::Rails.application.eager_load!
58
+ elsif defined?(::Rails::Initializer)
59
+ # Rails 2.3
60
+ $rails_rake_task = false
61
+ ::Rails::Initializer.run :load_application_classes
62
+ end
63
+ elsif File.file?(file)
64
+ require File.expand_path(file)
65
+ end
66
+ end
67
+
68
+ end
69
+ end
@@ -0,0 +1,85 @@
1
+ require 'aws-sdk-v1'
2
+ require 'thwait'
3
+ require 'dotenv'
4
+ require 'active_support/inflector'
5
+ require 'bender/watcher'
6
+
7
+ Dotenv.load
8
+
9
+ module Bender
10
+
11
+ def self.logger
12
+ @@logger ||= Logger.new(STDOUT)
13
+ end
14
+
15
+ class Client
16
+
17
+ class << self
18
+ def keep_running?
19
+ @@keep_running
20
+ end
21
+
22
+ def queue_prefix
23
+ @@queue_prefix ||= "#{ENV['QUEUE_PREFIX']}-#{Socket.gethostname}"
24
+ end
25
+ end
26
+
27
+ def initialize(config)
28
+ @config = config
29
+ initialize_watchers
30
+ end
31
+
32
+ def trap_signals
33
+ %w{INT TERM}.each do |signal|
34
+ Signal.trap(signal) {
35
+ stop_watchers
36
+ exit
37
+ }
38
+ end
39
+ end
40
+
41
+ def start_watchers
42
+ Bender.logger.info("Starting Watchers - Press Ctrl+C to stop watchers...")
43
+ @@keep_running = true
44
+ @threads = []
45
+ @watchers.each do |watcher|
46
+ @threads << Thread.new do
47
+ watcher.start
48
+ end
49
+ end
50
+ trap_signals
51
+ ThreadsWait.all_waits(*@threads)
52
+ end
53
+
54
+ def stop_watchers
55
+ puts "Stopping watchers..."
56
+ @@keep_running = false
57
+ ThreadsWait.all_waits(*@threads)
58
+ end
59
+
60
+ def publish(watcher, message)
61
+ sent = @watchers.select{|w| w.class.to_s.underscore == watcher}.collect do |watcher|
62
+ watcher.publish(message)
63
+ end
64
+ Bender.logger.info("Sent #{sent.size} message(s)")
65
+ end
66
+
67
+ def config
68
+ @config
69
+ end
70
+
71
+ def watchers
72
+ @watchers
73
+ end
74
+
75
+ private
76
+
77
+ def initialize_watchers
78
+ @watchers = @config[:watchers].collect do |watcher_config|
79
+ Bender.logger.info("Loading #{watcher_config[:name]}")
80
+ WatcherFactory.create(watcher_config, self.config)
81
+ end
82
+ end
83
+
84
+ end
85
+ end
@@ -0,0 +1,3 @@
1
+ module Bender
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,67 @@
1
+ module WatcherFactory
2
+ def self.create(config, default_config)
3
+ watcher_class = config[:name]
4
+ require "bender/watchers/#{watcher_class}"
5
+ watcher_class.classify.constantize.new(default_config)
6
+ end
7
+ end
8
+
9
+ class Watcher
10
+ def self.sqs
11
+ @@sqs ||= AWS::SQS.new({
12
+ :access_key_id => ENV['AWS_ACCESS_KEY'],
13
+ :secret_access_key => ENV['AWS_SECRET_ACCESS'],
14
+ :region => ENV['AWS_REGION']
15
+ })
16
+ end
17
+
18
+ def initialize(options)
19
+ @options = options
20
+ load_queue
21
+ end
22
+
23
+ def start
24
+ subscribe
25
+ end
26
+
27
+ def load_queue
28
+ @queue ||= Watcher.sqs.queues.create(
29
+ "#{Bender::Client.queue_prefix}-#{@options[:name]}",
30
+ @options[:create_options]
31
+ )
32
+ rescue Exception => ex
33
+ Bender.logger.error("#{self.class}: #{ex.message}#{ex.backtrace.join("\n")}")
34
+ end
35
+
36
+ def subscribe
37
+ while Bender::Client.keep_running? do
38
+ Bender.logger.info("Polling #{@queue.arn} for #{self.class.to_s}")
39
+ @queue.poll(@options[:poll_options]) do |received_message|
40
+ safe_perform(received_message.body)
41
+ end
42
+ end
43
+ rescue Exception => ex
44
+ Bender.logger.error("#{self.class}: #{ex.message}#{ex.backtrace.join("\n")}")
45
+ end
46
+
47
+ def publish(message)
48
+ message = message.to_json if message.is_a? Hash
49
+ @queue.send_message(message)
50
+ rescue Exception => ex
51
+ Bender.logger.error("#{self.class}: #{ex.message}#{ex.backtrace.join("\n")}")
52
+ end
53
+
54
+ private
55
+
56
+ def safe_perform(json)
57
+ message = JSON.parse(json, :symbolize_names => true) rescue :invalid
58
+ if message == :invalid
59
+ Bender.logger.error("#{self.class}: Unable to parse message: #{json}")
60
+ else
61
+ self.perform(message)
62
+ end
63
+ rescue Exception => ex
64
+ Bender.logger.error("#{self.class}: Perform : #{ex.message}#{ex.backtrace.join("\n")}")
65
+ end
66
+
67
+ end
@@ -0,0 +1,28 @@
1
+ require 'open3'
2
+
3
+ class GodUnmonitor < Watcher
4
+
5
+ # Expects a message in the following format
6
+ # :task_or_group_name => 'resque'
7
+ def perform(message)
8
+ task_or_group_name = message[:task_or_group_name]
9
+
10
+ if task_or_group_name.nil?
11
+ Bender.logger.warn("GodUnmonitor: task_or_group_name not defined - #{message}")
12
+ return
13
+ end
14
+
15
+ Bender.logger.info("GodUnmonitor: #{task_or_group_name}")
16
+
17
+ # TODO: sanitize input
18
+
19
+ Open3.popen3("sudo god unmonitor #{task_or_group_name}") do |stdin, stdout, stderr, wait_thr|
20
+ info = stdout.read
21
+ error = stderr.read
22
+ Bender.logger.info("GodUnmonitor: #{info.rstrip}") unless info.empty?
23
+ Bender.logger.error("GodUnmonitor: #{error.rstrip}") unless error.empty?
24
+ end
25
+
26
+ end
27
+
28
+ end
@@ -0,0 +1,7 @@
1
+ class WatcherLifeCycleHook < Watcher
2
+
3
+ def perform(message)
4
+ Bender.logger.info("Got message #{message}")
5
+ end
6
+
7
+ end
data/lib/bender.rb ADDED
@@ -0,0 +1 @@
1
+ require 'bender/cli'
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Bender" do
4
+
5
+ it "reads a config file" do
6
+ create_options = {:create_options => {
7
+ :visibility_timeout => 90,
8
+ :maximum_message_size => 262144
9
+ }}
10
+
11
+ poll_options = {:poll_options => {
12
+ :wait_time_seconds => 10,
13
+ :idle_timeout => 5
14
+ }}
15
+
16
+ config = {
17
+ :watchers => [{
18
+ :perform => :watcher_life_cycle_hook,
19
+ :queue => {
20
+ :name => "watcher_life_cycle_hook",
21
+ }.merge(create_options).merge(poll_options)
22
+ },
23
+ {
24
+ :perform => :god_unmonitor,
25
+ :queue => {
26
+ :name => "god_unmonitor",
27
+ }.merge(create_options).merge(poll_options)
28
+ }]
29
+ }
30
+ bender = Bender.new(config)
31
+
32
+ expect(bender.config).to eq(config)
33
+ expect(bender.watchers.count).to eq(config[:watchers].count)
34
+
35
+ watchers = bender.watchers.collect(&:class)
36
+ config[:watchers].each do |watcher|
37
+ expect(watchers).to include(watcher[:perform].to_s.classify.constantize)
38
+ end
39
+
40
+ bender.start_watchers
41
+ end
42
+
43
+ end
@@ -0,0 +1,7 @@
1
+ require 'rspec'
2
+ require 'active_support/inflector'
3
+ require './bender/lib/bender.rb'
4
+
5
+ RSpec.configure do |c|
6
+
7
+ end
data/watchers.yml ADDED
@@ -0,0 +1,11 @@
1
+ create_options:
2
+ visibility_timeout: 90
3
+ maximum_message_size: 262144
4
+
5
+ poll_options:
6
+ wait_time_seconds: 10
7
+ idle_timeout: 5
8
+
9
+ watchers:
10
+ - name: watcher_life_cycle_hook
11
+ - name: god_unmonitor
metadata ADDED
@@ -0,0 +1,193 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bender
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Anthony Leak
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-01-26 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.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
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: pry
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.10'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.10'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry-byebug
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '2.12'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '2.12'
83
+ - !ruby/object:Gem::Dependency
84
+ name: aws-sdk-v1
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.61'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.61'
97
+ - !ruby/object:Gem::Dependency
98
+ name: activesupport
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '4.2'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '4.2'
111
+ - !ruby/object:Gem::Dependency
112
+ name: dotenv
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '1.0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '1.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: thor
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '0.19'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '0.19'
139
+ description: We all love Bender.
140
+ email:
141
+ - anthony.leak@gmail.com
142
+ executables:
143
+ - bender
144
+ extensions: []
145
+ extra_rdoc_files: []
146
+ files:
147
+ - ".env_sample"
148
+ - ".gitignore"
149
+ - ".rspec"
150
+ - Gemfile
151
+ - Gemfile.lock
152
+ - LICENSE.txt
153
+ - README.md
154
+ - Rakefile
155
+ - bender.gemspec
156
+ - bin/bender
157
+ - lib/bender.rb
158
+ - lib/bender/cli.rb
159
+ - lib/bender/client.rb
160
+ - lib/bender/version.rb
161
+ - lib/bender/watcher.rb
162
+ - lib/bender/watchers/god_unmonitor.rb
163
+ - lib/bender/watchers/watcher_life_cycle_hook.rb
164
+ - spec/bender_spec.rb
165
+ - spec/spec_helper.rb
166
+ - watchers.yml
167
+ homepage: https://www.github.com/aleak/bender
168
+ licenses:
169
+ - MIT
170
+ metadata: {}
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.2.2
188
+ signing_key:
189
+ specification_version: 4
190
+ summary: Bender - Just a super guy.
191
+ test_files:
192
+ - spec/bender_spec.rb
193
+ - spec/spec_helper.rb