bot_mob 0.3.0 → 0.3.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6463fee5649865aa2f59e0e19b7b3670ff5e20c8
4
- data.tar.gz: e96b710afa365c7b9152a2fd6b5af76dec618a0f
3
+ metadata.gz: 1b85965cd3ed7759eb4a7d79ca601dc94536cf04
4
+ data.tar.gz: 22edb2f9215b9e1414dab19908b5d33001897e65
5
5
  SHA512:
6
- metadata.gz: a7172822c373e804dfe65fb589ddf12bd78403f8416e2b91ce2bf9269268cce4f36039d452d1a9ee5c880ae30372eecb8d8caea8c953e40956fc6ac94ca8faa3
7
- data.tar.gz: 2c70c6c01e9bb1d4c6a6537ce889e5774bf486c2feac444bc75c64a61eeb1375b20c74e056c9efa046b0aae87f6fa34b3c55550e61380132cbc2741e31954163
6
+ metadata.gz: 82652bacc7af4349f248d6674c480fc96ee0ab6c682a70c7147099808a40c01a0c2b24d31c725cf8725b20a6b2e8e651aee65c124978597f773b9eb503331164
7
+ data.tar.gz: 7dbfbfd3c16abb88e1230e7227138b1741d47256753d3ebff5cc31fe7632c72739e3bfe2740fc992cb189d7b054c18b5612d6ba32c9dee31312b54e9e342ddd2
data/examples/server.rb CHANGED
@@ -1,7 +1,10 @@
1
+ require 'dotenv'
1
2
  require_relative 'fizz_buzz_bot'
2
3
  require_relative 'hello_bot'
3
4
 
5
+ Dotenv.load
6
+
4
7
  BotMob.start! do |app|
5
8
  app.register FizzBuzzBot
6
- app.register HelloBot.new(network: :slack, token: ENV['SLACK_TOKEN'])
9
+ app.register HelloBot.new(slack: { token: ENV['SLACK_TOKEN'] })
7
10
  end
data/lib/bot_mob.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  require 'logger'
2
- require 'slack-ruby-client'
3
2
  require 'bot_mob/core_ext/hash'
4
3
  require 'bot_mob/core_ext/string'
5
4
  require 'bot_mob/version'
@@ -19,6 +18,7 @@ module BotMob
19
18
  autoload :Command, 'bot_mob/command'
20
19
  autoload :Connection, 'bot_mob/connection'
21
20
  autoload :InboundMessage, 'bot_mob/inbound_message'
21
+ autoload :Logger, 'bot_mob/logger'
22
22
  autoload :OutboundMessage, 'bot_mob/outbound_message'
23
23
  autoload :Roster, 'bot_mob/roster'
24
24
  autoload :Server, 'bot_mob/server'
@@ -61,7 +61,7 @@ module BotMob
61
61
  # Provide a logger for the BotMob gem, silences test env output by default
62
62
  def self.logger
63
63
  @logger ||= begin
64
- buffer = Logger.new(ENV['MOB_ENV'] == 'test' ? '/dev/null' : STDOUT)
64
+ buffer = BotMob::Logger.new(ENV['MOB_ENV'] == 'test' ? '/dev/null' : STDOUT)
65
65
  if buffer
66
66
  buffer.level = ($PROGRAM_NAME == 'irb' ? Logger::DEBUG : Logger::INFO)
67
67
  buffer.formatter = proc { |_s, _d, _p, msg| "#{msg}\n" }
data/lib/bot_mob/bot.rb CHANGED
@@ -56,13 +56,10 @@ module BotMob
56
56
  def receive(message, options = {})
57
57
  inbound_message = BotMob::InboundMessage.prepare(message, options)
58
58
 
59
- warrant_response = respond?(inbound_message)
60
- log_message(inbound_message) if warrant_response || log_responseless_activity?
61
- unless warrant_response
62
- if log_responseless_activity?
63
- BotMob.logger.info(' > Does not warrant response')
64
- end
65
-
59
+ BotMob.logger.log_request(self, :message, inbound_message.params)
60
+ BotMob.logger.info('-> Received message was from a bot') unless inbound_message.human?
61
+ unless respond?(inbound_message)
62
+ BotMob.logger.info('-> Does not warrant response')
66
63
  return
67
64
  end
68
65
 
@@ -77,11 +74,18 @@ module BotMob
77
74
  # bot.receive('foo')
78
75
  #
79
76
  # Specify *message* as the received data
80
- def receive_command(command)
81
- BotMob.logger.info("#{name} received command at #{Time.now}")
82
- BotMob.logger.info(" Parameters: {:text => \"#{command}\"}")
77
+ def receive_command(command, params = {})
78
+ BotMob.logger.log_request(self, :command, command: command)
79
+
80
+ return unless valid_command?(command)
83
81
 
84
- send(command) if valid_command?(command)
82
+ begin
83
+ send(command, params)
84
+ rescue ArgumentError => e
85
+ BotMob.logger.warn("#{name}##{command} is not accepting parameters")
86
+ BotMob.logger.warn("ArgumentError - #{e.message}")
87
+ send(command)
88
+ end
85
89
  end
86
90
 
87
91
  # ## `valid_command?`
@@ -106,9 +110,9 @@ module BotMob
106
110
  # contents of the inbound message. Commonly used for checking language
107
111
  # used or regex matching of the inbound messages' contents.
108
112
  #
109
- # Defaults to true
110
- def respond?(_inbound_message)
111
- true
113
+ # Defaults to true for human messages
114
+ def respond?(inbound_message)
115
+ inbound_message.human?
112
116
  end
113
117
 
114
118
  # ## `respond`
@@ -161,10 +165,5 @@ module BotMob
161
165
  def log_responseless_activity?
162
166
  BotMob.env.development?
163
167
  end
164
-
165
- def log_message(message)
166
- BotMob.logger.info("#{name} received message at #{Time.now}")
167
- BotMob.logger.info(" Parameters: #{message.params}")
168
- end
169
168
  end
170
169
  end
@@ -3,24 +3,102 @@ module BotMob
3
3
  #
4
4
  # Structured data provided to a bot
5
5
  class InboundMessage
6
- attr_reader :body, :network
6
+ attr_reader :user_name, :body, :network
7
7
 
8
8
  def initialize(**options)
9
- @network = options[:network]
10
- @body = options[:body]
9
+ @body ||= options[:body]
10
+ @network ||= options[:network]
11
+
12
+ provided_message_attributes(options).each do |attr|
13
+ instance_variable_set("@#{attr}".to_sym, options[attr.to_sym])
14
+ end
11
15
  end
12
16
 
17
+ # ## `prepare`
18
+ #
19
+ # Prepare accepts three different data types and attempts to coerce
20
+ # it into a contextual inbound message. In the case of an inbound
21
+ # message, it simply assumes the provided message is already correct.
22
+ # In the case of a hash, it passes the hash along as the `initialize`
23
+ # attrs. In the case of a string, it overrides the `body` key of the
24
+ # provided options, then passes the options provided to `prepare` as
25
+ # the `initialize` params
13
26
  def self.prepare(message, options = {})
14
27
  return message if message.is_a?(BotMob::InboundMessage)
28
+ options.symbolize_keys!
29
+
30
+ approach = "prepare_#{message.class.to_s.downcase}_attrs".to_sym
31
+ attrs = send(approach, message, options)
32
+ message_delegate(attrs[:network]).new(attrs)
33
+ end
15
34
 
16
- BotMob::InboundMessage.new(
17
- network: options[:network] || :roaming,
18
- body: message
19
- )
35
+ # ## `human?`
36
+ #
37
+ # This should be overrode in the inheriting bot class. Use this
38
+ # to determine if the inbound message was written by a human
39
+ def human?
40
+ ENV['MOB_NAME'] != user_name
20
41
  end
21
42
 
43
+ # ## `params`
44
+ #
45
+ # A representation of the relevant data attached to a bot
22
46
  def params
23
- @params || { body: body }
47
+ @params ||= {
48
+ body: body,
49
+ network: network,
50
+ user_name: user_name
51
+ }
52
+ end
53
+
54
+ class << self
55
+ def message_attrs(*attrs)
56
+ @message_attrs = attrs
57
+ attr_reader(*@message_attrs)
58
+ end
59
+
60
+ def message_attributes
61
+ @message_attrs || []
62
+ end
63
+
64
+ def default_user_name
65
+ ENV['MOB_NAME'] || 'nomad'
66
+ end
67
+
68
+ def default_network
69
+ :roaming
70
+ end
71
+
72
+ private
73
+
74
+ def prepare_hash_attrs(message, options)
75
+ attrs = message.symbolize_keys.merge(options)
76
+ attrs.merge(
77
+ network: attrs[:network] || default_network,
78
+ user_name: attrs[:user_name] || default_user_name
79
+ )
80
+ end
81
+
82
+ def prepare_string_attrs(message, options)
83
+ options.merge(
84
+ network: options[:network] || default_network,
85
+ user_name: options[:user_name] || default_user_name,
86
+ body: message
87
+ )
88
+ end
89
+
90
+ def message_delegate(network)
91
+ delegate = BotMob::Networks.const_get(network.to_s.camelize)
92
+ delegate.const_get('InboundMessage')
93
+ rescue NameError
94
+ raise BotMob::InvalidNetworkError
95
+ end
96
+ end
97
+
98
+ private
99
+
100
+ def provided_message_attributes(options)
101
+ self.class.message_attributes.select { |attr| options[attr.to_sym] }
24
102
  end
25
103
  end
26
104
  end
@@ -0,0 +1,22 @@
1
+ module BotMob
2
+ # # BotMob::Logger
3
+ #
4
+ # Wrapper for the logger implemented by BotMob
5
+ class Logger < ::Logger
6
+ OMITTED_PARAMS = %w(splat captures).freeze
7
+
8
+ def log_request(source, action = :request, params = {})
9
+ source_network = params[:network] || 'roaming'
10
+ ts = Time.now.strftime('%Y-%m-%d %H:%M:%S%Z')
11
+
12
+ info "\n#{source.name} received #{action} from :#{source_network} at #{ts}"
13
+ info "Parameters: #{logged_params(params).inspect}"
14
+ end
15
+
16
+ private
17
+
18
+ def logged_params(params)
19
+ params.reject { |k, _| OMITTED_PARAMS.include?(k) }
20
+ end
21
+ end
22
+ end
@@ -5,7 +5,8 @@ module BotMob
5
5
  # The default network for a bot that has not yet connected to
6
6
  # an external network
7
7
  module Roaming
8
- autoload :Connection, 'bot_mob/networks/roaming/connection'
8
+ autoload :Connection, 'bot_mob/networks/roaming/connection'
9
+ autoload :InboundMessage, 'bot_mob/networks/roaming/inbound_message'
9
10
  autoload :OutboundMessage, 'bot_mob/networks/roaming/outbound_message'
10
11
  end
11
12
  end
@@ -0,0 +1,15 @@
1
+ module BotMob
2
+ module Networks
3
+ module Roaming
4
+ # # BotMob::InboundMessage
5
+ #
6
+ # Structured data provided to a bot without a connected network
7
+ class InboundMessage < BotMob::InboundMessage
8
+ def initialize(**options)
9
+ @network = :roaming
10
+ super
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,10 +1,13 @@
1
+ require 'slack-ruby-client'
2
+
1
3
  module BotMob
2
4
  module Networks
3
5
  # ## BotMob::Networks::Slack
4
6
  #
5
7
  # Network connection adapters to work with Slack
6
8
  module Slack
7
- autoload :Connection, 'bot_mob/networks/slack/connection'
9
+ autoload :Connection, 'bot_mob/networks/slack/connection'
10
+ autoload :InboundMessage, 'bot_mob/networks/slack/inbound_message'
8
11
  autoload :OutboundMessage, 'bot_mob/networks/slack/outbound_message'
9
12
  end
10
13
  end
@@ -0,0 +1,36 @@
1
+ module BotMob
2
+ module Networks
3
+ module Slack
4
+ # # BotMob::InboundMessage
5
+ #
6
+ # Structured data provided to a bot by Slack via sinatra params
7
+ # {
8
+ # "token": "NiI3K5i7SORx0MAf8U9QRfCX",
9
+ # "team_id": "T09K1L491",
10
+ # "team_domain": "foobar",
11
+ # "service_id": "16319829032",
12
+ # "channel_id": "C29R5RZLN",
13
+ # "channel_name": "general",
14
+ # "timestamp": "1482729119.000014",
15
+ # "user_id": "U07R1RUJA",
16
+ # "user_name": "matthew",
17
+ # "text": "Hi Everyone!",
18
+ # "splat": [],
19
+ # "captures": [
20
+ # "slack"
21
+ # ],
22
+ # "network": "slack"
23
+ # }
24
+ class InboundMessage < BotMob::InboundMessage
25
+ message_attrs :domain, :channel_name, :user_name, :timestamp,
26
+ :token, :team_id, :service_id, :channel_id, :user_id
27
+
28
+ def initialize(**options)
29
+ @network = :slack
30
+ @body = options[:text]
31
+ super
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -10,8 +10,31 @@ module BotMob
10
10
  @bots = []
11
11
  end
12
12
 
13
- def register(bot, **_options)
14
- @bots << (bot.is_a?(Class) ? bot.new : bot)
13
+ def register(bot, **options)
14
+ @bots << (bot.is_a?(Class) ? bot.new(options) : bot)
15
+ end
16
+
17
+ # ## `disseminate`
18
+ #
19
+ # This method will distribute a message or command to all bots
20
+ # on the roster. It collects and returns a compacted array
21
+ # of the bots' responses
22
+ def disseminate(action, params = {})
23
+ bots.map do |bot|
24
+ approach = "handle_#{action}".to_sym
25
+ respond_to?(approach, true) ? send(approach, bot, params) : nil
26
+ end.compact
27
+ end
28
+
29
+ private
30
+
31
+ def handle_message(bot, params)
32
+ bot.receive(params)
33
+ end
34
+
35
+ def handle_command(bot, params)
36
+ method_name = params[:method].to_sym
37
+ bot.receive_command(method_name, params)
15
38
  end
16
39
  end
17
40
  end
@@ -11,6 +11,10 @@ module BotMob
11
11
  super
12
12
  end
13
13
 
14
+ def name
15
+ 'Server'
16
+ end
17
+
14
18
  get '/' do
15
19
  erb :index
16
20
  end
@@ -19,29 +23,27 @@ module BotMob
19
23
  erb :console
20
24
  end
21
25
 
22
- get '/authorize' do
23
- erb :authorize
24
- end
26
+ get '/:network/callback' do
27
+ BotMob.logger.log_request(self, :callback, params)
25
28
 
26
- get '/message' do
27
- results = []
28
- settings.roster.bots.map do |bot|
29
- result = bot.receive(params[:text], network: params[:network])
30
- results << result.body unless result.nil?
29
+ case params[:network].to_sym
30
+ when :facebook
31
+ params['hub.challenge']
32
+ else
33
+ erb :authorize
31
34
  end
35
+ end
36
+
37
+ post '/:network/message' do
38
+ BotMob.logger.log_request(self, :message, params)
32
39
 
33
- results.join(', ')
40
+ settings.roster.disseminate(:message, params).join(', ')
34
41
  end
35
42
 
36
- get '/command/:method' do
37
- results = []
38
- settings.roster.bots.map do |bot|
39
- method_name = params[:method].to_sym
40
- result = bot.receive_command(method_name)
41
- results << result unless result.nil?
42
- end
43
+ post '/:network/command/:method' do
44
+ BotMob.logger.log_request(self, :command, params)
43
45
 
44
- results.join(', ')
46
+ settings.roster.disseminate(:command, params).join(', ')
45
47
  end
46
48
  end
47
49
  end
@@ -1,3 +1,3 @@
1
1
  module BotMob
2
- VERSION = '0.3.0'.freeze
2
+ VERSION = '0.3.2'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bot_mob
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew Werner
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-12-26 00:00:00.000000000 Z
11
+ date: 2016-12-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sinatra
@@ -168,11 +168,14 @@ files:
168
168
  - lib/bot_mob/core_ext/string.rb
169
169
  - lib/bot_mob/environment.rb
170
170
  - lib/bot_mob/inbound_message.rb
171
+ - lib/bot_mob/logger.rb
171
172
  - lib/bot_mob/networks/roaming.rb
172
173
  - lib/bot_mob/networks/roaming/connection.rb
174
+ - lib/bot_mob/networks/roaming/inbound_message.rb
173
175
  - lib/bot_mob/networks/roaming/outbound_message.rb
174
176
  - lib/bot_mob/networks/slack.rb
175
177
  - lib/bot_mob/networks/slack/connection.rb
178
+ - lib/bot_mob/networks/slack/inbound_message.rb
176
179
  - lib/bot_mob/networks/slack/outbound_message.rb
177
180
  - lib/bot_mob/outbound_message.rb
178
181
  - lib/bot_mob/public/console.js