dory 0.0.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 40cc6a4df9ad06bae1d7a31759ecb53adc6d572c
4
+ data.tar.gz: 24555f11409591b5cffed182d40116470f18f102
5
+ SHA512:
6
+ metadata.gz: e3d2b23ee537f119442b8026363f34e9c337ecb6113a1d25d8c0a6ca89c15ad2dc3e0486a63f13c4cae1d540a0086bc4bac7fd177b62cd93ad1e62762db93694
7
+ data.tar.gz: 332ae28ca60a47895871ecfd4454023545a1328709b9bde41578707344386c0735135c328a05c5131f98c073ff250b0f9fca377d25a62ab0a20c8249ee28c409
@@ -0,0 +1,210 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'thor'
4
+ require 'yaml'
5
+
6
+ require 'dory'
7
+
8
+ class DoryBin < Thor
9
+ class_option :verbose, type: :boolean, aliases: 'v', default: false
10
+
11
+ desc 'up', 'Bring up dory services (nginx-proxy, dnsmasq, resolv)'
12
+ long_desc <<-LONGDESC
13
+ Bring up dory services (nginx-proxy, dnsmasq, resolv)
14
+
15
+ When run, the docker container for the nginx proxy is started,
16
+ along with a local dnsmasq instance to resolve DNS requests
17
+ for your custom domain to the nginx proxy. The local resolver
18
+ will also be configured to use the dnsmasq instance as a nameserver
19
+
20
+ You can optionally pass in [-s|--server] or [-c|--client] if doing
21
+ development on a cloud server. This will tell dory to only bring
22
+ up the nginx proxy container if passed --server or only the
23
+ dnsmasq/resolv if passed --client. If both server and client
24
+ are passed, it is equivalent to a naked 'up'
25
+
26
+ > $ dory up [-s|--server] [-c|--client]
27
+ LONGDESC
28
+ option :client, type: :boolean, aliases: 'c', default: false
29
+ option :server, type: :boolean, aliases: 's', default: false
30
+ def up
31
+ exec_up(options)
32
+ end
33
+
34
+ desc 'down', 'Stop all dory services'
35
+ long_desc <<-LONGDESC
36
+ Stops all dory services. Can optionally pass [-d|--destroy]
37
+ to destroy the containers when they stop.
38
+
39
+ > $ dory down [-d|--destroy]
40
+ LONGDESC
41
+ option :destroy, type: :boolean, aliases: 'd', default: true
42
+ def down
43
+ exec_down(options)
44
+ end
45
+
46
+ desc 'version', 'Check current installed version of dory'
47
+ def version
48
+ puts "Dory - Version: #{Dory::VERSION}"
49
+ end
50
+
51
+ desc 'restart', 'Stop and restart all dory services'
52
+ long_desc <<-LONGDESC
53
+ Stop and restart dory services (nginx-proxy, dnsmasq, resolv)
54
+
55
+ > $ dory restart [-d|--destroy] [-s|--server] [-c|--client]
56
+ LONGDESC
57
+ option :client, type: :boolean, aliases: 'c', default: false
58
+ option :server, type: :boolean, aliases: 's', default: false
59
+ option :destroy, type: :boolean, aliases: 'd', default: true
60
+ def restart
61
+ exec_down(options)
62
+ exec_up(options)
63
+ end
64
+
65
+ desc 'status', 'Report status of the dory services'
66
+ long_desc <<-LONGDESC
67
+ Checks the current status of the services managed by dory.
68
+ This includes nginx-proxy, dnsmasq, and resolv
69
+
70
+ > $ dory status
71
+ LONGDESC
72
+ def status
73
+ exec_status(options)
74
+ end
75
+
76
+ desc 'config-file', 'Write a default config file'
77
+ long_desc <<-LONGDESC
78
+ Writes a dory config file to #{Dory::Config.filename}
79
+ containing the default settings. This can then be configured
80
+ as preferred.
81
+ LONGDESC
82
+ def config_file
83
+ exec_config_file(options)
84
+ end
85
+
86
+ private
87
+
88
+ def exec_config_file(options)
89
+ if File.exist?(Dory::Config.filename)
90
+ print "A config file already exists at #{Dory::Config.filename}. Overwrite with default settings? (Y/N): ".yellow
91
+ conf = STDIN.gets.chomp
92
+ unless conf =~ /y/i
93
+ puts "User declined over-writing. Not writing config file".red
94
+ return
95
+ end
96
+ end
97
+ puts "Writing config file to #{Dory::Config.filename}".green
98
+ Dory::Config.write_default_settings_file
99
+ end
100
+
101
+ def exec_up(options)
102
+ full = (!options[:server] && !options[:client]) ||
103
+ ( options[:server] && options[:client])
104
+
105
+ puts "Reading settings file at '#{Dory::Config.filename}'".green if options[:verbose]
106
+ settings = Dory::Config.settings
107
+ if settings[:dory][:nginx_proxy][:enabled]
108
+ puts "nginx_proxy enabled in config file".green if options[:verbose]
109
+ if Dory::Proxy.start
110
+ puts "Successfully started nginx proxy".green
111
+ else
112
+ puts "Error starting nginx proxy".red
113
+ end
114
+ else
115
+ puts "nginx_proxy disabled in config file".yellow if options[:verbose]
116
+ end
117
+
118
+ if settings[:dory][:dnsmasq][:enabled]
119
+ puts "dnsmasq enabled in config file".green if options[:verbose]
120
+ if Dory::Dnsmasq.start
121
+ puts "Successfully started dnsmasq".green
122
+ else
123
+ puts "Error starting dnsmasq".red
124
+ end
125
+ else
126
+ puts "dnsmasq disabled in config file".yellow if options[:verbose]
127
+ end
128
+
129
+ if settings[:dory][:resolv][:enabled]
130
+ if Dory::Resolv.configure
131
+ puts "Successfully configured local resolver".green
132
+ else
133
+ puts "Error configuring local resolver".red
134
+ end
135
+ puts "resolv enabled in config file".green if options[:verbose]
136
+ else
137
+ puts "resolv disabled in config file".yellow if options[:verbose]
138
+ end
139
+ end
140
+
141
+ def exec_status(options)
142
+ settings = Dory::Config.settings
143
+
144
+ if Dory::Proxy.running?
145
+ puts "[*] Nginx proxy: Running as docker container #{Dory::Proxy.container_name}".green
146
+ elsif !settings[:dory][:nginx_proxy][:enabled]
147
+ puts "[*] Nginx proxy is disabled in config file".yellow
148
+ else
149
+ puts "[*] Nginx proxy is not running".red
150
+ end
151
+
152
+ if Dory::Dnsmasq.running?
153
+ puts "[*] Dnsmasq: Running as docker container #{Dory::Dnsmasq.container_name}".green
154
+ elsif !settings[:dory][:dnsmasq][:enabled]
155
+ puts "[*] Dnsmasq is disabled in config file".yellow
156
+ else
157
+ puts "[*] Dnsmasq is not running".red
158
+ end
159
+
160
+ if Dory::Resolv.has_our_nameserver?
161
+ puts "[*] Resolv: configured with nameserver #{}".green
162
+ elsif !settings[:dory][:resolv][:enabled]
163
+ puts "[*] Resolv is disabled in config file".yellow
164
+ else
165
+ puts "[*] Resolv is not configured".red
166
+ end
167
+ end
168
+
169
+ def exec_down(options)
170
+ destroy = options[:destroy]
171
+
172
+ if Dory::Resolv.clean
173
+ puts "nameserver removed from resolv file".green
174
+ else
175
+ puts "Unable to remove nameserver from resolv file".red
176
+ end
177
+
178
+ if Dory::Dnsmasq.stop
179
+ puts "Dnsmasq container stopped".green
180
+ if options[:destroy]
181
+ if Dory::Dnsmasq.delete
182
+ puts "Dnsmasq container successfully deleted".green
183
+ else
184
+ puts "Dnsmasq container failed to delete".red
185
+ end
186
+ end
187
+ else
188
+ puts "Dnsmasq container failed to stop".red
189
+ end
190
+
191
+ if Dory::Proxy.stop
192
+ puts "Nginx proxy stopped".green
193
+ if options[:destroy]
194
+ if Dory::Proxy.delete
195
+ puts "Nginx proxy container successfully deleted".green
196
+ else
197
+ puts "Nginx proxy container failed to delete".red
198
+ end
199
+ end
200
+ else
201
+ puts "Nginx proxy failed to stop".red
202
+ end
203
+ end
204
+ end
205
+
206
+ if !ARGV.empty? && %w[-v --version].include?(ARGV.first)
207
+ puts "Dory - Version: #{Dory::VERSION}"
208
+ else
209
+ DoryBin.start(ARGV)
210
+ end
@@ -0,0 +1,3 @@
1
+ Gem.find_files('dory/**/*.rb').each do |path|
2
+ require path.gsub(/\.rb$/, '') unless path =~ /bot.*cli/
3
+ end
@@ -0,0 +1,54 @@
1
+ require 'yaml'
2
+
3
+ module Dory
4
+ class Config
5
+ def self.filename
6
+ "#{Dir.home}/.dory.yml"
7
+ end
8
+
9
+ def self.default_yaml
10
+ %q(---
11
+ :dory:
12
+ # Be careful if you change the settings of some of
13
+ # these services. They may not talk to each other
14
+ # if you change IP Addresses.
15
+ # For example, resolv expects a nameserver listening at
16
+ # the specifed address. dnsmasq normally does this,
17
+ # but if you disable dnsmasq, it
18
+ # will make your system look for a name server that
19
+ # doesn't exist.
20
+ :dnsmasq:
21
+ :enabled: true
22
+ :domain: docker # domain that will be listend for
23
+ :address: 127.0.0.1 # address returned for queries against domain
24
+ :container_name: dory_dnsmasq
25
+ :nginx_proxy:
26
+ :enabled: true
27
+ :container_name: dory_dinghy_http_proxy
28
+ :resolv:
29
+ :enabled: true
30
+ :nameserver: 127.0.0.1
31
+ ).split("\n").map{|s| s.sub(' ' * 8, '')}.join("\n")
32
+ end
33
+
34
+ def self.default_settings
35
+ YAML.load(self.default_yaml)
36
+ end
37
+
38
+ def self.settings(filename = self.filename)
39
+ if File.exist?(filename)
40
+ self.default_settings.merge(YAML.load_file(filename))
41
+ else
42
+ self.default_settings
43
+ end
44
+ end
45
+
46
+ def self.write_settings(settings, filename = self.filename)
47
+ File.write(filename, settings)
48
+ end
49
+
50
+ def self.write_default_settings_file(filename = self.filename)
51
+ self.write_settings(self.default_yaml, filename)
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,28 @@
1
+ require_relative 'docker_service'
2
+
3
+ module Dory
4
+ class Dnsmasq
5
+ extend Dory::DockerService
6
+
7
+ def self.dnsmasq_image_name
8
+ 'freedomben/dory-dnsmasq'
9
+ end
10
+
11
+ def self.container_name
12
+ Dory::Config.settings[:dory][:dnsmasq][:container_name]
13
+ end
14
+
15
+ def self.domain
16
+ Dory::Config.settings[:dory][:dnsmasq][:domain]
17
+ end
18
+
19
+ def self.addr
20
+ Dory::Config.settings[:dory][:dnsmasq][:address]
21
+ end
22
+
23
+ def self.run_cmd(domain = self.domain, addr = self.addr)
24
+ "docker run -d -p 53:53/tcp -p 53:53/udp --name=#{self.container_name} " \
25
+ "--cap-add=NET_ADMIN #{self.dnsmasq_image_name} #{self.domain} #{self.addr}"
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,54 @@
1
+ module Dory
2
+ module DockerService
3
+ def start
4
+ unless self.running?
5
+ success = if self.container_exists?
6
+ Sh.run_command("docker start #{self.container_name}")
7
+ else
8
+ Sh.run_command(self.run_cmd).success?
9
+ end
10
+ unless success
11
+ raise RuntimeError.new(
12
+ "Failed to run nginx proxy. Command #{self.run_cmd} failed"
13
+ )
14
+ end
15
+ end
16
+ self.running?
17
+ end
18
+
19
+ def running?(container_name = self.container_name)
20
+ !!(self.ps =~ /#{container_name}/)
21
+ end
22
+
23
+ def container_exists?(container_name = self.container_name)
24
+ !!(self.ps(all: true) =~ /#{container_name}/)
25
+ end
26
+
27
+ def ps(all: false)
28
+ cmd = "docker ps#{all ? ' -a' : ''}"
29
+ ret = Sh.run_command(cmd)
30
+ if ret.success?
31
+ return ret.stdout
32
+ else
33
+ raise RuntimeError.new("Failure running command '#{cmd}'")
34
+ end
35
+ end
36
+
37
+ def has_docker_client?
38
+ Sh.run_command('which docker').success?
39
+ end
40
+
41
+ def stop(container_name = self.container_name)
42
+ Sh.run_command("docker kill #{container_name}") if self.running?
43
+ !self.running?
44
+ end
45
+
46
+ def delete(container_name = self.container_name)
47
+ if self.container_exists?
48
+ self.stop if self.running?
49
+ Sh.run_command("docker rm #{container_name}")
50
+ end
51
+ !self.container_exists?
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,33 @@
1
+ module InstVarsToHash
2
+ def to_s
3
+ to_h.to_s
4
+ end
5
+
6
+ def to_h
7
+ retval = {}
8
+ instance_variables.each do |iv|
9
+ retval[iv.to_s.delete('@').to_sym] = elem_to_h(instance_variable_get(iv))
10
+ end
11
+ retval
12
+ end
13
+
14
+ private
15
+
16
+ def expandable_classes
17
+ [ InstVarsToHash ]
18
+ end
19
+
20
+ def expandable_to_hash(klass)
21
+ expandable_classes.any?{ |k| klass == k || klass < k }
22
+ end
23
+
24
+ def elem_to_h(elem)
25
+ if elem.class == Array
26
+ elem.map { |el| elem_to_h(el) }
27
+ elsif expandable_to_hash(elem.class)
28
+ elem.to_h
29
+ else
30
+ elem
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,53 @@
1
+ module Dory
2
+ module Linux
3
+ def self.bash(command)
4
+ system("bash -c '#{command}'")
5
+ end
6
+
7
+ def self.ubuntu?
8
+ self.bash(self.ubuntu_cmd)
9
+ end
10
+
11
+ def self.fedora?
12
+ self.bash(self.fedora_cmd)
13
+ end
14
+
15
+ def self.arch?
16
+ self.bash(self.arch_cmd)
17
+ end
18
+
19
+ def self.osx?
20
+ self.bash('uname -a | grep "Darwin" > /dev/null')
21
+ end
22
+
23
+ def self.ubuntu_cmd
24
+ %q(
25
+ if $(which lsb_release >/dev/null 2>&1); then
26
+ lsb_release -d | grep --color=auto "Ubuntu" > /dev/null
27
+ else
28
+ uname -a | grep --color=auto "Ubuntu" > /dev/null
29
+ fi
30
+ )
31
+ end
32
+
33
+ def self.fedora_cmd
34
+ %q(
35
+ if $(which lsb_release >/dev/null 2>&1); then
36
+ lsb_release -d | grep --color=auto "Fedora" > /dev/null
37
+ else
38
+ uname -r | grep --color=auto "fc" > /dev/null
39
+ fi
40
+ )
41
+ end
42
+
43
+ def self.arch_cmd
44
+ %q(
45
+ if $(which lsb_release >/dev/null 2>&1); then
46
+ lsb_release -d | grep --color=auto "Arch" > /dev/null
47
+ else
48
+ uname -a | grep --color=auto "ARCH" > /dev/null
49
+ fi
50
+ )
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,21 @@
1
+ require_relative 'docker_service'
2
+
3
+ module Dory
4
+ class Proxy
5
+ extend Dory::DockerService
6
+
7
+ def self.dinghy_http_proxy_image_name
8
+ 'codekitchen/dinghy-http-proxy:2.0.3'
9
+ end
10
+
11
+ def self.container_name
12
+ Dory::Config.settings[:dory][:nginx_proxy][:container_name]
13
+ end
14
+
15
+ def self.run_cmd
16
+ "docker run -d -p 80:80 -v /var/run/docker.sock:/tmp/docker.sock -e " \
17
+ "'CONTAINER_NAME=#{self.container_name}' --name " \
18
+ "'#{self.container_name}' #{dinghy_http_proxy_image_name}"
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,85 @@
1
+ require 'colorize'
2
+
3
+ module Dory
4
+ module Resolv
5
+ def self.common_resolv_file
6
+ '/etc/resolv.conf'
7
+ end
8
+
9
+ def self.ubuntu_resolv_file
10
+ '/etc/resolvconf/resolv.conf.d/base'
11
+ end
12
+
13
+ def self.file_comment
14
+ '# added by dory'
15
+ end
16
+
17
+ def self.nameserver
18
+ Dory::Config.settings[:dory][:resolv][:nameserver]
19
+ end
20
+
21
+ def self.file_nameserver_line
22
+ "nameserver #{self.nameserver}"
23
+ end
24
+
25
+ def self.nameserver_contents
26
+ "#{self.file_nameserver_line} #{self.file_comment}"
27
+ end
28
+
29
+ def self.resolv_file
30
+ if Linux.ubuntu?
31
+ return self.ubuntu_resolv_file if Linux.ubuntu?
32
+ elsif Linux.fedora? || Linux.arch? || File.exist?(self.common_resolv_file)
33
+ return self.common_resolv_file
34
+ else
35
+ raise RuntimeError.new(
36
+ "Unable to determine location of resolv file"
37
+ )
38
+ end
39
+ end
40
+
41
+ def self.configure
42
+ # we want to be the first nameserver in the list for performance reasons
43
+ # we only want to add the nameserver if it isn't already there
44
+ prev_conts = self.resolv_file_contents
45
+ unless self.contents_has_our_nameserver?(prev_conts)
46
+ if prev_conts =~ /nameserver/
47
+ prev_conts.sub!(/nameserver/, "#{self.nameserver_contents}\nnameserver")
48
+ else
49
+ prev_conts = "#{prev_conts}\n#{self.nameserver_contents}"
50
+ end
51
+ prev_conts.gsub!(/\s+$/, '')
52
+ self.write_to_file(prev_conts)
53
+ end
54
+ self.has_our_nameserver?
55
+ end
56
+
57
+ def self.clean
58
+ prev_conts = self.resolv_file_contents
59
+ if self.contents_has_our_nameserver?(prev_conts)
60
+ prev_conts.gsub!(/#{Regexp.escape(self.nameserver_contents + "\n")}/, '')
61
+ prev_conts.gsub!(/\s+$/, '')
62
+ self.write_to_file(prev_conts)
63
+ end
64
+ !self.has_our_nameserver?
65
+ end
66
+
67
+ def self.write_to_file(contents)
68
+ # have to use this hack cuz we don't run as root :-(
69
+ puts "Requesting sudo to write to #{self.resolv_file}".green
70
+ Bash.run_command("echo -e '#{contents}' | sudo tee #{self.resolv_file} >/dev/null")
71
+ end
72
+
73
+ def self.resolv_file_contents
74
+ File.read(self.resolv_file)
75
+ end
76
+
77
+ def self.has_our_nameserver?
78
+ self.contents_has_our_nameserver?(self.resolv_file_contents)
79
+ end
80
+
81
+ def self.contents_has_our_nameserver?(contents)
82
+ !!((contents =~ /#{self.file_comment}/) || (contents =~ /#{self.file_nameserver_line}/))
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,25 @@
1
+ require 'ostruct'
2
+
3
+ module Dory
4
+ module Sh
5
+ def self.run_command(command)
6
+ stdout = `#{command}`
7
+ OpenStruct.new({
8
+ success?: $?.exitstatus == 0,
9
+ exitstatus: $?.exitstatus,
10
+ stdout: stdout
11
+ })
12
+ end
13
+ end
14
+
15
+ module Bash
16
+ def self.run_command(command)
17
+ stdout = `bash -c "#{command}"`
18
+ OpenStruct.new({
19
+ success?: $?.exitstatus == 0,
20
+ exitstatus: $?.exitstatus,
21
+ stdout: stdout
22
+ })
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,3 @@
1
+ module Dory
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,146 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dory
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Ben Porter
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-03-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: colorize
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.7'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: thor
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.19'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.19'
41
+ - !ruby/object:Gem::Dependency
42
+ name: ptools
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.3'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: byebug
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: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.4'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.4'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '10.5'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '10.5'
97
+ description: The slack web api is good, but very raw. What you need is a great ruby
98
+ framework to abstract away all that. This is it! This framework allows you to
99
+ write bots easily by providing methods that are easy to call. Behind the scenes,
100
+ the framework is negotiating your real time stream, converting channel names and
101
+ user names to and from IDs so you can use the names instead, and parsing/classifying
102
+ the real time messages into useful types that you can hook into. Don't write your
103
+ bot without this.
104
+ email: BenjaminPorter86@gmail.com
105
+ executables:
106
+ - dory
107
+ extensions: []
108
+ extra_rdoc_files: []
109
+ files:
110
+ - bin/dory
111
+ - lib/dory.rb
112
+ - lib/dory/config.rb
113
+ - lib/dory/dnsmasq.rb
114
+ - lib/dory/docker_service.rb
115
+ - lib/dory/inst_vars_to_hash.rb
116
+ - lib/dory/linux.rb
117
+ - lib/dory/proxy.rb
118
+ - lib/dory/resolv.rb
119
+ - lib/dory/shell.rb
120
+ - lib/dory/version.rb
121
+ homepage: https://github.com/FreedomBen/dory
122
+ licenses:
123
+ - MIT
124
+ metadata: {}
125
+ post_install_message:
126
+ rdoc_options: []
127
+ require_paths:
128
+ - lib
129
+ required_ruby_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ required_rubygems_version: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ requirements: []
140
+ rubyforge_project:
141
+ rubygems_version: 2.2.5
142
+ signing_key:
143
+ specification_version: 4
144
+ summary: slackbot_frd provides a dirt-simple framework for implementing one or more
145
+ slack bots
146
+ test_files: []