atig 0.0.1
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.
- 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
|