atig 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +24 -0
- data/Gemfile +3 -0
- data/README.mkdn +52 -0
- data/Rakefile +15 -0
- data/atig.gemspec +25 -0
- data/bin/atig +74 -0
- data/docs/OMakefile +32 -0
- data/docs/OMakeroot +45 -0
- data/docs/_static/allow.png +0 -0
- data/docs/_static/emacs.png +0 -0
- data/docs/_static/irc_setting.png +0 -0
- data/docs/_static/irssi.png +0 -0
- data/docs/_static/limechat.png +0 -0
- data/docs/_static/limechat_s.png +0 -0
- data/docs/_static/oauth_channel.png +0 -0
- data/docs/_static/screenshot.png +0 -0
- data/docs/_static/structure.png +0 -0
- data/docs/_static/verify.png +0 -0
- data/docs/changelog.rst +96 -0
- data/docs/commandline_options.rst +21 -0
- data/docs/commands.rst +84 -0
- data/docs/conf.py +194 -0
- data/docs/config.rst +159 -0
- data/docs/feature.rst +41 -0
- data/docs/graphics.graffle +1995 -0
- data/docs/hacking_guide.rst +43 -0
- data/docs/index.rst +109 -0
- data/docs/irc.rst +31 -0
- data/docs/options.rst +75 -0
- data/docs/quickstart.rst +89 -0
- data/docs/resize.sh +7 -0
- data/docs/tiarra.rst +2 -0
- data/docs/tig.rst +21 -0
- data/lib/atig.rb +19 -0
- data/lib/atig/agent.rb +8 -0
- data/lib/atig/agent/agent.rb +38 -0
- data/lib/atig/agent/clenup.rb +23 -0
- data/lib/atig/agent/dm.rb +35 -0
- data/lib/atig/agent/following.rb +45 -0
- data/lib/atig/agent/full_list.rb +20 -0
- data/lib/atig/agent/list.rb +55 -0
- data/lib/atig/agent/list_status.rb +46 -0
- data/lib/atig/agent/mention.rb +13 -0
- data/lib/atig/agent/other_list.rb +18 -0
- data/lib/atig/agent/own_list.rb +18 -0
- data/lib/atig/agent/stream_follow.rb +38 -0
- data/lib/atig/agent/timeline.rb +13 -0
- data/lib/atig/agent/user_stream.rb +31 -0
- data/lib/atig/basic_twitter.rb +116 -0
- data/lib/atig/bitly.rb +52 -0
- data/lib/atig/channel.rb +5 -0
- data/lib/atig/channel/channel.rb +17 -0
- data/lib/atig/channel/dm.rb +14 -0
- data/lib/atig/channel/list.rb +76 -0
- data/lib/atig/channel/mention.rb +20 -0
- data/lib/atig/channel/retweet.rb +28 -0
- data/lib/atig/channel/timeline.rb +74 -0
- data/lib/atig/command.rb +21 -0
- data/lib/atig/command/autofix.rb +58 -0
- data/lib/atig/command/command.rb +24 -0
- data/lib/atig/command/command_helper.rb +95 -0
- data/lib/atig/command/destroy.rb +44 -0
- data/lib/atig/command/dm.rb +31 -0
- data/lib/atig/command/favorite.rb +27 -0
- data/lib/atig/command/info.rb +50 -0
- data/lib/atig/command/limit.rb +15 -0
- data/lib/atig/command/location.rb +23 -0
- data/lib/atig/command/name.rb +18 -0
- data/lib/atig/command/option.rb +37 -0
- data/lib/atig/command/refresh.rb +18 -0
- data/lib/atig/command/reply.rb +37 -0
- data/lib/atig/command/retweet.rb +63 -0
- data/lib/atig/command/search.rb +51 -0
- data/lib/atig/command/spam.rb +26 -0
- data/lib/atig/command/status.rb +41 -0
- data/lib/atig/command/thread.rb +44 -0
- data/lib/atig/command/time.rb +32 -0
- data/lib/atig/command/uptime.rb +32 -0
- data/lib/atig/command/user.rb +42 -0
- data/lib/atig/command/user_info.rb +27 -0
- data/lib/atig/command/version.rb +49 -0
- data/lib/atig/command/whois.rb +39 -0
- data/lib/atig/db/db.rb +60 -0
- data/lib/atig/db/followings.rb +131 -0
- data/lib/atig/db/listenable.rb +22 -0
- data/lib/atig/db/lists.rb +76 -0
- data/lib/atig/db/roman.rb +30 -0
- data/lib/atig/db/sized_uniq_array.rb +62 -0
- data/lib/atig/db/sql.rb +35 -0
- data/lib/atig/db/statuses.rb +147 -0
- data/lib/atig/db/transaction.rb +47 -0
- data/lib/atig/exception_util.rb +26 -0
- data/lib/atig/gateway.rb +62 -0
- data/lib/atig/gateway/channel.rb +99 -0
- data/lib/atig/gateway/session.rb +326 -0
- data/lib/atig/http.rb +95 -0
- data/lib/atig/ifilter.rb +7 -0
- data/lib/atig/ifilter/expand_url.rb +74 -0
- data/lib/atig/ifilter/retweet.rb +14 -0
- data/lib/atig/ifilter/retweet_time.rb +16 -0
- data/lib/atig/ifilter/sanitize.rb +18 -0
- data/lib/atig/ifilter/strip.rb +15 -0
- data/lib/atig/ifilter/utf7.rb +26 -0
- data/lib/atig/ifilter/xid.rb +36 -0
- data/lib/atig/levenshtein.rb +49 -0
- data/lib/atig/monkey.rb +4 -0
- data/lib/atig/oauth-patch.rb +40 -0
- data/lib/atig/oauth.rb +55 -0
- data/lib/atig/ofilter.rb +4 -0
- data/lib/atig/ofilter/escape_url.rb +102 -0
- data/lib/atig/ofilter/footer.rb +20 -0
- data/lib/atig/ofilter/geo.rb +17 -0
- data/lib/atig/ofilter/short_url.rb +47 -0
- data/lib/atig/option.rb +90 -0
- data/lib/atig/scheduler.rb +79 -0
- data/lib/atig/search.rb +22 -0
- data/lib/atig/search_twitter.rb +21 -0
- data/lib/atig/sized_hash.rb +33 -0
- data/lib/atig/stream.rb +66 -0
- data/lib/atig/twitter.rb +79 -0
- data/lib/atig/twitter_struct.rb +63 -0
- data/lib/atig/unu.rb +27 -0
- data/lib/atig/update_checker.rb +53 -0
- data/lib/atig/url_escape.rb +62 -0
- data/lib/atig/util.rb +16 -0
- data/lib/atig/version.rb +3 -0
- data/lib/memory_profiler.rb +77 -0
- data/spec/command/autofix_spec.rb +35 -0
- data/spec/command/destroy_spec.rb +98 -0
- data/spec/command/dm_spec.rb +28 -0
- data/spec/command/favorite_spec.rb +55 -0
- data/spec/command/limit_spec.rb +27 -0
- data/spec/command/location_spec.rb +25 -0
- data/spec/command/name_spec.rb +19 -0
- data/spec/command/option_spec.rb +133 -0
- data/spec/command/refresh_spec.rb +22 -0
- data/spec/command/reply_spec.rb +79 -0
- data/spec/command/retweet_spec.rb +66 -0
- data/spec/command/spam_spec.rb +27 -0
- data/spec/command/status_spec.rb +44 -0
- data/spec/command/thread_spec.rb +91 -0
- data/spec/command/time_spec.rb +52 -0
- data/spec/command/uptime_spec.rb +55 -0
- data/spec/command/user_info_spec.rb +42 -0
- data/spec/command/user_spec.rb +50 -0
- data/spec/command/version_spec.rb +67 -0
- data/spec/command/whois_spec.rb +78 -0
- data/spec/db/followings_spec.rb +100 -0
- data/spec/db/listenable_spec.rb +32 -0
- data/spec/db/lists_spec.rb +104 -0
- data/spec/db/roman_spec.rb +17 -0
- data/spec/db/sized_uniq_array_spec.rb +63 -0
- data/spec/db/statuses_spec.rb +180 -0
- data/spec/ifilter/expand_url_spec.rb +44 -0
- data/spec/ifilter/retweet_spec.rb +28 -0
- data/spec/ifilter/retweet_time_spec.rb +25 -0
- data/spec/ifilter/sanitize_spec.rb +25 -0
- data/spec/ifilter/sid_spec.rb +29 -0
- data/spec/ifilter/strip_spec.rb +23 -0
- data/spec/ifilter/tid_spec.rb +29 -0
- data/spec/ifilter/utf7_spec.rb +30 -0
- data/spec/levenshtein_spec.rb +24 -0
- data/spec/ofilter/escape_url_spec.rb +50 -0
- data/spec/ofilter/footer_spec.rb +32 -0
- data/spec/ofilter/geo_spec.rb +33 -0
- data/spec/ofilter/short_url_spec.rb +127 -0
- data/spec/option_spec.rb +91 -0
- data/spec/sized_hash_spec.rb +45 -0
- data/spec/spec_helper.rb +35 -0
- data/spec/update_checker_spec.rb +55 -0
- metadata +326 -0
data/lib/atig/bitly.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# -*- mode:ruby; coding:utf-8 -*-
|
2
|
+
require 'rubygems'
|
3
|
+
require 'json'
|
4
|
+
require 'atig/http'
|
5
|
+
|
6
|
+
module Atig
|
7
|
+
class Bitly
|
8
|
+
class << self
|
9
|
+
def no_login(logger)
|
10
|
+
self.new logger, nil, nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def login(logger, login, key)
|
14
|
+
self.new logger, login, key
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(logger, login, key)
|
19
|
+
@log = logger
|
20
|
+
@login = login
|
21
|
+
@key = key
|
22
|
+
@http = Http.new logger
|
23
|
+
end
|
24
|
+
|
25
|
+
def shorten(url)
|
26
|
+
return url if url =~ /bit\.ly/
|
27
|
+
bitly = URI("http://api.bit.ly/v3/shorten")
|
28
|
+
if @login and @key
|
29
|
+
bitly.path = "/shorten"
|
30
|
+
bitly.query = {
|
31
|
+
:format => "json", :longUrl => url, :login => @login, :apiKey => @key,
|
32
|
+
}.to_query_str(";")
|
33
|
+
req = @http.req(:get, bitly, {})
|
34
|
+
res = @http.http(bitly, 5, 10).request(req)
|
35
|
+
|
36
|
+
res = JSON.parse(res.body)
|
37
|
+
|
38
|
+
if res['statusCode'] == "ERROR" then
|
39
|
+
@log.error res['errorMessage']
|
40
|
+
url
|
41
|
+
else
|
42
|
+
res["results"][url]['shortUrl']
|
43
|
+
end
|
44
|
+
else
|
45
|
+
url
|
46
|
+
end
|
47
|
+
rescue Errno::ETIMEDOUT, JSON::ParserError, IOError, Timeout::Error, Errno::ECONNRESET => e
|
48
|
+
@log.error e
|
49
|
+
url
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/atig/channel.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# -*- mode:ruby; coding:utf-8 -*-
|
2
|
+
|
3
|
+
module Atig
|
4
|
+
module Channel
|
5
|
+
class Channel
|
6
|
+
def initialize(context, gateway, db)
|
7
|
+
@db = db
|
8
|
+
@channel = gateway.channel channel_name, :handler=>self
|
9
|
+
@channel.join_me
|
10
|
+
|
11
|
+
db.statuses.listen do|entry|
|
12
|
+
@channel.topic entry if entry.user.id == db.me.id
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# -*- mode:ruby; coding:utf-8 -*-
|
2
|
+
|
3
|
+
module Atig
|
4
|
+
module Channel
|
5
|
+
class List
|
6
|
+
class Handler
|
7
|
+
def initialize(db, name)
|
8
|
+
@db = db
|
9
|
+
@name = name
|
10
|
+
end
|
11
|
+
|
12
|
+
def on_invite(api, nick)
|
13
|
+
return if @name.include? '^'
|
14
|
+
|
15
|
+
api.post("#{@db.me.screen_name}/#{@name}/members", :id => nick )
|
16
|
+
@db.lists.invalidate @name
|
17
|
+
end
|
18
|
+
|
19
|
+
def on_kick(api, nick)
|
20
|
+
return if @name.include? '^'
|
21
|
+
|
22
|
+
api.delete("#{@db.me.screen_name}/#{@name}/members", :id => nick )
|
23
|
+
@db.lists.invalidate @name
|
24
|
+
end
|
25
|
+
|
26
|
+
def on_who(&f)
|
27
|
+
return unless f
|
28
|
+
@db.lists[@name].users.each(&f)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize(context, gateway, db)
|
33
|
+
@channels = Hash.new do|hash,name|
|
34
|
+
channel = gateway.channel "##{name}", :handler => Handler.new(db, name)
|
35
|
+
channel.join_me
|
36
|
+
hash[name] = channel
|
37
|
+
end
|
38
|
+
|
39
|
+
db.statuses.listen do|entry|
|
40
|
+
if entry.source == :list then
|
41
|
+
@channels[entry.list].message entry
|
42
|
+
else
|
43
|
+
lists = db.lists.find_by_screen_name(entry.user.screen_name)
|
44
|
+
lists.each{|name|
|
45
|
+
@channels[name].message entry
|
46
|
+
}
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
db.statuses.listen do|entry|
|
51
|
+
if entry.user.id == db.me.id
|
52
|
+
@channels.each{|_,channel|
|
53
|
+
channel.topic entry
|
54
|
+
}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
db.lists.listen do|kind, name, users|
|
59
|
+
case kind
|
60
|
+
when :new
|
61
|
+
@channels[name].join_me
|
62
|
+
@channels[name].join db.lists[name].users
|
63
|
+
when :del
|
64
|
+
@channels[name].part_me "No longer follow the list #{name}"
|
65
|
+
when :join
|
66
|
+
@channels[name].join users
|
67
|
+
when :part
|
68
|
+
@channels[name].part users
|
69
|
+
when :mode
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- mode:ruby; coding:utf-8 -*-
|
2
|
+
|
3
|
+
require 'atig/channel/channel'
|
4
|
+
module Atig
|
5
|
+
module Channel
|
6
|
+
class Mention < Atig::Channel::Channel
|
7
|
+
def initialize(context, gateway, db)
|
8
|
+
super
|
9
|
+
|
10
|
+
db.statuses.listen do|entry|
|
11
|
+
if entry.status.text.include?("@#{db.me.screen_name}")
|
12
|
+
@channel.message(entry)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def channel_name; "#mention" end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- mode:ruby; coding:utf-8 -*-
|
2
|
+
require 'atig/channel/channel'
|
3
|
+
|
4
|
+
module Atig
|
5
|
+
module Channel
|
6
|
+
class Retweet < Atig::Channel::Channel
|
7
|
+
def initialize(context, gateway, db)
|
8
|
+
super
|
9
|
+
|
10
|
+
db.statuses.find_all(:limit=>50).reverse_each {|entry|
|
11
|
+
message entry
|
12
|
+
}
|
13
|
+
|
14
|
+
db.statuses.listen {|entry|
|
15
|
+
message entry
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def channel_name; "#retweet" end
|
20
|
+
|
21
|
+
def message(entry)
|
22
|
+
if entry.status.retweeted_status then
|
23
|
+
@channel.message entry
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# -*- mode:ruby; coding:utf-8 -*-
|
2
|
+
|
3
|
+
require 'atig/channel/channel'
|
4
|
+
require 'atig/util'
|
5
|
+
require 'atig/update_checker'
|
6
|
+
|
7
|
+
module Atig
|
8
|
+
module Channel
|
9
|
+
class Timeline < Atig::Channel::Channel
|
10
|
+
include Util
|
11
|
+
|
12
|
+
def initialize(context, gateway, db)
|
13
|
+
super
|
14
|
+
@log = context.log
|
15
|
+
|
16
|
+
@channel.notify "Client options: #{context.opts.marshal_dump.inspect}"
|
17
|
+
|
18
|
+
# つないだときに発言がないとさみしいので
|
19
|
+
db.statuses.find_all(:limit=>50).reverse_each do|entry|
|
20
|
+
case entry.source
|
21
|
+
when :timeline, :me
|
22
|
+
@channel.message entry
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# 最新版のチェック
|
27
|
+
daemon do
|
28
|
+
log :info,"check update"
|
29
|
+
messages = UpdateChecker.latest
|
30
|
+
unless messages.empty?
|
31
|
+
@channel.notify "\002New version is available.\017 run 'git pull'."
|
32
|
+
messages[0, 3].each do |m|
|
33
|
+
@channel.notify " \002#{m[/.+/]}\017"
|
34
|
+
end
|
35
|
+
@channel.notify(" ... and more. check it: http://mzp.github.com/atig/") if messages.size > 3
|
36
|
+
end
|
37
|
+
sleep (3*60*60)
|
38
|
+
end
|
39
|
+
|
40
|
+
db.statuses.listen do|entry|
|
41
|
+
if db.followings.include?(entry.user) or
|
42
|
+
entry.source == :timeline or
|
43
|
+
entry.source == :user_stream or
|
44
|
+
entry.source == :me then
|
45
|
+
@channel.message entry
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
@channel.send :join, db.followings.users
|
50
|
+
|
51
|
+
db.followings.listen do|kind, users|
|
52
|
+
@channel.send(kind, users) if @channel.respond_to?(kind)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def on_invite(api, nick)
|
57
|
+
api.post("friendships/create/#{nick}")
|
58
|
+
@db.followings.invalidate
|
59
|
+
end
|
60
|
+
|
61
|
+
def on_kick(api, nick)
|
62
|
+
api.post("friendships/destroy/#{nick}")
|
63
|
+
@db.followings.invalidate
|
64
|
+
end
|
65
|
+
|
66
|
+
def on_who(&f)
|
67
|
+
return unless f
|
68
|
+
@db.followings.users.each(&f)
|
69
|
+
end
|
70
|
+
|
71
|
+
def channel_name; "#twitter" end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/lib/atig/command.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'atig/command/retweet'
|
2
|
+
require 'atig/command/reply'
|
3
|
+
require 'atig/command/user'
|
4
|
+
require 'atig/command/favorite'
|
5
|
+
require 'atig/command/uptime'
|
6
|
+
require 'atig/command/destroy'
|
7
|
+
require 'atig/command/status'
|
8
|
+
require 'atig/command/thread'
|
9
|
+
require 'atig/command/time'
|
10
|
+
require 'atig/command/version'
|
11
|
+
require 'atig/command/user_info'
|
12
|
+
require 'atig/command/whois'
|
13
|
+
require 'atig/command/option'
|
14
|
+
require 'atig/command/location'
|
15
|
+
require 'atig/command/name'
|
16
|
+
require 'atig/command/autofix'
|
17
|
+
require 'atig/command/limit'
|
18
|
+
require 'atig/command/search'
|
19
|
+
require 'atig/command/refresh'
|
20
|
+
require 'atig/command/spam'
|
21
|
+
require 'atig/command/dm'
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# -*- mode:ruby; coding:utf-8 -*-
|
2
|
+
require 'atig/command/command'
|
3
|
+
require 'atig/levenshtein'
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'jcode'
|
7
|
+
rescue LoadError
|
8
|
+
end
|
9
|
+
|
10
|
+
module Atig
|
11
|
+
module Command
|
12
|
+
class Autofix < Atig::Command::Command
|
13
|
+
def initialize(*args); super end
|
14
|
+
def command_name; /(?:autofix|topic|overwwrite)!?/ end
|
15
|
+
|
16
|
+
def distance(s1, s2)
|
17
|
+
c1 = s1.split(//)
|
18
|
+
c2 = s2.split(//)
|
19
|
+
distance = Atig::Levenshtein.levenshtein c1, c2
|
20
|
+
distance.to_f / [ c1.size, c2.size ].max
|
21
|
+
end
|
22
|
+
|
23
|
+
def fix?(command, text, prev)
|
24
|
+
command[-1,1] == '!' or distance(text, prev.status.text) < 0.5
|
25
|
+
end
|
26
|
+
|
27
|
+
def action(target, mesg, command, args)
|
28
|
+
if args.empty?
|
29
|
+
yield "/me #{command} blah blah"
|
30
|
+
return
|
31
|
+
end
|
32
|
+
text = mesg.split(" ", 2)[1]
|
33
|
+
q = gateway.output_message(:status => text)
|
34
|
+
|
35
|
+
prev,*_ = db.statuses.find_by_user( db.me, :limit => 1)
|
36
|
+
|
37
|
+
unless fix?(command, q[:status], prev) then
|
38
|
+
api.delay(0, :retry=>3) do|t|
|
39
|
+
ret = t.post("statuses/update", q)
|
40
|
+
gateway.update_status ret, target
|
41
|
+
end
|
42
|
+
else
|
43
|
+
api.delay(0, :retry=>3) do|t|
|
44
|
+
yield "Similar update in previous. Conclude that it has error."
|
45
|
+
yield "And overwrite previous as new status: #{q[:status]}"
|
46
|
+
|
47
|
+
ret = t.post("statuses/update", q)
|
48
|
+
gateway.update_status ret, target
|
49
|
+
t.post("statuses/destroy/#{prev.status.id}")
|
50
|
+
db.statuses.transaction{|d|
|
51
|
+
d.remove_by_id prev.id
|
52
|
+
}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- mode:ruby; coding:utf-8 -*-
|
2
|
+
module Atig
|
3
|
+
module Command
|
4
|
+
class Command
|
5
|
+
attr_reader :gateway, :api, :db, :opts
|
6
|
+
def initialize(context, gateway, api, db)
|
7
|
+
@log = context.log
|
8
|
+
@opts = context.opts
|
9
|
+
@gateway = gateway
|
10
|
+
@api = api
|
11
|
+
@db = db
|
12
|
+
@gateway.ctcp_action(*command_name) do |target, mesg, command, args|
|
13
|
+
action(target, mesg, command, args){|m|
|
14
|
+
gateway[target].notify m
|
15
|
+
}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def find_by_tid(tid)
|
20
|
+
@db.statuses.find_by_tid tid
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# -*- mode:ruby; coding:utf-8 -*-
|
2
|
+
|
3
|
+
class FakeGateway
|
4
|
+
attr_reader :names,:action,:filtered,:updated, :notified
|
5
|
+
|
6
|
+
def initialize(channel)
|
7
|
+
@channel = channel
|
8
|
+
end
|
9
|
+
|
10
|
+
def ctcp_action(*names, &action)
|
11
|
+
@names = names
|
12
|
+
@action = action
|
13
|
+
end
|
14
|
+
|
15
|
+
def output_message(m); @filtered = m end
|
16
|
+
|
17
|
+
def update_status(*args); @updated = args end
|
18
|
+
|
19
|
+
def [](name)
|
20
|
+
@notified = name
|
21
|
+
@channel
|
22
|
+
end
|
23
|
+
|
24
|
+
def server_name; "server-name" end
|
25
|
+
end
|
26
|
+
|
27
|
+
class FakeScheduler
|
28
|
+
def initialize(api)
|
29
|
+
@api = api
|
30
|
+
end
|
31
|
+
|
32
|
+
def delay(interval,opt={},&f)
|
33
|
+
f.call @api
|
34
|
+
end
|
35
|
+
|
36
|
+
def limit; @api.limit end
|
37
|
+
def remain; @api.remain end
|
38
|
+
def reset; @api.reset end
|
39
|
+
end
|
40
|
+
|
41
|
+
class FakeDb
|
42
|
+
attr_reader :statuses, :followings,:lists, :me
|
43
|
+
def initialize(statuses, followings,lists, me)
|
44
|
+
@statuses = statuses
|
45
|
+
@followings = followings
|
46
|
+
@lists = lists
|
47
|
+
@me = me
|
48
|
+
end
|
49
|
+
|
50
|
+
def transaction(&f)
|
51
|
+
f.call self
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class FakeDbEntry
|
56
|
+
def initialize(name)
|
57
|
+
@name = name
|
58
|
+
end
|
59
|
+
|
60
|
+
def transaction(&f)
|
61
|
+
f.call self
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
module CommandHelper
|
66
|
+
def init(klass)
|
67
|
+
@log = mock 'log'
|
68
|
+
@opts = Atig::Option.new({})
|
69
|
+
context = OpenStruct.new :log=>@log, :opts=>@opts
|
70
|
+
|
71
|
+
@channel = mock 'channel'
|
72
|
+
@gateway = FakeGateway.new @channel
|
73
|
+
@api = mock 'api'
|
74
|
+
@statuses = FakeDbEntry.new 'status DB'
|
75
|
+
@followings = FakeDbEntry.new 'followings DB'
|
76
|
+
@lists = {
|
77
|
+
"A" => FakeDbEntry.new('list A'),
|
78
|
+
"B" => FakeDbEntry.new('list B')
|
79
|
+
}
|
80
|
+
|
81
|
+
@me = user 1,'me'
|
82
|
+
@db = FakeDb.new @statuses, @followings, @lists, @me
|
83
|
+
@command = klass.new context, @gateway, FakeScheduler.new(@api), @db
|
84
|
+
end
|
85
|
+
|
86
|
+
def call(channel, command, args)
|
87
|
+
@gateway.action.call channel, "#{command} #{args.join(' ')}", command, args
|
88
|
+
end
|
89
|
+
|
90
|
+
def stub_status(key, hash)
|
91
|
+
@statuses.stub!(key).and_return{|arg,*_|
|
92
|
+
hash.fetch(arg, hash[:default])
|
93
|
+
}
|
94
|
+
end
|
95
|
+
end
|