pepito 0.0.2 → 0.0.3

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: b765db41f66cec333a433f4af03b7d0027174402
4
- data.tar.gz: 22d589c8034f06dd5b86a554c0e54ac93d548aa7
3
+ metadata.gz: 6df931c406711b8ff0167baf10b00cc7bc8142ff
4
+ data.tar.gz: 396e1fc731cd469d9c56034f65e8dbb93c23aa7e
5
5
  SHA512:
6
- metadata.gz: d0a1cd4baab73d27ce0d0b1293d72543fd2664de1e9a7d438ce27b96e4b1d3feb3006bae8647fca5fa2761bacd0e1a32ff01af2233e232d55ea9486363be1eef
7
- data.tar.gz: 8ba4898f785b4d9e1f4990496167d22707476202e2b88550fc67f6c4b833f53d3a2f0fff2cef622ad37cee1582cf1fff9887b9431cabfbad3106ff092d52f382
6
+ metadata.gz: 25aa6bacb406a0d808510575aac07daf714bc747c517b1b001267a24f8aeb5d129821863271c24b4d6c39d2166d96ef85f97343c27e9ac9b38414c02c4e7f693
7
+ data.tar.gz: 36c9d51a7a2538a36229018e9f4448444aa7ae76c080f714ad6c83dc60c602533f0dc0b8d53b5a05d44b6b7d6a0e09598bd593ca01399d2c279d1bec52b7dfd0
data/Gemfile CHANGED
@@ -1,3 +1,6 @@
1
1
  source 'http://rubygems.org'
2
2
 
3
+ # gem 'pepito-queenbee', path: '../pepito-queenbee'
4
+ gem 'queenbee', '~> 0.0.5'
5
+
3
6
  gemspec
@@ -1,4 +1,5 @@
1
1
  module Pepito
2
+ # Adapters module placeholder, required to use const_get because we have no default adapters
2
3
  module Adapters
3
4
  end
4
5
  end
@@ -8,15 +8,35 @@ module Pepito
8
8
  include Handler::HTTPRouter
9
9
  include Handler::ChatRouter
10
10
 
11
+ class << self
12
+ # Configs for the handler, method should be overriden in the handler if
13
+ # parameters are necessary
14
+ # @return [Array<Hash>] Array of hashes with the config parameters
15
+ def configs
16
+ [{}]
17
+ end
18
+ end
19
+
11
20
  # Currently running robot
12
21
  # @return [Pepito::Robot]
13
22
  attr_reader :robot
14
23
 
24
+ # Config
25
+ # @return [Hash<>]
26
+ attr_reader :config
27
+
15
28
  # Initializes the Adapter class
16
29
  # @param robot [Pepito::Robot] The currently running robot
17
30
  # @return [void]
18
- def initialize(robot)
31
+ def initialize(robot, config)
19
32
  @robot = robot
33
+ @config = config
34
+
35
+ begin
36
+ missing_configuration_values
37
+ rescue => e
38
+ raise e
39
+ end
20
40
  end
21
41
 
22
42
  # Starts the handler
@@ -34,5 +54,22 @@ module Pepito
34
54
  @robot.http_api.router.add_route(route.route)
35
55
  end if @http_routes
36
56
  end
57
+
58
+ # Check whether all required configuration values exist
59
+ # Raises a [Pepito::Errors::MissingConfigurationValueError] if methods are missing
60
+ # @return [void]
61
+ def missing_configuration_values
62
+ confs = []
63
+ self.class.configs.each do |c|
64
+ confs << c[:name] if c[:required] && !configuration_value?(c[:name])
65
+ end
66
+ raise Errors::MissingConfigurationValueError.new(confs), 'missing required configuration values' unless confs.empty?
67
+ end
68
+
69
+ # Whether a configuration_value is present or not.
70
+ # @return [Boolean] True if is present, False otherwise.
71
+ def configuration_value?(name)
72
+ !@config.nil? && @config.keys.include?(name) && !@config[name].nil? && !@config[name].empty?
73
+ end
37
74
  end
38
75
  end
@@ -0,0 +1,45 @@
1
+ require 'rubygems/dependency_installer'
2
+ require 'rubygems/uninstaller'
3
+
4
+ module Pepito
5
+ # Class with helper functions
6
+ module Helpers
7
+ # Method to install gem
8
+ # @param gem_name[String]
9
+ # @return void
10
+ def gem_install(gem_name)
11
+ inst = Gem::DependencyInstaller.new
12
+ inst.install gem_name
13
+ require gem_name
14
+ rescue => e
15
+ raise e
16
+ end
17
+
18
+ def gem_uninstall(gem_name)
19
+ uninst = Gem::Uninstaller.new gem_name
20
+ uninst.uninstall
21
+ rescue => e
22
+ raise e
23
+ end
24
+
25
+ def gem_installed?(gem_name)
26
+ Gem::Specification.find_by_name gem_name
27
+ return true
28
+ rescue LoadError
29
+ return false
30
+ end
31
+
32
+ def gem_load(gem_name)
33
+ if gem_installed?(gem_name)
34
+ require gem_name
35
+ else
36
+ begin
37
+ gem_install gem_name
38
+ require gem_name
39
+ rescue => e
40
+ raise e
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -2,21 +2,27 @@ require 'logger'
2
2
  require 'puma'
3
3
  require 'rubygems'
4
4
  require 'rubygems/dependency_installer'
5
+ require 'rest-client'
6
+ require 'multi_json'
5
7
 
6
8
  require_relative 'http_api/rack_app'
7
9
  require_relative 'web_app/app'
8
10
  require_relative 'handlers/info'
9
11
  require_relative 'handlers/extensions_catalog'
10
12
  require_relative 'handlers/help'
13
+ require_relative 'handlers/queenbee'
11
14
  require_relative 'handlers/room'
12
15
  require_relative 'database'
13
16
  require_relative 'adapters'
17
+ require_relative 'helpers'
14
18
  require_relative 'errors/required_methods_error'
15
19
  require_relative 'errors/missing_configuration_value_error'
16
20
 
17
21
  module Pepito
18
22
  # The robot component of the bot.
19
23
  class Robot
24
+ include Pepito::Helpers
25
+
20
26
  # The running http_api.
21
27
  # @return [Pepito::HTTPApi::RackApp]
22
28
  attr_reader :http_api
@@ -80,7 +86,7 @@ module Pepito
80
86
 
81
87
  @web_app = WebApp::App
82
88
 
83
- @default_handlers = %w(Info Help Room)
89
+ @default_handlers = %w(Info Help Room ExtensionsCatalog Queenbee)
84
90
  @handlers = {}
85
91
 
86
92
  @default_adapters = []
@@ -122,24 +128,19 @@ module Pepito
122
128
  # Retrieve the list of possible handlers to install from server
123
129
  # @return [Array<String>]
124
130
  def handlers_list
125
- %w(Info Help ExtensionsCatalog Room)
131
+ catalog_url = 'https://raw.githubusercontent.com/yafoy/pepito-catalog/master/all.json'
132
+ response = RestClient.get(catalog_url)
133
+ integrations = MultiJson.load(response.body, symbolize_keys: true)
134
+ integrations[:handlers]
126
135
  end
127
136
 
128
137
  # Retrieve the list of possible adapters to install from server
129
138
  # @return [Array<String>]
130
139
  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
- ]
140
+ catalog_url = 'https://raw.githubusercontent.com/yafoy/pepito-catalog/master/all.json'
141
+ response = RestClient.get(catalog_url)
142
+ integrations = MultiJson.load(response.body, symbolize_keys: true)
143
+ integrations[:adapters]
143
144
  end
144
145
 
145
146
  # Starts an handler.
@@ -148,27 +149,46 @@ module Pepito
148
149
  # 0 - If success
149
150
  # 1 - If failed because handler is already running
150
151
  # 2 - If handler can't be found
151
- # 3 - Other errors
152
- def start_handler(handler)
152
+ # 3 - If handler is missing configuration values
153
+ # 4 - Other errors
154
+ def start_handler(handler, gem_name, config)
153
155
  @logger.info('"' + handler.to_s + '" handler starting')
154
156
  if @handlers.key?(handler)
155
157
  @logger.warn('"' + handler.to_s + '" handler is already running')
156
158
  return 1
157
159
  else
160
+ # Installing gem
161
+ begin
162
+ gem_load gem_name
163
+ rescue => e
164
+ @logger.error(e)
165
+ return 2
166
+ end
167
+
158
168
  begin
159
- @handlers[handler] = Handlers.const_get(handler).new(self)
169
+ @handlers[handler] = Handlers.const_get(handler).new(self, config)
160
170
  rescue NameError
161
171
  @logger.error('"' + handler.to_s + '" handler does not exist')
162
172
  return 2
173
+ rescue Pepito::Errors::MissingConfigurationValueError => e
174
+ @logger.error('"' + handler.to_s + '" handler failed to start. ' + e.message + ': ' + e.configuration_values.to_s)
175
+ return 3
163
176
  rescue => e
164
177
  @logger.error('"' + handler.to_s + '" handler failed to start. Error: ' + e.message.to_s)
165
178
  @logger.error(e)
166
- return 3
179
+ return 4
167
180
  end
181
+
168
182
  @http_api.router.uncompile
169
183
  @handlers[handler].run
170
184
  @handlers[handler].start
171
185
  @database.sadd('handlers', handler)
186
+ @database.set(handler + ':gem', gem_name)
187
+ # Setup new config in database
188
+ config.each do |key, value|
189
+ @database.hset(handler + ':config', key, value)
190
+ end
191
+
172
192
  @logger.info('"' + handler.to_s + '" handler started successfully')
173
193
  return 0
174
194
  end
@@ -191,6 +211,8 @@ module Pepito
191
211
  else
192
212
  @handlers.delete(handler)
193
213
  @database.srem('handlers', handler)
214
+ @database.del(handler + ':config')
215
+ @database.del(handler + ':gem')
194
216
  @http_api.router.reset!
195
217
  @handlers.each do |_, h|
196
218
  h.start
@@ -224,17 +246,12 @@ module Pepito
224
246
  @logger.warn('"' + adapter.to_s + '" adapter already running')
225
247
  return 1
226
248
  else
249
+ # Installing gem
227
250
  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
251
+ gem_load gem_name
252
+ rescue => e
253
+ @logger.error(e)
254
+ return 2
238
255
  end
239
256
 
240
257
  begin
@@ -343,11 +360,11 @@ module Pepito
343
360
  def run_handlers
344
361
  @logger.info('Starting the handlers')
345
362
  @default_handlers.each do |handler|
346
- start_handler(handler)
363
+ start_handler(handler, 'pepito', [])
347
364
  end
348
365
 
349
366
  @database.smembers('handlers').each do |handler|
350
- start_handler(handler) unless @default_handlers.include?(handler)
367
+ start_handler(handler, @database.get(handler + ':gem'), @database.hgetall(handler + ':config')) unless @default_handlers.include?(handler)
351
368
  end
352
369
  end
353
370
 
@@ -1,4 +1,4 @@
1
1
  module Pepito
2
2
  # The current version of Pepito
3
- VERSION = '0.0.2'.freeze
3
+ VERSION = '0.0.3'.freeze
4
4
  end
@@ -1,14 +1,33 @@
1
1
  require 'sinatra/base'
2
2
  require 'tilt/erb'
3
+ require 'rest-client'
4
+
5
+ require_relative '../helpers'
3
6
 
4
7
  module Pepito
5
8
  module WebApp
6
9
  # Web App to control the bot
7
10
  class App < Sinatra::Base
11
+ include Pepito::Helpers
12
+
8
13
  get '/' do
9
14
  @handlers = settings.robot.handlers_list
15
+ @handlers.each do |h|
16
+ if gem_installed?(h[:gem])
17
+ gem_load h[:gem]
18
+ h[:configs] = Pepito::Handlers.const_get(h[:name].to_s).configs
19
+ end
20
+ end
21
+
10
22
  @adapters = settings.robot.adapters_list
11
- erb :index
23
+ @adapters.each do |a|
24
+ if gem_installed?(a[:gem].to_s)
25
+ gem_load a[:gem].to_s
26
+ a[:configs] = Pepito::Adapters.const_get(a[:name].to_s).configs
27
+ end
28
+ end
29
+
30
+ erb :index, layout: :layout
12
31
  end
13
32
 
14
33
  post '/deactivate/handler/:handler' do
@@ -17,7 +36,13 @@ module Pepito
17
36
  end
18
37
 
19
38
  post '/activate/handler/:handler' do
20
- settings.robot.start_handler(params['handler'])
39
+ c = {}
40
+ params.each do |key, value|
41
+ if key.start_with?(params['handler'] + ':config:')
42
+ c[key.split(params['handler'] + ':config:')[1]] = value
43
+ end
44
+ end
45
+ settings.robot.start_handler(params['handler'], params[params['handler'] + ':gem_name'], c)
21
46
  redirect to('/')
22
47
  end
23
48
 
@@ -36,6 +61,28 @@ module Pepito
36
61
  settings.robot.start_adapter(params['adapter'], params[params['adapter'] + ':gem_name'], c)
37
62
  redirect to('/')
38
63
  end
64
+
65
+ post '/install/:gem' do
66
+ gem_install params['gem']
67
+ redirect to('/')
68
+ end
69
+
70
+ post '/uninstall/:gem' do
71
+ gem_uninstall params['gem']
72
+ redirect to('/')
73
+ end
74
+
75
+ get '/integrations' do
76
+ begin
77
+ catalog_url = 'https://raw.githubusercontent.com/yafoy/pepito-catalog/master/all.json'
78
+ response = RestClient.get(catalog_url)
79
+ @integrations = JSON.parse response.body
80
+ rescue RestClient::ExceptionWithResponse => err
81
+ err.response
82
+ @integrations = []
83
+ end
84
+ erb :integrations, layout: :layout
85
+ end
39
86
  end
40
87
  end
41
88
  end
@@ -0,0 +1 @@
1
+ body{margin:0}aside,details,main,summary{display:block}template{display:none}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}.grd{padding-left:1rem;padding-right:1rem}.grd-row{box-sizing:border-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;max-width:100%}.grd-row-col-1-6{max-width:16.66667%;-webkit-flex-basis:16.66667%;-ms-flex-preferred-size:16.66667%;flex-basis:16.66667%}.grd-row-col-2-6{max-width:33.33333%;-webkit-flex-basis:33.33333%;-ms-flex-preferred-size:33.33333%;flex-basis:33.33333%}.grd-row-col-3-6{max-width:50%;-webkit-flex-basis:50%;-ms-flex-preferred-size:50%;flex-basis:50%}.grd-row-col-4-6{max-width:66.66667%;-webkit-flex-basis:66.66667%;-ms-flex-preferred-size:66.66667%;flex-basis:66.66667%}.grd-row-col-5-6{max-width:83.33333%;-webkit-flex-basis:83.33333%;-ms-flex-preferred-size:83.33333%;flex-basis:83.33333%}.grd-row-col-6{max-width:100%;-webkit-flex-basis:100%;-ms-flex-preferred-size:100%;flex-basis:100%}.grd-row-col-1-6,.grd-row-col-1-6--lg,.grd-row-col-1-6--md,.grd-row-col-1-6--sm,.grd-row-col-2-6,.grd-row-col-2-6--lg,.grd-row-col-2-6--md,.grd-row-col-2-6--sm,.grd-row-col-3-6,.grd-row-col-3-6--lg,.grd-row-col-3-6--md,.grd-row-col-3-6--sm,.grd-row-col-4-6,.grd-row-col-4-6--lg,.grd-row-col-4-6--md,.grd-row-col-4-6--sm,.grd-row-col-5-6,.grd-row-col-5-6--lg,.grd-row-col-5-6--md,.grd-row-col-5-6--sm,.grd-row-col-6,.grd-row-col-6--lg,.grd-row-col-6--md,.grd-row-col-6--sm{-webkit-flex:1;-ms-flex:1;flex:1;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;box-sizing:border-box}.grd-row-col-1-6--lg,.grd-row-col-1-6--md,.grd-row-col-1-6--sm,.grd-row-col-2-6--lg,.grd-row-col-2-6--md,.grd-row-col-2-6--sm,.grd-row-col-3-6--lg,.grd-row-col-3-6--md,.grd-row-col-3-6--sm,.grd-row-col-4-6--lg,.grd-row-col-4-6--md,.grd-row-col-4-6--sm,.grd-row-col-5-6--lg,.grd-row-col-5-6--md,.grd-row-col-5-6--sm,.grd-row-col-6--lg,.grd-row-col-6--md,.grd-row-col-6--sm{max-width:100%;-webkit-flex-basis:100%;-ms-flex-preferred-size:100%;flex-basis:100%}@media screen and (min-width:32rem){.grd-row-col-1-6--sm{max-width:16.66667%;-webkit-flex-basis:16.66667%;-ms-flex-preferred-size:16.66667%;flex-basis:16.66667%}.grd-row-col-2-6--sm{max-width:33.33333%;-webkit-flex-basis:33.33333%;-ms-flex-preferred-size:33.33333%;flex-basis:33.33333%}.grd-row-col-3-6--sm{max-width:50%;-webkit-flex-basis:50%;-ms-flex-preferred-size:50%;flex-basis:50%}.grd-row-col-4-6--sm{max-width:66.66667%;-webkit-flex-basis:66.66667%;-ms-flex-preferred-size:66.66667%;flex-basis:66.66667%}.grd-row-col-5-6--sm{max-width:83.33333%;-webkit-flex-basis:83.33333%;-ms-flex-preferred-size:83.33333%;flex-basis:83.33333%}.grd-row-col-6--sm{max-width:100%;-webkit-flex-basis:100%;-ms-flex-preferred-size:100%;flex-basis:100%}}@media screen and (min-width:48rem){.grd-row-col-1-6--md{max-width:16.66667%;-webkit-flex-basis:16.66667%;-ms-flex-preferred-size:16.66667%;flex-basis:16.66667%}.grd-row-col-2-6--md{max-width:33.33333%;-webkit-flex-basis:33.33333%;-ms-flex-preferred-size:33.33333%;flex-basis:33.33333%}.grd-row-col-3-6--md{max-width:50%;-webkit-flex-basis:50%;-ms-flex-preferred-size:50%;flex-basis:50%}.grd-row-col-4-6--md{max-width:66.66667%;-webkit-flex-basis:66.66667%;-ms-flex-preferred-size:66.66667%;flex-basis:66.66667%}.grd-row-col-5-6--md{max-width:83.33333%;-webkit-flex-basis:83.33333%;-ms-flex-preferred-size:83.33333%;flex-basis:83.33333%}.grd-row-col-6--md{max-width:100%;-webkit-flex-basis:100%;-ms-flex-preferred-size:100%;flex-basis:100%}}@media screen and (min-width:64rem){.grd-row-col-1-6--lg{max-width:16.66667%;-webkit-flex-basis:16.66667%;-ms-flex-preferred-size:16.66667%;flex-basis:16.66667%}.grd-row-col-2-6--lg{max-width:33.33333%;-webkit-flex-basis:33.33333%;-ms-flex-preferred-size:33.33333%;flex-basis:33.33333%}.grd-row-col-3-6--lg{max-width:50%;-webkit-flex-basis:50%;-ms-flex-preferred-size:50%;flex-basis:50%}.grd-row-col-4-6--lg{max-width:66.66667%;-webkit-flex-basis:66.66667%;-ms-flex-preferred-size:66.66667%;flex-basis:66.66667%}.grd-row-col-5-6--lg{max-width:83.33333%;-webkit-flex-basis:83.33333%;-ms-flex-preferred-size:83.33333%;flex-basis:83.33333%}.grd-row-col-6--lg{max-width:100%;-webkit-flex-basis:100%;-ms-flex-preferred-size:100%;flex-basis:100%}}*,::after,::before{box-sizing:border-box}.measure{max-width:48rem;margin:0 auto}a{color:#3498db}a:active,a:focus,a:hover{color:#217dbb}.bg--red{background-color:#e74c3c}.bg--orange{background-color:#f39c12}.bg--blue{background-color:#3498db}.bg--green{background-color:#25ba84}.bg--white{background-color:#fff}.bg--light-gray{background-color:rgba(216,216,216,.99)}.bg--mid-gray{background-color:rgba(144,144,144,.99)}.bg--dark-gray{background-color:rgba(72,72,72,.99)}.bg--off-white{background-color:rgba(250,250,250,.99)}.fnt--red{color:#e74c3c}.fnt--orange{color:#f39c12}.fnt--blue{color:#3498db}.fnt--green{color:#25ba84}.fnt--white{color:#fff}.fnt--light-gray{color:rgba(216,216,216,.99)}.fnt--mid-gray{color:rgba(144,144,144,.99)}.fnt--dark-gray{color:rgba(72,72,72,.99)}.fnt--off-white{color:rgba(250,250,250,.99)}.m0{margin:0}.mx0{margin-left:0;margin-right:0}.my0{margin-top:0;margin-bottom:0}.m1{margin:1rem}.mx1{margin-left:1rem;margin-right:1rem}.my1{margin-top:1rem;margin-bottom:1rem}.m2{margin:2rem}.mx2{margin-left:2rem;margin-right:2rem}.my2{margin-top:2rem;margin-bottom:2rem}.p0{padding:0}.px0{padding-left:0;padding-right:0}.py0{padding-top:0;padding-bottom:0}.p1{padding:1rem}.px1{padding-left:1rem;padding-right:1rem}.py1{padding-top:1rem;padding-bottom:1rem}.p2{padding:2rem}.px2{padding-left:2rem;padding-right:2rem}.py2{padding-top:2rem;padding-bottom:2rem}html{font-size:12px}@media screen and (min-width:32rem) and (max-width:48rem){html{font-size:15px}}@media screen and (min-width:48rem){html{font-size:16px}}body{font-family:HelveticaNeue-Light,"Helvetica Neue Light","Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:400;line-height:1.85;color:#333}.p,p{font-size:1rem;margin-bottom:1.3rem}.h1,.h2,.h3,.h4,h1,h2,h3,h4{margin:1.414rem 0 .5rem;font-weight:inherit;line-height:1.42}.h1,h1{margin-top:0;font-size:3.998rem}.h2,h2{font-size:2.827rem}.h3,h3{font-size:1.999rem}.h4,h4{font-size:1.414rem}.h5,h5,table th{font-size:1.121rem}.h6,h6{font-size:.88rem}.btn--s,.small,small{font-size:.707em}code,pre{font-family:Monaco,"Lucida Console",Courier,monospace}.italic{font-style:italic}.thin{font-weight:100}.bold{font-weight:700}.caps,table th{font-variant:small-caps}.justify{text-align:justify}.ellipsis{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.muted{opacity:.7}.clearfix:after{content:"";display:table;clear:both}.flt--left{float:left}.flt--right{float:right}.flt--none{float:none}.center{margin:auto}.txt--center{text-align:center}.txt--right{text-align:right}.txt--left,table th{text-align:left}.oflow-y--scroll{overflow-y:scroll}.w100,.w100--s{width:100%;display:block}@media screen and (min-width:32rem){.w100--s{width:auto;display:inline-block}}canvas,iframe,img,select,svg,textarea,video{max-width:100%}.brdr--rounded,.btn,.btn--blue,.btn--gray,.btn--green,.btn--link,.btn--red{border-radius:3px}.brdr--light-gray{border:thin solid rgba(216,216,216,.99)}.brdr--mid-gray{border:thin solid rgba(144,144,144,.99)}.brdr--dark-gray{border:thin solid rgba(72,72,72,.99)}.brdr--off-white{border:thin solid rgba(250,250,250,.99)}.btn,.btn--blue,.btn--gray,.btn--green,.btn--link,.btn--red{padding:.5rem 1rem;border:2px solid #ccc;color:#333;text-decoration:none;text-align:center}.btn:active,.btn:focus,.btn:hover{background-color:rgba(0,0,0,.05);color:#000}.btn--link{border-color:transparent;color:#3498db}.btn--link:hover{background-color:transparent;color:#1d6fa5}.btn--blue{border-color:#2792d9;background-color:#3498db;color:#fff}.btn--blue:active,.btn--blue:focus,.btn--blue:hover{color:#fff;background-color:#217dbb}.btn--green{border-color:#22a977;background-color:#25ba84;color:#fff}.btn--green:active,.btn--green:focus,.btn--green:hover{color:#fff;background-color:#1d8f65}.btn--gray{border-color:rgba(59,59,59,.99);background-color:rgba(72,72,72,.99);color:#fff}.btn--gray:active,.btn--gray:focus,.btn--gray:hover{color:#fff;background-color:rgba(46,46,46,.99)}.btn--red{border-color:#e43525;background-color:#e74c3c;color:#fff}.btn--red:active,.btn--red:focus,.btn--red:hover{color:#fff;background-color:#d62a1a}.btn--s{padding:.5rem}.list--unstyled{list-style-type:none}input,textarea{padding:.5rem;margin-bottom:.5rem;display:block;width:100%;box-shadow:none;border:thin solid rgba(216,216,216,.99)}input[type=submit]{margin-top:.85rem}.media{display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:flex-start;-ms-flex-align:start;align-items:flex-start}.media .media-figure{margin-right:1em}.media .media-body{-webkit-flex:1 0 0;-ms-flex:1 0 0;flex:1 0 0}table>thead{border-bottom:thin solid rgba(250,250,250,.99)}table td,table th{padding:.25rem;word-wrap:normal;line-height:1}
@@ -0,0 +1,31 @@
1
+ .container {
2
+ max-width: 48rem;
3
+ margin: 4rem auto
4
+ }
5
+
6
+ table {
7
+ width: 100%;
8
+ max-width: 100%;
9
+ margin-bottom: 2rem;
10
+ }
11
+
12
+ .table > thead > tr > th,
13
+ .table > tbody > tr > th,
14
+ .table > tfoot > tr > th,
15
+ .table > thead > tr > td,
16
+ .table > tbody > tr > td,
17
+ .table > tfoot > tr > td {
18
+ padding: 8px;
19
+ line-height: 1.25rem;
20
+ vertical-align: top;
21
+ }
22
+
23
+ .table > thead > tr > th {
24
+ vertical-align: bottom;
25
+ }
26
+
27
+
28
+ /* Furtive override */
29
+ .btn--s {
30
+ font-size: 0.95em;
31
+ }
@@ -1,69 +1,122 @@
1
- <h1><%= settings.robot.name.capitalize %> bot!</h1>
1
+ <h1>Manage <%= settings.robot.name.capitalize %> bot</h1>
2
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| %>
3
+ <h3>Adapters</h3>
4
+
5
+ <p class="h5">Adapters connect to chat service. Only Slack is supported at the moment but we're planning to add more. A valid adapter must be configured for the bot to work.</p>
6
+
7
+ <table class="table">
8
+ <thead>
10
9
  <tr>
11
- <td><%= handler.to_s %></td>
12
- <td>Default Handler, can not be deactivated.</td>
10
+ <th>Adapter</th>
11
+ <th>Action</th>
13
12
  </tr>
14
- <% end %>
15
- <% @handlers.each do |handler| %>
16
- <% if !settings.robot.default_handlers.include?(handler) %>
13
+ </thead>
14
+ <tbody>
15
+ <% settings.robot.default_adapters.each do |adapter| %>
17
16
  <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>
17
+ <td><%= adapter[:name].to_s %></td>
18
+ <td>Default Adapter, can not be deactivated.</td>
30
19
  </tr>
31
20
  <% end %>
32
- <% end %>
21
+ <% @adapters.each do |adapter| %>
22
+ <% if !settings.robot.default_adapters.include?(adapter[:name]) %>
23
+ <tr>
24
+ <td><%= adapter[:name].to_s %></td>
25
+ <td>
26
+ <% if gem_installed? adapter[:gem] %>
27
+ <% if settings.robot.adapters.keys.include?(adapter[:name]) %>
28
+ <form action="/deactivate/adapter/<%= adapter[:name].to_s %>" method="POST">
29
+ <input type="submit" value="Deactivate" class="btn--gray btn--s">
30
+ </form>
31
+ <% else %>
32
+ <form action="/activate/adapter/<%= adapter[:name].to_s %>" method="POST">
33
+ <input type="hidden" name="<%= adapter[:name].to_s %>:gem_name" value="<%= adapter[:gem].to_s %>">
34
+ <% adapter[:configs].each do |c| %>
35
+ <label for="<%= c[:name].to_s %>">
36
+ <%= c[:name].to_s %>
37
+ <% if !c[:required] %>(optional)<% end %>:
38
+ </label>
39
+ <input type="text" name="<%= adapter[:name].to_s %>:config:<%= c[:name].to_s %>">
40
+ <% end %>
41
+ <input type="submit" value="Activate" class="btn--green btn--s">
42
+ </form>
43
+
44
+ <form action="/uninstall/<%= adapter[:gem].to_s %>" method="POST">
45
+ <input type="submit" value="Uninstall Adapter" class="btn--green btn--s">
46
+ </form>
47
+ <% end %>
48
+ <% else %>
49
+ <form action="/install/<%= adapter[:gem].to_s %>" method="POST">
50
+ <input type="submit" value="Install Adapter" class="btn--gray btn--s">
51
+ </form>
52
+ <% end %>
53
+ </td>
54
+ </tr>
55
+ <% end %>
56
+ <% end %>
57
+ </tbody>
33
58
  </table>
34
59
 
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| %>
60
+ <h3>Core Handlers</h3>
61
+
62
+ <p class="h5">Built-in handlers provide basic information about the bot and extend its capabilites. Interact with those handlers through the active chat service.</p>
63
+
64
+ <table class="table">
65
+ <thead>
42
66
  <tr>
43
- <td><%= adapter[:name].to_s %></td>
44
- <td>Default Adapter, can not be deactivated.</td>
67
+ <th>Handler</th>
68
+ <th>Action</th>
45
69
  </tr>
46
- <% end %>
47
- <% @adapters.each do |adapter| %>
48
- <% if !settings.robot.default_adapters.include?(adapter[:name]) %>
70
+ </thead>
71
+ <tbody>
72
+ <% settings.robot.default_handlers.each do |handler| %>
49
73
  <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>
74
+ <td><%= handler.to_s %></td>
75
+ <td>Default Handler, can not be deactivated.</td>
66
76
  </tr>
67
77
  <% end %>
68
- <% end %>
78
+ <% @handlers.each do |handler| %>
79
+ <% if !settings.robot.default_handlers.include?(handler[:name]) %>
80
+ <tr>
81
+ <td><%= handler[:name].to_s %></td>
82
+ <td>
83
+ <% if gem_installed? handler[:gem] %>
84
+ <% if settings.robot.handlers.keys.include?(handler[:name]) %>
85
+ <form action="/deactivate/handler/<%= handler[:name].to_s %>" method="POST">
86
+ <input type="submit" value="Deactivate" class="btn--gray btn--s">
87
+ </form>
88
+ <% else %>
89
+ <form action="/activate/handler/<%= handler[:name].to_s %>" method="POST">
90
+ <input type="hidden" name="<%= handler[:name].to_s %>:gem_name" value="<%= handler[:gem].to_s %>">
91
+ <% handler[:configs].each do |c| %>
92
+ <label for="<%= c[:name].to_s %>">
93
+ <%= c[:name].to_s %>
94
+ <% if !c[:required] %>(optional)<% end %>:
95
+ </label>
96
+ <input type="text" name="<%= handler[:name].to_s %>:config:<%= c[:name].to_s %>">
97
+ <% end %>
98
+ <input type="submit" value="Activate" class="btn--green btn--s">
99
+ </form>
100
+ <% end %>
101
+
102
+ <form action="/uninstall/<%= handler[:gem].to_s %>" method="POST">
103
+ <input type="submit" value="Uninstall Adapter" class="btn--green btn--s">
104
+ </form>
105
+ <% else %>
106
+ <form action="/install/<%= handler[:gem].to_s %>" method="POST">
107
+ <input type="submit" value="Install Adapter" class="btn--gray btn--s">
108
+ </form>
109
+ <% end %>
110
+ </td>
111
+ </tr>
112
+ <% end %>
113
+ <% end %>
114
+ </tbody>
69
115
  </table>
116
+
117
+ <h3>Extensions</h3>
118
+
119
+ <p class="h5">Extensions adds new functionality to the bot. They are tailored to respond to specific commands and perform task. Browse through the list of available extensions or build your own.</p>
120
+
121
+ <a href="/integrations">View public extensions</a> or
122
+ <a href="https://github.com/yafoy/pepito">build one</a>
@@ -0,0 +1,19 @@
1
+ <h1>Integration</h1>
2
+
3
+ <% if @integrations.any? %>
4
+ <% @integrations["extensions"].each do |integration| %>
5
+ <div class="media py2">
6
+ <div class="media-figure">
7
+ <img src="<%= integration['image_url'] %>" alt="<%= integration['name'] %>" width="90px" height="90px">
8
+ </div>
9
+ <div class="media-body">
10
+ <h6 class="m0 p0">
11
+ <a href="<%= integration['url'] %>" target="_blank" class="p"><%= integration['name'] %></a>
12
+ </h6>
13
+ <p class="m0 p0">
14
+ <%= integration['description'] %>
15
+ </p>
16
+ </div>
17
+ </div>
18
+ <% end %>
19
+ <% end %>
@@ -0,0 +1,18 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title><%= settings.robot.name.capitalize %></title>
5
+ <meta charset="utf-8">
6
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
7
+ <meta name="viewport" content="width=device-width, initial-scale=1">
8
+ <link rel="stylesheet" href="stylesheets/furtive.min.css">
9
+ <link rel="stylesheet" href="stylesheets/layout.css">
10
+ <style>
11
+ </style>
12
+ </head>
13
+ <body>
14
+ <div class='container my2'>
15
+ <%= yield %>
16
+ </div>
17
+ </body>
18
+ </html>
@@ -28,8 +28,11 @@ Gem::Specification.new do |s|
28
28
  s.add_runtime_dependency 'sinatra', '~> 1.4.6', '>= 1.4.6'
29
29
  s.add_runtime_dependency 'tilt', '~> 2.0.2', '>= 2.0.2'
30
30
  s.add_runtime_dependency 'puma', '~> 2.15.3', '>= 2.15.3'
31
+ s.add_runtime_dependency 'rest-client', '~> 1.8', '>= 1.8'
32
+ # s.add_runtime_dependency 'pepito-queenbee'
31
33
 
32
34
  s.add_development_dependency 'rake', '~> 10.5'
33
35
  s.add_development_dependency 'minitest', '~> 5.8'
36
+ s.add_development_dependency 'minitest-reporters', '~> 1.0'
34
37
  s.add_development_dependency 'rubocop', '~> 0.37'
35
38
  end
@@ -3,7 +3,7 @@ require 'pepito/handlers/room'
3
3
 
4
4
  class TestPepitoHandlersExtensionsCatalog < MiniTest::Test
5
5
  def setup
6
- @handler = Pepito::Handlers::ExtensionsCatalog.new(nil)
6
+ @handler = Pepito::Handlers::ExtensionsCatalog.new(nil, {})
7
7
  @handler.run
8
8
  end
9
9
 
@@ -8,7 +8,7 @@ class TestPepitoHandlersHelp < MiniTest::Test
8
8
 
9
9
  def setup
10
10
  @mock_robot = Struct::Robot.new('pepito', [])
11
- @handler = Pepito::Handlers::Help.new(@mock_robot)
11
+ @handler = Pepito::Handlers::Help.new(@mock_robot, {})
12
12
  @handler.run
13
13
  end
14
14
 
@@ -4,7 +4,7 @@ require 'pepito/version'
4
4
 
5
5
  class TestPepitoHandlersInfo < MiniTest::Test
6
6
  def setup
7
- @handler = Pepito::Handlers::Info.new(nil)
7
+ @handler = Pepito::Handlers::Info.new(nil, {})
8
8
  @handler.run
9
9
  end
10
10
 
@@ -3,7 +3,7 @@ require 'pepito/handlers/room'
3
3
 
4
4
  class TestPepitoHandlersRoom < MiniTest::Test
5
5
  def setup
6
- @handler = Pepito::Handlers::Room.new(nil)
6
+ @handler = Pepito::Handlers::Room.new(nil, {})
7
7
  @handler.run
8
8
  end
9
9
 
@@ -16,7 +16,7 @@ class TestPepitoHandler < MiniTest::Test
16
16
  mock_robot = MiniTest::Mock.new
17
17
  mock_robot.expect(:http_api, mock_http_api)
18
18
 
19
- handler = Pepito::Handler.new(mock_robot)
19
+ handler = Pepito::Handler.new(mock_robot, {})
20
20
  handler.http_routes << mock_route
21
21
  handler.start
22
22
 
@@ -0,0 +1,37 @@
1
+ require 'minitest/autorun'
2
+ require 'pepito/helpers'
3
+
4
+ class TestPepitoHelpers < MiniTest::Test
5
+ include Pepito::Helpers
6
+
7
+ def test_install_gem
8
+ gem_name = 'pepito'
9
+
10
+ mock_dependency_installer = MiniTest::Mock.new
11
+ mock_dependency_installer.expect(:install, nil, [gem_name])
12
+
13
+ Gem::DependencyInstaller.stub :new, mock_dependency_installer do
14
+ gem_install gem_name
15
+ end
16
+
17
+ assert mock_dependency_installer.verify
18
+ end
19
+
20
+ def test_uninstall_gem
21
+ gem_name = 'pepito'
22
+
23
+ mock_uninstaller = MiniTest::Mock.new
24
+ mock_uninstaller.expect(:uninstall, nil, [])
25
+
26
+ Gem::Uninstaller.stub :new, mock_uninstaller do
27
+ gem_uninstall gem_name
28
+ end
29
+
30
+ assert mock_uninstaller.verify
31
+ end
32
+
33
+ def test_gem_installed
34
+ assert gem_installed? 'pepito'
35
+ refute gem_installed? ''
36
+ end
37
+ end
@@ -52,45 +52,51 @@ class TestPepitoRobot < MiniTest::Test
52
52
  def test_start_handler
53
53
  # Fail to start if handler is running
54
54
  @robot.handlers.stub :key?, true do
55
- assert_equal 1, @robot.start_handler('')
55
+ assert_equal 1, @robot.start_handler('', 'pepito', {})
56
56
  end
57
57
 
58
58
  # Fail to start if handler does not exist
59
59
  @robot.handlers.stub :key?, false do
60
- assert_equal 2, @robot.start_handler('')
60
+ assert_equal 2, @robot.start_handler('', 'pepito', {})
61
61
  end
62
62
 
63
63
  # Fail with other errors
64
64
  @robot.handlers.stub :key?, false do
65
65
  mock_handler = Class.new do
66
- def initialize(_robot)
66
+ def initialize(_robot, _config)
67
67
  raise 'error'
68
68
  end
69
69
  end
70
70
  Pepito::Handlers.stub :const_get, mock_handler do
71
- assert_equal 3, @robot.start_handler('')
71
+ assert_equal 4, @robot.start_handler('', 'pepito', {})
72
72
  end
73
73
  end
74
74
 
75
75
  # Start handler successfully
76
76
  @robot.handlers.stub :key?, false do
77
77
  name = 'handler_name'
78
+ gem_name = 'pepito'
79
+ config = { 'name' => 'option' }
78
80
 
79
81
  mock_handler = MiniTest::Mock.new
80
82
  mock_handler.expect(:run, nil)
81
83
  mock_handler.expect(:start, nil)
82
84
 
83
85
  mock_handler_klass = MiniTest::Mock.new
84
- mock_handler_klass.expect(:new, mock_handler, [@robot])
86
+ mock_handler_klass.expect(:new, mock_handler, [@robot, config])
85
87
 
86
88
  mock_router = MiniTest::Mock.new
87
89
  mock_router.expect(:uncompile, nil)
88
90
 
89
91
  @mock_http_api.expect(:router, mock_router)
90
92
  @mock_database.expect(:sadd, nil, ['handlers', name])
93
+ @mock_database.expect(:set, nil, [name + ':gem', gem_name])
94
+ config.each do |k, v|
95
+ @mock_database.expect(:hset, nil, [name + ':config', k, v])
96
+ end
91
97
 
92
98
  Pepito::Handlers.stub :const_get, mock_handler_klass do
93
- assert_equal 0, @robot.start_handler(name)
99
+ assert_equal 0, @robot.start_handler(name, gem_name, config)
94
100
  assert mock_handler.verify
95
101
  assert mock_router.verify
96
102
  assert mock_handler_klass.verify
@@ -121,6 +127,8 @@ class TestPepitoRobot < MiniTest::Test
121
127
  mock_router = MiniTest::Mock.new
122
128
  mock_router.expect(:reset!, nil)
123
129
  @mock_database.expect(:srem, nil, ['handlers', name])
130
+ @mock_database.expect(:del, nil, [name + ':config'])
131
+ @mock_database.expect(:del, nil, [name + ':gem'])
124
132
  @mock_http_api.expect(:router, mock_router)
125
133
 
126
134
  assert_equal 0, @robot.stop_handler(name)
@@ -1,6 +1,13 @@
1
1
  require 'minitest/autorun'
2
+ require 'minitest/reporters'
2
3
  require 'pepito'
3
4
 
5
+ Minitest::Reporters.use!(
6
+ Minitest::Reporters::SpecReporter.new,
7
+ ENV,
8
+ Minitest.backtrace_filter
9
+ )
10
+
4
11
  class TestPepito < MiniTest::Test
5
12
  def test_redis_namespace_is_pepito
6
13
  assert_equal :pepito, Pepito::REDIS_NAMESPACE
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pepito
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Olivier
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-15 00:00:00.000000000 Z
11
+ date: 2016-03-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis-namespace
@@ -170,6 +170,26 @@ dependencies:
170
170
  - - ">="
171
171
  - !ruby/object:Gem::Version
172
172
  version: 2.15.3
173
+ - !ruby/object:Gem::Dependency
174
+ name: rest-client
175
+ requirement: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - "~>"
178
+ - !ruby/object:Gem::Version
179
+ version: '1.8'
180
+ - - ">="
181
+ - !ruby/object:Gem::Version
182
+ version: '1.8'
183
+ type: :runtime
184
+ prerelease: false
185
+ version_requirements: !ruby/object:Gem::Requirement
186
+ requirements:
187
+ - - "~>"
188
+ - !ruby/object:Gem::Version
189
+ version: '1.8'
190
+ - - ">="
191
+ - !ruby/object:Gem::Version
192
+ version: '1.8'
173
193
  - !ruby/object:Gem::Dependency
174
194
  name: rake
175
195
  requirement: !ruby/object:Gem::Requirement
@@ -198,6 +218,20 @@ dependencies:
198
218
  - - "~>"
199
219
  - !ruby/object:Gem::Version
200
220
  version: '5.8'
221
+ - !ruby/object:Gem::Dependency
222
+ name: minitest-reporters
223
+ requirement: !ruby/object:Gem::Requirement
224
+ requirements:
225
+ - - "~>"
226
+ - !ruby/object:Gem::Version
227
+ version: '1.0'
228
+ type: :development
229
+ prerelease: false
230
+ version_requirements: !ruby/object:Gem::Requirement
231
+ requirements:
232
+ - - "~>"
233
+ - !ruby/object:Gem::Version
234
+ version: '1.0'
201
235
  - !ruby/object:Gem::Dependency
202
236
  name: rubocop
203
237
  requirement: !ruby/object:Gem::Requirement
@@ -239,6 +273,7 @@ files:
239
273
  - lib/pepito/handlers/help.rb
240
274
  - lib/pepito/handlers/info.rb
241
275
  - lib/pepito/handlers/room.rb
276
+ - lib/pepito/helpers.rb
242
277
  - lib/pepito/http_api/http_callback.rb
243
278
  - lib/pepito/http_api/http_route.rb
244
279
  - lib/pepito/http_api/rack_app.rb
@@ -247,7 +282,11 @@ files:
247
282
  - lib/pepito/source.rb
248
283
  - lib/pepito/version.rb
249
284
  - lib/pepito/web_app/app.rb
285
+ - lib/pepito/web_app/public/stylesheets/furtive.min.css
286
+ - lib/pepito/web_app/public/stylesheets/layout.css
250
287
  - lib/pepito/web_app/views/index.erb
288
+ - lib/pepito/web_app/views/integrations.erb
289
+ - lib/pepito/web_app/views/layout.erb
251
290
  - pepito.gemspec
252
291
  - test/pepito/handler/test_chat_router.rb
253
292
  - test/pepito/handler/test_http_router.rb
@@ -257,6 +296,7 @@ files:
257
296
  - test/pepito/handlers/test_room.rb
258
297
  - test/pepito/test_adapter.rb
259
298
  - test/pepito/test_handler.rb
299
+ - test/pepito/test_helpers.rb
260
300
  - test/pepito/test_message.rb
261
301
  - test/pepito/test_robot.rb
262
302
  - test/pepito/test_source.rb
@@ -294,6 +334,7 @@ test_files:
294
334
  - test/pepito/handlers/test_room.rb
295
335
  - test/pepito/test_adapter.rb
296
336
  - test/pepito/test_handler.rb
337
+ - test/pepito/test_helpers.rb
297
338
  - test/pepito/test_message.rb
298
339
  - test/pepito/test_robot.rb
299
340
  - test/pepito/test_source.rb