slacks 0.2.3 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +68 -10
- data/lib/slacks/connection.rb +17 -20
- data/lib/slacks/observer.rb +29 -0
- data/lib/slacks/version.rb +1 -1
- data/lib/slacks.rb +1 -1
- data/slacks.gemspec +1 -2
- metadata +4 -23
- data/lib/slacks/event.rb +0 -38
- data/lib/slacks/listener.rb +0 -17
- data/lib/slacks/listener_collection.rb +0 -22
- data/lib/slacks/message.rb +0 -51
- data/lib/slacks/rtm_event.rb +0 -30
- data/lib/slacks/session.rb +0 -79
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3e10c085c812db7ebb4c4882d2d29963c9b29941
|
4
|
+
data.tar.gz: 8d4fcc5ce2622251a901d97b35d895819e874fbd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3eb4f58e4f8cd344d133539ccf3413ff6fce1622fc3228a61ca77cff35c9ff8cbe25c288d4a4cf7425e99d62802efe4db58f191a01b8c85b32aa20416df63640
|
7
|
+
data.tar.gz: f5094c0ede839359afed74c5726df6a2df7731b19317210e73b4f6d4d558653916f7a061a2a77168e377b7d80a98e8126483eca01e5c9d36818739222988613b
|
data/README.md
CHANGED
@@ -2,34 +2,92 @@
|
|
2
2
|
|
3
3
|
A library for communicating via Slack
|
4
4
|
|
5
|
-
## Installation
|
6
5
|
|
7
|
-
|
6
|
+
|
7
|
+
## Usage
|
8
|
+
|
9
|
+
##### Speaking
|
10
|
+
|
11
|
+
Slacks uses [Slack's Web API](https://api.slack.com/web) to allow your bot to communicate on Slack:
|
8
12
|
|
9
13
|
```ruby
|
10
|
-
|
14
|
+
require "slacks"
|
15
|
+
slack = Slacks::Connection.new("xoxb-0123456789-abcdefghijklmnopqrstuvwx")
|
16
|
+
slack.send_message "Hi everyone!", channel: "#general"
|
11
17
|
```
|
12
18
|
|
13
|
-
|
19
|
+
You can post [attachment](https://api.slack.com/docs/attachments):
|
14
20
|
|
15
|
-
|
21
|
+
```ruby
|
22
|
+
slack.send_message "", channel: "#general", attachments: [{
|
23
|
+
color: "#36a64f",
|
24
|
+
fallback: "Tests passed!",
|
25
|
+
text: "Tests passed!",
|
26
|
+
fields: [{
|
27
|
+
title: "Tests",
|
28
|
+
value: "143",
|
29
|
+
short: true
|
30
|
+
}, {
|
31
|
+
title: "Assertions",
|
32
|
+
value: "298",
|
33
|
+
short: true
|
34
|
+
}]
|
35
|
+
}]
|
36
|
+
```
|
16
37
|
|
17
|
-
|
38
|
+
(For more information about sending messages, see [chat.postMessage](https://api.slack.com/methods/chat.postMessage).)
|
18
39
|
|
19
|
-
|
40
|
+
You can indicate that your bot is typing:
|
20
41
|
|
42
|
+
```ruby
|
43
|
+
slack.typing_on "#general"
|
44
|
+
```
|
45
|
+
|
46
|
+
You can react to messages:
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
slack.add_reaction "+1", message.ts
|
50
|
+
```
|
21
51
|
|
22
52
|
|
23
|
-
|
53
|
+
|
54
|
+
#### Listening
|
55
|
+
|
56
|
+
Slacks uses [Slack's RTM API](https://api.slack.com/rtm) to allow your bot to listen on Slack. Slacks connects to a websocket provided by Slack and allows you to set up listeners for events by type:
|
24
57
|
|
25
58
|
```ruby
|
26
59
|
require "slacks"
|
27
60
|
slack = Slacks::Connection.new("xoxb-0123456789-abcdefghijklmnopqrstuvwx")
|
28
|
-
slack.
|
29
|
-
|
61
|
+
slack.on "message" do |event|
|
62
|
+
puts "I heard #{event["user"]} say #{event["text"].inspect}"
|
63
|
+
end
|
64
|
+
slack.on "reaction_added" do |event|
|
65
|
+
next unless event["item"]["type"] == "message"
|
66
|
+
message = slack.get_message data["item"]["channel"], data["item"]["ts"]
|
67
|
+
puts "#{event["user"]} added #{event["reaction"]} to #{message["text"].inspect}"
|
30
68
|
end
|
69
|
+
slack.listen!
|
70
|
+
```
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
## Installation
|
75
|
+
|
76
|
+
Add this line to your application's Gemfile:
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
gem "slacks"
|
31
80
|
```
|
32
81
|
|
82
|
+
And then execute:
|
83
|
+
|
84
|
+
$ bundle
|
85
|
+
|
86
|
+
Or install it yourself as:
|
87
|
+
|
88
|
+
$ gem install slacks
|
89
|
+
|
90
|
+
|
33
91
|
|
34
92
|
|
35
93
|
## Development
|
data/lib/slacks/connection.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
require "slacks/bot_user"
|
2
2
|
require "slacks/channel"
|
3
3
|
require "slacks/driver"
|
4
|
+
require "slacks/observer"
|
4
5
|
require "slacks/errors"
|
5
6
|
require "slacks/guest_channel"
|
6
|
-
require "slacks/rtm_event"
|
7
7
|
require "slacks/team"
|
8
8
|
require "slacks/user"
|
9
9
|
require "faraday"
|
@@ -11,15 +11,11 @@ require "faraday/raise_errors"
|
|
11
11
|
|
12
12
|
module Slacks
|
13
13
|
class Connection
|
14
|
+
include ::Slacks::Observer
|
15
|
+
|
14
16
|
attr_reader :team, :bot, :token
|
15
17
|
attr_accessor :typing_speed
|
16
18
|
|
17
|
-
EVENT_MESSAGE = "message".freeze
|
18
|
-
EVENT_GROUP_JOINED = "group_joined".freeze
|
19
|
-
EVENT_USER_JOINED = "team_join".freeze
|
20
|
-
EVENT_REACTION_ADDED = "reaction_added".freeze
|
21
|
-
EVENT_REACTION_REMOVED = "reaction_removed".freeze
|
22
|
-
|
23
19
|
def initialize(token, options={})
|
24
20
|
@token = token
|
25
21
|
@typing_speed = options.fetch(:typing_speed, 100.0)
|
@@ -87,7 +83,7 @@ module Slacks
|
|
87
83
|
|
88
84
|
|
89
85
|
|
90
|
-
def listen!
|
86
|
+
def listen!
|
91
87
|
response = api("rtm.start")
|
92
88
|
unless response["ok"]
|
93
89
|
raise MigrationInProgress if response["error"] == "migration_in_progress"
|
@@ -97,7 +93,7 @@ module Slacks
|
|
97
93
|
|
98
94
|
@websocket = Slacks::Driver.new
|
99
95
|
websocket.connect_to websocket_url
|
100
|
-
|
96
|
+
trigger "connected"
|
101
97
|
|
102
98
|
websocket.on(:error) do |event|
|
103
99
|
raise ConnectionError.new(event)
|
@@ -115,33 +111,34 @@ module Slacks
|
|
115
111
|
@users_by_id[user["id"]] = user
|
116
112
|
@user_id_by_name[user["name"]] = user["id"]
|
117
113
|
|
118
|
-
when
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
when EVENT_REACTION_REMOVED
|
124
|
-
# Only care if someone reacted to something the bot said
|
125
|
-
next unless data["item_user"] == bot.id
|
126
|
-
callbacks.reaction_removed(data)
|
114
|
+
when EVENT_CHANNEL_CREATED
|
115
|
+
channel = data["channel"]
|
116
|
+
@channels_by_id[channel["id"]] = channel
|
117
|
+
@channel_id_by_name[channel["name"]] = channel["id"]
|
127
118
|
|
128
119
|
when EVENT_MESSAGE
|
129
120
|
# Don't respond to things that this bot said
|
130
121
|
next if data["user"] == bot.id
|
131
122
|
# ...or to messages with no text
|
132
123
|
next if data["text"].nil? || data["text"].empty?
|
133
|
-
callbacks.message(data)
|
134
124
|
end
|
125
|
+
|
126
|
+
trigger data["type"], data
|
135
127
|
end
|
136
128
|
|
137
129
|
websocket.main_loop
|
138
130
|
|
139
131
|
rescue EOFError
|
140
132
|
# Slack hung up on us, we'll ask for a new WebSocket URL and reconnect.
|
141
|
-
|
133
|
+
trigger "error", "Websocket Driver received EOF; reconnecting"
|
142
134
|
retry
|
143
135
|
end
|
144
136
|
|
137
|
+
EVENT_CHANNEL_CREATED = "channel_created".freeze
|
138
|
+
EVENT_GROUP_JOINED = "group_joined".freeze
|
139
|
+
EVENT_MESSAGE = "message".freeze
|
140
|
+
EVENT_USER_JOINED = "team_join".freeze
|
141
|
+
|
145
142
|
|
146
143
|
|
147
144
|
def channels
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "concurrent/array"
|
2
|
+
require "concurrent/hash"
|
3
|
+
|
4
|
+
module Slacks
|
5
|
+
module Observer
|
6
|
+
|
7
|
+
def on(event, &block)
|
8
|
+
observers_of(event).push(block)
|
9
|
+
end
|
10
|
+
|
11
|
+
protected
|
12
|
+
|
13
|
+
def trigger(event, *args)
|
14
|
+
observers_of(event).each do |block|
|
15
|
+
block.call(*args)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def observers_of(event)
|
20
|
+
observers[event.to_sym]
|
21
|
+
end
|
22
|
+
|
23
|
+
def observers
|
24
|
+
return @observers if defined?(@observers)
|
25
|
+
@observers = Concurrent::Hash.new { |hash, key| hash[key] = Concurrent::Array.new }
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
data/lib/slacks/version.rb
CHANGED
data/lib/slacks.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
require "slacks/version"
|
2
|
-
require "slacks/
|
2
|
+
require "slacks/connection"
|
data/slacks.gemspec
CHANGED
@@ -23,8 +23,7 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.add_dependency "multi_json"
|
24
24
|
spec.add_dependency "faraday"
|
25
25
|
spec.add_dependency "faraday-raise-errors"
|
26
|
-
spec.add_dependency "
|
27
|
-
spec.add_dependency "attentive"
|
26
|
+
spec.add_dependency "concurrent-ruby"
|
28
27
|
|
29
28
|
spec.add_development_dependency "bundler", "~> 1.10"
|
30
29
|
spec.add_development_dependency "rake", "~> 10.0"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: slacks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bob Lail
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-06-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: websocket-driver
|
@@ -67,21 +67,7 @@ dependencies:
|
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
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: attentive
|
70
|
+
name: concurrent-ruby
|
85
71
|
requirement: !ruby/object:Gem::Requirement
|
86
72
|
requirements:
|
87
73
|
- - ">="
|
@@ -201,13 +187,8 @@ files:
|
|
201
187
|
- lib/slacks/core_ext/exception.rb
|
202
188
|
- lib/slacks/driver.rb
|
203
189
|
- lib/slacks/errors.rb
|
204
|
-
- lib/slacks/event.rb
|
205
190
|
- lib/slacks/guest_channel.rb
|
206
|
-
- lib/slacks/
|
207
|
-
- lib/slacks/listener_collection.rb
|
208
|
-
- lib/slacks/message.rb
|
209
|
-
- lib/slacks/rtm_event.rb
|
210
|
-
- lib/slacks/session.rb
|
191
|
+
- lib/slacks/observer.rb
|
211
192
|
- lib/slacks/team.rb
|
212
193
|
- lib/slacks/user.rb
|
213
194
|
- lib/slacks/version.rb
|
data/lib/slacks/event.rb
DELETED
@@ -1,38 +0,0 @@
|
|
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 typing
|
28
|
-
channel.typing
|
29
|
-
end
|
30
|
-
|
31
|
-
def start_conversation!
|
32
|
-
Conversation.new(session, channel, sender)
|
33
|
-
end
|
34
|
-
|
35
|
-
private
|
36
|
-
attr_reader :session
|
37
|
-
end
|
38
|
-
end
|
data/lib/slacks/listener.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
require "attentive/listener"
|
2
|
-
|
3
|
-
module Slacks
|
4
|
-
class Listener < Attentive::Listener
|
5
|
-
attr_accessor :conversation
|
6
|
-
|
7
|
-
def matches_context?(message)
|
8
|
-
contexts = message.contexts.dup
|
9
|
-
contexts << :conversation if conversation && conversation.includes?(message)
|
10
|
-
|
11
|
-
return false unless contexts.superset? @required_contexts
|
12
|
-
return false unless contexts.disjoint? @prohibited_contexts
|
13
|
-
true
|
14
|
-
end
|
15
|
-
|
16
|
-
end
|
17
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
require "attentive/listener_collection"
|
2
|
-
require "slacks/listener"
|
3
|
-
|
4
|
-
module Slacks
|
5
|
-
class ListenerCollection < Attentive::ListenerCollection
|
6
|
-
|
7
|
-
def overhear(*args, &block)
|
8
|
-
options = args.last.is_a?(::Hash) ? args.pop : {}
|
9
|
-
options[:context] = { in: :any }
|
10
|
-
listen_for(*args, options, &block)
|
11
|
-
end
|
12
|
-
|
13
|
-
def listen_for(*args, &block)
|
14
|
-
options = args.last.is_a?(::Hash) ? args.pop : {}
|
15
|
-
|
16
|
-
Slacks::Listener.new(self, args, options, block).tap do |listener|
|
17
|
-
push listener
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
end
|
22
|
-
end
|
data/lib/slacks/message.rb
DELETED
@@ -1,51 +0,0 @@
|
|
1
|
-
require "attentive/message"
|
2
|
-
|
3
|
-
module Slacks
|
4
|
-
class Message < ::Attentive::Message
|
5
|
-
|
6
|
-
def initialize(session, data, params={})
|
7
|
-
@session = session
|
8
|
-
@data = data
|
9
|
-
super data["text"], params
|
10
|
-
contexts << :conversation if channel.direct_message?
|
11
|
-
end
|
12
|
-
|
13
|
-
|
14
|
-
def channel
|
15
|
-
return @channel if defined?(@channel)
|
16
|
-
@channel = session.slack.find_channel data["channel"]
|
17
|
-
end
|
18
|
-
|
19
|
-
def sender
|
20
|
-
return @sender if defined?(@sender)
|
21
|
-
@sender = session.slack.find_user data["user"]
|
22
|
-
end
|
23
|
-
|
24
|
-
def timestamp
|
25
|
-
data["ts"]
|
26
|
-
end
|
27
|
-
|
28
|
-
def type
|
29
|
-
data.fetch("subtype", "message")
|
30
|
-
end
|
31
|
-
|
32
|
-
|
33
|
-
def add_reaction(emoji)
|
34
|
-
session.slack.add_reaction(emoji, self)
|
35
|
-
end
|
36
|
-
|
37
|
-
|
38
|
-
def respond_to_missing?(method, include_all)
|
39
|
-
return true if text.respond_to?(method)
|
40
|
-
super
|
41
|
-
end
|
42
|
-
|
43
|
-
def method_missing(method, *args, &block)
|
44
|
-
return text.public_send(method, *args, &block) if text.respond_to?(method)
|
45
|
-
super
|
46
|
-
end
|
47
|
-
|
48
|
-
private
|
49
|
-
attr_reader :session, :data
|
50
|
-
end
|
51
|
-
end
|
data/lib/slacks/rtm_event.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
require "slacks/event"
|
2
|
-
|
3
|
-
module Slacks
|
4
|
-
class RtmEvent < Event
|
5
|
-
attr_reader :match
|
6
|
-
|
7
|
-
def initialize(session, match)
|
8
|
-
@match = match
|
9
|
-
@listener = match.listener
|
10
|
-
message = match.message
|
11
|
-
super(session: session, message: message, channel: message.channel, sender: message.sender)
|
12
|
-
end
|
13
|
-
|
14
|
-
def matched?(key)
|
15
|
-
match.matched?(key)
|
16
|
-
end
|
17
|
-
|
18
|
-
def stop_listening!
|
19
|
-
listener.stop_listening!
|
20
|
-
end
|
21
|
-
|
22
|
-
def react(emoji)
|
23
|
-
message.add_reaction(emoji)
|
24
|
-
end
|
25
|
-
|
26
|
-
private
|
27
|
-
attr_reader :listener
|
28
|
-
|
29
|
-
end
|
30
|
-
end
|
data/lib/slacks/session.rb
DELETED
@@ -1,79 +0,0 @@
|
|
1
|
-
require "slacks/connection"
|
2
|
-
require "slacks/listener_collection"
|
3
|
-
require "slacks/message"
|
4
|
-
require "attentive"
|
5
|
-
|
6
|
-
module Slacks
|
7
|
-
class Session
|
8
|
-
include Attentive
|
9
|
-
|
10
|
-
attr_reader :slack
|
11
|
-
|
12
|
-
def initialize(token, &block)
|
13
|
-
@slack = Slacks::Connection.new(token)
|
14
|
-
|
15
|
-
if block_given?
|
16
|
-
listeners.instance_eval(&block)
|
17
|
-
start!
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def listeners
|
22
|
-
@listeners ||= Slacks::ListenerCollection.new
|
23
|
-
end
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
def start!
|
28
|
-
slack.listen!(self)
|
29
|
-
end
|
30
|
-
|
31
|
-
def connected
|
32
|
-
Attentive.invocations = [slack.bot.name, slack.bot.to_s]
|
33
|
-
end
|
34
|
-
|
35
|
-
def error(error_message)
|
36
|
-
end
|
37
|
-
|
38
|
-
def message(data)
|
39
|
-
|
40
|
-
# Don't respond to things that another bot said
|
41
|
-
return if data.fetch("subtype", "message") == "bot_message"
|
42
|
-
|
43
|
-
# Normalize mentions of users
|
44
|
-
data["text"].gsub!(/<@U[^|]+\|([^>]*)>/, %q{@\1})
|
45
|
-
|
46
|
-
# Normalize mentions of channels
|
47
|
-
data["text"].gsub!(/<[@#]?([UC][^>]+)>/) do |match|
|
48
|
-
begin
|
49
|
-
slack.find_channel($1)
|
50
|
-
rescue ArgumentError
|
51
|
-
match
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
message = Slacks::Message.new(self, data)
|
56
|
-
hear(message).each do |match|
|
57
|
-
|
58
|
-
event = Slacks::RtmEvent.new(self, match)
|
59
|
-
invoke! match.listener, event
|
60
|
-
|
61
|
-
# Invoke only one listener per message
|
62
|
-
return
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def reaction_added(data)
|
67
|
-
end
|
68
|
-
|
69
|
-
def reaction_removed(data)
|
70
|
-
end
|
71
|
-
|
72
|
-
protected
|
73
|
-
|
74
|
-
def invoke!(listener, event)
|
75
|
-
listener.call(event)
|
76
|
-
end
|
77
|
-
|
78
|
-
end
|
79
|
-
end
|