lita 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.travis.yml +6 -0
- data/Gemfile +3 -0
- data/README.md +77 -0
- data/Rakefile +1 -0
- data/bin/lita +6 -0
- data/lib/lita.rb +57 -0
- data/lib/lita/adapter.rb +40 -0
- data/lib/lita/adapters/shell.rb +23 -0
- data/lib/lita/cli.rb +24 -0
- data/lib/lita/config.rb +41 -0
- data/lib/lita/errors.rb +6 -0
- data/lib/lita/handler.rb +73 -0
- data/lib/lita/message.rb +37 -0
- data/lib/lita/robot.rb +36 -0
- data/lib/lita/rspec.rb +51 -0
- data/lib/lita/source.rb +10 -0
- data/lib/lita/version.rb +3 -0
- data/lita.gemspec +29 -0
- data/skeleton/Gemfile +9 -0
- data/skeleton/lita_config.rb +20 -0
- data/spec/lita/adapter_spec.rb +29 -0
- data/spec/lita/adapters/shell_spec.rb +27 -0
- data/spec/lita/config_spec.rb +47 -0
- data/spec/lita/handler_spec.rb +110 -0
- data/spec/lita/message_spec.rb +62 -0
- data/spec/lita/robot_spec.rb +42 -0
- data/spec/lita/rspec_spec.rb +23 -0
- data/spec/lita/source_spec.rb +13 -0
- data/spec/lita_spec.rb +52 -0
- data/spec/spec_helper.rb +10 -0
- metadata +185 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b75112b772520840f9fa41dd68bd92950b4e6714
|
4
|
+
data.tar.gz: 567d841b587ec14f27a958a27081c384ca0a2c3f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5fc9e89ef72af2fd35c8b859baa2c67fec936cfc4faf899bf413ae4f5bf2abda4b2bcb1087b83228f7fdd73008743b2f3e5f99fddfc8a81b709a9e21ebbb8946
|
7
|
+
data.tar.gz: 0ec04ae916a4adfdce35b6f9761a7a8634bdf3e511921ba8486e82081c73fb4da0f6848bb0accaa94d3cd1eee443bb2618c5d9976dedfc84d533caa221cf9f3e
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
# Lita
|
2
|
+
|
3
|
+
[![Build Status](https://travis-ci.org/jimmycuadra/lita.png)](https://travis-ci.org/jimmycuadra/lita)
|
4
|
+
[![Code Climate](https://codeclimate.com/github/jimmycuadra/lita.png)](https://codeclimate.com/github/jimmycuadra/lita)
|
5
|
+
[![Coverage Status](https://coveralls.io/repos/jimmycuadra/lita/badge.png)](https://coveralls.io/r/jimmycuadra/lita)
|
6
|
+
|
7
|
+
**Lita** is a chat bot written in Ruby with persistent storage provided by [Redis](http://redis.io/). It can connect to any chat service (given that there is an [adapter](#adapters) available for it) and can have new behavior added via [handlers](#handlers). The plugin system is managed with regular RubyGems and [Bundler](http://gembundler.com/).
|
8
|
+
|
9
|
+
Automate your business and have fun with your very own robot companion.
|
10
|
+
|
11
|
+
## Dependencies
|
12
|
+
|
13
|
+
* Ruby 2.0
|
14
|
+
* Redis
|
15
|
+
|
16
|
+
## Installation
|
17
|
+
|
18
|
+
First, install the gem with `gem install lita`. This gives you access to the `lita` commmand. Run `lita help` to list available tasks.
|
19
|
+
|
20
|
+
Generate a new Lita instance by running `lita new NAME`. This will create a new directory called NAME (defaults to "lita") with a Gemfile and Lita configuration file.
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
To start your Lita instance, simply run `bundle exec lita`. This will load up all the plugins (adapters and handlers) declared in your Gemfile, load any configuration you've defined (more on that later) and start the bot.
|
25
|
+
|
26
|
+
## Adapters
|
27
|
+
|
28
|
+
The core Lita gem by itself doesn't do much. To make real use of it, you'll want to install an adapter gem to allow Lita to connect to the chat service of your choice. Find the gem for the service you want to use on [the list of adapters](https://github.com/jimmycuadra/lita/wiki/Adapters), then add it to your Gemfile. For example:
|
29
|
+
|
30
|
+
``` ruby
|
31
|
+
gem "lita-hipchat"
|
32
|
+
```
|
33
|
+
|
34
|
+
Adapters will likely require some configuration to be able to connect. See the documentation for the adapter for details.
|
35
|
+
|
36
|
+
Without installing an adapter, you can use the default shell adapter to chat with Lita in your terminal. Lita doesn't respond to any messages by default, however, so you'll want to add some new behavior to Lita via handlers.
|
37
|
+
|
38
|
+
## Handlers
|
39
|
+
|
40
|
+
Handlers are gems that add new behavior to Lita. They are responsible for listening for incoming messages and responding to them appropriately. Find the handler gems you want for your bot on [the list of handlers](https://github.com/jimmycuadra/lita/wiki/Handlers), then add them to your Gemfile. For example:
|
41
|
+
|
42
|
+
``` ruby
|
43
|
+
gem "lita-karma"
|
44
|
+
```
|
45
|
+
|
46
|
+
## Configuration
|
47
|
+
|
48
|
+
To configure Lita, edit the file `lita_config.rb` generated by the `lita new` command. This is just a plain Ruby file that will be evaluated when the bot is starting up. A Lita config file looks something like this:
|
49
|
+
|
50
|
+
``` ruby
|
51
|
+
Lita.configure do |config|
|
52
|
+
config.robot.name = "Sir Bottington"
|
53
|
+
config.robot.adapter = :example_chat_service
|
54
|
+
config.adapter.username = "bottington"
|
55
|
+
config.adapter.password = "secret"
|
56
|
+
config.redis.host = "redis.example.com"
|
57
|
+
config.handlers.karma.rate_limit = 300
|
58
|
+
config.handlers.google_images.safe_search = false
|
59
|
+
end
|
60
|
+
```
|
61
|
+
|
62
|
+
The main config objects are:
|
63
|
+
|
64
|
+
* robot: General settings for Lita.
|
65
|
+
* name: The name the bot will use on the chat service.
|
66
|
+
* adapter: A symbol or string indicating the adapter to load.
|
67
|
+
* adapter: Options for the chosen adapter. See the adapter's documentation.
|
68
|
+
* redis: Options for the Redis connection. See the [Redis gem](https://github.com/redis/redis-rb) documentation.
|
69
|
+
* handlers: Handlers may choose to expose a config object here with their own options. See the handler's documentation.
|
70
|
+
|
71
|
+
## Acknowledgements
|
72
|
+
|
73
|
+
Lita draws much inspiration from GitHub's fantastic [Hubot](http://hubot.github.com/).
|
74
|
+
|
75
|
+
## License
|
76
|
+
|
77
|
+
[MIT](http://opensource.org/licenses/MIT)
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/lita
ADDED
data/lib/lita.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
require "set"
|
3
|
+
require "shellwords"
|
4
|
+
|
5
|
+
require "redis-namespace"
|
6
|
+
|
7
|
+
module Lita
|
8
|
+
REDIS_NAMESPACE = "lita"
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def adapters
|
12
|
+
@adapters ||= {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def register_adapter(key, adapter)
|
16
|
+
adapters[key.to_sym] = adapter
|
17
|
+
end
|
18
|
+
|
19
|
+
def handlers
|
20
|
+
@handlers ||= Set.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def register_handler(handler)
|
24
|
+
handlers << handler
|
25
|
+
end
|
26
|
+
|
27
|
+
def config
|
28
|
+
@config ||= Config.default_config
|
29
|
+
end
|
30
|
+
|
31
|
+
def configure
|
32
|
+
yield config
|
33
|
+
end
|
34
|
+
|
35
|
+
def redis
|
36
|
+
@redis ||= begin
|
37
|
+
redis = Redis.new(config.redis)
|
38
|
+
Redis::Namespace.new(REDIS_NAMESPACE, redis: redis)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def run
|
43
|
+
Config.load_user_config
|
44
|
+
Robot.new.run
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
require "lita/version"
|
50
|
+
require "lita/errors"
|
51
|
+
require "lita/config"
|
52
|
+
require "lita/source"
|
53
|
+
require "lita/message"
|
54
|
+
require "lita/robot"
|
55
|
+
require "lita/adapter"
|
56
|
+
require "lita/adapters/shell"
|
57
|
+
require "lita/handler"
|
data/lib/lita/adapter.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
module Lita
|
2
|
+
class Adapter
|
3
|
+
attr_reader :robot
|
4
|
+
|
5
|
+
class << self
|
6
|
+
attr_reader :required_configs
|
7
|
+
|
8
|
+
def require_config(*keys)
|
9
|
+
@required_configs ||= []
|
10
|
+
@required_configs.concat(keys.flatten.map(&:to_sym))
|
11
|
+
end
|
12
|
+
|
13
|
+
alias_method :require_configs, :require_config
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(robot)
|
17
|
+
@robot = robot
|
18
|
+
ensure_required_configs
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def ensure_required_configs
|
24
|
+
required_configs = self.class.required_configs
|
25
|
+
return if required_configs.nil?
|
26
|
+
|
27
|
+
missing_keys = []
|
28
|
+
|
29
|
+
required_configs.each do |key|
|
30
|
+
missing_keys << key unless Lita.config.adapter[key]
|
31
|
+
end
|
32
|
+
|
33
|
+
unless missing_keys.empty?
|
34
|
+
raise Lita::ConfigError.new(
|
35
|
+
"The following keys are required on config.adapter: #{missing_keys.join(", ")}"
|
36
|
+
)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Lita
|
2
|
+
module Adapters
|
3
|
+
class Shell < Adapter
|
4
|
+
def run
|
5
|
+
puts 'Type "exit" or "quit" to end the session.'
|
6
|
+
loop do
|
7
|
+
print "#{robot.name} > "
|
8
|
+
input = gets.chomp.strip
|
9
|
+
break if input == "exit" || input == "quit"
|
10
|
+
source = Source.new("Shell User")
|
11
|
+
message = Message.new(robot, input, source)
|
12
|
+
robot.receive(message)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def send_messages(target, *strings)
|
17
|
+
puts *strings
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
Lita.register_adapter(:shell, Shell)
|
22
|
+
end
|
23
|
+
end
|
data/lib/lita/cli.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require "thor"
|
2
|
+
|
3
|
+
module Lita
|
4
|
+
class CLI < Thor
|
5
|
+
include Thor::Actions
|
6
|
+
|
7
|
+
def self.source_root
|
8
|
+
File.expand_path("../../..", __FILE__)
|
9
|
+
end
|
10
|
+
|
11
|
+
default_task :start
|
12
|
+
|
13
|
+
desc "start", "Starts Lita"
|
14
|
+
def start
|
15
|
+
Bundler.require
|
16
|
+
Lita.run
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "new NAME", "Generates a new Lita project (default name: lita)"
|
20
|
+
def new(name = "lita")
|
21
|
+
directory "skeleton", name
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/lita/config.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
module Lita
|
2
|
+
class Config < Hash
|
3
|
+
def self.default_config
|
4
|
+
new.tap do |c|
|
5
|
+
c.robot = new
|
6
|
+
c.robot.name = "Lita"
|
7
|
+
c.robot.adapter = :shell
|
8
|
+
c.redis = new
|
9
|
+
c.adapter = new
|
10
|
+
c.handlers = new
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.load_user_config
|
15
|
+
config_path = File.expand_path("lita_config.rb", Dir.pwd)
|
16
|
+
|
17
|
+
begin
|
18
|
+
load(config_path)
|
19
|
+
rescue Exception
|
20
|
+
raise ConfigError
|
21
|
+
end if File.exist?(config_path)
|
22
|
+
end
|
23
|
+
|
24
|
+
def []=(key, value)
|
25
|
+
super(key.to_sym, value)
|
26
|
+
end
|
27
|
+
|
28
|
+
def [](key)
|
29
|
+
super(key.to_sym)
|
30
|
+
end
|
31
|
+
|
32
|
+
def method_missing(name, *args)
|
33
|
+
name_string = name.to_s
|
34
|
+
if name_string.chomp!("=")
|
35
|
+
self[name_string] = args.first
|
36
|
+
else
|
37
|
+
self[name_string]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/lita/errors.rb
ADDED
data/lib/lita/handler.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
module Lita
|
2
|
+
class Handler
|
3
|
+
extend Forwardable
|
4
|
+
|
5
|
+
attr_reader :redis
|
6
|
+
private :redis
|
7
|
+
|
8
|
+
def_delegators :@message, :args, :command?, :scan
|
9
|
+
|
10
|
+
class Route < Struct.new(:pattern, :method_name, :command)
|
11
|
+
alias_method :command?, :command
|
12
|
+
end
|
13
|
+
|
14
|
+
class << self
|
15
|
+
def route(pattern, to: nil, command: false)
|
16
|
+
@routes ||= []
|
17
|
+
@routes << Route.new(pattern, to, command)
|
18
|
+
end
|
19
|
+
|
20
|
+
def dispatch(robot, message)
|
21
|
+
instance = new(robot, message)
|
22
|
+
|
23
|
+
@routes.each do |route|
|
24
|
+
if route_applies?(route, instance)
|
25
|
+
instance.public_send(
|
26
|
+
route.method_name,
|
27
|
+
matches_for_route(route, instance)
|
28
|
+
)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def route_applies?(route, instance)
|
36
|
+
if route.pattern === instance.message_body
|
37
|
+
if route.command?
|
38
|
+
return instance.command?
|
39
|
+
else
|
40
|
+
return true
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
false
|
45
|
+
end
|
46
|
+
|
47
|
+
def matches_for_route(route, instance)
|
48
|
+
instance.scan(route.pattern)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def initialize(robot, message)
|
53
|
+
@robot = robot
|
54
|
+
@message = message
|
55
|
+
@redis = Redis::Namespace.new(redis_namespace, redis: Lita.redis)
|
56
|
+
end
|
57
|
+
|
58
|
+
def reply(*strings)
|
59
|
+
@robot.send_messages(@message.source, *strings)
|
60
|
+
end
|
61
|
+
|
62
|
+
def message_body
|
63
|
+
@message.body
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def redis_namespace
|
69
|
+
name = self.class.name.split("::").last.downcase
|
70
|
+
"handlers:#{name}"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/lib/lita/message.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
module Lita
|
2
|
+
class Message
|
3
|
+
extend Forwardable
|
4
|
+
|
5
|
+
attr_reader :body, :source
|
6
|
+
alias_method :message, :body
|
7
|
+
|
8
|
+
def_delegators :@body, :scan
|
9
|
+
|
10
|
+
def initialize(robot, body, source)
|
11
|
+
@robot = robot
|
12
|
+
@body = body
|
13
|
+
@source = source
|
14
|
+
|
15
|
+
@command = !!@body.sub!(/^\s*@?#{@robot.name}[:,]?\s*/, "")
|
16
|
+
end
|
17
|
+
|
18
|
+
def args
|
19
|
+
begin
|
20
|
+
command, *args = message.shellsplit
|
21
|
+
rescue ArgumentError
|
22
|
+
command, *args =
|
23
|
+
message.split(/\s+/).map(&:shellescape).join(" ").shellsplit
|
24
|
+
end
|
25
|
+
|
26
|
+
args
|
27
|
+
end
|
28
|
+
|
29
|
+
def command!
|
30
|
+
@command = true
|
31
|
+
end
|
32
|
+
|
33
|
+
def command?
|
34
|
+
@command
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/lita/robot.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
module Lita
|
2
|
+
class Robot
|
3
|
+
attr_reader :name
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@name = Lita.config.robot.name
|
7
|
+
load_adapter
|
8
|
+
end
|
9
|
+
|
10
|
+
def receive(message)
|
11
|
+
Lita.handlers.each { |handler| handler.dispatch(self, message) }
|
12
|
+
end
|
13
|
+
|
14
|
+
def run
|
15
|
+
@adapter.run
|
16
|
+
end
|
17
|
+
|
18
|
+
def send_messages(target, *strings)
|
19
|
+
@adapter.send_messages(target, strings.flatten)
|
20
|
+
end
|
21
|
+
alias_method :send_message, :send_messages
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def load_adapter
|
26
|
+
adapter_name = Lita.config.robot.adapter
|
27
|
+
adapter_class = Lita.adapters[adapter_name.to_sym]
|
28
|
+
|
29
|
+
unless adapter_class
|
30
|
+
raise UnknownAdapterError.new("Unknown adapter: :#{adapter_name}")
|
31
|
+
end
|
32
|
+
|
33
|
+
@adapter = adapter_class.new(self)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/lita/rspec.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
module Lita
|
2
|
+
module RSpec
|
3
|
+
def self.included(base)
|
4
|
+
base.class_eval do
|
5
|
+
let(:robot) { Robot.new }
|
6
|
+
|
7
|
+
before do
|
8
|
+
allow(Lita).to receive(:handlers).and_return([described_class])
|
9
|
+
stub_const("Lita::REDIS_NAMESPACE", "lita.test")
|
10
|
+
keys = Lita.redis.keys("*")
|
11
|
+
Lita.redis.del(keys) unless keys.empty?
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def send_test_message(body)
|
17
|
+
source = Source.new("Test User")
|
18
|
+
message = Message.new(robot, body, source)
|
19
|
+
robot.receive(message)
|
20
|
+
end
|
21
|
+
|
22
|
+
def routes(message)
|
23
|
+
RouteMatcher.new(self, message)
|
24
|
+
end
|
25
|
+
|
26
|
+
def does_not_route(message)
|
27
|
+
RouteMatcher.new(self, message, invert: true)
|
28
|
+
end
|
29
|
+
alias_method :doesnt_route, :does_not_route
|
30
|
+
end
|
31
|
+
|
32
|
+
class RouteMatcher
|
33
|
+
def initialize(context, message_body, invert: false)
|
34
|
+
@context = context
|
35
|
+
@message_body = message_body
|
36
|
+
@method = invert ? :not_to : :to
|
37
|
+
end
|
38
|
+
|
39
|
+
def to(route)
|
40
|
+
@context.expect_any_instance_of(
|
41
|
+
@context.described_class
|
42
|
+
).public_send(@method, @context.receive(route))
|
43
|
+
|
44
|
+
@context.send_test_message(@message_body)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
RSpec.configure do |config|
|
50
|
+
config.include Lita::RSpec, lita_handler: true
|
51
|
+
end
|
data/lib/lita/source.rb
ADDED
data/lib/lita/version.rb
ADDED
data/lita.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "lita/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "lita"
|
8
|
+
spec.version = Lita::VERSION
|
9
|
+
spec.authors = ["Jimmy Cuadra"]
|
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.}
|
13
|
+
spec.homepage = "https://github.com/jimmycuadra/lita"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_runtime_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_runtime_dependency "redis-namespace", "~> 1.3.0"
|
23
|
+
spec.add_runtime_dependency "thor", "~> 0.18.1"
|
24
|
+
|
25
|
+
spec.add_development_dependency "rake"
|
26
|
+
spec.add_development_dependency "rspec", ">= 2.14.0rc1"
|
27
|
+
spec.add_development_dependency "simplecov"
|
28
|
+
spec.add_development_dependency "coveralls"
|
29
|
+
end
|
data/skeleton/Gemfile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Lita.configure do |config|
|
2
|
+
# The name your robot will use.
|
3
|
+
config.robot.name = "Lita"
|
4
|
+
|
5
|
+
# The adapter you want to connect with. Make sure you've added the
|
6
|
+
# appropriate gem to the Gemfile.
|
7
|
+
config.robot.adapter = :shell
|
8
|
+
|
9
|
+
## Example: Set options for the chosen adapter.
|
10
|
+
# config.adapter.username = "myname"
|
11
|
+
# config.adapter.password = "secret"
|
12
|
+
|
13
|
+
## Example: Set options for the Redis connection.
|
14
|
+
# config.redis.host = "127.0.0.1"
|
15
|
+
# config.redis.port = 1234
|
16
|
+
|
17
|
+
## Example: Set configuration for any loaded handlers. See the handler's
|
18
|
+
## documentation for options.
|
19
|
+
# config.handlers.some_handler.some_config_key = "value"
|
20
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Lita::Adapter do
|
4
|
+
let(:robot) { double("Robot") }
|
5
|
+
|
6
|
+
subject { described_class.new(robot) }
|
7
|
+
|
8
|
+
it "stores a Robot" do
|
9
|
+
expect(subject.robot).to eql(robot)
|
10
|
+
end
|
11
|
+
|
12
|
+
describe ".require_config" do
|
13
|
+
let(:adapter_class) do
|
14
|
+
Class.new(described_class) do
|
15
|
+
require_config :foo
|
16
|
+
require_configs :bar, :baz
|
17
|
+
require_configs ["blah", :bleh]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
subject { adapter_class.new(robot) }
|
22
|
+
|
23
|
+
it "ensures that config keys are present on initialization" do
|
24
|
+
expect do
|
25
|
+
subject
|
26
|
+
end.to raise_error(Lita::ConfigError, /foo, bar, baz, blah, bleh/)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
describe Lita::Adapters::Shell do
|
2
|
+
let(:robot) do
|
3
|
+
robot = double("Robot")
|
4
|
+
allow(robot).to receive(:name).and_return("Lita")
|
5
|
+
robot
|
6
|
+
end
|
7
|
+
|
8
|
+
subject { described_class.new(robot) }
|
9
|
+
|
10
|
+
describe "#run" do
|
11
|
+
before { allow(subject).to receive(:puts) }
|
12
|
+
|
13
|
+
it "passes input to the Robot and breaks on an exit message" do
|
14
|
+
expect(subject).to receive(:print).with("#{robot.name} > ").twice
|
15
|
+
allow(subject).to receive(:gets).and_return("foo", "exit")
|
16
|
+
expect(robot).to receive(:receive).with(an_instance_of(Lita::Message))
|
17
|
+
subject.run
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#send_message" do
|
22
|
+
it "prints its input" do
|
23
|
+
expect(subject).to receive(:puts).with("bar")
|
24
|
+
subject.send_messages(double("target"), "bar")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Lita::Config do
|
4
|
+
let(:value) { double("arbitrary config key's value") }
|
5
|
+
|
6
|
+
it "allows hash-style access with symbols or strings" do
|
7
|
+
subject[:foo] = value
|
8
|
+
expect(subject[:foo]).to eql(value)
|
9
|
+
expect(subject["foo"]).to eql(value)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "allows struct-style access" do
|
13
|
+
subject.foo = value
|
14
|
+
expect(subject.foo).to eql(value)
|
15
|
+
end
|
16
|
+
|
17
|
+
describe ".default_config" do
|
18
|
+
it "has predefined values for certain keys" do
|
19
|
+
expect(described_class.default_config.robot.name).to eq("Lita")
|
20
|
+
expect(described_class.default_config.robot.adapter).to eq(:shell)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe ".load_user_config" do
|
25
|
+
it "loads and evals lita_config.rb" do
|
26
|
+
allow(File).to receive(:exist?).and_return(true)
|
27
|
+
allow(described_class).to receive(:load) do
|
28
|
+
Lita.configure { |config| config.robot.name = "Not Lita" }
|
29
|
+
end
|
30
|
+
described_class.load_user_config
|
31
|
+
expect(Lita.config.robot.name).to eq("Not Lita")
|
32
|
+
end
|
33
|
+
|
34
|
+
it "doesn't attempt to load lita_config.rb if it doesn't exist" do
|
35
|
+
expect(described_class).not_to receive(:load)
|
36
|
+
described_class.load_user_config
|
37
|
+
end
|
38
|
+
|
39
|
+
it "raises an exception if lita_config.rb raises an exception" do
|
40
|
+
allow(File).to receive(:exist?).and_return(true)
|
41
|
+
allow(described_class).to receive(:load) { Lita.non_existent_method }
|
42
|
+
expect do
|
43
|
+
described_class.load_user_config
|
44
|
+
end.to raise_error(Lita::ConfigError)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Lita::Handler do
|
4
|
+
let(:robot) do
|
5
|
+
robot = double("Robot")
|
6
|
+
allow(robot).to receive(:name).and_return("Lita")
|
7
|
+
robot
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:message) do
|
11
|
+
message = double("Message")
|
12
|
+
allow(message).to receive(:scan).and_return(matches)
|
13
|
+
allow(message).to receive(:command?).and_return(false)
|
14
|
+
allow(message).to receive(:source).and_return(source)
|
15
|
+
message
|
16
|
+
end
|
17
|
+
|
18
|
+
let(:matches) { double("MatchData") }
|
19
|
+
|
20
|
+
let(:source) { double("Source") }
|
21
|
+
|
22
|
+
let(:handler_class) do
|
23
|
+
Class.new(described_class) do
|
24
|
+
route(/\w{3}/, to: :foo)
|
25
|
+
route(/\w{4}/, to: :blah, command: true)
|
26
|
+
|
27
|
+
def foo(matches)
|
28
|
+
end
|
29
|
+
|
30
|
+
def blah(matches)
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.name
|
34
|
+
"Lita::Handlers::Test"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
subject { described_class.new(robot, message) }
|
40
|
+
|
41
|
+
describe ".dispatch" do
|
42
|
+
it "routes a matching message to the supplied method" do
|
43
|
+
allow(message).to receive(:body).and_return("bar")
|
44
|
+
expect_any_instance_of(handler_class).to receive(:foo)
|
45
|
+
handler_class.dispatch(robot, message)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "routes a matching message even if addressed to the Robot" do
|
49
|
+
allow(message).to receive(:body).and_return("#{robot.name}: bar")
|
50
|
+
allow(message).to receive(:command?).and_return(true)
|
51
|
+
expect_any_instance_of(handler_class).to receive(:foo)
|
52
|
+
handler_class.dispatch(robot, message)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "routes a command message to the supplied method" do
|
56
|
+
allow(message).to receive(:body).and_return("#{robot.name}: bar")
|
57
|
+
allow(message).to receive(:command?).and_return(true)
|
58
|
+
expect_any_instance_of(handler_class).to receive(:blah)
|
59
|
+
handler_class.dispatch(robot, message)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "requires command routes to be addressed to the Robot" do
|
63
|
+
allow(message).to receive(:body).and_return("blah")
|
64
|
+
expect_any_instance_of(handler_class).not_to receive(:blah)
|
65
|
+
handler_class.dispatch(robot, message)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "doesn't route messages that don't match anything" do
|
69
|
+
allow(message).to receive(:body).and_return("yo")
|
70
|
+
expect_any_instance_of(handler_class).not_to receive(:foo)
|
71
|
+
expect_any_instance_of(handler_class).not_to receive(:blah)
|
72
|
+
handler_class.dispatch(robot, message)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "#args" do
|
77
|
+
it "delegates to Message" do
|
78
|
+
expect(message).to receive(:args)
|
79
|
+
subject.args
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "#command?" do
|
84
|
+
it "delegates to Message" do
|
85
|
+
expect(message).to receive(:command?)
|
86
|
+
subject.command?
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "#message_body" do
|
91
|
+
it "delegates to Message" do
|
92
|
+
expect(message).to receive(:body)
|
93
|
+
subject.message_body
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe "#reply" do
|
98
|
+
it "calls Robot#send_message with the messages to send" do
|
99
|
+
expect(robot).to receive(:send_messages).with(source, "foo", "bar")
|
100
|
+
subject.reply("foo", "bar")
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe "#scan" do
|
105
|
+
it "delegates to Message" do
|
106
|
+
expect(message).to receive(:scan)
|
107
|
+
subject.scan
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Lita::Message do
|
4
|
+
let(:robot) do
|
5
|
+
robot = double("Robot")
|
6
|
+
allow(robot).to receive(:name).and_return("Lita")
|
7
|
+
robot
|
8
|
+
end
|
9
|
+
|
10
|
+
subject do
|
11
|
+
described_class.new(robot, "Hello", "Carl")
|
12
|
+
end
|
13
|
+
|
14
|
+
it "has a body" do
|
15
|
+
expect(subject.body).to eq("Hello")
|
16
|
+
end
|
17
|
+
|
18
|
+
it "aliases #body with #message" do
|
19
|
+
expect(subject.message).to eq("Hello")
|
20
|
+
end
|
21
|
+
|
22
|
+
it "has a source" do
|
23
|
+
expect(subject.source).to eq("Carl")
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#args" do
|
27
|
+
it "returns an array of the 2nd through nth word in the message" do
|
28
|
+
subject = described_class.new(robot, "args foo bar", "Carl")
|
29
|
+
expect(subject.args).to eq(["foo", "bar"])
|
30
|
+
end
|
31
|
+
|
32
|
+
it "escapes messages that have mismatched quotes" do
|
33
|
+
subject = described_class.new(robot, "args it's working", "Carl")
|
34
|
+
expect(subject.args).to eq(["it's", "working"])
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#command!" do
|
39
|
+
it "marks a message as a command" do
|
40
|
+
subject.command!
|
41
|
+
expect(subject).to be_a_command
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "#command?" do
|
46
|
+
it "is true when the message is addressed to the Robot" do
|
47
|
+
subject = described_class.new(robot, "#{robot.name}: hello", "Carl")
|
48
|
+
expect(subject).to be_a_command
|
49
|
+
end
|
50
|
+
|
51
|
+
it "is false when the message is not addressed to the Robot" do
|
52
|
+
expect(subject).not_to be_a_command
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "#scan" do
|
57
|
+
it "delegates to #body" do
|
58
|
+
expect(subject.body).to receive(:scan)
|
59
|
+
subject.scan
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Lita::Robot do
|
4
|
+
it "raises an exception if the specified adapter can't be found" do
|
5
|
+
adapter_registry = double("adapter_registry")
|
6
|
+
allow(Lita).to receive(:adapters).and_return(adapter_registry)
|
7
|
+
allow(adapter_registry).to receive(:[]).and_return(nil)
|
8
|
+
expect { subject }.to raise_error(Lita::UnknownAdapterError)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "#receive" do
|
12
|
+
let(:handler1) { double("Handler 1") }
|
13
|
+
let(:handler2) { double("Handler 2") }
|
14
|
+
|
15
|
+
it "dispatches messages to every registered handler" do
|
16
|
+
allow(Lita).to receive(:handlers).and_return([handler1, handler2])
|
17
|
+
expect(handler1).to receive(:dispatch).with(subject, "foo")
|
18
|
+
expect(handler2).to receive(:dispatch).with(subject, "foo")
|
19
|
+
subject.receive("foo")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "#run" do
|
24
|
+
it "starts the adapter" do
|
25
|
+
expect_any_instance_of(Lita::Adapters::Shell).to receive(:run)
|
26
|
+
subject.run
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#send_message" do
|
31
|
+
let(:message) { double("Message") }
|
32
|
+
|
33
|
+
it "delegates to the adapter" do
|
34
|
+
expect_any_instance_of(
|
35
|
+
Lita::Adapters::Shell
|
36
|
+
).to receive(:send_messages).with(
|
37
|
+
message, ["foo", "bar"]
|
38
|
+
)
|
39
|
+
subject.send_messages(message, "foo", "bar")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
handler_class = Class.new(Lita::Handler) do
|
4
|
+
route(/\w{3}/, to: :foo)
|
5
|
+
route(/\w{4}/, to: :blah, command: true)
|
6
|
+
|
7
|
+
def foo(matches)
|
8
|
+
end
|
9
|
+
|
10
|
+
def blah(matches)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.name
|
14
|
+
"Lita::Handlers::Test"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe handler_class, lita_handler: true do
|
19
|
+
it { routes("foo").to(:foo) }
|
20
|
+
it { routes("#{robot.name}: blah").to(:blah) }
|
21
|
+
it { doesnt_route("blah").to(:blah) }
|
22
|
+
it { does_not_route("blah").to(:blah) }
|
23
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Lita::Source do
|
4
|
+
it "has a user" do
|
5
|
+
subject = described_class.new("Carl")
|
6
|
+
expect(subject.user).to eq("Carl")
|
7
|
+
end
|
8
|
+
|
9
|
+
it "has a room" do
|
10
|
+
subject = described_class.new("Carl", "#litabot")
|
11
|
+
expect(subject.room).to eq("#litabot")
|
12
|
+
end
|
13
|
+
end
|
data/spec/lita_spec.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Lita do
|
4
|
+
it "memoizes a hash of Adapters" do
|
5
|
+
adapter_class = double("Adapter")
|
6
|
+
described_class.register_adapter(:foo, adapter_class)
|
7
|
+
expect(described_class.adapters[:foo]).to eql(adapter_class)
|
8
|
+
expect(described_class.adapters).to eql(described_class.adapters)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "memoizes a set of Handlers" do
|
12
|
+
handler_class = double("Handler")
|
13
|
+
described_class.register_handler(handler_class)
|
14
|
+
described_class.register_handler(handler_class)
|
15
|
+
expect(described_class.handlers.to_a).to eq([handler_class])
|
16
|
+
expect(described_class.handlers).to eql(described_class.handlers)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "memoizes a Config" do
|
20
|
+
expect(described_class.config).to be_a(Lita::Config)
|
21
|
+
expect(described_class.config).to eql(described_class.config)
|
22
|
+
end
|
23
|
+
|
24
|
+
describe ".configure" do
|
25
|
+
it "yields the Config object" do
|
26
|
+
described_class.configure { |c| c.robot.name = "Not Lita" }
|
27
|
+
expect(described_class.config.robot.name).to eq("Not Lita")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe ".redis" do
|
32
|
+
it "memoizes a Redis::Namespace" do
|
33
|
+
expect(described_class.redis.namespace).to eq(
|
34
|
+
described_class::REDIS_NAMESPACE
|
35
|
+
)
|
36
|
+
expect(described_class.redis).to eql(described_class.redis)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe ".run" do
|
41
|
+
it "laods the user config" do
|
42
|
+
expect(Lita::Config).to receive(:load_user_config)
|
43
|
+
allow_any_instance_of(Lita::Robot).to receive(:run)
|
44
|
+
described_class.run
|
45
|
+
end
|
46
|
+
|
47
|
+
it "runs a new Robot" do
|
48
|
+
expect_any_instance_of(Lita::Robot).to receive(:run)
|
49
|
+
described_class.run
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,185 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: lita
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jimmy Cuadra
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-06-15 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: redis-namespace
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.3.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.3.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: thor
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.18.1
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.18.1
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 2.14.0rc1
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 2.14.0rc1
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: simplecov
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: coveralls
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
description: A multi-service chat bot with extendable behavior.
|
112
|
+
email:
|
113
|
+
- jimmy@jimmycuadra.com
|
114
|
+
executables:
|
115
|
+
- lita
|
116
|
+
extensions: []
|
117
|
+
extra_rdoc_files: []
|
118
|
+
files:
|
119
|
+
- .gitignore
|
120
|
+
- .travis.yml
|
121
|
+
- Gemfile
|
122
|
+
- README.md
|
123
|
+
- Rakefile
|
124
|
+
- bin/lita
|
125
|
+
- lib/lita.rb
|
126
|
+
- lib/lita/adapter.rb
|
127
|
+
- lib/lita/adapters/shell.rb
|
128
|
+
- lib/lita/cli.rb
|
129
|
+
- lib/lita/config.rb
|
130
|
+
- lib/lita/errors.rb
|
131
|
+
- lib/lita/handler.rb
|
132
|
+
- lib/lita/message.rb
|
133
|
+
- lib/lita/robot.rb
|
134
|
+
- lib/lita/rspec.rb
|
135
|
+
- lib/lita/source.rb
|
136
|
+
- lib/lita/version.rb
|
137
|
+
- lita.gemspec
|
138
|
+
- skeleton/Gemfile
|
139
|
+
- skeleton/lita_config.rb
|
140
|
+
- spec/lita/adapter_spec.rb
|
141
|
+
- spec/lita/adapters/shell_spec.rb
|
142
|
+
- spec/lita/config_spec.rb
|
143
|
+
- spec/lita/handler_spec.rb
|
144
|
+
- spec/lita/message_spec.rb
|
145
|
+
- spec/lita/robot_spec.rb
|
146
|
+
- spec/lita/rspec_spec.rb
|
147
|
+
- spec/lita/source_spec.rb
|
148
|
+
- spec/lita_spec.rb
|
149
|
+
- spec/spec_helper.rb
|
150
|
+
homepage: https://github.com/jimmycuadra/lita
|
151
|
+
licenses:
|
152
|
+
- MIT
|
153
|
+
metadata: {}
|
154
|
+
post_install_message:
|
155
|
+
rdoc_options: []
|
156
|
+
require_paths:
|
157
|
+
- lib
|
158
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
159
|
+
requirements:
|
160
|
+
- - '>='
|
161
|
+
- !ruby/object:Gem::Version
|
162
|
+
version: '0'
|
163
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
164
|
+
requirements:
|
165
|
+
- - '>='
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
version: '0'
|
168
|
+
requirements: []
|
169
|
+
rubyforge_project:
|
170
|
+
rubygems_version: 2.0.3
|
171
|
+
signing_key:
|
172
|
+
specification_version: 4
|
173
|
+
summary: A multi-service chat bot with extendable behavior.
|
174
|
+
test_files:
|
175
|
+
- spec/lita/adapter_spec.rb
|
176
|
+
- spec/lita/adapters/shell_spec.rb
|
177
|
+
- spec/lita/config_spec.rb
|
178
|
+
- spec/lita/handler_spec.rb
|
179
|
+
- spec/lita/message_spec.rb
|
180
|
+
- spec/lita/robot_spec.rb
|
181
|
+
- spec/lita/rspec_spec.rb
|
182
|
+
- spec/lita/source_spec.rb
|
183
|
+
- spec/lita_spec.rb
|
184
|
+
- spec/spec_helper.rb
|
185
|
+
has_rdoc:
|