pepito 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.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +41 -0
  3. data/.rubocop.yml +8 -0
  4. data/Gemfile +3 -0
  5. data/README.md +26 -0
  6. data/Rakefile +11 -0
  7. data/bin/pepito +5 -0
  8. data/lib/pepito/adapter.rb +101 -0
  9. data/lib/pepito/adapters.rb +4 -0
  10. data/lib/pepito/database.rb +14 -0
  11. data/lib/pepito/errors/missing_configuration_value_error.rb +15 -0
  12. data/lib/pepito/errors/required_methods_error.rb +15 -0
  13. data/lib/pepito/handler/chat_router.rb +36 -0
  14. data/lib/pepito/handler/http_router.rb +30 -0
  15. data/lib/pepito/handler.rb +38 -0
  16. data/lib/pepito/handlers/extensions_catalog.rb +108 -0
  17. data/lib/pepito/handlers/help.rb +36 -0
  18. data/lib/pepito/handlers/info.rb +40 -0
  19. data/lib/pepito/handlers/room.rb +23 -0
  20. data/lib/pepito/http_api/http_callback.rb +49 -0
  21. data/lib/pepito/http_api/http_route.rb +48 -0
  22. data/lib/pepito/http_api/rack_app.rb +27 -0
  23. data/lib/pepito/message.rb +59 -0
  24. data/lib/pepito/robot.rb +367 -0
  25. data/lib/pepito/source.rb +32 -0
  26. data/lib/pepito/version.rb +4 -0
  27. data/lib/pepito/web_app/app.rb +41 -0
  28. data/lib/pepito/web_app/views/index.erb +69 -0
  29. data/lib/pepito.rb +21 -0
  30. data/pepito.gemspec +35 -0
  31. data/test/pepito/handler/test_chat_router.rb +37 -0
  32. data/test/pepito/handler/test_http_router.rb +20 -0
  33. data/test/pepito/handlers/test_extensions_catalog.rb +38 -0
  34. data/test/pepito/handlers/test_help.rb +38 -0
  35. data/test/pepito/handlers/test_info.rb +32 -0
  36. data/test/pepito/handlers/test_room.rb +33 -0
  37. data/test/pepito/test_adapter.rb +71 -0
  38. data/test/pepito/test_handler.rb +28 -0
  39. data/test/pepito/test_message.rb +101 -0
  40. data/test/pepito/test_robot.rb +259 -0
  41. data/test/pepito/test_source.rb +27 -0
  42. data/test/test_pepito.rb +8 -0
  43. metadata +300 -0
@@ -0,0 +1,27 @@
1
+ require 'rack'
2
+ require 'http_router'
3
+
4
+ module Pepito
5
+ module HTTPApi
6
+ # The rack app for the http api.
7
+ class RackApp
8
+ # Router for the rack app.
9
+ # @return [HttpRouter]
10
+ attr_reader :router
11
+
12
+ # Rack App
13
+ # @return [Object]
14
+ attr_reader :app
15
+
16
+ # @return [void]
17
+ def initialize
18
+ @router = HttpRouter.new
19
+
20
+ builder = Rack::Builder.new
21
+ builder.run(@router)
22
+
23
+ @app = builder.to_app
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,59 @@
1
+ module Pepito
2
+ # Message received by an adapter
3
+ class Message
4
+ # The source of the message.
5
+ # @return [Pepito::Source]
6
+ attr_reader :source
7
+
8
+ # The text received.
9
+ # @return [String]
10
+ attr_reader :body
11
+
12
+ # The command part of the message.
13
+ # Example: body is -> "pepito info", command is "info".
14
+ # @return [String, nil] Returns nil if command could not be parsed.
15
+ attr_reader :command
16
+
17
+ # The currently running robot.
18
+ # @return [Pepito::Robot]
19
+ attr_reader :robot
20
+
21
+ # @param robot [Pepito::Robot] The currently running robot.
22
+ # @param source [Pepito::Source] The source of the message.
23
+ # @param body [String] The text received.
24
+ # @return [void]
25
+ def initialize(robot, source, body)
26
+ @robot = robot
27
+ @source = source
28
+ @body = body
29
+
30
+ @command = parse_command
31
+ end
32
+
33
+ # Returns whether a command exists or not.
34
+ # @return [Boolean]
35
+ def command?
36
+ @command.nil? ? false : true
37
+ end
38
+
39
+ # Returns whether a message matches a route or not
40
+ # @return [Boolean]
41
+ def match_route?(route)
42
+ return true if !route.command && route.pattern.match(body)
43
+ return true if route.command && command? && route.pattern.match(command)
44
+ false
45
+ end
46
+
47
+ private
48
+
49
+ # Parses the command from the body attribute.
50
+ # @return [String] The command string
51
+ def parse_command
52
+ return nil if @robot.name.nil? || @robot.name.empty?
53
+
54
+ command_data = /^#{@robot.name}\s?(?<command>.*)$/.match(@body)
55
+
56
+ command_data[:command] unless command_data.nil?
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,367 @@
1
+ require 'logger'
2
+ require 'puma'
3
+ require 'rubygems'
4
+ require 'rubygems/dependency_installer'
5
+
6
+ require_relative 'http_api/rack_app'
7
+ require_relative 'web_app/app'
8
+ require_relative 'handlers/info'
9
+ require_relative 'handlers/extensions_catalog'
10
+ require_relative 'handlers/help'
11
+ require_relative 'handlers/room'
12
+ require_relative 'database'
13
+ require_relative 'adapters'
14
+ require_relative 'errors/required_methods_error'
15
+ require_relative 'errors/missing_configuration_value_error'
16
+
17
+ module Pepito
18
+ # The robot component of the bot.
19
+ class Robot
20
+ # The running http_api.
21
+ # @return [Pepito::HTTPApi::RackApp]
22
+ attr_reader :http_api
23
+
24
+ # The thread running the HTTP API.
25
+ # @return [Thread]
26
+ attr_reader :http_api_thread
27
+
28
+ # The Puma::Server running the HTTP API
29
+ # @return [Puma::Server]
30
+ attr_reader :http_api_server
31
+
32
+ # The web app.
33
+ # @return [Pepito::WebApp::App]
34
+ attr_reader :web_app
35
+
36
+ # The thread running the web app.
37
+ # @return [Thread]
38
+ attr_reader :web_app_thread
39
+
40
+ # The Puma::Server running the Web App
41
+ # @return [Puma::Server]
42
+ attr_reader :web_app_server
43
+
44
+ # List of running handlers.
45
+ # @return [Hash] A map of handler's keys to classes.
46
+ attr_reader :handlers
47
+
48
+ # List of running adapters.
49
+ # @return [Hash] A map of adapter's keys to classes.
50
+ attr_reader :adapters
51
+
52
+ # Name of the bot.
53
+ # @return [String]
54
+ attr_reader :name
55
+
56
+ # Redis connection
57
+ # @return [Pepito::Database]
58
+ attr_reader :database
59
+
60
+ # Logger
61
+ # @return [Logger]
62
+ attr_reader :logger
63
+
64
+ # Default handlers that can't be turned off
65
+ # @return [Array<String>]
66
+ attr_reader :default_handlers
67
+
68
+ # Default adapters that can't be turned off
69
+ # @return [Array<String>]
70
+ attr_reader :default_adapters
71
+
72
+ # @return [void]
73
+ def initialize
74
+ @logger = Logger.new(ENV['LOG_FILE'] || STDOUT)
75
+
76
+ @logger.info('Connecting to the database')
77
+ @database = Database.new
78
+
79
+ @http_api = HTTPApi::RackApp.new
80
+
81
+ @web_app = WebApp::App
82
+
83
+ @default_handlers = %w(Info Help Room)
84
+ @handlers = {}
85
+
86
+ @default_adapters = []
87
+ @adapters = {}
88
+
89
+ @name = @database.get('name') || 'pepito'
90
+ end
91
+
92
+ # Runs the robot.
93
+ # @return [void]
94
+ def run
95
+ run_http_api
96
+ run_web_app
97
+ run_handlers
98
+ run_adapters
99
+ begin
100
+ sleep
101
+ rescue Interrupt
102
+ @logger.info('Exiting')
103
+ end
104
+ end
105
+
106
+ # Helper to receive a message.
107
+ # @param message [Pepito::Message] A message received by an adapter.
108
+ # @return [void]
109
+ def receive_message(message)
110
+ match = @handlers.dup.map do |_, handler|
111
+ handler.chat_routes.map do |route|
112
+ next unless message.match_route?(route)
113
+ strings = handler.public_send(route.func, message.source, route.pattern.match(message.command || message.body))
114
+ message.source.adapter.send_messages(message.source, strings) unless strings.nil?
115
+ true
116
+ end.any?
117
+ end.any?
118
+
119
+ message.source.adapter.send_messages(message.source, ['No match for command "' + message.command + '"']) if !match && message.command
120
+ end
121
+
122
+ # Retrieve the list of possible handlers to install from server
123
+ # @return [Array<String>]
124
+ def handlers_list
125
+ %w(Info Help ExtensionsCatalog Room)
126
+ end
127
+
128
+ # Retrieve the list of possible adapters to install from server
129
+ # @return [Array<String>]
130
+ def adapters_list
131
+ [
132
+ {
133
+ name: 'Slack',
134
+ gem: 'pepito-slack',
135
+ configs: [
136
+ {
137
+ name: 'SLACK_API_TOKEN',
138
+ required: true
139
+ }
140
+ ]
141
+ }
142
+ ]
143
+ end
144
+
145
+ # Starts an handler.
146
+ # @param handler [String] Name of the handler to start.
147
+ # @return [Integer]
148
+ # 0 - If success
149
+ # 1 - If failed because handler is already running
150
+ # 2 - If handler can't be found
151
+ # 3 - Other errors
152
+ def start_handler(handler)
153
+ @logger.info('"' + handler.to_s + '" handler starting')
154
+ if @handlers.key?(handler)
155
+ @logger.warn('"' + handler.to_s + '" handler is already running')
156
+ return 1
157
+ else
158
+ begin
159
+ @handlers[handler] = Handlers.const_get(handler).new(self)
160
+ rescue NameError
161
+ @logger.error('"' + handler.to_s + '" handler does not exist')
162
+ return 2
163
+ rescue => e
164
+ @logger.error('"' + handler.to_s + '" handler failed to start. Error: ' + e.message.to_s)
165
+ @logger.error(e)
166
+ return 3
167
+ end
168
+ @http_api.router.uncompile
169
+ @handlers[handler].run
170
+ @handlers[handler].start
171
+ @database.sadd('handlers', handler)
172
+ @logger.info('"' + handler.to_s + '" handler started successfully')
173
+ return 0
174
+ end
175
+ end
176
+
177
+ # Stops an handler.
178
+ # @param handler [String] Name of the handler to stop. Must match the handler's class name.
179
+ # @return [Integer]
180
+ # 0 - If handler stopped
181
+ # 1 - If it is a default handler
182
+ # 2 - If it is not running
183
+ def stop_handler(handler)
184
+ @logger.info('Stopping "' + handler.to_s + '" handler')
185
+ if @default_handlers.include?(handler)
186
+ @logger.error('Can\'t stop "' + handler.to_s + '" because it is a default handler')
187
+ return 1
188
+ elsif !@handlers.key?(handler)
189
+ @logger.warn('"' + handler.to_s + '" handler is not running')
190
+ return 2
191
+ else
192
+ @handlers.delete(handler)
193
+ @database.srem('handlers', handler)
194
+ @http_api.router.reset!
195
+ @handlers.each do |_, h|
196
+ h.start
197
+ end
198
+ @logger.info('"' + handler.to_s + '" handler stopped successfully')
199
+ return 0
200
+ end
201
+ end
202
+
203
+ # Checks if an handler is running or not.
204
+ # @param handler [String] Name of the handler.
205
+ # @return [Boolean]
206
+ def handler?(handler)
207
+ @handlers.key?(handler)
208
+ end
209
+
210
+ # Starts an adapter.
211
+ # @param adapter [String] Name of the adapter to start. Must match the adapter's class name.
212
+ # @param gem_name [String] Name of the gem for the adapter
213
+ # @param config [Hash<String,String>] The config for the adapter
214
+ # @return [Integer]
215
+ # 0 - if adapter was started
216
+ # 1 - if adapter is already running
217
+ # 2 - if adapter can't be found
218
+ # 3 - if there are missing methods on the adapter
219
+ # 4 - if there are missing configuration values
220
+ # 5 - other errors
221
+ def start_adapter(adapter, gem_name, config)
222
+ @logger.info('"' + adapter.to_s + '" adapter starting')
223
+ if @adapters.key?(adapter)
224
+ @logger.warn('"' + adapter.to_s + '" adapter already running')
225
+ return 1
226
+ else
227
+ begin
228
+ require gem_name
229
+ rescue LoadError
230
+ begin
231
+ inst = Gem::DependencyInstaller.new
232
+ inst.install gem_name
233
+ require gem_name
234
+ rescue => e
235
+ @logger.error(e)
236
+ return 2
237
+ end
238
+ end
239
+
240
+ begin
241
+ adp = Pepito::Adapters.const_get(adapter).new(self, config)
242
+ rescue NameError => e
243
+ @logger.error('"' + adapter.to_s + '" adapter could not be found')
244
+ @logger.error(e)
245
+ return 2
246
+ rescue Pepito::Errors::RequiredMethodsError => e
247
+ @logger.error('"' + adapter.to_s + '" adapter failed to start. ' + e.message + ': ' + e.missing_methods.to_s)
248
+ return 3
249
+ rescue Pepito::Errors::MissingConfigurationValueError => e
250
+ @logger.error('"' + adapter.to_s + '" adapter failed to start. ' + e.message + ': ' + e.configuration_values.to_s)
251
+ return 4
252
+ rescue => e
253
+ @logger.error('"' + adapter.to_s + '" adapter failed to start. Error: ' + e.message.to_s)
254
+ @logger.error(e)
255
+ return 5
256
+ end
257
+
258
+ # If it didnt fail, spawn adapter thread
259
+ @adapters[adapter] = adp
260
+ @database.sadd('adapters', adapter)
261
+ # Clear old config in database
262
+ @database.del(adapter)
263
+ # Set gem name in database
264
+ @database.set(adapter + ':gem', gem_name)
265
+ # Setup new config in database
266
+ config.each do |key, value|
267
+ @database.hset(adapter + ':config', key, value)
268
+ end
269
+
270
+ Thread.new do
271
+ adp.run
272
+ end
273
+
274
+ @logger.info('"' + adapter.to_s + '" adapter started successfully')
275
+ return 0
276
+ end
277
+ end
278
+
279
+ # Stops an adapter.
280
+ # @param adapter [String] Name of the adapter to stop. Must match the adapter's class name.
281
+ # @return [Integer]
282
+ # 0 - If successful
283
+ # 1 - If adapter is default
284
+ # 2 - If adapter is not running
285
+ def stop_adapter(adapter)
286
+ if @default_adapters.include?(adapter)
287
+ @logger.error('Can\'t stop "' + adapter.to_s + '" adapter because it is a default adapter')
288
+ return 1
289
+ elsif !@adapters.key?(adapter)
290
+ @logger.warn('"' + adapter.to_s + '" adapter is not running')
291
+ return 2
292
+ else
293
+ @adapters[adapter].stop
294
+ @adapters.delete(adapter)
295
+ @database.del(adapter + ':config')
296
+ @database.del(adapter + ':gem')
297
+ @database.srem('adapters', adapter)
298
+ @logger.info('"' + adapter.to_s + '" adapter stopped successfully')
299
+ return 0
300
+ end
301
+ end
302
+
303
+ # Checks if an adapter is running or not.
304
+ # @param adapter [String] Name of the adapter.
305
+ # @return [Boolean]
306
+ def adapter?(adapter)
307
+ @adapters.key?(adapter)
308
+ end
309
+
310
+ private
311
+
312
+ # Runs the http api in a new thread.
313
+ # @return [void]
314
+ def run_http_api
315
+ @logger.info('Starting the HTTP API')
316
+ @http_api_thread = Thread.new do
317
+ @http_api_server = Puma::Server.new(@http_api.app)
318
+ @http_api_server.add_tcp_listener('127.0.0.1', 8080)
319
+ @http_api_server.run
320
+ end
321
+
322
+ @http_api_thread.abort_on_exception = true
323
+ end
324
+
325
+ # Runs the web app in a new thread.
326
+ # @return [void]
327
+ def run_web_app
328
+ @logger.info('Starting the web app')
329
+ @web_app_thread = Thread.new do
330
+ @web_app.set(:robot, self)
331
+
332
+ @web_app_server = Puma::Server.new(@web_app)
333
+ @web_app_server.add_tcp_listener('127.0.0.1', 4567)
334
+
335
+ @web_app_server.run
336
+ end
337
+
338
+ @web_app_thread.abort_on_exception = true
339
+ end
340
+
341
+ # Runs the handlers saved in the database
342
+ # @return [void]
343
+ def run_handlers
344
+ @logger.info('Starting the handlers')
345
+ @default_handlers.each do |handler|
346
+ start_handler(handler)
347
+ end
348
+
349
+ @database.smembers('handlers').each do |handler|
350
+ start_handler(handler) unless @default_handlers.include?(handler)
351
+ end
352
+ end
353
+
354
+ # Runs the adapters saved in the database
355
+ # @return [void]
356
+ def run_adapters
357
+ @logger.info('Starting the adapters')
358
+ @default_adapters.each do |adapter, gem_name, configs|
359
+ start_adapter(adapter, gem_name, configs)
360
+ end
361
+
362
+ @database.smembers('adapters').each do |adapter|
363
+ start_adapter(adapter, @database.get(adapter + ':gem'), @database.hgetall(adapter + ':config')) unless @default_adapters.include?(adapter)
364
+ end
365
+ end
366
+ end
367
+ end
@@ -0,0 +1,32 @@
1
+ module Pepito
2
+ # Source for a message, where it comes from, where it should go
3
+ class Source
4
+ # Adapter that received the message.
5
+ # @return [Pepito::Adapter]
6
+ attr_reader :adapter
7
+
8
+ # User that sent the message.
9
+ # @return [String]
10
+ attr_reader :user
11
+
12
+ # Room where the message originated
13
+ # @return [String]
14
+ attr_reader :room
15
+
16
+ # Whether the message is private or not
17
+ # @return [Boolean]
18
+ attr_reader :private_message
19
+
20
+ # @param adapter [Adapter] The adapter that received the message.
21
+ # @param user [String] The user that sent the message.
22
+ # @param room [String] The room where the message was sent from.
23
+ # @param private_message [Boolean] Whether the message is private or not.
24
+ # @return [void]
25
+ def initialize(adapter, user, room, private_message)
26
+ @adapter = adapter
27
+ @user = user
28
+ @room = room
29
+ @private_message = private_message
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,4 @@
1
+ module Pepito
2
+ # The current version of Pepito
3
+ VERSION = '0.0.1'.freeze
4
+ end
@@ -0,0 +1,41 @@
1
+ require 'sinatra/base'
2
+ require 'tilt/erb'
3
+
4
+ module Pepito
5
+ module WebApp
6
+ # Web App to control the bot
7
+ class App < Sinatra::Base
8
+ get '/' do
9
+ @handlers = settings.robot.handlers_list
10
+ @adapters = settings.robot.adapters_list
11
+ erb :index
12
+ end
13
+
14
+ post '/deactivate/handler/:handler' do
15
+ settings.robot.stop_handler(params['handler'])
16
+ redirect to('/')
17
+ end
18
+
19
+ post '/activate/handler/:handler' do
20
+ settings.robot.start_handler(params['handler'])
21
+ redirect to('/')
22
+ end
23
+
24
+ post '/deactivate/adapter/:adapter' do
25
+ settings.robot.stop_adapter(params['adapter'])
26
+ redirect to('/')
27
+ end
28
+
29
+ post '/activate/adapter/:adapter' do
30
+ c = {}
31
+ params.each do |key, value|
32
+ if key.start_with?(params['adapter'] + ':config:')
33
+ c[key.split(params['adapter'] + ':config:')[1]] = value
34
+ end
35
+ end
36
+ settings.robot.start_adapter(params['adapter'], params[params['adapter'] + ':gem_name'], c)
37
+ redirect to('/')
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,69 @@
1
+ <h1><%= settings.robot.name.capitalize %> bot!</h1>
2
+
3
+ <h3>Handlers List</h3>
4
+ <table border=1 style="text-align: left; min-width: 200px">
5
+ <tr>
6
+ <th>Handler</th>
7
+ <th>Action</th>
8
+ </tr>
9
+ <% settings.robot.default_handlers.each do |handler| %>
10
+ <tr>
11
+ <td><%= handler.to_s %></td>
12
+ <td>Default Handler, can not be deactivated.</td>
13
+ </tr>
14
+ <% end %>
15
+ <% @handlers.each do |handler| %>
16
+ <% if !settings.robot.default_handlers.include?(handler) %>
17
+ <tr>
18
+ <td><%= handler.to_s %></td>
19
+ <td>
20
+ <% if settings.robot.handlers.keys.include?(handler) %>
21
+ <form action="/deactivate/handler/<%= handler.to_s %>" method="POST">
22
+ <input type="submit" value="Deactivate">
23
+ </form>
24
+ <% else %>
25
+ <form action="/activate/handler/<%= handler.to_s %>" method="POST">
26
+ <input type="submit" value="Activate">
27
+ </form>
28
+ <% end %>
29
+ </td>
30
+ </tr>
31
+ <% end %>
32
+ <% end %>
33
+ </table>
34
+
35
+ <h3>Adapters List</h3>
36
+ <table border=1 style="text-align: left; min-width: 200px;">
37
+ <tr>
38
+ <th>Handler</th>
39
+ <th>Action</th>
40
+ </tr>
41
+ <% settings.robot.default_adapters.each do |adapter| %>
42
+ <tr>
43
+ <td><%= adapter[:name].to_s %></td>
44
+ <td>Default Adapter, can not be deactivated.</td>
45
+ </tr>
46
+ <% end %>
47
+ <% @adapters.each do |adapter| %>
48
+ <% if !settings.robot.default_adapters.include?(adapter[:name]) %>
49
+ <tr>
50
+ <td><%= adapter[:name].to_s %></td>
51
+ <td>
52
+ <% if settings.robot.adapters.keys.include?(adapter[:name]) %>
53
+ <form action="/deactivate/adapter/<%= adapter[:name].to_s %>" method="POST">
54
+ <input type="submit" value="Deactivate">
55
+ </form>
56
+ <% else %>
57
+ <form action="/activate/adapter/<%= adapter[:name].to_s %>" method="POST">
58
+ <input type="hidden" name="<%= adapter[:name].to_s %>:gem_name" value="<%= adapter[:gem].to_s %>">
59
+ <% adapter[:configs].each do |c| %>
60
+ <%= c[:name].to_s %><% if !c[:required] %>(optional)<% end %>: <input type="text" name="<%= adapter[:name].to_s %>:config:<%= c[:name].to_s %>"><br>
61
+ <% end %>
62
+ <input type="submit" value="Activate">
63
+ </form>
64
+ <% end %>
65
+ </td>
66
+ </tr>
67
+ <% end %>
68
+ <% end %>
69
+ </table>
data/lib/pepito.rb ADDED
@@ -0,0 +1,21 @@
1
+ require_relative 'pepito/http_api/rack_app'
2
+ require_relative 'pepito/robot'
3
+
4
+ # Pepito's main namespace
5
+ module Pepito
6
+ # Name for redis table
7
+ REDIS_NAMESPACE = :pepito
8
+
9
+ class << self
10
+ # Running robot
11
+ # @return [Pepito::Robot]
12
+ attr_reader :robot
13
+
14
+ # Initializes the robot and runs it.
15
+ def run
16
+ @robot = Pepito::Robot.new
17
+
18
+ @robot.run
19
+ end
20
+ end
21
+ end
data/pepito.gemspec ADDED
@@ -0,0 +1,35 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib/', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require File.expand_path('../lib/pepito/version', __FILE__)
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = 'pepito'
8
+ s.version = Pepito::VERSION
9
+ s.authors = ['Olivier']
10
+ s.email = ['olivier@yafoy.com']
11
+ s.summary = 'Pepito is your very own corporate bot'
12
+ s.description = 'Integrate a bot in your company with custom extensions'
13
+ s.homepage = 'https://github.com/yafoy/pepito'
14
+ s.license = 'MIT'
15
+
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.require_paths = ['lib']
20
+
21
+ s.required_ruby_version = '>= 2.0.0'
22
+
23
+ s.add_runtime_dependency 'redis-namespace', '~> 1.5', '>= 1.5.2'
24
+ s.add_runtime_dependency 'multi_json', '~> 1.11', '>= 1.11.2'
25
+ s.add_runtime_dependency 'rack', '~> 1.6', '>= 1.6.4'
26
+ s.add_runtime_dependency 'eventmachine', '~> 1.0.8', '>= 1.0.8'
27
+ s.add_runtime_dependency 'http_router', '~> 0.11.2', '>= 0.11.2'
28
+ s.add_runtime_dependency 'sinatra', '~> 1.4.6', '>= 1.4.6'
29
+ s.add_runtime_dependency 'tilt', '~> 2.0.2', '>= 2.0.2'
30
+ s.add_runtime_dependency 'puma', '~> 2.15.3', '>= 2.15.3'
31
+
32
+ s.add_development_dependency 'rake'
33
+ s.add_development_dependency 'minitest'
34
+ s.add_development_dependency 'rubocop', '~> 0.37'
35
+ end
@@ -0,0 +1,37 @@
1
+ require 'minitest/autorun'
2
+ require 'pepito/handler/chat_router'
3
+
4
+ class Stub
5
+ include Pepito::Handler::ChatRouter
6
+ end
7
+
8
+ class TestPepitoHandlerChatRouter < MiniTest::Test
9
+ def test_emtpy_routes
10
+ stub = Stub.new
11
+ assert_empty stub.chat_routes
12
+ end
13
+
14
+ def test_add_route
15
+ stub = Stub.new
16
+ stub.chat_route(/test/, :func_sym, command: true, help: 'help')
17
+
18
+ assert_equal stub.chat_routes[0].pattern, /test/
19
+ assert_equal stub.chat_routes[0].func, :func_sym
20
+ assert_equal stub.chat_routes[0].command, true
21
+ assert_equal stub.chat_routes[0].help, 'help'
22
+ end
23
+
24
+ def test_add_route_no_command
25
+ stub = Stub.new
26
+ stub.chat_route(/test/, :func_sym)
27
+
28
+ assert_equal stub.chat_routes[0].command, false
29
+ end
30
+
31
+ def test_add_route_no_help
32
+ stub = Stub.new
33
+ stub.chat_route(/test/, :func_sym)
34
+
35
+ assert_nil stub.chat_routes[0].help
36
+ end
37
+ end