lita 2.7.2 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/.rubocop.yml +26 -0
  4. data/CONTRIBUTING.md +1 -1
  5. data/README.md +6 -470
  6. data/Rakefile +3 -3
  7. data/lib/lita.rb +27 -19
  8. data/lib/lita/adapter.rb +46 -5
  9. data/lib/lita/adapters/shell.rb +18 -13
  10. data/lib/lita/authorization.rb +1 -1
  11. data/lib/lita/cli.rb +37 -23
  12. data/lib/lita/common.rb +35 -0
  13. data/lib/lita/config.rb +33 -13
  14. data/lib/lita/daemon.rb +15 -12
  15. data/lib/lita/handler.rb +49 -9
  16. data/lib/lita/handlers/authorization.rb +47 -47
  17. data/lib/lita/handlers/help.rb +16 -17
  18. data/lib/lita/handlers/info.rb +38 -0
  19. data/lib/lita/handlers/room.rb +32 -0
  20. data/lib/lita/http_route.rb +30 -19
  21. data/lib/lita/message.rb +3 -6
  22. data/lib/lita/rack_app.rb +11 -89
  23. data/lib/lita/response.rb +5 -15
  24. data/lib/lita/robot.rb +26 -10
  25. data/lib/lita/rspec.rb +6 -8
  26. data/lib/lita/rspec/handler.rb +49 -121
  27. data/lib/lita/rspec/matchers/event_subscription_matcher.rb +67 -0
  28. data/lib/lita/rspec/matchers/http_route_matcher.rb +72 -0
  29. data/lib/lita/rspec/matchers/route_matcher.rb +69 -0
  30. data/lib/lita/source.rb +5 -18
  31. data/lib/lita/timer.rb +45 -0
  32. data/lib/lita/user.rb +51 -4
  33. data/lib/lita/util.rb +5 -5
  34. data/lib/lita/version.rb +1 -1
  35. data/lita.gemspec +6 -3
  36. data/spec/lita/adapter_spec.rb +10 -2
  37. data/spec/lita/adapters/shell_spec.rb +3 -3
  38. data/spec/lita/authorization_spec.rb +11 -11
  39. data/spec/lita/config_spec.rb +8 -0
  40. data/spec/lita/daemon_spec.rb +65 -0
  41. data/spec/lita/handler_spec.rb +50 -11
  42. data/spec/lita/handlers/authorization_spec.rb +1 -1
  43. data/spec/lita/handlers/info_spec.rb +31 -0
  44. data/spec/lita/handlers/room_spec.rb +20 -0
  45. data/spec/lita/logger_spec.rb +1 -1
  46. data/spec/lita/message_spec.rb +4 -4
  47. data/spec/lita/rack_app_spec.rb +92 -0
  48. data/spec/lita/response_spec.rb +17 -8
  49. data/spec/lita/robot_spec.rb +23 -14
  50. data/spec/lita/rspec_spec.rb +1 -1
  51. data/spec/lita/source_spec.rb +0 -16
  52. data/spec/lita/timer_spec.rb +30 -0
  53. data/spec/lita/user_spec.rb +66 -6
  54. data/spec/lita_spec.rb +37 -0
  55. data/spec/spec_helper.rb +11 -0
  56. data/templates/locales/en.yml +90 -0
  57. data/templates/plugin/Rakefile +1 -1
  58. data/templates/plugin/lib/lita/plugin_type/plugin.tt +4 -0
  59. data/templates/plugin/locales/en.yml.tt +4 -0
  60. metadata +77 -18
  61. data/lib/lita/handlers/web.rb +0 -25
  62. data/spec/lita/handlers/web_spec.rb +0 -19
@@ -26,10 +26,7 @@ module Lita
26
26
  @source = source
27
27
 
28
28
  name_pattern = Regexp.escape(@robot.mention_name)
29
-
30
- if @robot.alias
31
- name_pattern = "#{name_pattern}|#{Regexp.escape(@robot.alias)}"
32
- end
29
+ name_pattern = "#{name_pattern}|#{Regexp.escape(@robot.alias)}" if @robot.alias
33
30
 
34
31
  @command = !!@body.sub!(/^\s*@?(?:#{name_pattern})[:,]?\s*/i, "")
35
32
  end
@@ -39,9 +36,9 @@ module Lita
39
36
  # @return [Array<String>] The array of arguments.
40
37
  def args
41
38
  begin
42
- command, *args = body.shellsplit
39
+ _command, *args = body.shellsplit
43
40
  rescue ArgumentError
44
- command, *args =
41
+ _command, *args =
45
42
  body.split(/\s+/).map(&:shellescape).join(" ").shellsplit
46
43
  end
47
44
 
@@ -1,114 +1,36 @@
1
1
  module Lita
2
2
  # A +Rack+ application to serve routes registered by handlers.
3
3
  class RackApp
4
- # The character that separates the pieces of a URL's path component.
5
- PATH_SEPARATOR = "/"
6
-
7
- # A +Struct+ representing a route's destination handler and method name.
8
- RouteMapping = Struct.new(:handler, :method_name)
9
-
10
- # All registered paths. Used to respond to HEAD requests.
11
- # @return [Array<String>] The array of paths.
12
- attr_reader :all_paths
13
-
14
4
  # The currently running robot.
15
5
  # @return [Lita::Robot] The robot.
16
6
  attr_reader :robot
17
7
 
18
- # A hash mapping HTTP request methods and paths to handlers and methods.
19
- # @return [Hash] The mapping.
20
- attr_reader :routes
8
+ # An +HttpRouter+ used for dispatch.
9
+ # @return [HttpRouter] The router.
10
+ attr_reader :router
21
11
 
22
12
  # @param robot [Lita::Robot] The currently running robot.
23
13
  def initialize(robot)
24
14
  @robot = robot
25
- @routes = Hash.new { |h, k| h[k] = {} }
15
+ @router = HttpRouter.new
26
16
  compile
27
17
  end
28
18
 
19
+ # Entry point for Lita's HTTP routes. Invokes the Rack application.
20
+ # @param env [Hash] A Rack environment.
21
+ # @return [void]
29
22
  def call(env)
30
- request = Rack::Request.new(env)
31
- mapping = get_mapping(request)
32
-
33
- if mapping
34
- serve(mapping, request)
35
- elsif request.head? && all_paths.include?(request.path)
36
- Lita.logger.info "HTTP HEAD #{request.path} was a 204."
37
- [204, {}, []]
38
- else
39
- Lita.logger.info <<-LOG.chomp
40
- HTTP #{request.request_method} #{request.path} was a 404.
41
- LOG
42
- [404, {}, ["Route not found."]]
43
- end
44
- end
45
-
46
- # Creates a +Rack+ application from the compiled routes.
47
- # @return [Rack::Builder] The +Rack+ application.
48
- def to_app
49
- app = Rack::Builder.new
50
- app.run(self)
51
- app
23
+ env["lita.robot"] = robot
24
+ router.call(env)
52
25
  end
53
26
 
54
27
  private
55
28
 
56
- # Collect all registered paths. Used for responding to HEAD requests.
57
- def collect_paths
58
- @all_paths = routes.values.map { |hash| hash.keys.first }.uniq
59
- end
60
-
61
- # Registers routes in the route mapping for each handler's defined routes.
29
+ # Registers routes in the router for each handler's defined routes.
62
30
  def compile
63
31
  Lita.handlers.each do |handler|
64
- handler.http_routes.each { |route| register_route(handler, route) }
65
- end
66
- collect_paths
67
- end
68
-
69
- def get_mapping(request)
70
- routes[request.request_method][request.path]
71
- end
72
-
73
- # Registers a route.
74
- def register_route(handler, route)
75
- cleaned_path = clean_path(route.path)
76
-
77
- if @routes[route.http_method][cleaned_path]
78
- Lita.logger.fatal <<-ERR.chomp
79
- #{handler.name} attempted to register an HTTP route that was already \
80
- registered: #{route.http_method} "#{cleaned_path}"
81
- ERR
82
- abort
32
+ handler.http_routes.each { |route| router.add_route(route) }
83
33
  end
84
-
85
- Lita.logger.debug <<-LOG.chomp
86
- Registering HTTP route: #{route.http_method} #{cleaned_path} to \
87
- #{handler}##{route.method_name}.
88
- LOG
89
- @routes[route.http_method][cleaned_path] = RouteMapping.new(
90
- handler,
91
- route.method_name
92
- )
93
- end
94
-
95
- def serve(mapping, request)
96
- Lita.logger.info <<-LOG.chomp
97
- Routing HTTP #{request.request_method} #{request.path} to \
98
- #{mapping.handler}##{mapping.method_name}.
99
- LOG
100
- response = Rack::Response.new
101
- instance = mapping.handler.new(robot)
102
- instance.public_send(mapping.method_name, request, response)
103
- response.finish
104
- end
105
-
106
- # Ensures that paths begin with one slash and do not end with one.
107
- def clean_path(path)
108
- path.strip!
109
- path.chop! while path.end_with?(PATH_SEPARATOR)
110
- path = path[1..-1] while path.start_with?(PATH_SEPARATOR)
111
- "/#{path}"
112
34
  end
113
35
  end
114
36
  end
@@ -23,20 +23,10 @@ module Lita
23
23
  def_delegators :message, :args, :reply, :reply_privately, :user, :command?
24
24
 
25
25
  # @param message [Lita::Message] The incoming message.
26
- # @param matches [Regexp] The pattern the incoming message matched.
27
- def initialize(*args)
28
- options = args.last.is_a?(Hash) ? args.pop : {}
29
-
30
- self.message = args[0]
31
- self.pattern = args[1]
32
-
33
- if options[:matches]
34
- Lita.logger.warn <<-WARNING.chomp
35
- Passing a "matches" option to Response's constructor is deprecated. \
36
- Use Response.new(message, pattern) instead.
37
- WARNING
38
- @matches = options[:matches]
39
- end
26
+ # @param pattern [Regexp] The pattern the incoming message matched.
27
+ def initialize(message, pattern)
28
+ self.message = message
29
+ self.pattern = pattern
40
30
  end
41
31
 
42
32
  # An array of matches from scanning the message against the route pattern.
@@ -48,7 +38,7 @@ Use Response.new(message, pattern) instead.
48
38
  # A +MatchData+ object from running the pattern against the message body.
49
39
  # @return [MatchData] The +MatchData+.
50
40
  def match_data
51
- @match_data ||= pattern.match(message.body) if pattern
41
+ @match_data ||= pattern.match(message.body)
52
42
  end
53
43
  end
54
44
  end
@@ -26,7 +26,7 @@ module Lita
26
26
  @name = Lita.config.robot.name
27
27
  @mention_name = Lita.config.robot.mention_name || @name
28
28
  @alias = Lita.config.robot.alias
29
- @app = RackApp.new(self).to_app
29
+ @app = RackApp.new(self)
30
30
  load_adapter
31
31
  trigger(:loaded)
32
32
  end
@@ -49,6 +49,22 @@ module Lita
49
49
  shut_down
50
50
  end
51
51
 
52
+ # Makes the robot join a room with the specified ID.
53
+ # @param room_id [String] The ID of the room.
54
+ # @return [void]
55
+ # @since 3.0.0
56
+ def join(room_id)
57
+ @adapter.join(room_id)
58
+ end
59
+
60
+ # Makes the robot part from the room with the specified ID.
61
+ # @param room_id [String] The ID of the room.
62
+ # @return [void]
63
+ # @since 3.0.0
64
+ def part(room_id)
65
+ @adapter.part(room_id)
66
+ end
67
+
52
68
  # Sends one or more messages to a user or room.
53
69
  # @param target [Lita::Source] The user or room to send to. If the Source
54
70
  # has a room, it will choose the room. Otherwise, it will send to the
@@ -74,7 +90,7 @@ module Lita
74
90
  # @return [void]
75
91
  def shut_down
76
92
  trigger(:shut_down_started)
77
- @server.stop if @server
93
+ @server.stop(true) if @server
78
94
  @server_thread.join if @server_thread
79
95
  @adapter.shut_down
80
96
  trigger(:shut_down_complete)
@@ -100,7 +116,7 @@ module Lita
100
116
  adapter_class = Lita.adapters[adapter_name.to_sym]
101
117
 
102
118
  unless adapter_class
103
- Lita.logger.fatal("Unknown adapter: :#{adapter_name}.")
119
+ Lita.logger.fatal I18n.t("lita.robot.unknown_adapter", adapter: adapter_name)
104
120
  abort
105
121
  end
106
122
 
@@ -109,14 +125,14 @@ module Lita
109
125
 
110
126
  # Starts the web server.
111
127
  def run_app
128
+ http_config = Lita.config.http
129
+
112
130
  @server_thread = Thread.new do
113
- @server = Thin::Server.new(
114
- app,
115
- Lita.config.http.port.to_i,
116
- signals: false
117
- )
118
- @server.silent = true unless Lita.config.http.debug
119
- @server.start
131
+ @server = Puma::Server.new(app)
132
+ @server.add_tcp_listener(http_config.host, http_config.port.to_i)
133
+ @server.min_threads = http_config.min_threads
134
+ @server.max_threads = http_config.max_threads
135
+ @server.run
120
136
  end
121
137
 
122
138
  @server_thread.abort_on_exception = true
@@ -3,15 +3,13 @@ begin
3
3
  require "rspec/expectations"
4
4
  require "rspec/mocks"
5
5
  rescue LoadError
6
- abort "Lita::RSpec requires both RSpec::Mocks and RSpec::Expectations."
6
+ abort I18n.t("lita.rspec.full_suite_required")
7
7
  end
8
8
 
9
- major, minor, patch, *pre = RSpec::Mocks::Version::STRING.split(/\./)
10
- if major == "2" && minor.to_i < 14
11
- abort "RSpec::Mocks 2.14 or greater is required to use Lita::RSpec."
12
- end
9
+ major, minor, _patch, *_pre = RSpec::Mocks::Version::STRING.split(/\./)
10
+ abort I18n.t("lita.rspec.mocks_expect_syntax_required") if major == "2" && minor.to_i < 14
13
11
 
14
- require "lita/rspec/handler"
12
+ require_relative "rspec/handler"
15
13
 
16
14
  module Lita
17
15
  # Extras for +RSpec+ that facilitate the testing of Lita code.
@@ -32,14 +30,14 @@ module Lita
32
30
  end
33
31
  end
34
32
 
35
- set_up_redis(base)
33
+ prepare_redis(base)
36
34
  end
37
35
 
38
36
  private
39
37
 
40
38
  # Set up Redis to use the test namespace and clear out before each
41
39
  # example.
42
- def set_up_redis(base)
40
+ def prepare_redis(base)
43
41
  base.class_eval do
44
42
  before do
45
43
  stub_const("Lita::REDIS_NAMESPACE", "lita.test")
@@ -1,3 +1,7 @@
1
+ require_relative "matchers/route_matcher"
2
+ require_relative "matchers/http_route_matcher"
3
+ require_relative "matchers/event_subscription_matcher"
4
+
1
5
  module Lita
2
6
  module RSpec
3
7
  # Extras for +RSpec+ to facilitate testing Lita handlers.
@@ -9,29 +13,23 @@ module Lita
9
13
  include Lita::RSpec
10
14
  end
11
15
 
12
- set_up_let_blocks(base)
13
- set_up_subject(base)
14
- set_up_before_block(base)
16
+ prepare_handlers(base)
17
+ prepare_let_blocks(base)
18
+ prepare_subject(base)
19
+ prepare_robot(base)
15
20
  end
16
21
 
17
22
  private
18
23
 
19
- # Stub Lita.handlers and Lita::Robot#send_messages.
20
- def set_up_before_block(base)
24
+ # Stub Lita.handlers.
25
+ def prepare_handlers(base)
21
26
  base.class_eval do
22
- before do
23
- allow(Lita).to receive(:handlers).and_return([described_class])
24
- [:send_messages, :send_message].each do |message|
25
- allow(robot).to receive(message) do |target, *strings|
26
- replies.concat(strings)
27
- end
28
- end
29
- end
27
+ before { allow(Lita).to receive(:handlers).and_return([described_class]) }
30
28
  end
31
29
  end
32
30
 
33
31
  # Create common test objects.
34
- def set_up_let_blocks(base)
32
+ def prepare_let_blocks(base)
35
33
  base.class_eval do
36
34
  let(:robot) { Robot.new }
37
35
  let(:source) { Source.new(user: user) }
@@ -40,10 +38,24 @@ module Lita
40
38
  end
41
39
  end
42
40
 
41
+ # Stub Lita::Robot#send_messages.
42
+ def prepare_robot(base)
43
+ base.class_eval do
44
+ before do
45
+ [:send_messages, :send_message].each do |message|
46
+ allow(robot).to receive(message) do |target, *strings|
47
+ replies.concat(strings)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+
43
54
  # Set up a working test subject.
44
- def set_up_subject(base)
55
+ def prepare_subject(base)
45
56
  base.class_eval do
46
57
  subject { described_class.new(robot) }
58
+ before { allow(described_class).to receive(:new).and_return(subject) }
47
59
  end
48
60
  end
49
61
  end
@@ -73,42 +85,38 @@ module Lita
73
85
  # Starts a chat routing test chain, asserting that a message should
74
86
  # trigger a route.
75
87
  # @param message [String] The message that should trigger the route.
76
- # @return [RouteMatcher] A {RouteMatcher} that should have +to+ called on
77
- # it to complete the test.
88
+ # @return [Matchers::RouteMatcher] A {Matchers::RouteMatcher} that should have +to+
89
+ # called on it to complete the test.
78
90
  def routes(message)
79
- RouteMatcher.new(self, message)
91
+ Matchers::RouteMatcher.new(self, message)
80
92
  end
81
93
 
82
94
  # Starts a chat routing test chain, asserting that a message should not
83
95
  # trigger a route.
84
96
  # @param message [String] The message that should not trigger the route.
85
- # @return [RouteMatcher] A {RouteMatcher} that should have +to+ called on
86
- # it to complete the test.
97
+ # @return [Matchers::RouteMatcher] A {Matchers::RouteMatcher} that should have +to+
98
+ # called on it to complete the test.
87
99
  def does_not_route(message)
88
- RouteMatcher.new(self, message, invert: true)
100
+ Matchers::RouteMatcher.new(self, message, expectation: false)
89
101
  end
90
102
  alias_method :doesnt_route, :does_not_route
91
103
 
92
104
  # Starts a chat routing test chain, asserting that a "command" message
93
105
  # should trigger a route.
94
106
  # @param message [String] The message that should trigger the route.
95
- # @return [RouteMatcher] A {RouteMatcher} that should have +to+ called on
96
- # it to complete the test.
107
+ # @return [Matchers::RouteMatcher] A {Matchers::RouteMatcher} that should have +to+
108
+ # called on it to complete the test.
97
109
  def routes_command(message)
98
- RouteMatcher.new(self, "#{robot.mention_name}: #{message}")
110
+ Matchers::RouteMatcher.new(self, "#{robot.mention_name}: #{message}")
99
111
  end
100
112
 
101
113
  # Starts a chat routing test chain, asserting that a "command" message
102
114
  # should not trigger a route.
103
115
  # @param message [String] The message that should not trigger the route.
104
- # @return [RouteMatcher] A {RouteMatcher} that should have +to+ called on
105
- # it to complete the test.
116
+ # @return [Matchers::RouteMatcher] A {Matchers::RouteMatcher} that should have +to+
117
+ # called on it to complete the test.
106
118
  def does_not_route_command(message)
107
- RouteMatcher.new(
108
- self,
109
- "#{robot.mention_name}: #{message}",
110
- invert: true
111
- )
119
+ Matchers::RouteMatcher.new(self, "#{robot.mention_name}: #{message}", expectation: false)
112
120
  end
113
121
  alias_method :doesnt_route_command, :does_not_route_command
114
122
 
@@ -118,10 +126,10 @@ module Lita
118
126
  # the route.
119
127
  # @param path [String] The path URL component that should trigger the
120
128
  # route.
121
- # @return [HTTPRouteMatcher] An {HTTPRouteMatcher} that should have +to+
122
- # called on it to complete the test.
129
+ # @return [Matchers::HTTPRouteMatcher] A {Matchers::HTTPRouteMatcher} that should
130
+ # have +to+ called on it to complete the test.
123
131
  def routes_http(http_method, path)
124
- HTTPRouteMatcher.new(self, http_method, path)
132
+ Matchers::HTTPRouteMatcher.new(self, http_method, path)
125
133
  end
126
134
 
127
135
  # Starts an HTTP routing test chain, asserting that a request to the given
@@ -130,10 +138,10 @@ module Lita
130
138
  # trigger the route.
131
139
  # @param path [String] The path URL component that should not trigger the
132
140
  # route.
133
- # @return [HTTPRouteMatcher] An {HTTPRouteMatcher} that should have +to+
134
- # called on it to complete the test.
141
+ # @return [Matchers::HTTPRouteMatcher] A {Matchers::HTTPRouteMatcher} that should
142
+ # have +to+ called on it to complete the test.
135
143
  def does_not_route_http(http_method, path)
136
- HTTPRouteMatcher.new(self, http_method, path, invert: true)
144
+ Matchers::HTTPRouteMatcher.new(self, http_method, path, expectation: false)
137
145
  end
138
146
  alias_method :doesnt_route_http, :does_not_route_http
139
147
 
@@ -141,102 +149,22 @@ module Lita
141
149
  # trigger the target method.
142
150
  # @param event_name [String, Symbol] The name of the event that should
143
151
  # be triggered.
144
- # @return [EventSubscriptionMatcher] An {EventSubscriptionMatcher} that
152
+ # @return [Matchers::EventSubscriptionMatcher] A {Matchers::EventSubscriptionMatcher} that
145
153
  # should have +to+ called on it to complete the test.
146
154
  def routes_event(event_name)
147
- EventSubscriptionMatcher.new(self, event_name)
155
+ Matchers::EventSubscriptionMatcher.new(self, event_name)
148
156
  end
149
157
 
150
158
  # Starts an event subscription test chain, asserting that an event should
151
159
  # not trigger the target method.
152
160
  # @param event_name [String, Symbol] The name of the event that should
153
161
  # not be triggered.
154
- # @return [EventSubscriptionMatcher] An {EventSubscriptionMatcher} that
162
+ # @return [Matchers::EventSubscriptionMatcher] A {Matchers::EventSubscriptionMatcher} that
155
163
  # should have +to+ called on it to complete the test.
156
164
  def does_not_route_event(event_name)
157
- EventSubscriptionMatcher.new(self, event_name, invert: true)
165
+ Matchers::EventSubscriptionMatcher.new(self, event_name, expectation: false)
158
166
  end
159
167
  alias_method :doesnt_route_event, :does_not_route_event
160
168
  end
161
-
162
- # Used to complete a chat routing test chain.
163
- class RouteMatcher
164
- def initialize(context, message_body, invert: false)
165
- @context = context
166
- @message_body = message_body
167
- @method = invert ? :not_to : :to
168
- end
169
-
170
- # Sets an expectation that a route will or will not be triggered, then
171
- # sends the message originally provided.
172
- # @param route [Symbol] The name of the method that should or should not
173
- # be triggered.
174
- # @return [void]
175
- def to(route)
176
- m = @method
177
- b = @message_body
178
-
179
- @context.instance_eval do
180
- allow(Authorization).to receive(:user_in_group?).and_return(true)
181
- expect_any_instance_of(described_class).public_send(m, receive(route))
182
- send_message(b)
183
- end
184
- end
185
- end
186
-
187
- # Used to complete an HTTP routing test chain.
188
- class HTTPRouteMatcher
189
- def initialize(context, http_method, path, invert: false)
190
- @context = context
191
- @http_method = http_method
192
- @path = path
193
- @method = invert ? :not_to : :to
194
- end
195
-
196
- # Sets an expectation that an HTTP route will or will not be triggered,
197
- # then makes an HTTP request against the app with the HTTP request
198
- # method and path originally provided.
199
- # @param route [Symbol] The name of the method that should or should not
200
- # be triggered.
201
- # @return [void]
202
- def to(route)
203
- m = @method
204
- h = @http_method
205
- p = @path
206
-
207
- @context.instance_eval do
208
- expect_any_instance_of(described_class).public_send(m, receive(route))
209
- env = Rack::MockRequest.env_for(p, method: h)
210
- robot.app.call(env)
211
- end
212
- end
213
- end
214
-
215
- # Used to complete an event subscription test chain.
216
- class EventSubscriptionMatcher
217
- def initialize(context, event_name, invert: false)
218
- @context = context
219
- @event_name = event_name
220
- @method = invert ? :not_to : :to
221
- end
222
-
223
- # Sets an expectation that a handler method will or will not be called in
224
- # response to a triggered event, then triggers the event.
225
- # @param target_method_name [String, Symbol] The name of the method that
226
- # should or should not be triggered.
227
- # @return [void]
228
- def to(target_method_name)
229
- e = @event_name
230
- m = @method
231
-
232
- @context.instance_eval do
233
- expect_any_instance_of(described_class).public_send(
234
- m,
235
- receive(target_method_name)
236
- )
237
- robot.trigger(e)
238
- end
239
- end
240
- end
241
169
  end
242
170
  end