ruboty 1.0.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 +7 -0
- data/.gitignore +22 -0
- data/.travis.yml +9 -0
- data/CHANGELOG.md +73 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +67 -0
- data/Rakefile +5 -0
- data/bin/ruboty +6 -0
- data/images/screenshot.png +0 -0
- data/lib/ruboty/action.rb +48 -0
- data/lib/ruboty/actions/base.rb +11 -0
- data/lib/ruboty/actions/help.rb +27 -0
- data/lib/ruboty/actions/ping.rb +19 -0
- data/lib/ruboty/actions/whoami.rb +9 -0
- data/lib/ruboty/adapter_builder.rb +23 -0
- data/lib/ruboty/adapters/base.rb +21 -0
- data/lib/ruboty/adapters/shell.rb +82 -0
- data/lib/ruboty/brains/base.rb +25 -0
- data/lib/ruboty/brains/memory.rb +9 -0
- data/lib/ruboty/command_builder.rb +30 -0
- data/lib/ruboty/commands/base.rb +11 -0
- data/lib/ruboty/commands/generate.rb +33 -0
- data/lib/ruboty/commands/run.rb +9 -0
- data/lib/ruboty/env/missing_required_key_error.rb +6 -0
- data/lib/ruboty/env/validatable.rb +33 -0
- data/lib/ruboty/env/validation_error.rb +6 -0
- data/lib/ruboty/env.rb +33 -0
- data/lib/ruboty/handlers/base.rb +37 -0
- data/lib/ruboty/handlers/help.rb +11 -0
- data/lib/ruboty/handlers/ping.rb +11 -0
- data/lib/ruboty/handlers/whoami.rb +15 -0
- data/lib/ruboty/logger.rb +10 -0
- data/lib/ruboty/message.rb +47 -0
- data/lib/ruboty/robot.rb +76 -0
- data/lib/ruboty/version.rb +3 -0
- data/lib/ruboty.rb +58 -0
- data/ruboty.gemspec +29 -0
- data/spec/ruboty/adapter_builder_spec.rb +36 -0
- data/spec/ruboty/adapters/shell_spec.rb +56 -0
- data/spec/ruboty/commands/generate_spec.rb +39 -0
- data/spec/ruboty/commands/run_spec.rb +22 -0
- data/spec/ruboty/env/validatable_spec.rb +48 -0
- data/spec/ruboty/handlers/base_spec.rb +28 -0
- data/spec/ruboty/handlers/help_spec.rb +41 -0
- data/spec/ruboty/handlers/ping_spec.rb +40 -0
- data/spec/ruboty/handlers/whoami_spec.rb +36 -0
- data/spec/ruboty/robot_spec.rb +38 -0
- data/spec/spec_helper.rb +16 -0
- data/templates/Gemfile +3 -0
- metadata +246 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
module Ruboty
|
2
|
+
module Handlers
|
3
|
+
class Base
|
4
|
+
class << self
|
5
|
+
include Mem
|
6
|
+
|
7
|
+
def inherited(child)
|
8
|
+
Ruboty.handlers << child
|
9
|
+
end
|
10
|
+
|
11
|
+
def on(pattern, options = {})
|
12
|
+
actions << Action.new(pattern, options)
|
13
|
+
end
|
14
|
+
|
15
|
+
def actions
|
16
|
+
[]
|
17
|
+
end
|
18
|
+
memoize :actions
|
19
|
+
end
|
20
|
+
|
21
|
+
include Env::Validatable
|
22
|
+
|
23
|
+
attr_reader :robot
|
24
|
+
|
25
|
+
def initialize(robot)
|
26
|
+
@robot = robot
|
27
|
+
validate!
|
28
|
+
end
|
29
|
+
|
30
|
+
def call(message)
|
31
|
+
self.class.actions.each do |action|
|
32
|
+
action.call(self, message)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Ruboty
|
2
|
+
class Message
|
3
|
+
attr_reader(
|
4
|
+
:match_data,
|
5
|
+
:original,
|
6
|
+
)
|
7
|
+
|
8
|
+
def initialize(original)
|
9
|
+
@original = original
|
10
|
+
end
|
11
|
+
|
12
|
+
def body
|
13
|
+
@original[:body]
|
14
|
+
end
|
15
|
+
|
16
|
+
def from
|
17
|
+
@original[:from]
|
18
|
+
end
|
19
|
+
|
20
|
+
# @note Some chat service such as XMPP has 2 types of address, address and username
|
21
|
+
# @return [String] User identifier in the Chat service
|
22
|
+
def from_name
|
23
|
+
@original[:from_name] || from
|
24
|
+
end
|
25
|
+
|
26
|
+
def robot
|
27
|
+
@original[:robot]
|
28
|
+
end
|
29
|
+
|
30
|
+
def to
|
31
|
+
@original[:to]
|
32
|
+
end
|
33
|
+
|
34
|
+
def match(pattern)
|
35
|
+
@match_data = pattern.match(body)
|
36
|
+
end
|
37
|
+
|
38
|
+
def [](index)
|
39
|
+
match_data[index]
|
40
|
+
end
|
41
|
+
|
42
|
+
def reply(body, options = {})
|
43
|
+
attributes = { body: body, from: to, to: from, original: original }.merge(options)
|
44
|
+
robot.say(attributes)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/ruboty/robot.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
module Ruboty
|
2
|
+
class Robot
|
3
|
+
DEFAULT_ROBOT_NAME = "ruboty"
|
4
|
+
|
5
|
+
include Mem
|
6
|
+
|
7
|
+
delegate :say, to: :adapter
|
8
|
+
|
9
|
+
attr_reader :options
|
10
|
+
|
11
|
+
def initialize(options = {})
|
12
|
+
@options = options
|
13
|
+
end
|
14
|
+
|
15
|
+
def run
|
16
|
+
dotenv
|
17
|
+
bundle
|
18
|
+
setup
|
19
|
+
remember
|
20
|
+
handle
|
21
|
+
adapt
|
22
|
+
end
|
23
|
+
|
24
|
+
def receive(attributes)
|
25
|
+
message = Message.new(attributes.merge(robot: self))
|
26
|
+
handlers.each do |handler|
|
27
|
+
handler.call(message)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def name
|
32
|
+
ENV["ROBOT_NAME"] || DEFAULT_ROBOT_NAME
|
33
|
+
end
|
34
|
+
|
35
|
+
def brain
|
36
|
+
Brains::Base.find_class.new
|
37
|
+
end
|
38
|
+
memoize :brain
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def adapt
|
43
|
+
adapter.run
|
44
|
+
end
|
45
|
+
|
46
|
+
def adapter
|
47
|
+
AdapterBuilder.new(self).build
|
48
|
+
end
|
49
|
+
memoize :adapter
|
50
|
+
|
51
|
+
def bundle
|
52
|
+
Bundler.require
|
53
|
+
end
|
54
|
+
|
55
|
+
def dotenv
|
56
|
+
Dotenv.load if options[:dotenv]
|
57
|
+
end
|
58
|
+
|
59
|
+
def setup
|
60
|
+
load(options[:load]) if options[:load]
|
61
|
+
end
|
62
|
+
|
63
|
+
def handlers
|
64
|
+
Ruboty.handlers.map {|handler_class| handler_class.new(self) }
|
65
|
+
end
|
66
|
+
memoize :handlers
|
67
|
+
|
68
|
+
def remember
|
69
|
+
brain
|
70
|
+
end
|
71
|
+
|
72
|
+
def handle
|
73
|
+
handlers
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
data/lib/ruboty.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require "active_support/concern"
|
2
|
+
require "active_support/core_ext/module/delegation"
|
3
|
+
require "active_support/core_ext/string/inflections"
|
4
|
+
require "bundler"
|
5
|
+
require "dotenv"
|
6
|
+
require "mem"
|
7
|
+
require "slop"
|
8
|
+
|
9
|
+
module Ruboty
|
10
|
+
class << self
|
11
|
+
include Mem
|
12
|
+
|
13
|
+
def logger
|
14
|
+
@logger ||= Ruboty::Logger.new($stdout)
|
15
|
+
end
|
16
|
+
|
17
|
+
def die(message)
|
18
|
+
logger.error("Error: #{message}")
|
19
|
+
exit(1)
|
20
|
+
end
|
21
|
+
|
22
|
+
def handlers
|
23
|
+
[]
|
24
|
+
end
|
25
|
+
memoize :handlers
|
26
|
+
|
27
|
+
def actions
|
28
|
+
handlers.map(&:actions).flatten.sort_by(&:all?)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
require "ruboty/action"
|
34
|
+
require "ruboty/actions/base"
|
35
|
+
require "ruboty/actions/help"
|
36
|
+
require "ruboty/actions/ping"
|
37
|
+
require "ruboty/actions/whoami"
|
38
|
+
require "ruboty/adapter_builder"
|
39
|
+
require "ruboty/env"
|
40
|
+
require "ruboty/env/missing_required_key_error"
|
41
|
+
require "ruboty/env/validatable"
|
42
|
+
require "ruboty/env/validation_error"
|
43
|
+
require "ruboty/adapters/base"
|
44
|
+
require "ruboty/adapters/shell"
|
45
|
+
require "ruboty/brains/base"
|
46
|
+
require "ruboty/brains/memory"
|
47
|
+
require "ruboty/command_builder"
|
48
|
+
require "ruboty/commands/base"
|
49
|
+
require "ruboty/commands/generate"
|
50
|
+
require "ruboty/commands/run"
|
51
|
+
require "ruboty/handlers/base"
|
52
|
+
require "ruboty/handlers/help"
|
53
|
+
require "ruboty/handlers/ping"
|
54
|
+
require "ruboty/handlers/whoami"
|
55
|
+
require "ruboty/logger"
|
56
|
+
require "ruboty/message"
|
57
|
+
require "ruboty/robot"
|
58
|
+
require "ruboty/version"
|
data/ruboty.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
lib = File.expand_path("../lib", __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require "ruboty/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "ruboty"
|
7
|
+
spec.version = Ruboty::VERSION
|
8
|
+
spec.authors = ["Ryo Nakamura"]
|
9
|
+
spec.email = ["r7kamura@gmail.com"]
|
10
|
+
spec.summary = "Ruby + Bot = Ruboty"
|
11
|
+
spec.homepage = "https://github.com/r7kamura/ruboty"
|
12
|
+
spec.license = "MIT"
|
13
|
+
|
14
|
+
spec.files = `git ls-files -z`.split("\x0")
|
15
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
16
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
17
|
+
spec.require_paths = ["lib"]
|
18
|
+
|
19
|
+
spec.add_dependency "activesupport"
|
20
|
+
spec.add_dependency "bundler"
|
21
|
+
spec.add_dependency "dotenv"
|
22
|
+
spec.add_dependency "mem"
|
23
|
+
spec.add_dependency "slop"
|
24
|
+
spec.add_development_dependency "codeclimate-test-reporter", ">= 0.3.0"
|
25
|
+
spec.add_development_dependency "pry"
|
26
|
+
spec.add_development_dependency "rake"
|
27
|
+
spec.add_development_dependency "rspec", "2.14.1"
|
28
|
+
spec.add_development_dependency "simplecov"
|
29
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Ruboty::AdapterBuilder do
|
4
|
+
let(:builder) do
|
5
|
+
described_class.new(robot)
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:robot) do
|
9
|
+
Ruboty::Robot.new
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#build" do
|
13
|
+
context "with no other adapter class definition" do
|
14
|
+
it "returns a Ruboty::Adapters::Shell as a default adapter" do
|
15
|
+
builder.build.should be_a Ruboty::Adapters::Shell
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context "with another adapter class definition" do
|
20
|
+
after do
|
21
|
+
Ruboty::AdapterBuilder.adapter_classes.pop
|
22
|
+
end
|
23
|
+
|
24
|
+
let!(:another_adapter_class) do
|
25
|
+
Class.new(Ruboty::Adapters::Base) do
|
26
|
+
def run
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
it "returns an instance of that adapter class" do
|
32
|
+
builder.build.should be_a another_adapter_class
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Ruboty::Adapters::Shell do
|
4
|
+
before do
|
5
|
+
Ruboty.logger.stub(:info)
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:adapter) do
|
9
|
+
described_class.new(robot)
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:robot) do
|
13
|
+
Ruboty::Robot.new
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#run" do
|
17
|
+
context "with `exit`" do
|
18
|
+
it "stops" do
|
19
|
+
Readline.stub(readline: "exit")
|
20
|
+
adapter.should_receive(:stop).and_call_original
|
21
|
+
adapter.run
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context "with `quit`" do
|
26
|
+
it "stops" do
|
27
|
+
Readline.stub(readline: "exit")
|
28
|
+
adapter.should_receive(:stop).and_call_original
|
29
|
+
adapter.run
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context "with Inturrupt from console" do
|
34
|
+
it "stops" do
|
35
|
+
Readline.stub(:readline).and_raise(Interrupt)
|
36
|
+
adapter.should_receive(:stop).and_call_original
|
37
|
+
adapter.run
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context "without `exit` nor `quit`" do
|
42
|
+
it "passes given message to robot" do
|
43
|
+
Readline.stub(:readline).and_return("a", "exit")
|
44
|
+
robot.should_receive(:receive).with(body: "a", source: described_class::SOURCE)
|
45
|
+
adapter.run
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "#say" do
|
51
|
+
it "shows given message body on stdout" do
|
52
|
+
Ruboty.logger.should_receive(:info).with("a")
|
53
|
+
adapter.say(body: "a")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Ruboty::Commands::Generate do
|
4
|
+
describe "#call" do
|
5
|
+
after do
|
6
|
+
FileUtils.rmtree("./ruboty/")
|
7
|
+
end
|
8
|
+
|
9
|
+
let(:command) do
|
10
|
+
Ruboty::CommandBuilder.new(arguments).build
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:call) do
|
14
|
+
command.call
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:arguments) do
|
18
|
+
["--generate"]
|
19
|
+
end
|
20
|
+
|
21
|
+
context "with normal condition" do
|
22
|
+
it "generates ./ruboty/ directory from our templates" do
|
23
|
+
call
|
24
|
+
File.exists?("./ruboty/").should == true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "when ./ruboty/ directory already exists" do
|
29
|
+
before do
|
30
|
+
FileUtils.mkdir("./ruboty/")
|
31
|
+
end
|
32
|
+
|
33
|
+
it "exits process with dying message" do
|
34
|
+
Ruboty.logger.should_receive(:error).with("Error: ./ruboty/ already exists.")
|
35
|
+
expect { call }.to raise_error(SystemExit)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Ruboty::Commands::Run do
|
4
|
+
describe "#call" do
|
5
|
+
let(:command) do
|
6
|
+
Ruboty::CommandBuilder.new(arguments).build
|
7
|
+
end
|
8
|
+
|
9
|
+
let(:call) do
|
10
|
+
command.call
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:arguments) do
|
14
|
+
[]
|
15
|
+
end
|
16
|
+
|
17
|
+
it "creates an adapter and calls .run to it" do
|
18
|
+
Ruboty::Adapters::Shell.any_instance.should_receive(:run)
|
19
|
+
call
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Ruboty::Env::Validatable do
|
4
|
+
let(:validatable_class) do
|
5
|
+
Class.new do
|
6
|
+
include Ruboty::Env::Validatable
|
7
|
+
|
8
|
+
env :A, "description of A"
|
9
|
+
env :B, "description of B", optional: true
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:instance) do
|
14
|
+
validatable_class.new
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#validate" do
|
18
|
+
context "without required ENV" do
|
19
|
+
it "raises Ruboty::Env::ValidationError" do
|
20
|
+
expect { instance.validate }.to raise_error(Ruboty::Env::ValidationError)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "without optional ENV" do
|
25
|
+
before do
|
26
|
+
ENV["A"] = "dummy"
|
27
|
+
end
|
28
|
+
|
29
|
+
after do
|
30
|
+
ENV["A"] = nil
|
31
|
+
end
|
32
|
+
|
33
|
+
it "does nothing" do
|
34
|
+
expect { instance.validate }.not_to raise_error
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "#validate!" do
|
40
|
+
context "without required ENV" do
|
41
|
+
it "dies with usage as erorr message" do
|
42
|
+
Ruboty.logger.should_receive(:error).with(/description of A/)
|
43
|
+
Ruboty.should_receive(:exit)
|
44
|
+
instance.validate!
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Ruboty::Handlers::Base do
|
4
|
+
after do
|
5
|
+
Ruboty.handlers.pop
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:robot) do
|
9
|
+
Ruboty::Robot.new
|
10
|
+
end
|
11
|
+
|
12
|
+
let!(:handler_class) do
|
13
|
+
Class.new(described_class) do
|
14
|
+
on(/(\d+) \+ (\d+)/, name: "addition", all: true)
|
15
|
+
|
16
|
+
def addition(message)
|
17
|
+
robot.say(message[1].to_i + message[2].to_i)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe ".on" do
|
23
|
+
it "registers an action to the handler" do
|
24
|
+
robot.should_receive(:say).with(2)
|
25
|
+
robot.receive(body: "1 + 1")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Ruboty::Handlers::Help do
|
4
|
+
let(:robot) do
|
5
|
+
Ruboty::Robot.new
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "#help" do
|
9
|
+
let(:from) do
|
10
|
+
"alice"
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:to) do
|
14
|
+
"#general"
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:body) do
|
18
|
+
<<-EOS.strip_heredoc.strip
|
19
|
+
ruboty /help( me)?\\z/i - Show this help message
|
20
|
+
ruboty /ping\\z/i - Return PONG to PING
|
21
|
+
ruboty /who am i\\?/i - Answer who you are
|
22
|
+
EOS
|
23
|
+
end
|
24
|
+
|
25
|
+
it "responds to `@ruboty help` and says each handler's usage" do
|
26
|
+
robot.should_receive(:say).with(
|
27
|
+
body: body,
|
28
|
+
code: true,
|
29
|
+
from: to,
|
30
|
+
to: from,
|
31
|
+
original: {
|
32
|
+
body: "@ruboty help",
|
33
|
+
from: from,
|
34
|
+
robot: robot,
|
35
|
+
to: to,
|
36
|
+
},
|
37
|
+
)
|
38
|
+
robot.receive(body: "@ruboty help", from: from, to: to)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Ruboty::Handlers::Ping do
|
4
|
+
let(:robot) do
|
5
|
+
Ruboty::Robot.new
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "#ping" do
|
9
|
+
let(:from) do
|
10
|
+
"alice"
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:to) do
|
14
|
+
"#general"
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:said) do
|
18
|
+
"@ruboty ping"
|
19
|
+
end
|
20
|
+
|
21
|
+
let(:replied) do
|
22
|
+
"pong"
|
23
|
+
end
|
24
|
+
|
25
|
+
it "returns PONG to PING" do
|
26
|
+
robot.should_receive(:say).with(
|
27
|
+
body: replied,
|
28
|
+
from: to,
|
29
|
+
to: from,
|
30
|
+
original: {
|
31
|
+
body: said,
|
32
|
+
from: from,
|
33
|
+
robot: robot,
|
34
|
+
to: to,
|
35
|
+
},
|
36
|
+
)
|
37
|
+
robot.receive(body: said, from: from, to: to)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Ruboty::Handlers::Whoami do
|
4
|
+
let(:robot) do
|
5
|
+
Ruboty::Robot.new
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "#ping" do
|
9
|
+
let(:from) do
|
10
|
+
"alice"
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:to) do
|
14
|
+
"#general"
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:said) do
|
18
|
+
"@ruboty Who am I?"
|
19
|
+
end
|
20
|
+
|
21
|
+
it "returns PONG to PING" do
|
22
|
+
robot.should_receive(:say).with(
|
23
|
+
body: from,
|
24
|
+
from: to,
|
25
|
+
to: from,
|
26
|
+
original: {
|
27
|
+
body: said,
|
28
|
+
from: from,
|
29
|
+
robot: robot,
|
30
|
+
to: to,
|
31
|
+
},
|
32
|
+
)
|
33
|
+
robot.receive(body: said, from: from, to: to)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Ruboty::Robot do
|
4
|
+
let(:instance) do
|
5
|
+
described_class.new(options)
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:options) do
|
9
|
+
{}
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#brain" do
|
13
|
+
context "without any Brain class" do
|
14
|
+
it "returns a Ruboty::Brains::Memory" do
|
15
|
+
instance.brain.should be_a Ruboty::Brains::Memory
|
16
|
+
end
|
17
|
+
|
18
|
+
it "can be used as a Hash object" do
|
19
|
+
instance.brain.data["a"] = 1
|
20
|
+
instance.brain.data["a"].should == 1
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "with another Brain class" do
|
25
|
+
after do
|
26
|
+
Ruboty::Brains::Base.brain_classes.pop
|
27
|
+
end
|
28
|
+
|
29
|
+
let!(:another_brain_class) do
|
30
|
+
Class.new(Ruboty::Brains::Base)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "returns its instance as a Brain" do
|
34
|
+
instance.brain.should be_a another_brain_class
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|