draftcode-termtter 1.0.8
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/History.txt +4 -0
- data/README.rdoc +100 -0
- data/Rakefile +55 -0
- data/bin/kill_termtter +22 -0
- data/bin/termtter +6 -0
- data/lib/plugins/addspace.rb +27 -0
- data/lib/plugins/april_fool.rb +15 -0
- data/lib/plugins/bomb.rb +39 -0
- data/lib/plugins/clear.rb +14 -0
- data/lib/plugins/command_plus.rb +47 -0
- data/lib/plugins/confirm.rb +33 -0
- data/lib/plugins/cool.rb +10 -0
- data/lib/plugins/countter.rb +23 -0
- data/lib/plugins/devel.rb +18 -0
- data/lib/plugins/direct_messages.rb +36 -0
- data/lib/plugins/en2ja.rb +11 -0
- data/lib/plugins/english.rb +25 -0
- data/lib/plugins/erb.rb +17 -0
- data/lib/plugins/exec.rb +17 -0
- data/lib/plugins/exec_and_update.rb +14 -0
- data/lib/plugins/expand-tinyurl.rb +34 -0
- data/lib/plugins/fib.rb +28 -0
- data/lib/plugins/fib_filter.rb +14 -0
- data/lib/plugins/filter.rb +69 -0
- data/lib/plugins/graduatter.rb +8 -0
- data/lib/plugins/grass.rb +27 -0
- data/lib/plugins/group.rb +64 -0
- data/lib/plugins/growl.rb +52 -0
- data/lib/plugins/growl2.rb +143 -0
- data/lib/plugins/hatebu.rb +59 -0
- data/lib/plugins/hatebu_and_update.rb +58 -0
- data/lib/plugins/history.rb +93 -0
- data/lib/plugins/ignore.rb +19 -0
- data/lib/plugins/keyword.rb +18 -0
- data/lib/plugins/l2.rb +25 -0
- data/lib/plugins/log.rb +73 -0
- data/lib/plugins/me.rb +10 -0
- data/lib/plugins/modify_arg_hook_sample.rb +7 -0
- data/lib/plugins/msagent.rb +38 -0
- data/lib/plugins/multi_reply.rb +27 -0
- data/lib/plugins/notify-send.rb +22 -0
- data/lib/plugins/notify-send2.rb +52 -0
- data/lib/plugins/notify-send3.rb +45 -0
- data/lib/plugins/open_url.rb +59 -0
- data/lib/plugins/otsune.rb +21 -0
- data/lib/plugins/outputz.rb +33 -0
- data/lib/plugins/pause.rb +3 -0
- data/lib/plugins/post_exec_hook_sample.rb +9 -0
- data/lib/plugins/pre_exec_hook_sample.rb +9 -0
- data/lib/plugins/primes.rb +30 -0
- data/lib/plugins/quicklook.rb +41 -0
- data/lib/plugins/random.rb +23 -0
- data/lib/plugins/reblog.rb +40 -0
- data/lib/plugins/reload.rb +3 -0
- data/lib/plugins/reply.rb +8 -0
- data/lib/plugins/retweet.rb +46 -0
- data/lib/plugins/reverse.rb +13 -0
- data/lib/plugins/say.rb +26 -0
- data/lib/plugins/scrape.rb +41 -0
- data/lib/plugins/screen-notify.rb +20 -0
- data/lib/plugins/screen.rb +24 -0
- data/lib/plugins/shell.rb +14 -0
- data/lib/plugins/sl.rb +48 -0
- data/lib/plugins/spam.rb +16 -0
- data/lib/plugins/standard_plugins.rb +525 -0
- data/lib/plugins/stdout.rb +220 -0
- data/lib/plugins/storage.rb +55 -0
- data/lib/plugins/storage/DB.rb +37 -0
- data/lib/plugins/storage/status.rb +83 -0
- data/lib/plugins/storage/status_mook.rb +30 -0
- data/lib/plugins/switch_user.rb +22 -0
- data/lib/plugins/system_status.rb +33 -0
- data/lib/plugins/timer.rb +18 -0
- data/lib/plugins/tinyurl.rb +20 -0
- data/lib/plugins/translation.rb +38 -0
- data/lib/plugins/typable_id.rb +94 -0
- data/lib/plugins/update_editor.rb +53 -0
- data/lib/plugins/uri-open.rb +66 -0
- data/lib/plugins/wassr_post.rb +22 -0
- data/lib/plugins/yhara.rb +148 -0
- data/lib/plugins/yhara_filter.rb +8 -0
- data/lib/plugins/yonda.rb +21 -0
- data/lib/termtter.rb +38 -0
- data/lib/termtter/api.rb +57 -0
- data/lib/termtter/client.rb +324 -0
- data/lib/termtter/command.rb +80 -0
- data/lib/termtter/config.rb +68 -0
- data/lib/termtter/config_setup.rb +38 -0
- data/lib/termtter/connection.rb +41 -0
- data/lib/termtter/hook.rb +31 -0
- data/lib/termtter/optparse.rb +14 -0
- data/lib/termtter/system_extensions.rb +115 -0
- data/lib/termtter/task.rb +17 -0
- data/lib/termtter/task_manager.rb +116 -0
- data/lib/termtter/version.rb +4 -0
- data/spec/plugins/cool_spec.rb +10 -0
- data/spec/plugins/english_spec.rb +19 -0
- data/spec/plugins/fib_spec.rb +15 -0
- data/spec/plugins/filter_spec.rb +18 -0
- data/spec/plugins/pause_spec.rb +8 -0
- data/spec/plugins/primes_spec.rb +15 -0
- data/spec/plugins/shell_spec.rb +10 -0
- data/spec/plugins/sl_spec.rb +8 -0
- data/spec/plugins/spam_spec.rb +4 -0
- data/spec/plugins/standard_plugins_spec.rb +23 -0
- data/spec/plugins/storage/DB_spec.rb +12 -0
- data/spec/plugins/storage/status_spec.rb +24 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/termtter/client_spec.rb +255 -0
- data/spec/termtter/command_spec.rb +107 -0
- data/spec/termtter/config_spec.rb +111 -0
- data/spec/termtter/hook_spec.rb +78 -0
- data/spec/termtter/task_manager_spec.rb +78 -0
- data/spec/termtter/task_spec.rb +22 -0
- data/spec/termtter_spec.rb +29 -0
- data/test/friends_timeline.json +5 -0
- data/test/search.json +8 -0
- metadata +211 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
module Termtter
|
|
4
|
+
|
|
5
|
+
class Command
|
|
6
|
+
|
|
7
|
+
attr_accessor :name, :aliases, :exec_proc, :completion_proc, :help
|
|
8
|
+
|
|
9
|
+
# args
|
|
10
|
+
# name: Symbol as command name
|
|
11
|
+
# aliases: Array of command alias (ex. ['u', 'up'])
|
|
12
|
+
# exec_proc: Proc for procedure of the command. If need the proc must return object for hook.
|
|
13
|
+
# completion_proc: Proc for input completion. The proc must return Array of candidates (Optional)
|
|
14
|
+
# help: help text for the command (Optional)
|
|
15
|
+
def initialize(args)
|
|
16
|
+
raise ArgumentError, ":name is not given." unless args.has_key?(:name)
|
|
17
|
+
args[:exec_proc] ||= args[:exec]
|
|
18
|
+
args[:completion_proc] ||= args[:completion]
|
|
19
|
+
args[:aliases] ||= [args[:alias]].compact
|
|
20
|
+
|
|
21
|
+
cfg = {
|
|
22
|
+
:aliases => [],
|
|
23
|
+
:exec_proc => lambda {|arg| },
|
|
24
|
+
:comletion_proc => lambda {|command, arg| [] }
|
|
25
|
+
}.merge(args)
|
|
26
|
+
|
|
27
|
+
set cfg
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def set(cfg)
|
|
31
|
+
@name = cfg[:name].to_sym
|
|
32
|
+
@aliases = cfg[:aliases].map {|e| e.to_sym }
|
|
33
|
+
@exec_proc = cfg[:exec_proc]
|
|
34
|
+
@completion_proc = cfg[:completion_proc]
|
|
35
|
+
@help = cfg[:help]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def complement(input)
|
|
39
|
+
if match?(input) && input =~ /^[^\s]+\s/
|
|
40
|
+
if completion_proc
|
|
41
|
+
command_str, command_arg = Command.split_command_line(input)
|
|
42
|
+
[completion_proc.call(command_str, command_arg || '')].flatten.compact
|
|
43
|
+
else
|
|
44
|
+
[]
|
|
45
|
+
end
|
|
46
|
+
else
|
|
47
|
+
[name.to_s, aliases.to_s].grep(/^#{Regexp.quote(input)}/)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def call(cmd = nil, arg = nil, original_text = nil)
|
|
52
|
+
arg = case arg
|
|
53
|
+
when nil
|
|
54
|
+
''
|
|
55
|
+
when String
|
|
56
|
+
arg
|
|
57
|
+
else
|
|
58
|
+
raise ArgumentError, 'arg should be String or nil'
|
|
59
|
+
end
|
|
60
|
+
exec_proc.call(arg)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def match?(input)
|
|
64
|
+
(pattern =~ input) != nil
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def pattern
|
|
68
|
+
commands_regex = commands.map {|name| Regexp.quote(name.to_s) }.join('|')
|
|
69
|
+
/^((#{commands_regex})|(#{commands_regex})\s+(.*?))\s*$/
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def commands
|
|
73
|
+
[name] + aliases
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def self.split_command_line(line)
|
|
77
|
+
line.strip.split(/\s+/, 2)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
module Termtter
|
|
4
|
+
class Config
|
|
5
|
+
def initialize
|
|
6
|
+
@store = Hash.new(:undefined)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def inspect
|
|
10
|
+
@store.inspect
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# set_default :: (Symbol | String) -> a -> IO ()
|
|
14
|
+
def set_default(name, value)
|
|
15
|
+
match_p, init, last = *name.to_s.match(/^(.+)\.([^\.]+)$/)
|
|
16
|
+
if match_p
|
|
17
|
+
tmp = eval(init)
|
|
18
|
+
if tmp.__refer__(last.to_sym).empty?
|
|
19
|
+
tmp.__assign__(last.to_sym, value)
|
|
20
|
+
end
|
|
21
|
+
else
|
|
22
|
+
__assign__(name.to_sym, value) if __refer__(name.to_sym).empty?
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# empty? :: Boolean
|
|
27
|
+
def empty?
|
|
28
|
+
@store.empty?
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def method_missing(name, *args)
|
|
32
|
+
case name.to_s
|
|
33
|
+
when /(.*)=$/
|
|
34
|
+
__assign__($1.to_sym, args.first)
|
|
35
|
+
else
|
|
36
|
+
__refer__(name.to_sym)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# __assign__ :: Symbol -> a -> IO ()
|
|
41
|
+
def __assign__(name, value)
|
|
42
|
+
@store[name] = value
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# __refer__ :: Symbol -> IO a
|
|
46
|
+
def __refer__(name)
|
|
47
|
+
@store[name] == :undefined ? @store[name] = Termtter::Config.new : @store[name]
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def __values__
|
|
51
|
+
@store.dup
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
__instance = self.new
|
|
55
|
+
(class << self; self end).
|
|
56
|
+
__send__(:define_method, :instance) { __instance }
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def config
|
|
61
|
+
Termtter::Config.instance
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def configatron
|
|
65
|
+
# remove this method until Termtter-1.2.0
|
|
66
|
+
warn "configatron method will be removed. Use config instead. (#{caller.first})"
|
|
67
|
+
Termtter::Config.instance
|
|
68
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
module Termtter
|
|
4
|
+
module ConfigSetup
|
|
5
|
+
module_function
|
|
6
|
+
def run
|
|
7
|
+
ui = create_highline
|
|
8
|
+
username = ui.ask('your twitter username: ')
|
|
9
|
+
password = ui.ask('your twitter password: ') { |q| q.echo = false }
|
|
10
|
+
|
|
11
|
+
Dir.mkdir(Termtter::CONF_DIR) unless File.exists?(Termtter::CONF_DIR)
|
|
12
|
+
File.open(Termtter::CONF_FILE, 'w') {|io|
|
|
13
|
+
io.puts '# -*- coding: utf-8 -*-'
|
|
14
|
+
|
|
15
|
+
io.puts
|
|
16
|
+
io.puts "config.user_name = '#{username}'"
|
|
17
|
+
io.puts "config.password = '#{password}'"
|
|
18
|
+
io.puts "#config.update_interval = 120"
|
|
19
|
+
io.puts "#config.proxy.host = 'proxy host'"
|
|
20
|
+
io.puts "#config.proxy.port = '8080'"
|
|
21
|
+
io.puts "#config.proxy.user_name = 'proxy user'"
|
|
22
|
+
io.puts "#config.proxy.password = 'proxy password'"
|
|
23
|
+
io.puts
|
|
24
|
+
plugins = Dir.glob(File.expand_path(File.dirname(__FILE__) + "/../plugins/*.rb")).map {|f|
|
|
25
|
+
f.match(%r|lib/plugins/(.*?).rb$|)[1]
|
|
26
|
+
}
|
|
27
|
+
plugins -= %w[stdout standard_plugins]
|
|
28
|
+
plugins.each do |p|
|
|
29
|
+
io.puts "#plugin '#{p}'"
|
|
30
|
+
end
|
|
31
|
+
io.puts
|
|
32
|
+
io.puts "# vim: set filetype=ruby"
|
|
33
|
+
}
|
|
34
|
+
puts "generated: ~/.termtter/config"
|
|
35
|
+
puts "enjoy!"
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
module Termtter
|
|
4
|
+
class Connection
|
|
5
|
+
attr_reader :protocol, :port, :proxy_uri
|
|
6
|
+
|
|
7
|
+
def initialize
|
|
8
|
+
unless config.proxy.empty?
|
|
9
|
+
@proxy_host = config.proxy.host
|
|
10
|
+
@proxy_port = config.proxy.port
|
|
11
|
+
@proxy_user = config.proxy.user_name
|
|
12
|
+
@proxy_password = config.proxy.password
|
|
13
|
+
@proxy_uri = nil
|
|
14
|
+
@enable_ssl = config.enable_ssl
|
|
15
|
+
end
|
|
16
|
+
@protocol = "http"
|
|
17
|
+
@port = 80
|
|
18
|
+
|
|
19
|
+
if @proxy_host
|
|
20
|
+
@http_class = Net::HTTP::Proxy(@proxy_host, @proxy_port,
|
|
21
|
+
@proxy_user, @proxy_password)
|
|
22
|
+
@proxy_uri = "http://" + @proxy_host + ":" + @proxy_port + "/"
|
|
23
|
+
else
|
|
24
|
+
@http_class = Net::HTTP
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
if @enable_ssl
|
|
28
|
+
@protocol = "https"
|
|
29
|
+
@port = 443
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def start(host, port, &block)
|
|
34
|
+
http = @http_class.new(host, port)
|
|
35
|
+
http.use_ssl = @enable_ssl
|
|
36
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE if http.use_ssl?
|
|
37
|
+
http.start(&block)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
module Termtter
|
|
4
|
+
class Hook
|
|
5
|
+
attr_accessor :name, :points, :exec_proc
|
|
6
|
+
|
|
7
|
+
def initialize(args)
|
|
8
|
+
raise ArgumentError, ":name is not given." unless args.has_key?(:name)
|
|
9
|
+
@name = args[:name].to_sym
|
|
10
|
+
@points = args[:points] || [args[:point]].compact
|
|
11
|
+
@exec_proc = args[:exec_proc] || args[:exec] || lambda {}
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def match?(point)
|
|
15
|
+
!points.select{|pt|
|
|
16
|
+
case pt
|
|
17
|
+
when String, Symbol
|
|
18
|
+
pt.to_s == point.to_s
|
|
19
|
+
when Regexp
|
|
20
|
+
(pt =~ point.to_s) ? true : false
|
|
21
|
+
else
|
|
22
|
+
false
|
|
23
|
+
end
|
|
24
|
+
}.empty?
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def call(*args)
|
|
28
|
+
self.exec_proc.call(*args)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
OptionParser.new { |opt|
|
|
2
|
+
opt.on('-f', '--file config_file', 'Set path to configfile') do |val|
|
|
3
|
+
config.system.__assign__(:conf_file, val)
|
|
4
|
+
end
|
|
5
|
+
opt.on('-t', '--termtter-directory directory', 'Set termtter directory') do |val|
|
|
6
|
+
config.system.__assign__(:conf_dir, val)
|
|
7
|
+
end
|
|
8
|
+
opt.on('-d', '--devel', 'Start in developer mode') do |flg|
|
|
9
|
+
config.system.__assign__(:devel, true) if flg
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
Version = Termtter::VERSION
|
|
13
|
+
opt.parse!(ARGV)
|
|
14
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
def plugin(name, init = {})
|
|
4
|
+
unless init.empty?
|
|
5
|
+
init.each do |key, value|
|
|
6
|
+
config.plugins.__refer__(name.to_sym).__assign__(key.to_sym, value)
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
load "plugins/#{name}.rb"
|
|
10
|
+
rescue Exception => e
|
|
11
|
+
Termtter::Client.handle_error(e)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def filter(name, init = {})
|
|
15
|
+
warn "filter method will be removed. Use plugin instead."
|
|
16
|
+
plugin(name, init)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def win?
|
|
20
|
+
RUBY_PLATFORM.downcase =~ /mswin(?!ce)|mingw|bccwin/
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
if win?
|
|
24
|
+
require 'iconv'
|
|
25
|
+
require 'Win32API'
|
|
26
|
+
$wGetACP = Win32API.new('kernel32','GetACP','','I')
|
|
27
|
+
|
|
28
|
+
$wSetConsoleTextAttribute = Win32API.new('kernel32','SetConsoleTextAttribute','II','I')
|
|
29
|
+
$wGetConsoleScreenBufferInfo = Win32API.new("kernel32", "GetConsoleScreenBufferInfo", ['l', 'p'], 'i')
|
|
30
|
+
$wGetStdHandle = Win32API.new('kernel32','GetStdHandle','I','I')
|
|
31
|
+
$wGetACP = Win32API.new('kernel32','GetACP','','I')
|
|
32
|
+
|
|
33
|
+
$hStdOut = $wGetStdHandle.call(0xFFFFFFF5)
|
|
34
|
+
lpBuffer = ' ' * 22
|
|
35
|
+
$wGetConsoleScreenBufferInfo.call($hStdOut, lpBuffer)
|
|
36
|
+
$oldColor = lpBuffer.unpack('SSSSSssssSS')[4]
|
|
37
|
+
|
|
38
|
+
$colorMap = {
|
|
39
|
+
0 => 0x07|0x00|0x00|0x00, # black/white
|
|
40
|
+
37 => 0x08|0x00|0x00|0x00, # white/intensity
|
|
41
|
+
31 => 0x04|0x08|0x00|0x00, # red/red
|
|
42
|
+
32 => 0x02|0x08|0x00|0x00, # green/green
|
|
43
|
+
33 => 0x06|0x08|0x00|0x00, # yellow/yellow
|
|
44
|
+
34 => 0x01|0x08|0x00|0x00, # blue/blue
|
|
45
|
+
35 => 0x05|0x08|0x00|0x00, # magenta/purple
|
|
46
|
+
36 => 0x03|0x08|0x00|0x00, # cyan/aqua
|
|
47
|
+
39 => 0x07, # default
|
|
48
|
+
40 => 0x00|0x00|0xf0|0x00, # background:white
|
|
49
|
+
41 => 0x07|0x00|0x40|0x00, # background:red
|
|
50
|
+
42 => 0x07|0x00|0x20|0x00, # background:green
|
|
51
|
+
43 => 0x07|0x00|0x60|0x00, # background:yellow
|
|
52
|
+
44 => 0x07|0x00|0x10|0x00, # background:blue
|
|
53
|
+
45 => 0x07|0x00|0x50|0x80, # background:magenta
|
|
54
|
+
46 => 0x07|0x00|0x30|0x80, # background:cyan
|
|
55
|
+
47 => 0x07|0x00|0x70|0x80, # background:gray
|
|
56
|
+
49 => 0x70, # default
|
|
57
|
+
90 => 0x07|0x00|0x00|0x00, # erase/white
|
|
58
|
+
}
|
|
59
|
+
$iconv_u8_to_sj = Iconv.new("CP#{$wGetACP.call()}", 'UTF-8')
|
|
60
|
+
def print(str)
|
|
61
|
+
str.to_s.gsub("\xef\xbd\x9e", "\xe3\x80\x9c").split(/(\e\[\d*[a-zA-Z])/).each do |token|
|
|
62
|
+
case token
|
|
63
|
+
when /\e\[(\d+)m/
|
|
64
|
+
$wSetConsoleTextAttribute.call $hStdOut, $colorMap[$1.to_i].to_i
|
|
65
|
+
when /\e\[\d*[a-zA-Z]/
|
|
66
|
+
# do nothing
|
|
67
|
+
else
|
|
68
|
+
loop do
|
|
69
|
+
begin
|
|
70
|
+
STDOUT.print $iconv_u8_to_sj.iconv(token)
|
|
71
|
+
break
|
|
72
|
+
rescue Iconv::Failure
|
|
73
|
+
STDOUT.print "#{$!.success}?"
|
|
74
|
+
token = $!.failed[1..-1]
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
$wSetConsoleTextAttribute.call $hStdOut, $oldColor
|
|
80
|
+
$iconv_u8_to_sj.iconv(nil)
|
|
81
|
+
end
|
|
82
|
+
def puts(str)
|
|
83
|
+
print str
|
|
84
|
+
STDOUT.puts
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
unless Array.instance_methods.include?('take')
|
|
89
|
+
class Array
|
|
90
|
+
def take(n) self[0...n] end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
unless Symbol.instance_methods.include?('to_proc')
|
|
95
|
+
class Symbol
|
|
96
|
+
def to_proc
|
|
97
|
+
Proc.new { |*args| args.shift.__send__(self, *args) }
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
require 'highline'
|
|
103
|
+
def create_highline
|
|
104
|
+
HighLine.track_eof = false
|
|
105
|
+
if $stdin.respond_to?(:getbyte) # for ruby1.9
|
|
106
|
+
require 'delegate'
|
|
107
|
+
stdin_for_highline = SimpleDelegator.new($stdin)
|
|
108
|
+
def stdin_for_highline.getc
|
|
109
|
+
getbyte
|
|
110
|
+
end
|
|
111
|
+
else
|
|
112
|
+
stdin_for_highline = $stdin
|
|
113
|
+
end
|
|
114
|
+
HighLine.new(stdin_for_highline)
|
|
115
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
module Termtter
|
|
4
|
+
class Task
|
|
5
|
+
attr_accessor :name, :exec_at, :exec_proc, :interval, :work
|
|
6
|
+
def initialize(args = {}, &block)
|
|
7
|
+
@name = args[:name]
|
|
8
|
+
@exec_at = Time.now + (args[:after] || 0)
|
|
9
|
+
@interval = args[:interval]
|
|
10
|
+
@exec_proc = block || lambda {}
|
|
11
|
+
@work = true
|
|
12
|
+
end
|
|
13
|
+
def execute
|
|
14
|
+
exec_proc.call(self) if work
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
module Termtter
|
|
4
|
+
class TaskManager
|
|
5
|
+
|
|
6
|
+
INTERVAL = 1
|
|
7
|
+
|
|
8
|
+
def initialize()
|
|
9
|
+
@tasks = {}
|
|
10
|
+
@work = true
|
|
11
|
+
@mutex = Mutex.new
|
|
12
|
+
@pause = false
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def pause
|
|
16
|
+
@pause = true
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def resume
|
|
20
|
+
@pause = false
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def kill
|
|
24
|
+
@work = false
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def run
|
|
28
|
+
Thread.new do
|
|
29
|
+
while @work
|
|
30
|
+
step unless @pause
|
|
31
|
+
sleep INTERVAL
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def step
|
|
37
|
+
pull_due_tasks.each do |task|
|
|
38
|
+
invoke_and_wait do
|
|
39
|
+
task.execute
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def invoke_later
|
|
45
|
+
Thread.new do
|
|
46
|
+
invoke_and_wait do
|
|
47
|
+
yield
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def invoke_and_wait(&block)
|
|
53
|
+
synchronize do
|
|
54
|
+
begin
|
|
55
|
+
yield
|
|
56
|
+
rescue Exception => e
|
|
57
|
+
Termtter::Client.handle_error(e)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def add_task(args = {}, &block)
|
|
63
|
+
synchronize do
|
|
64
|
+
task = Task.new(args, &block)
|
|
65
|
+
@tasks[task.name || task.object_id] = task
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def get_task(key)
|
|
70
|
+
synchronize do
|
|
71
|
+
@tasks[key]
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def delete_task(key)
|
|
76
|
+
synchronize do
|
|
77
|
+
@tasks.delete(key)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
private
|
|
82
|
+
|
|
83
|
+
def synchronize
|
|
84
|
+
unless Thread.current == @thread_in_sync
|
|
85
|
+
@mutex.synchronize do
|
|
86
|
+
@thread_in_sync = Thread.current
|
|
87
|
+
yield
|
|
88
|
+
end
|
|
89
|
+
else
|
|
90
|
+
yield
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def pull_due_tasks()
|
|
95
|
+
synchronize do
|
|
96
|
+
time_now = Time.now
|
|
97
|
+
due_tasks = []
|
|
98
|
+
@tasks.delete_if do |key, task|
|
|
99
|
+
if task.work && task.exec_at <= time_now
|
|
100
|
+
due_tasks << task
|
|
101
|
+
if task.interval
|
|
102
|
+
task.exec_at = time_now + task.interval
|
|
103
|
+
false
|
|
104
|
+
else
|
|
105
|
+
true
|
|
106
|
+
end
|
|
107
|
+
else
|
|
108
|
+
false
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
return due_tasks
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
end
|
|
116
|
+
end
|