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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b317185fd4bf51c66e01de3aef18547d27d154ef
4
- data.tar.gz: 0ee25a799c8b033fb82e0e58fe3654ebaf974eea
3
+ metadata.gz: 68d6c55cacef1663c210df90ff03f764bca2c3b3
4
+ data.tar.gz: 4696fa739de19bb0a0245fd855666fe6a5622f31
5
5
  SHA512:
6
- metadata.gz: 23c70beb7798a316f725225c17a0b75f8e0fdd2d104e9d9f4c611ae6c423300810adb1c1a9805629287a0db1d27b60071779bd4bf7ecebfbef302a3fde3623f3
7
- data.tar.gz: 0498b930d44e0057058a25df985b8117d97de953f76ed89c414c7902482f889db1333b4376665aab01409f60fbcc55ae6fb3159594432cbfac0944b4bd8c9168
6
+ metadata.gz: 7701c02aa161e08559b50e1133ea1227cc79d53f4278a772ef274b090fceb9a9bad22a317263f067adfe036a336fc6d3ba6d0a546b014387e12f49cf46d52ec7
7
+ data.tar.gz: b4b212cee5587adaf06f0ad8944715b9653a678f041e18d71258bbc4d52864f5cf575c3fb010161325153a42d6bde5271f722202383c5a3ca48b035e2685d204
@@ -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.
@@ -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
- # Clears the global configuration object. The next call to {Lita.config}
65
- # will create a fresh config object.
66
- # @return [void]
67
- def clear_config
68
- @config = nil
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"
@@ -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 |*args|
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
@@ -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(target, strings)
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?
@@ -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]
@@ -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, command: false, restrict_to: nil, help: {})
37
- groups = restrict_to.nil? ? nil : Array(restrict_to)
38
- routes << Route.new(pattern, method, command, groups, help)
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(robot).public_send(
61
- route.method_name,
62
- Response.new(message, route.pattern)
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
- # Message must be a command if the route requires a command
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)
@@ -88,7 +88,7 @@ module Lita
88
88
 
89
89
  def valid_group?(response, identifier)
90
90
  unless identifier && @group
91
- response.reply "#{t('format')}: #{robot.name} auth add USER GROUP"
91
+ response.reply "#{t("format")}: #{robot.name} auth add USER GROUP"
92
92
  return
93
93
  end
94
94
 
@@ -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(request, response)
24
+ def web(_request, response)
25
25
  response.headers["Content-Type"] = "application/json"
26
26
  json = MultiJson.dump(
27
27
  lita_version: Lita::VERSION,
@@ -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, progname, msg|
12
+ logger.formatter = proc do |severity, datetime, _progname, msg|
13
13
  "[#{datetime.utc}] #{severity}: #{msg}\n"
14
14
  end
15
15
  logger
@@ -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
@@ -43,7 +43,7 @@ module Lita
43
43
  base.class_eval do
44
44
  before do
45
45
  [:send_messages, :send_message].each do |message|
46
- allow(robot).to receive(message) do |target, *strings|
46
+ allow(robot).to receive(message) do |_target, *strings|
47
47
  replies.concat(strings)
48
48
  end
49
49
  end
@@ -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] && '_'}#{Regexp.last_match[2].downcase}"
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')
@@ -1,4 +1,4 @@
1
1
  module Lita
2
2
  # The current version of Lita.
3
- VERSION = "3.1.0"
3
+ VERSION = "3.2.0"
4
4
  end
@@ -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{A multi-service chat bot with extendable behavior.}
12
- spec.summary = %q{A multi-service chat bot with extendable behavior.}
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
@@ -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 foo(response)
47
+ def self.default_config(config)
48
+ config.foo = "bar"
26
49
  end
27
50
 
28
- def blah(response)
51
+ def foo(_response)
29
52
  end
30
53
 
31
- def secret(response)
54
+ def blah(_response)
32
55
  end
33
56
 
34
- def danger(response)
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(response, queue)
43
- after(2) { |timer| queue.push("Waited 2 seconds!") }
74
+ def after_test(_response, queue)
75
+ after(2) { queue.push("Waited 2 seconds!") }
44
76
  end
45
77
 
46
- def every_test(response, queue)
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
 
@@ -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(request, response)
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(request, response)
27
+ def constraint(_request, response)
28
28
  response.write("constraint")
29
29
  end
30
30
 
31
- def no_constraint(request, response)
31
+ def no_constraint(_request, response)
32
32
  response.write("no constraint")
33
33
  end
34
34
 
@@ -28,4 +28,12 @@ describe Lita::Response do
28
28
  subject.match_data
29
29
  end
30
30
  end
31
+
32
+ describe "#extensions" do
33
+ it "can be populated with arbitrary data" do
34
+ subject.extensions[:foo] = :bar
35
+
36
+ expect(subject.extensions[:foo]).to eq(:bar)
37
+ end
38
+ end
31
39
  end
@@ -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(response)
20
+ def restricted(_response)
21
21
  end
22
22
 
23
- def web(request, response)
23
+ def web(_request, _response)
24
24
  end
25
25
 
26
- def greet(payload)
26
+ def greet(_payload)
27
27
  end
28
28
 
29
29
  def self.name
@@ -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
- before { Lita.config }
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
@@ -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 this when a new rspec-mocks beta including this patch is released:
18
- # https://github.com/rspec/rspec-mocks/pull/466
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
@@ -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
- <%- else -%>
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.1.0
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-04-11 00:00:00.000000000 Z
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: '0'
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: '0'
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