README.md in lita-2.4.0 vs README.md in lita-2.5.0
- old
+ new
@@ -16,10 +16,11 @@
* Can work with any chat service
* Simple installation and setup
* Easily extendable with plugins
* Data persistence with Redis
* Built-in web server and routing
+* Event system for behavior triggered in response to arbitrary events
* Support for outgoing HTTP requests
* Group-based authorization
* Configurable logging
* Generators for creating new plugins
* Built-in process daemonization
@@ -181,11 +182,11 @@
For more detailed examples, check out the built in shell adapter, [lita-hipchat](https://github.com/jimmycuadra/lita-hipchat), or [lita-irc](https://github.com/jimmycuadra/lita-irc). See the API documentation for the exact methods and signatures adapters must implement.
## Writing a handler
-A handler is packaged as a RubyGem. A handler is a class that inherits from `Lita::Handler` and is registered by calling `Lita.register_handler(TheHandlerClass)`. There are two components to a handler: route definitions, and the methods that implement those routes. There are both chat routes and HTTP routes available to handlers.
+A handler is packaged as a RubyGem. A handler is a class that inherits from `Lita::Handler` and is registered by calling `Lita.register_handler(TheHandlerClass)`. There are two components to a handler: route definitions, and the methods that implement those routes. There are chat routes, HTTP routes, and event subscriptions available to handlers.
To generate a starting template for a new handler gem, run `lita handler NAME`, where NAME is the name of the new gem.
### Chat routes
@@ -237,10 +238,31 @@
def baz(request, response)
response.body = "Hello, world!"
end
```
+### Event subscriptions
+
+Handlers can communicate with each other or respond to arbitrary system events with the built-in pub-sub event system. Subscribe to an event by name, and provide the name of the instance method that should be invoked when the event triggers. Event callback methods are passed a payload hash with any arbitrary data the caller chooses to provide.
+
+``` ruby
+on :connected, :greet
+
+def greet(payload)
+ target = Source.new(room: payload[:room])
+ robot.send_message(target, "Hello #{payload[:room]}!")
+end
+```
+
+Trigger an event from anywhere and pass any payload data you want the subscribed handlers to receive:
+
+``` ruby
+robot.trigger(:connected, room: "#litabot")
+```
+
+Since the `trigger` method is available on `Lita::Robot`, it can be used from anywhere in the Lita runtime (both adapters and handlers).
+
### Handler-specific configuration
If you want your handler to expose config settings to the user, use the class-level `default_config` method. This method accepts a single config object as an argument, which will be exposed to the user as `Lita.config.handlers.your_handler_namespace`.
``` ruby
@@ -316,52 +338,77 @@
For more detailed examples, check out the built in authorization, help, and web handlers, or external handlers [lita-karma](https://github.com/jimmycuadra/lita-karma) and [lita-google-images](https://github.com/jimmycuadra/lita-google-images). See the API documentation for exact specifications for handlers' methods.
## Testing
-It's a core philosophy of Lita that any plugins you write for your robot should be as thoroughly tested as any other program you would write. To make this easier, Lita ships with some handy extras for [RSpec](https://github.com/rspec/rspec) that make testing a handler dead simple. They require the full RSpec suite (rspec-core, rspec-expectations, and rspec-mocks) version 2.14 or higher, as they use the newer `expect(obj).to receive(:message)` syntax.
+It's a core philosophy of Lita that any plugins you write for your robot should be as thoroughly tested as any other program you would write. To make this easier, Lita ships with some handy extras for [RSpec](https://github.com/rspec/rspec) that make testing a plugin dead simple. They require the full RSpec suite (rspec-core, rspec-expectations, and rspec-mocks) version 2.14 or higher, as they use the newer "expect" syntax.
-### Testing handlers
+### Testing adapters
-To include Lita's RSpec extras for testing a handler, require "lita/rspec", then add `lita_handler: true` to the metadata for the example group.
+To include some helpful setup for testing Lita code, require "lita/rspec", then add `lita: true` to the metadata for an example group.
``` ruby
require "lita/rspec"
-describe Lita::Handlers::MyHandler, lita_handler: true do
+describe Lita::Adapters::MyAdapter, lita: true do
# ...
end
```
-This provides the following:
+This will have the following effects:
* All Redis interaction will be namespaced to a test environment and automatically cleared out before each example.
* Lita's logger is stubbed to prevent log messages from cluttering up your test output.
* Lita's configuration is cleared out before each example, so that the first call to `Lita.config` will start from the default configuration.
+
+### Testing handlers
+
+To include Lita's RSpec extras for testing a handler, require "lita/rspec", then add `lita_handler: true` to the metadata for the example group.
+
+``` ruby
+require "lita/rspec"
+
+describe Lita::Handlers::MyHandler, lita_handler: true do
+ # ...
+end
+```
+
+This will have the following effects, in addition to the effects of the `lita: true` metadata hook:
+
* `Lita.handlers` will return an array with only the class you're testing (`described_class`).
* Strings sent with `Lita::Robot#send_messages` will be pushed to an array accessible as `replies` so you can make expectations about output from the robot.
* You have access to the following cached objects set with `let`: `robot`, `source`, and `user`. Note that these objects are instances of the real classes and not test doubles.
-The custom helper methods are where `Lita::RSpec` really shines. You can test routes (both chat and HTTP routes) very easily using this syntax:
+The custom helper methods are where `Lita::RSpec` really shines. You can test routes (both chat and HTTP routes) and event subscriptions very easily using this syntax:
+#### Testing routes
+
``` ruby
it { routes("some message").to(:some_method) }
it { routes_command("directed message").to(:some_command_method) }
it { doesnt_route("message").to(:some_command_method) }
it { routes_http(:get, "/foo/bar").to(:baz) }
it { doesnt_route_http(:post, "/foo/bar").to(:baz) }
+it { routes_event(:connected).to(:greet) }
+it { doesnt_route_event(:some_other_event).to(:greet) }
```
* `routes` - Sets an expectation that the given string will trigger the given method when overheard by the robot.
* `routes_command` - Sets an expectation that the given string will trigger the given method when directed at the robot, either in a private message, or by prefixing a message in a chat room with the robot's mention name.
* `doesnt_route` - Sets an expectation that is the inverse of the one set by `routes`. Also aliased to `does_not_route`.
* `doesnt_route_command` - Sets an expectation that is the inverse of the one set by `routes_command`. Also aliased to `does_not_route_command`.
* `routes_http` - Sets an expectation that an HTTP request with the given HTTP method and path will route to the given handler method.
* `doesnt_route_http` - Sets an expectation that is the inverse of `routes_http`. Also aliased to `does_not_route_http`.
+* `routes_event` - Sets an expectation that the given event will trigger the given subscribed method.
+* `doesnt_route_event` - Sets an expectation that is the inverse of `routes_event`. Also aliased to `does_not_route_event`.
**Note: These routing helpers bypass authorization for routes restricted to authorization groups.**
+#### Testing handler methods
+
+Since the behavior in handlers are regular instance methods, you can unit test them just as you would any other methods in a Ruby class. However, if you prefer a more integration test approach, there are some helper methods available to help with this.
+
To send a message to the robot, use `send_message` and `send_command`. Then set expectations about the contents of the `replies` array.
``` ruby
it "lets everyone know when someone is happy" do
send_message("I'm happy!")
@@ -384,17 +431,9 @@
end
```
* `send_message(string, as: user)` - Sends the given string to the robot.
* `send_command(string, as: user)` - Sends the given string to the robot, prefixing it with the robot's mention name.
-
-### Testing adapters or other code
-
-If you use `lita: true` instead of `lita_handler: true` in the metadata for your example group, only a small subset of Lita's RSpec extras will be enabled:
-
-* All Redis interaction will be namespaced to a test environment and automatically cleared out before each example.
-* Lita's logger is stubbed to prevent log messages from cluttering up your test output.
-* Lita's configuration is cleared out before each example, so that the first call to `Lita.config` will start from the default configuration.
## Running as a daemon
Lita has built-in support for daemonization on Unix systems. When run as a daemon, Lita will redirect standard output and standard error to a log file, and write the process ID to a PID file. To start Lita as a daemon, run `lita -d`. There are additional command line flags for specifying the path of the log and PID files, which override the defaults. If an existing Lita process is running when `lita -d` is invoked, Lita will abort and leave the original process running, unless the `-k` flag is specified, in which case it will kill the existing process. Run `lita help` for information about all the possible command line flags.