slacks 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.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +41 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/slacks/bot_user.rb +15 -0
- data/lib/slacks/channel.rb +79 -0
- data/lib/slacks/connection.rb +287 -0
- data/lib/slacks/conversation.rb +48 -0
- data/lib/slacks/core_ext/exception.rb +7 -0
- data/lib/slacks/driver.rb +91 -0
- data/lib/slacks/errors.rb +33 -0
- data/lib/slacks/event.rb +34 -0
- data/lib/slacks/guest_channel.rb +34 -0
- data/lib/slacks/listener.rb +44 -0
- data/lib/slacks/listener_collection.rb +31 -0
- data/lib/slacks/message.rb +71 -0
- data/lib/slacks/rtm_event.rb +30 -0
- data/lib/slacks/session.rb +147 -0
- data/lib/slacks/team.rb +12 -0
- data/lib/slacks/user.rb +29 -0
- data/lib/slacks/version.rb +3 -0
- data/lib/slacks.rb +3 -0
- data/slacks.gemspec +32 -0
- metadata +197 -0
data/lib/slacks/event.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require "slacks/conversation"
|
2
|
+
|
3
|
+
module Slacks
|
4
|
+
class Event
|
5
|
+
attr_reader :message, :channel, :sender
|
6
|
+
|
7
|
+
def initialize(session: nil, message: nil, channel: nil, sender: nil)
|
8
|
+
@session = session
|
9
|
+
@message = message
|
10
|
+
@channel = channel
|
11
|
+
@sender = sender
|
12
|
+
end
|
13
|
+
|
14
|
+
def user
|
15
|
+
return @user if defined?(@user)
|
16
|
+
@user = sender && ::User.find_by_slack_username(sender.username)
|
17
|
+
end
|
18
|
+
|
19
|
+
def reply(*args)
|
20
|
+
channel.reply(*args)
|
21
|
+
end
|
22
|
+
|
23
|
+
def random_reply(*args)
|
24
|
+
channel.random_reply(*args)
|
25
|
+
end
|
26
|
+
|
27
|
+
def start_conversation!
|
28
|
+
Conversation.new(session, channel, sender)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
attr_reader :session
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# This is a channel that the bot is aware of
|
2
|
+
# but is not a member of — and cannot reply to.
|
3
|
+
#
|
4
|
+
# It should expose the same API as channel,
|
5
|
+
# but you will not be able to reply on this
|
6
|
+
# channel or start a conversation on it.
|
7
|
+
|
8
|
+
module Slacks
|
9
|
+
class GuestChannel < Channel
|
10
|
+
|
11
|
+
def initialize(attributes)
|
12
|
+
@id = attributes["channel_id"]
|
13
|
+
@name = attributes["channel_name"]
|
14
|
+
|
15
|
+
@type = :channel
|
16
|
+
@type = :group if id.start_with?("G")
|
17
|
+
@type = :direct_message if id.start_with?("D")
|
18
|
+
end
|
19
|
+
|
20
|
+
def reply(*args)
|
21
|
+
raise NotInChannelError, self
|
22
|
+
end
|
23
|
+
alias :say :reply
|
24
|
+
|
25
|
+
def random_reply(*args)
|
26
|
+
raise NotInChannelError, self
|
27
|
+
end
|
28
|
+
|
29
|
+
def guest?
|
30
|
+
true
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Slacks
|
2
|
+
class Listener
|
3
|
+
attr_reader :matcher, :flags
|
4
|
+
attr_accessor :conversation
|
5
|
+
|
6
|
+
def initialize(listeners, matcher, direct, flags, callback)
|
7
|
+
# flags.each do |flag|
|
8
|
+
# unless Slacks::Message.can_apply?(flag)
|
9
|
+
# raise ArgumentError, "#{flag.inspect} is not a recognized flag"
|
10
|
+
# end
|
11
|
+
# end
|
12
|
+
|
13
|
+
@listeners = listeners
|
14
|
+
@matcher = matcher.freeze
|
15
|
+
@flags = flags.sort.freeze
|
16
|
+
@direct = direct
|
17
|
+
@callback = callback
|
18
|
+
end
|
19
|
+
|
20
|
+
def match(message)
|
21
|
+
matcher.match message.to_s(flags)
|
22
|
+
end
|
23
|
+
|
24
|
+
def direct?
|
25
|
+
@direct
|
26
|
+
end
|
27
|
+
|
28
|
+
def indirect?
|
29
|
+
!direct?
|
30
|
+
end
|
31
|
+
|
32
|
+
def stop_listening!
|
33
|
+
listeners.delete self
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
def call(e)
|
38
|
+
@callback.call(e)
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
attr_reader :listeners
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require "thread_safe"
|
2
|
+
|
3
|
+
module Slacks
|
4
|
+
class ListenerCollection
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@listeners = ThreadSafe::Array.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def listen_for(matcher, flags=[], &block)
|
11
|
+
Listener.new(self, matcher, true, flags, block).tap do |listener|
|
12
|
+
@listeners.push listener
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def overhear(matcher, flags=[], &block)
|
17
|
+
Listener.new(self, matcher, false, flags, block).tap do |listener|
|
18
|
+
@listeners.push listener
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def each(&block)
|
23
|
+
@listeners.each(&block)
|
24
|
+
end
|
25
|
+
|
26
|
+
def delete(listener)
|
27
|
+
@listeners.delete listener
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Slacks
|
2
|
+
class Message
|
3
|
+
|
4
|
+
def initialize(session, data)
|
5
|
+
@session = session
|
6
|
+
@data = data
|
7
|
+
@processed_text = Hash.new do |hash, flags|
|
8
|
+
hash[flags] = flags.inject(text) { |text, flag| session.apply(flag, text) }.strip
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
def channel
|
14
|
+
return @channel if defined?(@channel)
|
15
|
+
@channel = session.slack.find_channel data["channel"]
|
16
|
+
end
|
17
|
+
|
18
|
+
def sender
|
19
|
+
return @sender if defined?(@sender)
|
20
|
+
@sender = session.slack.find_user data["user"]
|
21
|
+
end
|
22
|
+
|
23
|
+
def timestamp
|
24
|
+
data["ts"]
|
25
|
+
end
|
26
|
+
|
27
|
+
def type
|
28
|
+
data.fetch("subtype", "message")
|
29
|
+
end
|
30
|
+
|
31
|
+
def text
|
32
|
+
return @text if defined?(@text)
|
33
|
+
@text = self.class.normalize(data["text"])
|
34
|
+
end
|
35
|
+
alias :to_str :text
|
36
|
+
|
37
|
+
def to_s(flags=[])
|
38
|
+
processed_text[flags]
|
39
|
+
end
|
40
|
+
|
41
|
+
def inspect
|
42
|
+
"#{text.inspect} (from: #{sender}, channel: #{channel})"
|
43
|
+
end
|
44
|
+
|
45
|
+
def add_reaction(emoji)
|
46
|
+
session.slack.add_reaction(emoji, self)
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
def respond_to_missing?(method, include_all)
|
51
|
+
return true if text.respond_to?(method)
|
52
|
+
super
|
53
|
+
end
|
54
|
+
|
55
|
+
def method_missing(method, *args, &block)
|
56
|
+
return text.public_send(method, *args, &block) if text.respond_to?(method)
|
57
|
+
super
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
def self.normalize(text)
|
62
|
+
text
|
63
|
+
.gsub(/[“”]/, "\"")
|
64
|
+
.gsub(/[‘’]/, "'")
|
65
|
+
.strip
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
attr_reader :session, :data, :processed_text
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "slacks/event"
|
2
|
+
|
3
|
+
module Slacks
|
4
|
+
class RtmEvent < Event
|
5
|
+
attr_reader :match, :message_object
|
6
|
+
|
7
|
+
def initialize(session: nil, message: nil, match_data: nil, listener: nil)
|
8
|
+
super(session: session, message: message.text, channel: message.channel, sender: message.sender)
|
9
|
+
@message_object = message
|
10
|
+
@match = match_data
|
11
|
+
@listener = listener
|
12
|
+
end
|
13
|
+
|
14
|
+
def matched?(key)
|
15
|
+
match[key].present?
|
16
|
+
end
|
17
|
+
|
18
|
+
def stop_listening!
|
19
|
+
listener.stop_listening!
|
20
|
+
end
|
21
|
+
|
22
|
+
def react(emoji)
|
23
|
+
message_object.add_reaction(emoji)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
attr_reader :listener
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
require "slacks/connection"
|
2
|
+
require "slacks/listener_collection"
|
3
|
+
|
4
|
+
module Slacks
|
5
|
+
class Session
|
6
|
+
attr_reader :listeners, :typing_speed, :token, :slack
|
7
|
+
|
8
|
+
def initialize(token, &block)
|
9
|
+
@typing_speed = 100.0
|
10
|
+
@token = token
|
11
|
+
@listeners = Slacks::ListenerCollection.new
|
12
|
+
|
13
|
+
if block_given?
|
14
|
+
listeners.instance_eval(&block)
|
15
|
+
start!
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def listen_for(matcher, flags=[], &block)
|
20
|
+
listeners.listen_for(matcher, flags, &block)
|
21
|
+
end
|
22
|
+
|
23
|
+
def overhear(matcher, flags=[], &block)
|
24
|
+
listeners.overhear(matcher, flags, &block)
|
25
|
+
end
|
26
|
+
|
27
|
+
def start!
|
28
|
+
@slack = Slacks::Connection.new(self, token)
|
29
|
+
|
30
|
+
slack.listen! do |message|
|
31
|
+
process_message(message)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def error(message)
|
36
|
+
# TODO
|
37
|
+
puts "\e[33m[slack:error] #{message}\e[0m"
|
38
|
+
end
|
39
|
+
|
40
|
+
def apply(flag, text)
|
41
|
+
send :"_apply_#{flag}", text
|
42
|
+
end
|
43
|
+
|
44
|
+
def can_apply?(flag)
|
45
|
+
respond_to? :"_apply_#{flag}", true
|
46
|
+
end
|
47
|
+
|
48
|
+
protected
|
49
|
+
|
50
|
+
def process_message(data)
|
51
|
+
|
52
|
+
# Don't respond to things that another bot said
|
53
|
+
return if data.fetch("subtype", "message") == "bot_message"
|
54
|
+
|
55
|
+
# Normalize mentions of users
|
56
|
+
data["text"].gsub!(/<@U[^|]+\|([^>]*)>/, "@\\1")
|
57
|
+
|
58
|
+
# Normalize mentions of channels
|
59
|
+
data["text"].gsub!(/<[@#]?([UC][^>]+)>/) do |match|
|
60
|
+
begin
|
61
|
+
slack.find_channel($1)
|
62
|
+
rescue ArgumentError
|
63
|
+
match
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
message = Slacks::Message.new(self, data)
|
68
|
+
|
69
|
+
# Is someone talking directly to the bot?
|
70
|
+
direct_mention = message.channel.direct_message? || message[slack.bot.name]
|
71
|
+
|
72
|
+
listeners.each do |listener|
|
73
|
+
# Listeners come in two flavors: direct and indirect
|
74
|
+
#
|
75
|
+
# To trigger a direct listener, the but must be directly
|
76
|
+
# spoken to: as when the bot is mentioned or it is in
|
77
|
+
# a conversation with someone.
|
78
|
+
#
|
79
|
+
# An indirect listener is triggered in any context
|
80
|
+
# when it matches.
|
81
|
+
#
|
82
|
+
# We can ignore any listener that definitely doesn't
|
83
|
+
# meet these criteria.
|
84
|
+
next unless listener.indirect? or direct_mention or listener.conversation
|
85
|
+
|
86
|
+
message = Slacks::Message.new(self, data)
|
87
|
+
|
88
|
+
# Does the message match one of our listeners?
|
89
|
+
match_data = listener.match message
|
90
|
+
next unless match_data
|
91
|
+
|
92
|
+
# TODO: Want event.message to be the processed text
|
93
|
+
event = Slacks::RtmEvent.new(
|
94
|
+
session: self,
|
95
|
+
message: message,
|
96
|
+
match_data: match_data,
|
97
|
+
listener: listener)
|
98
|
+
|
99
|
+
# Skip listeners if they are not part of this conversation
|
100
|
+
next unless listener.indirect? or direct_mention or listener.conversation.includes?(event)
|
101
|
+
|
102
|
+
invoke! listener, event
|
103
|
+
end
|
104
|
+
# rescue Exception
|
105
|
+
# # TODO
|
106
|
+
# # Houston.report_exception $!
|
107
|
+
# puts "\e[31m[slack:exception] (#{$!.class}) #{$!.message}\n #{$!.backtrace.join("\n ")}\e[0m"
|
108
|
+
end
|
109
|
+
|
110
|
+
def invoke!(listener, event)
|
111
|
+
# # TODO
|
112
|
+
# puts "\e[35m[slack:hear:#{event.message_object.type}] #{event.message_object.inspect}\e[0m"
|
113
|
+
|
114
|
+
listener.call(event)
|
115
|
+
# Thread.new do
|
116
|
+
# begin
|
117
|
+
# @callback.call(e)
|
118
|
+
# rescue Exception # rescues StandardError by default; but we want to rescue and report all errors
|
119
|
+
# # TODO
|
120
|
+
# # Houston.report_exception $!, parameters: {channel: e.channel, message: e.message, sender: e.sender}
|
121
|
+
# puts "\e[31m[slack:exception] (#{$!.class}) #{$!.message}\n #{$!.backtrace.join("\n ")}\e[0m"
|
122
|
+
# e.reply "An error occurred when I was trying to answer you"
|
123
|
+
# ensure
|
124
|
+
# ActiveRecord::Base.clear_active_connections! if defined?(ActiveRecord)
|
125
|
+
# end
|
126
|
+
# end
|
127
|
+
end
|
128
|
+
|
129
|
+
def _apply_downcase(text)
|
130
|
+
text.downcase
|
131
|
+
end
|
132
|
+
|
133
|
+
def _apply_no_punctuation(text)
|
134
|
+
# Need to leave @ and # in @mentions and #channels
|
135
|
+
text.gsub(/[^\w\s@#]/, "")
|
136
|
+
end
|
137
|
+
|
138
|
+
def _apply_no_mentions(text)
|
139
|
+
text.gsub(/(?:^|\W+)#{slack.bot}\b/, "")
|
140
|
+
end
|
141
|
+
|
142
|
+
def _apply_no_emoji(text)
|
143
|
+
text.gsub(/(?::[^:]+:)/, "")
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
end
|
data/lib/slacks/team.rb
ADDED
data/lib/slacks/user.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
module Slacks
|
2
|
+
class User
|
3
|
+
attr_reader :id, :username, :email, :first_name, :last_name
|
4
|
+
|
5
|
+
def initialize(session, attributes={})
|
6
|
+
@session = session
|
7
|
+
|
8
|
+
profile = attributes["profile"]
|
9
|
+
@id = attributes["id"]
|
10
|
+
@username = attributes["name"]
|
11
|
+
@email = profile["email"]
|
12
|
+
@first_name = profile["first_name"]
|
13
|
+
@last_name = profile["last_name"]
|
14
|
+
end
|
15
|
+
|
16
|
+
def name
|
17
|
+
"#{first_name} #{last_name}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def inspect
|
21
|
+
"<Slacks::User id=\"#{id}\" name=\"#{name}\">"
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_s
|
25
|
+
"@#{username}"
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
data/lib/slacks.rb
ADDED
data/slacks.gemspec
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "slacks/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "slacks"
|
8
|
+
spec.version = Slacks::VERSION
|
9
|
+
spec.authors = ["Bob Lail"]
|
10
|
+
spec.email = ["bob.lailfamily@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{A library for communicating via Slack}
|
13
|
+
spec.homepage = "https://github.com/houston/slacks"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
spec.bindir = "exe"
|
18
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# https://blog.jcoglan.com/2013/05/06/websocket-driver-an-io-agnostic-websocket-module-or-why-most-protocol-libraries-arent/
|
22
|
+
spec.add_dependency "websocket-driver"
|
23
|
+
spec.add_dependency "multi_json"
|
24
|
+
spec.add_dependency "faraday"
|
25
|
+
spec.add_dependency "faraday-raise-errors"
|
26
|
+
spec.add_dependency "thread_safe"
|
27
|
+
|
28
|
+
spec.add_development_dependency "bundler", "~> 1.10"
|
29
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
30
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
31
|
+
spec.add_development_dependency "pry"
|
32
|
+
end
|
metadata
ADDED
@@ -0,0 +1,197 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: slacks
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Bob Lail
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-04-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: websocket-driver
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: multi_json
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: faraday
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
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: faraday-raise-errors
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: thread_safe
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: bundler
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.10'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1.10'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rake
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '10.0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '10.0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: minitest
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '5.0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '5.0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: pry
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
description:
|
140
|
+
email:
|
141
|
+
- bob.lailfamily@gmail.com
|
142
|
+
executables: []
|
143
|
+
extensions: []
|
144
|
+
extra_rdoc_files: []
|
145
|
+
files:
|
146
|
+
- ".gitignore"
|
147
|
+
- ".travis.yml"
|
148
|
+
- Gemfile
|
149
|
+
- LICENSE.txt
|
150
|
+
- README.md
|
151
|
+
- Rakefile
|
152
|
+
- bin/console
|
153
|
+
- bin/setup
|
154
|
+
- lib/slacks.rb
|
155
|
+
- lib/slacks/bot_user.rb
|
156
|
+
- lib/slacks/channel.rb
|
157
|
+
- lib/slacks/connection.rb
|
158
|
+
- lib/slacks/conversation.rb
|
159
|
+
- lib/slacks/core_ext/exception.rb
|
160
|
+
- lib/slacks/driver.rb
|
161
|
+
- lib/slacks/errors.rb
|
162
|
+
- lib/slacks/event.rb
|
163
|
+
- lib/slacks/guest_channel.rb
|
164
|
+
- lib/slacks/listener.rb
|
165
|
+
- lib/slacks/listener_collection.rb
|
166
|
+
- lib/slacks/message.rb
|
167
|
+
- lib/slacks/rtm_event.rb
|
168
|
+
- lib/slacks/session.rb
|
169
|
+
- lib/slacks/team.rb
|
170
|
+
- lib/slacks/user.rb
|
171
|
+
- lib/slacks/version.rb
|
172
|
+
- slacks.gemspec
|
173
|
+
homepage: https://github.com/houston/slacks
|
174
|
+
licenses:
|
175
|
+
- MIT
|
176
|
+
metadata: {}
|
177
|
+
post_install_message:
|
178
|
+
rdoc_options: []
|
179
|
+
require_paths:
|
180
|
+
- lib
|
181
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
182
|
+
requirements:
|
183
|
+
- - ">="
|
184
|
+
- !ruby/object:Gem::Version
|
185
|
+
version: '0'
|
186
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
187
|
+
requirements:
|
188
|
+
- - ">="
|
189
|
+
- !ruby/object:Gem::Version
|
190
|
+
version: '0'
|
191
|
+
requirements: []
|
192
|
+
rubyforge_project:
|
193
|
+
rubygems_version: 2.2.2
|
194
|
+
signing_key:
|
195
|
+
specification_version: 4
|
196
|
+
summary: A library for communicating via Slack
|
197
|
+
test_files: []
|