scamp 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/.rspec +1 -0
- data/README.md +27 -10
- data/Rakefile +12 -0
- data/examples/bot.rb +4 -4
- data/lib/scamp/action.rb +8 -5
- data/lib/scamp/channels.rb +23 -13
- data/lib/scamp/connection.rb +3 -7
- data/lib/scamp/matcher.rb +8 -7
- data/lib/scamp/users.rb +5 -8
- data/lib/scamp/version.rb +2 -2
- data/lib/scamp.rb +40 -7
- data/scamp.gemspec +2 -0
- data/spec/lib/scamp_spec.rb +112 -0
- data/spec/spec_helper.rb +1 -0
- metadata +26 -12
data/.gitignore
CHANGED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/README.md
CHANGED
@@ -14,11 +14,11 @@ Ruby >= 1.9.2 (At least for the named captures)
|
|
14
14
|
|
15
15
|
Matchers are tested in order and all that satisfy the match and conditions will be run. Careful, Scamp listens to itself, you could easily create an infinite loop. Look in the examples dir for more.
|
16
16
|
|
17
|
-
require '
|
17
|
+
require 'scamp'
|
18
18
|
|
19
|
-
scamp = Scamp.new(:api_key => "YOUR API KEY")
|
19
|
+
scamp = Scamp.new(:api_key => "YOUR API KEY", :subdomain => "yoursubdomain")
|
20
20
|
|
21
|
-
|
21
|
+
scamp.behaviour do
|
22
22
|
#
|
23
23
|
# Simple matching based on regex or string:
|
24
24
|
#
|
@@ -69,8 +69,24 @@ Matchers are tested in order and all that satisfy the match and conditions will
|
|
69
69
|
say "#{user} said something in channel #{channel}", "System Administration"
|
70
70
|
end
|
71
71
|
|
72
|
-
#
|
73
|
-
|
72
|
+
#
|
73
|
+
# A list of commands is available as command_list this matcher uses it
|
74
|
+
# to format a help text
|
75
|
+
#
|
76
|
+
match "help" do
|
77
|
+
max_command_length = command_list.map{|cl| cl.first.to_s }.max_by(&:size).size
|
78
|
+
format_string = "%#{max_command_length + 1}s"
|
79
|
+
formatted_commands = command_list.map{|action, conds| "#{sprintf(format_string, action)} | #{conds.size == 0 ? '' : conds.inspect}"}
|
80
|
+
say <<-EOS
|
81
|
+
#{sprintf("%-#{max_command_length + 1}s", "Command match")} | Conditions
|
82
|
+
--------------------------------------------------------------------------------
|
83
|
+
#{formatted_commands.join("\n")}
|
84
|
+
EOS
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Connect and join some channels
|
89
|
+
scamp.connect!([293788, "Monitoring"])
|
74
90
|
|
75
91
|
In the channel/user conditions you can use the name, regex or ID of a user or channel, in say you can ise a string or ID, eg:
|
76
92
|
|
@@ -87,15 +103,16 @@ In the channel/user conditions you can use the name, regex or ID of a user or ch
|
|
87
103
|
|
88
104
|
## TODO
|
89
105
|
|
90
|
-
* Write
|
106
|
+
* Write more tests
|
91
107
|
* Allow multiple values for conditions, eg: :conditions => {:channel => [/someregex/, "Some channel"]}
|
92
|
-
*
|
93
|
-
* Add
|
108
|
+
* Add paste/play support
|
109
|
+
* Add option to stop bot responding to itself
|
94
110
|
|
95
111
|
## Known issues
|
96
112
|
|
97
|
-
* Bot doesn't detect that it's been kicked out of a channel and
|
113
|
+
* Bot doesn't detect that it's been kicked out of a channel and reconnect
|
98
114
|
* Bot tends to crash when it encounters an error.
|
115
|
+
* When encountering a problem straming (Couldn't stream channel 401839 at url https://streaming.campfirenow.com/room/<channel_id>/live.json) no attempt is made to re-connect
|
99
116
|
|
100
117
|
## How to contribute
|
101
118
|
|
@@ -132,4 +149,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
132
149
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
133
150
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
134
151
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
135
|
-
THE SOFTWARE.
|
152
|
+
THE SOFTWARE.
|
data/Rakefile
CHANGED
@@ -1 +1,13 @@
|
|
1
1
|
require 'bundler/gem_tasks'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
RSpec::Core::RakeTask.new(:spec)
|
6
|
+
rescue LoadError => e
|
7
|
+
task "spec" do
|
8
|
+
puts "RSpec not loaded - make sure it's installed and you're using bundle exec"
|
9
|
+
exit 1
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
task :default => :spec
|
data/examples/bot.rb
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
$:.unshift File.join(File.dirname(__FILE__), '../lib')
|
4
4
|
|
5
|
-
require '
|
5
|
+
require 'scamp'
|
6
6
|
|
7
|
-
scamp = Scamp.new(:api_key => "YOUR API KEY")
|
7
|
+
scamp = Scamp.new(:api_key => "YOUR API KEY", :subdomain => "37s")
|
8
8
|
|
9
|
-
|
9
|
+
scamp.behaviour do
|
10
10
|
# Match some regex limited to a channel condition based on a channel id
|
11
11
|
match /^channel id (.+)$/, :conditions => {:channel => 401839} do
|
12
12
|
# Reply in the current channel
|
@@ -73,4 +73,4 @@ Scamp.behaviour do
|
|
73
73
|
end
|
74
74
|
|
75
75
|
# FIXME: this does if the channel doesn't exist. Need a better error.
|
76
|
-
scamp.connect!([293788, "Monitoring"])
|
76
|
+
scamp.connect!([293788, "Monitoring"])
|
data/lib/scamp/action.rb
CHANGED
@@ -9,7 +9,7 @@
|
|
9
9
|
class Scamp
|
10
10
|
class Action
|
11
11
|
|
12
|
-
|
12
|
+
attr_accessor :matches, :bot
|
13
13
|
|
14
14
|
def initialize(bot, action, message)
|
15
15
|
@bot = bot
|
@@ -24,12 +24,11 @@ class Scamp
|
|
24
24
|
self.class.send :define_method, name_s do
|
25
25
|
match[name_s]
|
26
26
|
end
|
27
|
-
end
|
27
|
+
end if match.respond_to?(:names) # 1.8 doesn't support named captures
|
28
28
|
end
|
29
29
|
|
30
30
|
def channel
|
31
|
-
|
32
|
-
@message[:room_id]
|
31
|
+
bot.channel_name_for @message[:room_id]
|
33
32
|
end
|
34
33
|
|
35
34
|
def user
|
@@ -50,8 +49,12 @@ class Scamp
|
|
50
49
|
|
51
50
|
private
|
52
51
|
|
52
|
+
def command_list
|
53
|
+
bot.command_list
|
54
|
+
end
|
55
|
+
|
53
56
|
def say(msg, channel_id_or_name = channel)
|
54
57
|
bot.say(msg, channel_id_or_name)
|
55
58
|
end
|
56
59
|
end
|
57
|
-
end
|
60
|
+
end
|
data/lib/scamp/channels.rb
CHANGED
@@ -7,10 +7,10 @@ class Scamp
|
|
7
7
|
|
8
8
|
# curl -vvv -H 'Content-Type: application/json' -d '{"message":{"body":"Yeeeeeaaaaaahh", "type":"Textmessage"}}' -u API_KEY:X https://37s.campfirenow.com/room/293788/speak.json
|
9
9
|
def say(message, channel)
|
10
|
-
url = "https
|
10
|
+
url = "https://#{subdomain}.campfirenow.com/room/#{channel_id(channel)}/speak.json"
|
11
11
|
http = EventMachine::HttpRequest.new(url).post :head => {'Content-Type' => 'application/json', 'authorization' => [api_key, 'X']}, :body => Yajl::Encoder.encode({:message => {:body => message, :type => "Textmessage"}})
|
12
12
|
|
13
|
-
http.errback {
|
13
|
+
http.errback { logger.error "Error speaking: '#{message}' to #{channel_id(channel)}" }
|
14
14
|
end
|
15
15
|
|
16
16
|
def paste(text, channel)
|
@@ -20,10 +20,11 @@ class Scamp
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def join(channel_id)
|
23
|
-
|
23
|
+
logger.info "Joining channel #{channel_id}"
|
24
|
+
url = "https://#{subdomain}.campfirenow.com/room/#{channel_id}/join.json"
|
24
25
|
http = EventMachine::HttpRequest.new(url).post :head => {'Content-Type' => 'application/json', 'authorization' => [api_key, 'X']}
|
25
26
|
|
26
|
-
http.errback {
|
27
|
+
http.errback { logger.error "Error joining channel: #{channel_id}" }
|
27
28
|
http.callback {
|
28
29
|
yield if block_given?
|
29
30
|
}
|
@@ -52,9 +53,9 @@ class Scamp
|
|
52
53
|
end
|
53
54
|
|
54
55
|
def populate_channel_list
|
55
|
-
url = "https
|
56
|
+
url = "https://#{subdomain}.campfirenow.com/rooms.json"
|
56
57
|
http = EventMachine::HttpRequest.new(url).get :head => {'authorization' => [api_key, 'X']}
|
57
|
-
http.errback {
|
58
|
+
http.errback { logger.error "Error populating the channel list: #{http.status.inspect}" }
|
58
59
|
http.callback {
|
59
60
|
new_channels = {}
|
60
61
|
Yajl::Parser.parse(http.response)['rooms'].each do |c|
|
@@ -69,12 +70,12 @@ class Scamp
|
|
69
70
|
end
|
70
71
|
|
71
72
|
def fetch_channel_data(channel_id)
|
72
|
-
|
73
|
-
url = "https
|
73
|
+
logger.debug "Fetching channel data for #{channel_id}"
|
74
|
+
url = "https://#{subdomain}.campfirenow.com/room/#{channel_id}.json"
|
74
75
|
http = EventMachine::HttpRequest.new(url).get :head => {'authorization' => [api_key, 'X']}
|
75
|
-
http.errback {
|
76
|
+
http.errback { logger.error "Couldn't get data for channel #{channel_id} at url #{url}" }
|
76
77
|
http.callback {
|
77
|
-
|
78
|
+
logger.debug "Fetched channel data for #{channel_id}"
|
78
79
|
room = Yajl::Parser.parse(http.response)['room']
|
79
80
|
channel_cache[room["id"]] = room
|
80
81
|
room['users'].each do |u|
|
@@ -83,19 +84,28 @@ class Scamp
|
|
83
84
|
}
|
84
85
|
end
|
85
86
|
|
87
|
+
def join_and_stream(id)
|
88
|
+
join(id) do
|
89
|
+
logger.info "Joined channel #{id} successfully"
|
90
|
+
fetch_channel_data(id)
|
91
|
+
stream(id)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
86
95
|
def stream(channel_id)
|
87
96
|
json_parser = Yajl::Parser.new :symbolize_keys => true
|
88
97
|
json_parser.on_parse_complete = method(:process_message)
|
89
98
|
|
90
99
|
url = "https://streaming.campfirenow.com/room/#{channel_id}/live.json"
|
91
100
|
http = EventMachine::HttpRequest.new(url).get :head => {'authorization' => [api_key, 'X']}
|
92
|
-
http.errback {
|
101
|
+
http.errback { logger.error "Couldn't stream channel #{channel_id} at url #{url}" }
|
102
|
+
http.callback { logger.error "Disconnected from #{url}" }
|
93
103
|
http.stream {|chunk| json_parser << chunk }
|
94
104
|
end
|
95
105
|
|
96
106
|
def channel_id_from_channel_name(channel_name)
|
97
|
-
|
107
|
+
logger.debug "Looking for channel id for #{channel_name}"
|
98
108
|
channels[channel_name]["id"]
|
99
109
|
end
|
100
110
|
end
|
101
|
-
end
|
111
|
+
end
|
data/lib/scamp/connection.rb
CHANGED
@@ -7,15 +7,11 @@ class Scamp
|
|
7
7
|
# Ideally populate_channel_list would block, but I can't see an easy way to do this, so a hacky callback it is.
|
8
8
|
populate_channel_list do
|
9
9
|
channels_to_join.map{|c| channel_id(c) }.each do |id|
|
10
|
-
|
11
|
-
join(id) do
|
12
|
-
fetch_channel_data(id)
|
13
|
-
stream(id)
|
14
|
-
end
|
10
|
+
join_and_stream(id)
|
15
11
|
end
|
16
12
|
end
|
17
13
|
end
|
18
14
|
end
|
19
15
|
|
20
|
-
end
|
21
|
-
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/scamp/matcher.rb
CHANGED
@@ -31,7 +31,7 @@ class Scamp
|
|
31
31
|
elsif trigger.is_a? Regexp
|
32
32
|
return trigger.match message_text
|
33
33
|
else
|
34
|
-
|
34
|
+
bot.logger.warn "Don't know what to do with #{trigger.inspect} at #{__FILE__}:#{__LINE__}"
|
35
35
|
end
|
36
36
|
false
|
37
37
|
end
|
@@ -43,7 +43,8 @@ class Scamp
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def conditions_satisfied_by(msg)
|
46
|
-
#
|
46
|
+
# bot.logger.warn "Need to take into account nick, channel and regexps at #{__FILE__}:#{__LINE__}"
|
47
|
+
bot.logger.info "Checking message against #{conditions.inspect}"
|
47
48
|
|
48
49
|
# nick
|
49
50
|
# channel name
|
@@ -55,10 +56,10 @@ class Scamp
|
|
55
56
|
# item will be :nick or :channel
|
56
57
|
# cond is the regex, int or string value.
|
57
58
|
conditions.each do |item, cond|
|
58
|
-
|
59
|
-
|
59
|
+
bot.logger.debug "Checking #{item} against #{cond}"
|
60
|
+
bot.logger.debug "msg is #{msg.inspect}"
|
60
61
|
if cond.is_a? Integer
|
61
|
-
#
|
62
|
+
# bot.logger.debug "item is #{msg[{:channel => :room_id, :user => :user_id}[item]]}"
|
62
63
|
return false unless msg[{:channel => :room_id, :user => :user_id}[item]] == cond
|
63
64
|
elsif cond.is_a? String
|
64
65
|
case item
|
@@ -67,7 +68,7 @@ class Scamp
|
|
67
68
|
when :user
|
68
69
|
return false unless bot.username_for(msg[:user_id]) == cond
|
69
70
|
end
|
70
|
-
|
71
|
+
bot.logger.error "Don't know how to deal with a match item of #{item}, cond #{cond}"
|
71
72
|
elsif cond.is_a? Regexp
|
72
73
|
return false
|
73
74
|
return false unless msg[item].match(cond)
|
@@ -76,4 +77,4 @@ class Scamp
|
|
76
77
|
true
|
77
78
|
end
|
78
79
|
end
|
79
|
-
end
|
80
|
+
end
|
data/lib/scamp/users.rb
CHANGED
@@ -22,23 +22,20 @@ class Scamp
|
|
22
22
|
private
|
23
23
|
|
24
24
|
def fetch_data_for(user_id)
|
25
|
-
url = "https
|
25
|
+
url = "https://#{subdomain}.campfirenow.com/users/#{user_id}.json"
|
26
26
|
http = EventMachine::HttpRequest.new(url).get(:head => {'authorization' => [api_key, 'X'], "Content-Type" => "application/json"})
|
27
|
-
|
27
|
+
logger.debug http.inspect
|
28
28
|
http.callback do
|
29
|
-
|
29
|
+
logger.debug "Got the data for #{user_id}"
|
30
30
|
update_user_cache_with(user_id, Yajl::Parser.parse(http.response)['user'])
|
31
31
|
end
|
32
32
|
http.errback do
|
33
|
-
|
34
|
-
STDERR.puts http.response_header.status
|
35
|
-
STDERR.puts http.response_header.inspect
|
36
|
-
STDERR.puts http.response.inspect
|
33
|
+
logger.error "Couldn't fetch user data for #{user_id} with url #{url}\n#{http.response_header.status.inspect}\n#{http.response_header.inspect}\n#{http.response.inspect}"
|
37
34
|
end
|
38
35
|
end
|
39
36
|
|
40
37
|
def update_user_cache_with(user_id, data)
|
41
|
-
|
38
|
+
logger.debug "Updated user cache for #{data['name']}"
|
42
39
|
user_cache[user_id] = data
|
43
40
|
end
|
44
41
|
end
|
data/lib/scamp/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
|
2
|
-
VERSION = "0.0.
|
1
|
+
class Scamp
|
2
|
+
VERSION = "0.0.2"
|
3
3
|
end
|
data/lib/scamp.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'eventmachine'
|
2
2
|
require 'em-http-request'
|
3
3
|
require 'yajl'
|
4
|
+
require "logger"
|
4
5
|
|
5
6
|
require "scamp/version"
|
6
7
|
require 'scamp/connection'
|
@@ -13,15 +14,23 @@ class Scamp
|
|
13
14
|
include Connection
|
14
15
|
include Channels
|
15
16
|
include Users
|
16
|
-
|
17
|
-
attr_accessor :channels, :user_cache, :channel_cache
|
18
|
-
attr :matchers, :api_key
|
17
|
+
|
18
|
+
attr_accessor :channels, :user_cache, :channel_cache, :matchers, :api_key, :subdomain, :logger, :verbose, :first_match_only
|
19
19
|
|
20
20
|
def initialize(options = {})
|
21
21
|
options ||= {}
|
22
22
|
raise ArgumentError, "You must pass an API key" unless options[:api_key]
|
23
|
-
|
24
|
-
|
23
|
+
raise ArgumentError, "You must pass a subdomain" unless options[:subdomain]
|
24
|
+
|
25
|
+
options.each do |k,v|
|
26
|
+
s = "#{k}="
|
27
|
+
if respond_to?(s)
|
28
|
+
send(s, v)
|
29
|
+
else
|
30
|
+
logger.warn "Scamp initialized with #{k.inspect} => #{v.inspect} but NO UNDERSTAND!"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
25
34
|
@channels = {}
|
26
35
|
@user_cache = {}
|
27
36
|
@channel_cache = {}
|
@@ -33,19 +42,43 @@ class Scamp
|
|
33
42
|
end
|
34
43
|
|
35
44
|
def connect!(channel_list)
|
45
|
+
logger.info "Starting up"
|
36
46
|
connect(api_key, channel_list)
|
37
47
|
end
|
38
48
|
|
49
|
+
def command_list
|
50
|
+
matchers.map{|m| [m.trigger, m.conditions] }
|
51
|
+
end
|
52
|
+
|
53
|
+
def logger
|
54
|
+
unless @logger
|
55
|
+
@logger = Logger.new(STDOUT)
|
56
|
+
@logger.level = (verbose ? Logger::DEBUG : Logger::INFO)
|
57
|
+
end
|
58
|
+
@logger
|
59
|
+
end
|
60
|
+
|
61
|
+
def verbose
|
62
|
+
@verbose = false if @verbose == nil
|
63
|
+
@verbose
|
64
|
+
end
|
65
|
+
|
66
|
+
def first_match_only
|
67
|
+
@first_match_only = false if @first_match_only == nil
|
68
|
+
@first_match_only
|
69
|
+
end
|
70
|
+
|
39
71
|
private
|
40
|
-
|
72
|
+
|
41
73
|
def match trigger, params={}, &block
|
42
74
|
params ||= {}
|
43
75
|
matchers << Matcher.new(self, {:trigger => trigger, :action => block, :conditions => params[:conditions]})
|
44
76
|
end
|
45
77
|
|
46
78
|
def process_message(msg)
|
79
|
+
logger.debug "Received message #{msg.inspect}"
|
47
80
|
matchers.each do |matcher|
|
48
|
-
matcher.attempt(msg)
|
81
|
+
break if first_match_only & matcher.attempt(msg)
|
49
82
|
end
|
50
83
|
end
|
51
84
|
end
|
data/scamp.gemspec
CHANGED
@@ -0,0 +1,112 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Scamp do
|
4
|
+
before do
|
5
|
+
@valid_params = {:api_key => "6124d98749365e3db2c9e5b27ca04db6", :subdomain => "oxygen"}
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "#initialize" do
|
9
|
+
it "should work with valid params" do
|
10
|
+
a(Scamp).should be_a(Scamp)
|
11
|
+
end
|
12
|
+
it "should warn if given an option it doesn't know" do
|
13
|
+
mock_logger
|
14
|
+
|
15
|
+
a(Scamp, :fred => "estaire").should be_a(Scamp)
|
16
|
+
|
17
|
+
logger_output.should =~ /WARN.*Scamp initialized with :fred => "estaire" but NO UNDERSTAND!/
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#verbose" do
|
22
|
+
it "should default to false" do
|
23
|
+
a(Scamp).verbose.should be_false
|
24
|
+
end
|
25
|
+
it "should be overridable at initialization" do
|
26
|
+
a(Scamp, :verbose => true).verbose.should be_true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#logger" do
|
31
|
+
context "default logger" do
|
32
|
+
before { @bot = a Scamp }
|
33
|
+
it { @bot.logger.should be_a(Logger) }
|
34
|
+
it { @bot.logger.level.should be == Logger::INFO }
|
35
|
+
end
|
36
|
+
context "default logger in verbose mode" do
|
37
|
+
before { @bot = a Scamp, :verbose => true }
|
38
|
+
it { @bot.logger.level.should be == Logger::DEBUG }
|
39
|
+
end
|
40
|
+
context "overriding default" do
|
41
|
+
before do
|
42
|
+
@custom_logger = Logger.new("/dev/null")
|
43
|
+
@bot = a Scamp, :logger => @custom_logger
|
44
|
+
end
|
45
|
+
it { @bot.logger.should be == @custom_logger }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "#first_match_only" do
|
50
|
+
it "should default to false" do
|
51
|
+
a(Scamp).first_match_only.should be_false
|
52
|
+
end
|
53
|
+
it "should be settable" do
|
54
|
+
a(Scamp, :first_match_only => true).first_match_only.should be_true
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "private methods" do
|
59
|
+
|
60
|
+
describe "#process_message" do
|
61
|
+
before do
|
62
|
+
@bot = a Scamp
|
63
|
+
$attempts = 0 # Yes, I hate it too. Works though.
|
64
|
+
@message = {:body => "my message here"}
|
65
|
+
|
66
|
+
@bot.behaviour do
|
67
|
+
2.times { match(/.*/) { $attempts += 1 } }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
after { $attempts = nil }
|
71
|
+
context "with first_match_only not set" do
|
72
|
+
before { @bot.first_match_only.should be_false }
|
73
|
+
it "should process all matchers which attempt the message" do
|
74
|
+
@bot.send(:process_message, @message)
|
75
|
+
$attempts.should be == 2
|
76
|
+
end
|
77
|
+
end
|
78
|
+
context "with first_match_only set" do
|
79
|
+
before do
|
80
|
+
@bot.first_match_only = true
|
81
|
+
@bot.first_match_only.should be_true
|
82
|
+
end
|
83
|
+
it "should only process the first matcher which attempts the message" do
|
84
|
+
@bot.send(:process_message, @message)
|
85
|
+
$attempts.should be == 1
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
def a klass, params={}
|
94
|
+
params ||= {}
|
95
|
+
params = @valid_params.merge(params) if klass == Scamp
|
96
|
+
klass.new(params)
|
97
|
+
end
|
98
|
+
|
99
|
+
# Urg
|
100
|
+
def mock_logger
|
101
|
+
@logger_string = StringIO.new
|
102
|
+
@fake_logger = Logger.new(@logger_string)
|
103
|
+
Scamp.any_instance.should_receive(:logger).and_return(@fake_logger)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Bleurgh
|
107
|
+
def logger_output
|
108
|
+
str = @logger_string.dup
|
109
|
+
str.rewind
|
110
|
+
str.read
|
111
|
+
end
|
112
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.expand_path("../lib/scamp", File.dirname(__FILE__))
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: scamp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,12 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-09-
|
13
|
-
default_executable:
|
12
|
+
date: 2011-09-17 00:00:00.000000000Z
|
14
13
|
dependencies:
|
15
14
|
- !ruby/object:Gem::Dependency
|
16
15
|
name: eventmachine
|
17
|
-
requirement: &
|
16
|
+
requirement: &70244078916620 !ruby/object:Gem::Requirement
|
18
17
|
none: false
|
19
18
|
requirements:
|
20
19
|
- - ~>
|
@@ -22,10 +21,10 @@ dependencies:
|
|
22
21
|
version: 0.12.10
|
23
22
|
type: :runtime
|
24
23
|
prerelease: false
|
25
|
-
version_requirements: *
|
24
|
+
version_requirements: *70244078916620
|
26
25
|
- !ruby/object:Gem::Dependency
|
27
26
|
name: yajl-ruby
|
28
|
-
requirement: &
|
27
|
+
requirement: &70244078916120 !ruby/object:Gem::Requirement
|
29
28
|
none: false
|
30
29
|
requirements:
|
31
30
|
- - ~>
|
@@ -33,10 +32,10 @@ dependencies:
|
|
33
32
|
version: 0.8.3
|
34
33
|
type: :runtime
|
35
34
|
prerelease: false
|
36
|
-
version_requirements: *
|
35
|
+
version_requirements: *70244078916120
|
37
36
|
- !ruby/object:Gem::Dependency
|
38
37
|
name: em-http-request
|
39
|
-
requirement: &
|
38
|
+
requirement: &70244078915660 !ruby/object:Gem::Requirement
|
40
39
|
none: false
|
41
40
|
requirements:
|
42
41
|
- - ~>
|
@@ -44,7 +43,18 @@ dependencies:
|
|
44
43
|
version: 0.3.0
|
45
44
|
type: :runtime
|
46
45
|
prerelease: false
|
47
|
-
version_requirements: *
|
46
|
+
version_requirements: *70244078915660
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rspec
|
49
|
+
requirement: &70244078915200 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 2.6.0
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70244078915200
|
48
58
|
description: Eventmachine based Campfire bot framework
|
49
59
|
email:
|
50
60
|
- will@willj.net
|
@@ -53,6 +63,7 @@ extensions: []
|
|
53
63
|
extra_rdoc_files: []
|
54
64
|
files:
|
55
65
|
- .gitignore
|
66
|
+
- .rspec
|
56
67
|
- Gemfile
|
57
68
|
- README.md
|
58
69
|
- Rakefile
|
@@ -65,7 +76,8 @@ files:
|
|
65
76
|
- lib/scamp/users.rb
|
66
77
|
- lib/scamp/version.rb
|
67
78
|
- scamp.gemspec
|
68
|
-
|
79
|
+
- spec/lib/scamp_spec.rb
|
80
|
+
- spec/spec_helper.rb
|
69
81
|
homepage: ''
|
70
82
|
licenses: []
|
71
83
|
post_install_message:
|
@@ -86,8 +98,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
86
98
|
version: '0'
|
87
99
|
requirements: []
|
88
100
|
rubyforge_project:
|
89
|
-
rubygems_version: 1.
|
101
|
+
rubygems_version: 1.8.10
|
90
102
|
signing_key:
|
91
103
|
specification_version: 3
|
92
104
|
summary: Eventmachine based Campfire bot framework
|
93
|
-
test_files:
|
105
|
+
test_files:
|
106
|
+
- spec/lib/scamp_spec.rb
|
107
|
+
- spec/spec_helper.rb
|