lita 3.1.0 → 3.2.0
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 +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
|
[](https://codeclimate.com/github/jimmycuadra/lita)
|
6
6
|
[](https://coveralls.io/r/jimmycuadra/lita)
|
7
7
|
|
8
|
-

|
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
|