lita 3.1.0 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +4 -0
- data/README.md +0 -2
- data/lib/lita.rb +74 -26
- data/lib/lita/adapter.rb +1 -1
- data/lib/lita/adapters/shell.rb +1 -1
- data/lib/lita/cli.rb +8 -0
- data/lib/lita/handler.rb +40 -28
- data/lib/lita/handlers/authorization.rb +1 -1
- data/lib/lita/handlers/info.rb +1 -1
- data/lib/lita/logger.rb +1 -1
- data/lib/lita/response.rb +6 -0
- data/lib/lita/route_validator.rb +63 -0
- data/lib/lita/rspec/handler.rb +1 -1
- data/lib/lita/util.rb +1 -1
- data/lib/lita/version.rb +1 -1
- data/lita.gemspec +3 -3
- data/spec/lita/handler_spec.rb +88 -7
- data/spec/lita/rack_app_spec.rb +3 -3
- data/spec/lita/response_spec.rb +8 -0
- data/spec/lita/rspec_spec.rb +3 -3
- data/spec/lita_spec.rb +46 -1
- data/spec/spec_helper.rb +2 -2
- data/templates/plugin/README.tt +10 -0
- data/templates/plugin/lib/lita/plugin_type/plugin.tt +6 -2
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 68d6c55cacef1663c210df90ff03f764bca2c3b3
|
4
|
+
data.tar.gz: 4696fa739de19bb0a0245fd855666fe6a5622f31
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7701c02aa161e08559b50e1133ea1227cc79d53f4278a772ef274b090fceb9a9bad22a317263f067adfe036a336fc6d3ba6d0a546b014387e12f49cf46d52ec7
|
7
|
+
data.tar.gz: b4b212cee5587adaf06f0ad8944715b9653a678f041e18d71258bbc4d52864f5cf575c3fb010161325153a42d6bde5271f722202383c5a3ca48b035e2685d204
|
data/.rubocop.yml
CHANGED
@@ -18,10 +18,14 @@ LineLength:
|
|
18
18
|
Max: 100
|
19
19
|
MethodLength:
|
20
20
|
Enabled: false
|
21
|
+
RegexpLiteral:
|
22
|
+
Enabled: false
|
21
23
|
RescueException:
|
22
24
|
Enabled: false
|
23
25
|
SignalException:
|
24
26
|
Enabled: false
|
27
|
+
SpecialGlobalVars:
|
28
|
+
Enabled: false
|
25
29
|
StringLiterals:
|
26
30
|
EnforcedStyle: double_quotes
|
27
31
|
TrailingComma:
|
data/README.md
CHANGED
@@ -5,8 +5,6 @@
|
|
5
5
|
[![Code Climate](https://codeclimate.com/github/jimmycuadra/lita.png)](https://codeclimate.com/github/jimmycuadra/lita)
|
6
6
|
[![Coverage Status](https://coveralls.io/repos/jimmycuadra/lita/badge.png)](https://coveralls.io/r/jimmycuadra/lita)
|
7
7
|
|
8
|
-
![Lita](http://f.cl.ly/items/0c271a2P3k2V180B1R0X/lita.jpg)
|
9
|
-
|
10
8
|
**Lita** is a chat bot written in [Ruby](https://www.ruby-lang.org/) with persistent storage provided by [Redis](http://redis.io/). It uses a plugin system to connect to different chat services and to provide new behavior. The plugin system uses the familiar tools of the Ruby ecosystem: [RubyGems](https://rubygems.org/) and [Bundler](http://gembundler.com/).
|
11
9
|
|
12
10
|
Automate your business and have fun with your very own robot companion.
|
data/lib/lita.rb
CHANGED
@@ -26,27 +26,6 @@ module Lita
|
|
26
26
|
@adapters ||= {}
|
27
27
|
end
|
28
28
|
|
29
|
-
# Adds an adapter to the global registry under the provided key.
|
30
|
-
# @param key [String, Symbol] The key that identifies the adapter.
|
31
|
-
# @param adapter [Lita::Adapter] The adapter class.
|
32
|
-
# @return [void]
|
33
|
-
def register_adapter(key, adapter)
|
34
|
-
adapters[key.to_sym] = adapter
|
35
|
-
end
|
36
|
-
|
37
|
-
# The global registry of handlers.
|
38
|
-
# @return [Set] The set of handlers.
|
39
|
-
def handlers
|
40
|
-
@handlers ||= Set.new
|
41
|
-
end
|
42
|
-
|
43
|
-
# Adds a handler to the global registry.
|
44
|
-
# @param handler [Lita::Handler] The handler class.
|
45
|
-
# @return [void]
|
46
|
-
def register_handler(handler)
|
47
|
-
handlers << handler
|
48
|
-
end
|
49
|
-
|
50
29
|
# The global configuration object. Provides user settings for the robot.
|
51
30
|
# @return [Lita::Config] The Lita configuration object.
|
52
31
|
def config
|
@@ -61,11 +40,17 @@ module Lita
|
|
61
40
|
yield config
|
62
41
|
end
|
63
42
|
|
64
|
-
#
|
65
|
-
#
|
66
|
-
|
67
|
-
|
68
|
-
|
43
|
+
# The global registry of handlers.
|
44
|
+
# @return [Set] The set of handlers.
|
45
|
+
def handlers
|
46
|
+
@handlers ||= Set.new
|
47
|
+
end
|
48
|
+
|
49
|
+
# The global registry of hook handler objects.
|
50
|
+
# @return [Hash] A hash mapping hook names to sets of objects that handle them.
|
51
|
+
# @since 3.2.0
|
52
|
+
def hooks
|
53
|
+
@hooks ||= Hash.new { |h, k| h[k] = Set.new }
|
69
54
|
end
|
70
55
|
|
71
56
|
# The global Logger object.
|
@@ -83,10 +68,72 @@ module Lita
|
|
83
68
|
end
|
84
69
|
end
|
85
70
|
|
71
|
+
# Adds an adapter to the global registry under the provided key.
|
72
|
+
# @param key [String, Symbol] The key that identifies the adapter.
|
73
|
+
# @param adapter [Lita::Adapter] The adapter class.
|
74
|
+
# @return [void]
|
75
|
+
def register_adapter(key, adapter)
|
76
|
+
adapters[key.to_sym] = adapter
|
77
|
+
end
|
78
|
+
|
79
|
+
# Adds a handler to the global registry.
|
80
|
+
# @param handler [Lita::Handler] The handler class.
|
81
|
+
# @return [void]
|
82
|
+
def register_handler(handler)
|
83
|
+
handlers << handler
|
84
|
+
end
|
85
|
+
|
86
|
+
# Adds a hook handler object to the global registry for the given hook.
|
87
|
+
# @return [void]
|
88
|
+
# @since 3.2.0
|
89
|
+
def register_hook(name, hook)
|
90
|
+
hooks[name.to_s.downcase.strip.to_sym] << hook
|
91
|
+
end
|
92
|
+
|
93
|
+
# Clears the global configuration object and the global adapter, handler, and hook registries.
|
94
|
+
# @return [void]
|
95
|
+
# @since 3.2.0
|
96
|
+
def reset
|
97
|
+
reset_adapters
|
98
|
+
reset_config
|
99
|
+
reset_handlers
|
100
|
+
reset_hooks
|
101
|
+
end
|
102
|
+
|
103
|
+
# Resets the global adapter registry, removing all registered adapters.
|
104
|
+
# @return [void]
|
105
|
+
# @since 3.2.0
|
106
|
+
def reset_adapters
|
107
|
+
@adapters = nil
|
108
|
+
end
|
109
|
+
|
110
|
+
# Resets the global configuration object. The next call to {Lita.config}
|
111
|
+
# will create a fresh config object.
|
112
|
+
# @return [void]
|
113
|
+
def reset_config
|
114
|
+
@config = nil
|
115
|
+
end
|
116
|
+
alias_method :clear_config, :reset_config
|
117
|
+
|
118
|
+
# Resets the global handler registry, removing all registered handlers.
|
119
|
+
# @return [void]
|
120
|
+
# @since 3.2.0
|
121
|
+
def reset_handlers
|
122
|
+
@handlers = nil
|
123
|
+
end
|
124
|
+
|
125
|
+
# Resets the global hooks registry, removing all registered hook handlers.
|
126
|
+
# @return [void]
|
127
|
+
# @since 3.2.0
|
128
|
+
def reset_hooks
|
129
|
+
@hooks = nil
|
130
|
+
end
|
131
|
+
|
86
132
|
# Loads user configuration and starts the robot.
|
87
133
|
# @param config_path [String] The path to the user configuration file.
|
88
134
|
# @return [void]
|
89
135
|
def run(config_path = nil)
|
136
|
+
hooks[:before_run].each { |hook| hook.call(config_path: config_path) }
|
90
137
|
Config.load_user_config(config_path)
|
91
138
|
Lita.config.finalize
|
92
139
|
self.locale = Lita.config.robot.locale
|
@@ -112,6 +159,7 @@ require_relative "lita/robot"
|
|
112
159
|
require_relative "lita/adapter"
|
113
160
|
require_relative "lita/adapters/shell"
|
114
161
|
require_relative "lita/handler"
|
162
|
+
require_relative "lita/route_validator"
|
115
163
|
require_relative "lita/handlers/authorization"
|
116
164
|
require_relative "lita/handlers/help"
|
117
165
|
require_relative "lita/handlers/info"
|
data/lib/lita/adapter.rb
CHANGED
@@ -89,7 +89,7 @@ module Lita
|
|
89
89
|
# @return [void]
|
90
90
|
# @abstract This should be implemented by the adapter.
|
91
91
|
[:join, :part, :run, :send_messages, :set_topic, :shut_down].each do |method|
|
92
|
-
define_method(method) do
|
92
|
+
define_method(method) do
|
93
93
|
Lita.logger.warn(I18n.t("lita.adapter.method_not_implemented", method: method))
|
94
94
|
end
|
95
95
|
end
|
data/lib/lita/adapters/shell.rb
CHANGED
@@ -20,7 +20,7 @@ module Lita
|
|
20
20
|
# shell environment.
|
21
21
|
# @param strings [Array<String>] An array of strings to output.
|
22
22
|
# @return [void]
|
23
|
-
def send_messages(
|
23
|
+
def send_messages(_target, strings)
|
24
24
|
strings = Array(strings)
|
25
25
|
strings.reject! { |string| string.empty? }
|
26
26
|
unless RbConfig::CONFIG["host_os"] =~ /mswin|mingw/ || !$stdout.tty?
|
data/lib/lita/cli.rb
CHANGED
@@ -99,6 +99,14 @@ module Lita
|
|
99
99
|
generate_templates(generate_config(name, "handler"))
|
100
100
|
end
|
101
101
|
|
102
|
+
desc "extension NAME", "Generates a new Lita extension"
|
103
|
+
# Generates a new Lita extension.
|
104
|
+
# @param name [String] The name for the new extension.
|
105
|
+
# @return [void]
|
106
|
+
def extension(name)
|
107
|
+
generate_templates(generate_config(name, "extension"))
|
108
|
+
end
|
109
|
+
|
102
110
|
desc "version", "Outputs the current version of Lita"
|
103
111
|
# Outputs the current version of Lita.
|
104
112
|
# @return [void]
|
data/lib/lita/handler.rb
CHANGED
@@ -17,7 +17,8 @@ module Lita
|
|
17
17
|
:method_name,
|
18
18
|
:command,
|
19
19
|
:required_groups,
|
20
|
-
:help
|
20
|
+
:help,
|
21
|
+
:extensions
|
21
22
|
)
|
22
23
|
alias_method :command?, :command
|
23
24
|
end
|
@@ -32,10 +33,19 @@ module Lita
|
|
32
33
|
# @param restrict_to [Array<Symbol, String>, nil] A list of authorization
|
33
34
|
# groups the user must be in to trigger the route.
|
34
35
|
# @param help [Hash] A map of example invocations to descriptions.
|
36
|
+
# @param extensions [Hash] Aribtrary additional data that can be used by Lita extensions.
|
35
37
|
# @return [void]
|
36
|
-
def route(pattern, method,
|
37
|
-
|
38
|
-
|
38
|
+
def route(pattern, method, **options)
|
39
|
+
options = default_route_options.merge(options)
|
40
|
+
options[:restrict_to] = options[:restrict_to].nil? ? nil : Array(options[:restrict_to])
|
41
|
+
routes << Route.new(
|
42
|
+
pattern,
|
43
|
+
method,
|
44
|
+
options.delete(:command),
|
45
|
+
options.delete(:restrict_to),
|
46
|
+
options.delete(:help),
|
47
|
+
options
|
48
|
+
)
|
39
49
|
end
|
40
50
|
|
41
51
|
# A list of chat routes defined by the handler.
|
@@ -57,10 +67,9 @@ module Lita
|
|
57
67
|
log_dispatch(route)
|
58
68
|
|
59
69
|
begin
|
60
|
-
new(
|
61
|
-
|
62
|
-
|
63
|
-
)
|
70
|
+
response = Response.new(message, route.pattern)
|
71
|
+
Lita.hooks[:trigger_route].each { |hook| hook.call(response: response, route: route) }
|
72
|
+
new(robot).public_send(route.method_name, response)
|
64
73
|
rescue Exception => e
|
65
74
|
log_dispatch_error(e)
|
66
75
|
raise e if rspec_loaded?
|
@@ -133,6 +142,14 @@ module Lita
|
|
133
142
|
|
134
143
|
private
|
135
144
|
|
145
|
+
def default_route_options
|
146
|
+
{
|
147
|
+
command: false,
|
148
|
+
restrict_to: nil,
|
149
|
+
help: {}
|
150
|
+
}
|
151
|
+
end
|
152
|
+
|
136
153
|
# A hash of arrays used to store event subscriptions registered with {on}.
|
137
154
|
def event_subscriptions
|
138
155
|
@event_subscriptions ||= Hash.new { |h, k| h[k] = [] }
|
@@ -140,19 +157,7 @@ module Lita
|
|
140
157
|
|
141
158
|
# Determines whether or not an incoming messages should trigger a route.
|
142
159
|
def route_applies?(route, message, robot)
|
143
|
-
|
144
|
-
return if route.command? && !message.command?
|
145
|
-
|
146
|
-
# Messages from self should be ignored to prevent infinite loops
|
147
|
-
return if message.user.name == robot.name
|
148
|
-
|
149
|
-
# Message must match the pattern
|
150
|
-
return unless route.pattern === message.body
|
151
|
-
|
152
|
-
# User must be in auth group if route is restricted
|
153
|
-
return unless authorized?(message.user, route.required_groups)
|
154
|
-
|
155
|
-
true
|
160
|
+
RouteValidator.new(route, message, robot).call
|
156
161
|
end
|
157
162
|
|
158
163
|
# Checks if RSpec is loaded. If so, assume we are testing and let handler
|
@@ -161,13 +166,6 @@ module Lita
|
|
161
166
|
defined?(::RSpec)
|
162
167
|
end
|
163
168
|
|
164
|
-
# Checks if the user is authorized to at least one of the given groups.
|
165
|
-
def authorized?(user, required_groups)
|
166
|
-
required_groups.nil? || required_groups.any? do |group|
|
167
|
-
Authorization.user_in_group?(user, group)
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
169
|
# Logs the dispatch of message.
|
172
170
|
def log_dispatch(route)
|
173
171
|
Lita.logger.debug I18n.t(
|
@@ -206,6 +204,13 @@ module Lita
|
|
206
204
|
Thread.new { Timer.new(interval: interval, &block).start }
|
207
205
|
end
|
208
206
|
|
207
|
+
# The handler's config object.
|
208
|
+
# @return [Lita::Config] The handler's config object.
|
209
|
+
# @since 3.2.0
|
210
|
+
def config
|
211
|
+
Lita.config.handlers[self.class.namespace]
|
212
|
+
end
|
213
|
+
|
209
214
|
# Invokes the given block repeatedly, waiting the given number of seconds between each
|
210
215
|
# invocation.
|
211
216
|
# @param interval [Integer] The number of seconds to wait before each invocation of the block.
|
@@ -227,6 +232,13 @@ module Lita
|
|
227
232
|
Faraday::Connection.new(nil, options, &block)
|
228
233
|
end
|
229
234
|
|
235
|
+
# The Lita logger.
|
236
|
+
# @return [Lita::Logger] The Lita logger.
|
237
|
+
# @since 3.2.0
|
238
|
+
def log
|
239
|
+
Lita.logger
|
240
|
+
end
|
241
|
+
|
230
242
|
# @see .translate
|
231
243
|
def translate(*args)
|
232
244
|
self.class.translate(*args)
|
data/lib/lita/handlers/info.rb
CHANGED
@@ -21,7 +21,7 @@ module Lita
|
|
21
21
|
# @param request [Rack::Request] The HTTP request.
|
22
22
|
# @param response [Rack::Response] The HTTP response.
|
23
23
|
# @return [void]
|
24
|
-
def web(
|
24
|
+
def web(_request, response)
|
25
25
|
response.headers["Content-Type"] = "application/json"
|
26
26
|
json = MultiJson.dump(
|
27
27
|
lita_version: Lita::VERSION,
|
data/lib/lita/logger.rb
CHANGED
@@ -9,7 +9,7 @@ module Lita
|
|
9
9
|
def get_logger(level)
|
10
10
|
logger = ::Logger.new(STDERR)
|
11
11
|
logger.level = get_level_constant(level)
|
12
|
-
logger.formatter = proc do |severity, datetime,
|
12
|
+
logger.formatter = proc do |severity, datetime, _progname, msg|
|
13
13
|
"[#{datetime.utc}] #{severity}: #{msg}\n"
|
14
14
|
end
|
15
15
|
logger
|
data/lib/lita/response.rb
CHANGED
@@ -8,6 +8,11 @@ module Lita
|
|
8
8
|
# @return [Lita::Message] The message.
|
9
9
|
attr_accessor :message
|
10
10
|
|
11
|
+
# A hash of arbitrary data that can be populated by Lita extensions.
|
12
|
+
# @return [Hash] The extensions data.
|
13
|
+
# @since 3.2.0
|
14
|
+
attr_accessor :extensions
|
15
|
+
|
11
16
|
# The pattern the incoming message matched.
|
12
17
|
# @return [Regexp] The pattern.
|
13
18
|
attr_accessor :pattern
|
@@ -29,6 +34,7 @@ module Lita
|
|
29
34
|
# @param pattern [Regexp] The pattern the incoming message matched.
|
30
35
|
def initialize(message, pattern)
|
31
36
|
self.message = message
|
37
|
+
self.extensions = {}
|
32
38
|
self.pattern = pattern
|
33
39
|
end
|
34
40
|
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Lita
|
2
|
+
# Determines if an incoming message should trigger a route.
|
3
|
+
# @api private
|
4
|
+
class RouteValidator
|
5
|
+
# The incoming message.
|
6
|
+
attr_reader :message
|
7
|
+
|
8
|
+
# The currently running robot.
|
9
|
+
attr_reader :robot
|
10
|
+
|
11
|
+
# The route being checked.
|
12
|
+
attr_reader :route
|
13
|
+
|
14
|
+
def initialize(route, message, robot)
|
15
|
+
@route = route
|
16
|
+
@message = message
|
17
|
+
@robot = robot
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns a boolean indicating whether or not the route should be triggered.
|
21
|
+
# @return [Boolean] Whether or not the route should be triggered.
|
22
|
+
def call
|
23
|
+
return unless passes_route_hooks?(route, message, robot)
|
24
|
+
return unless command_satisfied?(route, message)
|
25
|
+
return if from_self?(message, robot)
|
26
|
+
return unless matches_pattern?(route, message)
|
27
|
+
return unless authorized?(message.user, route.required_groups)
|
28
|
+
|
29
|
+
true
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
# Message must be a command if the route requires a command
|
35
|
+
def command_satisfied?(route, message)
|
36
|
+
!route.command? || message.command?
|
37
|
+
end
|
38
|
+
|
39
|
+
# Messages from self should be ignored to prevent infinite loops
|
40
|
+
def from_self?(message, robot)
|
41
|
+
message.user.name == robot.name
|
42
|
+
end
|
43
|
+
|
44
|
+
# Message must match the pattern
|
45
|
+
def matches_pattern?(route, message)
|
46
|
+
route.pattern === message.body
|
47
|
+
end
|
48
|
+
|
49
|
+
# Allow custom route hooks to reject the route
|
50
|
+
def passes_route_hooks?(route, message, robot)
|
51
|
+
Lita.hooks[:validate_route].all? do |hook|
|
52
|
+
hook.call(route: route, message: message, robot: robot)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# User must be in auth group if route is restricted.
|
57
|
+
def authorized?(user, required_groups)
|
58
|
+
required_groups.nil? || required_groups.any? do |group|
|
59
|
+
Authorization.user_in_group?(user, group)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/lib/lita/rspec/handler.rb
CHANGED
data/lib/lita/util.rb
CHANGED
@@ -22,7 +22,7 @@ module Lita
|
|
22
22
|
word = camel_cased_word.to_s.dup
|
23
23
|
word.gsub!("::", "/")
|
24
24
|
word.gsub!(/(?:([A-Za-z\d])|^)(#{ACRONYM_REGEX})(?=\b|[^a-z])/) do
|
25
|
-
"#{Regexp.last_match[1]}#{Regexp.last_match[1] &&
|
25
|
+
"#{Regexp.last_match[1]}#{Regexp.last_match[1] && "_"}#{Regexp.last_match[2].downcase}"
|
26
26
|
end
|
27
27
|
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
|
28
28
|
word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
|
data/lib/lita/version.rb
CHANGED
data/lita.gemspec
CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.version = Lita::VERSION
|
9
9
|
spec.authors = ["Jimmy Cuadra"]
|
10
10
|
spec.email = ["jimmy@jimmycuadra.com"]
|
11
|
-
spec.description = %q
|
12
|
-
spec.summary = %q
|
11
|
+
spec.description = %q(A multi-service chat bot with extendable behavior.)
|
12
|
+
spec.summary = %q(A multi-service chat bot with extendable behavior.)
|
13
13
|
spec.homepage = "https://github.com/jimmycuadra/lita"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
@@ -36,5 +36,5 @@ Gem::Specification.new do |spec|
|
|
36
36
|
spec.add_development_dependency "simplecov"
|
37
37
|
spec.add_development_dependency "coveralls"
|
38
38
|
spec.add_development_dependency "pry"
|
39
|
-
spec.add_development_dependency "rubocop"
|
39
|
+
spec.add_development_dependency "rubocop", "~> 0.21.0"
|
40
40
|
end
|
data/spec/lita/handler_spec.rb
CHANGED
@@ -12,38 +12,70 @@ describe Lita::Handler, lita: true do
|
|
12
12
|
|
13
13
|
let(:queue) { Queue.new }
|
14
14
|
|
15
|
+
let(:guard_hook) do
|
16
|
+
Class.new do
|
17
|
+
def self.call(payload)
|
18
|
+
if payload[:route].extensions[:guard]
|
19
|
+
payload[:message].body.include?("code word")
|
20
|
+
else
|
21
|
+
true
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
let(:response_hook) do
|
28
|
+
Class.new do
|
29
|
+
def self.call(payload)
|
30
|
+
payload[:response].extensions[:data] = payload[:route].extensions[:data]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
15
35
|
let(:handler_class) do
|
16
36
|
Class.new(described_class) do
|
17
37
|
route(/\w{3}/, :foo)
|
18
38
|
route(/\w{4}/, :blah, command: true)
|
19
39
|
route(/secret/, :secret, restrict_to: :admins)
|
20
40
|
route(/danger/, :danger)
|
41
|
+
route(/guard/, :guard, guard: true)
|
42
|
+
route(/trigger route hook/, :trigger_route_hook, data: :foo)
|
21
43
|
|
22
44
|
on :connected, :greet
|
23
45
|
on :some_hook, :test_payload
|
24
46
|
|
25
|
-
def
|
47
|
+
def self.default_config(config)
|
48
|
+
config.foo = "bar"
|
26
49
|
end
|
27
50
|
|
28
|
-
def
|
51
|
+
def foo(_response)
|
29
52
|
end
|
30
53
|
|
31
|
-
def
|
54
|
+
def blah(_response)
|
32
55
|
end
|
33
56
|
|
34
|
-
def
|
57
|
+
def secret(_response)
|
58
|
+
end
|
59
|
+
|
60
|
+
def danger(_response)
|
35
61
|
raise "The developer of this handler's got a bug in their code!"
|
36
62
|
end
|
37
63
|
|
64
|
+
def guard(_response)
|
65
|
+
end
|
66
|
+
|
67
|
+
def trigger_route_hook(_response)
|
68
|
+
end
|
69
|
+
|
38
70
|
def greet(payload)
|
39
71
|
robot.send_message("Hi, #{payload[:name]}! Lita has started!")
|
40
72
|
end
|
41
73
|
|
42
|
-
def after_test(
|
43
|
-
after(2) {
|
74
|
+
def after_test(_response, queue)
|
75
|
+
after(2) { queue.push("Waited 2 seconds!") }
|
44
76
|
end
|
45
77
|
|
46
|
-
def every_test(
|
78
|
+
def every_test(_response, queue)
|
47
79
|
array = [1, 2, 3]
|
48
80
|
|
49
81
|
every(2) do |timer|
|
@@ -138,6 +170,36 @@ describe Lita::Handler, lita: true do
|
|
138
170
|
allow(message).to receive(:body).and_return("#{robot.name}: danger")
|
139
171
|
expect { handler_class.dispatch(robot, message) }.to raise_error
|
140
172
|
end
|
173
|
+
|
174
|
+
context "with a custom validate_route hook" do
|
175
|
+
before { Lita.register_hook(:validate_route, guard_hook) }
|
176
|
+
after { Lita.reset_hooks }
|
177
|
+
|
178
|
+
it "matches if the hook returns true" do
|
179
|
+
allow(message).to receive(:body).and_return("guard code word")
|
180
|
+
expect_any_instance_of(handler_class).to receive(:guard)
|
181
|
+
handler_class.dispatch(robot, message)
|
182
|
+
end
|
183
|
+
|
184
|
+
it "does not match if the hook returns false" do
|
185
|
+
allow(message).to receive(:body).and_return("guard")
|
186
|
+
expect_any_instance_of(handler_class).not_to receive(:guard)
|
187
|
+
handler_class.dispatch(robot, message)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
context "with a custom trigger_route hook" do
|
192
|
+
before { Lita.register_hook(:trigger_route, response_hook) }
|
193
|
+
after { Lita.reset_hooks }
|
194
|
+
|
195
|
+
it "adds data to the response's extensions" do
|
196
|
+
allow(message).to receive(:body).and_return("trigger route hook")
|
197
|
+
allow_any_instance_of(handler_class).to receive(:trigger_route_hook) do |_robot, response|
|
198
|
+
expect(response.extensions[:data]).to eq(:foo)
|
199
|
+
end
|
200
|
+
handler_class.dispatch(robot, message)
|
201
|
+
end
|
202
|
+
end
|
141
203
|
end
|
142
204
|
|
143
205
|
describe ".namespace" do
|
@@ -171,6 +233,19 @@ describe Lita::Handler, lita: true do
|
|
171
233
|
end
|
172
234
|
end
|
173
235
|
|
236
|
+
describe "#config" do
|
237
|
+
before { Lita.register_handler(handler_class) }
|
238
|
+
subject { handler_class.new(robot) }
|
239
|
+
|
240
|
+
it "returns a Lita config" do
|
241
|
+
expect(subject.config).to be_a(Lita::Config)
|
242
|
+
end
|
243
|
+
|
244
|
+
it "contains the handler's config settings" do
|
245
|
+
expect(subject.config.foo).to eq("bar")
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
174
249
|
describe "#http" do
|
175
250
|
it "returns a Faraday connection" do
|
176
251
|
expect(subject.http).to be_a(Faraday::Connection)
|
@@ -194,6 +269,12 @@ describe Lita::Handler, lita: true do
|
|
194
269
|
end
|
195
270
|
end
|
196
271
|
|
272
|
+
describe "#log" do
|
273
|
+
it "returns the Lita logger" do
|
274
|
+
expect(subject.log).to eq(Lita.logger)
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
197
278
|
describe "timer methods" do
|
198
279
|
let(:response) { instance_double("Lita::Response") }
|
199
280
|
|
data/spec/lita/rack_app_spec.rb
CHANGED
@@ -10,7 +10,7 @@ describe Lita::RackApp do
|
|
10
10
|
http.get ":var/otherwise/identical/path", :constraint, var: /\d+/
|
11
11
|
http.get ":var/otherwise/identical/path", :no_constraint
|
12
12
|
|
13
|
-
def web(
|
13
|
+
def web(_request, response)
|
14
14
|
response.write("it worked")
|
15
15
|
end
|
16
16
|
|
@@ -24,11 +24,11 @@ describe Lita::RackApp do
|
|
24
24
|
response.write(segments.join("/"))
|
25
25
|
end
|
26
26
|
|
27
|
-
def constraint(
|
27
|
+
def constraint(_request, response)
|
28
28
|
response.write("constraint")
|
29
29
|
end
|
30
30
|
|
31
|
-
def no_constraint(
|
31
|
+
def no_constraint(_request, response)
|
32
32
|
response.write("no constraint")
|
33
33
|
end
|
34
34
|
|
data/spec/lita/response_spec.rb
CHANGED
data/spec/lita/rspec_spec.rb
CHANGED
@@ -17,13 +17,13 @@ handler_class = Class.new(Lita::Handler) do
|
|
17
17
|
response.reply "bongo", "wongo"
|
18
18
|
end
|
19
19
|
|
20
|
-
def restricted(
|
20
|
+
def restricted(_response)
|
21
21
|
end
|
22
22
|
|
23
|
-
def web(
|
23
|
+
def web(_request, _response)
|
24
24
|
end
|
25
25
|
|
26
|
-
def greet(
|
26
|
+
def greet(_payload)
|
27
27
|
end
|
28
28
|
|
29
29
|
def self.name
|
data/spec/lita_spec.rb
CHANGED
@@ -1,11 +1,20 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
describe Lita do
|
4
|
+
before { described_class.register_adapter(:shell, Lita::Adapters::Shell) }
|
5
|
+
|
4
6
|
it "memoizes a Config" do
|
5
7
|
expect(described_class.config).to be_a(Lita::Config)
|
6
8
|
expect(described_class.config).to eql(described_class.config)
|
7
9
|
end
|
8
10
|
|
11
|
+
it "keeps track of registered hooks" do
|
12
|
+
hook = double("hook")
|
13
|
+
described_class.register_hook("Foo ", hook)
|
14
|
+
described_class.register_hook(:foO, hook)
|
15
|
+
expect(described_class.hooks[:foo]).to eq(Set.new([hook]))
|
16
|
+
end
|
17
|
+
|
9
18
|
describe ".configure" do
|
10
19
|
it "yields the Config object" do
|
11
20
|
described_class.configure { |c| c.robot.name = "Not Lita" }
|
@@ -57,12 +66,48 @@ describe Lita do
|
|
57
66
|
end
|
58
67
|
end
|
59
68
|
|
69
|
+
describe ".reset" do
|
70
|
+
it "clears the config" do
|
71
|
+
described_class.config.robot.name = "Foo"
|
72
|
+
described_class.reset
|
73
|
+
expect(described_class.config.robot.name).to eq("Lita")
|
74
|
+
end
|
75
|
+
|
76
|
+
it "clears adapters" do
|
77
|
+
described_class.register_adapter(:foo, double)
|
78
|
+
described_class.reset
|
79
|
+
expect(described_class.adapters).to be_empty
|
80
|
+
end
|
81
|
+
|
82
|
+
it "clears handlers" do
|
83
|
+
described_class.register_handler(double)
|
84
|
+
described_class.reset
|
85
|
+
expect(described_class.handlers).to be_empty
|
86
|
+
end
|
87
|
+
|
88
|
+
it "clears hooks" do
|
89
|
+
described_class.register_hook(:foo, double)
|
90
|
+
described_class.reset
|
91
|
+
expect(described_class.hooks).to be_empty
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
60
95
|
describe ".run" do
|
61
|
-
|
96
|
+
let(:hook) { double("Hook") }
|
97
|
+
|
98
|
+
before do
|
99
|
+
allow_any_instance_of(Lita::Robot).to receive(:run)
|
100
|
+
end
|
62
101
|
|
63
102
|
it "runs a new Robot" do
|
64
103
|
expect_any_instance_of(Lita::Robot).to receive(:run)
|
65
104
|
described_class.run
|
66
105
|
end
|
106
|
+
|
107
|
+
it "calls before_run hooks" do
|
108
|
+
described_class.register_hook(:before_run, hook)
|
109
|
+
expect(hook).to receive(:call).with(config_path: "path/to/config")
|
110
|
+
described_class.run("path/to/config")
|
111
|
+
end
|
67
112
|
end
|
68
113
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -14,8 +14,8 @@ require "lita/rspec"
|
|
14
14
|
RSpec.configure do |config|
|
15
15
|
config.mock_with :rspec do |mocks_config|
|
16
16
|
mocks_config.verify_doubled_constant_names = true
|
17
|
-
# Enable config option
|
18
|
-
# https://github.com/rspec/rspec-mocks/pull/
|
17
|
+
# Enable config option when a new rspec-mocks beta including this patch is released:
|
18
|
+
# https://github.com/rspec/rspec-mocks/pull/615
|
19
19
|
#
|
20
20
|
# mocks_config.verify_partial_doubles = true
|
21
21
|
end
|
data/templates/plugin/README.tt
CHANGED
@@ -4,16 +4,26 @@ TODO: Add a description of the plugin.
|
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
7
|
+
<%- if config[:plugin_type] == "extension" -%>
|
8
|
+
Add <%= config[:gem_name] %> to your Lita plugin's gemspec:
|
9
|
+
|
10
|
+
``` ruby
|
11
|
+
spec.add_runtime_dependency "<%= config[:gem_name] %>"
|
12
|
+
```
|
13
|
+
<%- else -%>
|
7
14
|
Add <%= config[:gem_name] %> to your Lita instance's Gemfile:
|
8
15
|
|
9
16
|
``` ruby
|
10
17
|
gem "<%= config[:gem_name] %>"
|
11
18
|
```
|
19
|
+
<%- end -%>
|
12
20
|
|
21
|
+
<%- unless config[:plugin_type] == "extension" %>
|
13
22
|
## Configuration
|
14
23
|
|
15
24
|
TODO: Describe any configuration attributes the plugin exposes.
|
16
25
|
|
26
|
+
<%- end -%>
|
17
27
|
## Usage
|
18
28
|
|
19
29
|
TODO: Describe the plugin's features and how to use them.
|
@@ -1,12 +1,16 @@
|
|
1
1
|
module Lita
|
2
2
|
module <%= config[:constant_namespace] %>
|
3
|
-
class <%= config[:constant_name] %> < <%= config[:plugin_type].capitalize %>
|
3
|
+
class <%= config[:constant_name] %><% unless config[:plugin_type] == "extension" %> < <%= config[:plugin_type].capitalize %><% end %>
|
4
4
|
end
|
5
5
|
|
6
6
|
<%- if config[:plugin_type] == "adapter" -%>
|
7
7
|
Lita.register_adapter(:<%= config[:name] %>, <%= config[:constant_name] %>)
|
8
|
-
<%-
|
8
|
+
<%- elsif config[:plugin_type] == "handler" -%>
|
9
9
|
Lita.register_handler(<%= config[:constant_name] %>)
|
10
|
+
<%- else -%>
|
11
|
+
# If your extension needs to register with a Lita hook, uncomment the
|
12
|
+
# following line and change the hook name to the appropriate value:
|
13
|
+
# Lita.register_hook(:hook_name, <%= config[:constant_name] %>)
|
10
14
|
<%- end -%>
|
11
15
|
end
|
12
16
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lita
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jimmy Cuadra
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-05-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -224,16 +224,16 @@ dependencies:
|
|
224
224
|
name: rubocop
|
225
225
|
requirement: !ruby/object:Gem::Requirement
|
226
226
|
requirements:
|
227
|
-
- - "
|
227
|
+
- - "~>"
|
228
228
|
- !ruby/object:Gem::Version
|
229
|
-
version:
|
229
|
+
version: 0.21.0
|
230
230
|
type: :development
|
231
231
|
prerelease: false
|
232
232
|
version_requirements: !ruby/object:Gem::Requirement
|
233
233
|
requirements:
|
234
|
-
- - "
|
234
|
+
- - "~>"
|
235
235
|
- !ruby/object:Gem::Version
|
236
|
-
version:
|
236
|
+
version: 0.21.0
|
237
237
|
description: A multi-service chat bot with extendable behavior.
|
238
238
|
email:
|
239
239
|
- jimmy@jimmycuadra.com
|
@@ -270,6 +270,7 @@ files:
|
|
270
270
|
- lib/lita/rack_app.rb
|
271
271
|
- lib/lita/response.rb
|
272
272
|
- lib/lita/robot.rb
|
273
|
+
- lib/lita/route_validator.rb
|
273
274
|
- lib/lita/rspec.rb
|
274
275
|
- lib/lita/rspec/handler.rb
|
275
276
|
- lib/lita/rspec/matchers/event_subscription_matcher.rb
|