butler 1.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +4 -0
- data/GPL.txt +340 -0
- data/LICENSE.txt +52 -0
- data/README +37 -0
- data/Rakefile +334 -0
- data/bin/botcontrol +230 -0
- data/data/butler/config_template.yaml +4 -0
- data/data/butler/dialogs/backup.rb +19 -0
- data/data/butler/dialogs/botcontrol.rb +4 -0
- data/data/butler/dialogs/config.rb +1 -0
- data/data/butler/dialogs/create.rb +53 -0
- data/data/butler/dialogs/delete.rb +3 -0
- data/data/butler/dialogs/en/backup.yaml +6 -0
- data/data/butler/dialogs/en/botcontrol.yaml +5 -0
- data/data/butler/dialogs/en/create.yaml +11 -0
- data/data/butler/dialogs/en/delete.yaml +2 -0
- data/data/butler/dialogs/en/help.yaml +17 -0
- data/data/butler/dialogs/en/info.yaml +13 -0
- data/data/butler/dialogs/en/list.yaml +4 -0
- data/data/butler/dialogs/en/notyetimplemented.yaml +2 -0
- data/data/butler/dialogs/en/rename.yaml +3 -0
- data/data/butler/dialogs/en/start.yaml +3 -0
- data/data/butler/dialogs/en/sync_plugins.yaml +3 -0
- data/data/butler/dialogs/en/uninstall.yaml +5 -0
- data/data/butler/dialogs/en/unknown_command.yaml +2 -0
- data/data/butler/dialogs/help.rb +11 -0
- data/data/butler/dialogs/info.rb +27 -0
- data/data/butler/dialogs/interactive.rb +1 -0
- data/data/butler/dialogs/list.rb +10 -0
- data/data/butler/dialogs/notyetimplemented.rb +1 -0
- data/data/butler/dialogs/rename.rb +4 -0
- data/data/butler/dialogs/selectbot.rb +2 -0
- data/data/butler/dialogs/start.rb +5 -0
- data/data/butler/dialogs/sync_plugins.rb +30 -0
- data/data/butler/dialogs/uninstall.rb +17 -0
- data/data/butler/dialogs/unknown_command.rb +1 -0
- data/data/butler/plugins/core/logout.rb +41 -0
- data/data/butler/plugins/core/plugins.rb +134 -0
- data/data/butler/plugins/core/privilege.rb +103 -0
- data/data/butler/plugins/core/user.rb +166 -0
- data/data/butler/plugins/dev/eval.rb +64 -0
- data/data/butler/plugins/dev/nometa.rb +14 -0
- data/data/butler/plugins/dev/onhandlers.rb +93 -0
- data/data/butler/plugins/dev/raw.rb +36 -0
- data/data/butler/plugins/dev/rawlog.rb +77 -0
- data/data/butler/plugins/games/eightball.rb +54 -0
- data/data/butler/plugins/games/mastermind.rb +174 -0
- data/data/butler/plugins/irc/action.rb +36 -0
- data/data/butler/plugins/irc/join.rb +38 -0
- data/data/butler/plugins/irc/notice.rb +36 -0
- data/data/butler/plugins/irc/part.rb +38 -0
- data/data/butler/plugins/irc/privmsg.rb +36 -0
- data/data/butler/plugins/irc/quit.rb +36 -0
- data/data/butler/plugins/operator/deop.rb +41 -0
- data/data/butler/plugins/operator/devoice.rb +41 -0
- data/data/butler/plugins/operator/limit.rb +47 -0
- data/data/butler/plugins/operator/op.rb +41 -0
- data/data/butler/plugins/operator/voice.rb +41 -0
- data/data/butler/plugins/public/help.rb +69 -0
- data/data/butler/plugins/public/login.rb +72 -0
- data/data/butler/plugins/public/usage.rb +49 -0
- data/data/butler/plugins/service/clones.rb +56 -0
- data/data/butler/plugins/service/define.rb +47 -0
- data/data/butler/plugins/service/log.rb +183 -0
- data/data/butler/plugins/service/svn.rb +91 -0
- data/data/butler/plugins/util/cycle.rb +98 -0
- data/data/butler/plugins/util/load.rb +41 -0
- data/data/butler/plugins/util/pong.rb +29 -0
- data/data/butler/strings/random/acknowledge.en.yaml +5 -0
- data/data/butler/strings/random/gratitude.en.yaml +3 -0
- data/data/butler/strings/random/hello.en.yaml +4 -0
- data/data/butler/strings/random/ignorance.en.yaml +7 -0
- data/data/butler/strings/random/ignorance_about.en.yaml +3 -0
- data/data/butler/strings/random/insult.en.yaml +3 -0
- data/data/butler/strings/random/rejection.en.yaml +12 -0
- data/data/man/botcontrol.1 +17 -0
- data/lib/access.rb +187 -0
- data/lib/access/admin.rb +16 -0
- data/lib/access/privilege.rb +122 -0
- data/lib/access/role.rb +102 -0
- data/lib/access/savable.rb +18 -0
- data/lib/access/user.rb +180 -0
- data/lib/access/yamlbase.rb +126 -0
- data/lib/butler.rb +188 -0
- data/lib/butler/bot.rb +247 -0
- data/lib/butler/control.rb +93 -0
- data/lib/butler/dialog.rb +64 -0
- data/lib/butler/initialvalues.rb +40 -0
- data/lib/butler/irc/channel.rb +135 -0
- data/lib/butler/irc/channels.rb +96 -0
- data/lib/butler/irc/client.rb +351 -0
- data/lib/butler/irc/hostmask.rb +53 -0
- data/lib/butler/irc/message.rb +184 -0
- data/lib/butler/irc/parser.rb +125 -0
- data/lib/butler/irc/parser/commands.rb +83 -0
- data/lib/butler/irc/parser/generic.rb +343 -0
- data/lib/butler/irc/socket.rb +378 -0
- data/lib/butler/irc/string.rb +186 -0
- data/lib/butler/irc/topic.rb +15 -0
- data/lib/butler/irc/user.rb +265 -0
- data/lib/butler/irc/users.rb +112 -0
- data/lib/butler/plugin.rb +249 -0
- data/lib/butler/plugin/configproxy.rb +35 -0
- data/lib/butler/plugin/mapper.rb +85 -0
- data/lib/butler/plugin/matcher.rb +55 -0
- data/lib/butler/plugin/onhandlers.rb +70 -0
- data/lib/butler/plugin/trigger.rb +58 -0
- data/lib/butler/plugins.rb +147 -0
- data/lib/butler/version.rb +17 -0
- data/lib/cloptions.rb +217 -0
- data/lib/cloptions/adapters.rb +24 -0
- data/lib/cloptions/switch.rb +132 -0
- data/lib/configuration.rb +223 -0
- data/lib/dialogline.rb +296 -0
- data/lib/dialogline/localizations.rb +24 -0
- data/lib/durations.rb +57 -0
- data/lib/event.rb +295 -0
- data/lib/event/at.rb +64 -0
- data/lib/event/every.rb +56 -0
- data/lib/event/timed.rb +112 -0
- data/lib/installer.rb +75 -0
- data/lib/iterator.rb +34 -0
- data/lib/log.rb +68 -0
- data/lib/log/comfort.rb +85 -0
- data/lib/log/converter.rb +23 -0
- data/lib/log/entry.rb +152 -0
- data/lib/log/fakeio.rb +55 -0
- data/lib/log/file.rb +54 -0
- data/lib/log/filereader.rb +81 -0
- data/lib/log/forward.rb +49 -0
- data/lib/log/methods.rb +39 -0
- data/lib/log/nolog.rb +18 -0
- data/lib/log/splitter.rb +26 -0
- data/lib/ostructfixed.rb +26 -0
- data/lib/ruby/array/columnize.rb +38 -0
- data/lib/ruby/dir/mktree.rb +28 -0
- data/lib/ruby/enumerable/join.rb +13 -0
- data/lib/ruby/exception/detailed.rb +24 -0
- data/lib/ruby/file/append.rb +11 -0
- data/lib/ruby/file/write.rb +11 -0
- data/lib/ruby/hash/zip.rb +15 -0
- data/lib/ruby/kernel/bench.rb +15 -0
- data/lib/ruby/kernel/daemonize.rb +42 -0
- data/lib/ruby/kernel/non_verbose.rb +17 -0
- data/lib/ruby/kernel/safe_fork.rb +18 -0
- data/lib/ruby/range/stepped.rb +11 -0
- data/lib/ruby/string/arguments.rb +72 -0
- data/lib/ruby/string/chunks.rb +15 -0
- data/lib/ruby/string/post_arguments.rb +44 -0
- data/lib/ruby/string/unescaped.rb +17 -0
- data/lib/scheduler.rb +164 -0
- data/lib/scriptfile.rb +101 -0
- data/lib/templater.rb +86 -0
- data/test/cloptions.rb +134 -0
- data/test/cv.rb +28 -0
- data/test/irc/client.rb +85 -0
- data/test/irc/client_login.txt +53 -0
- data/test/irc/client_subscribe.txt +8 -0
- data/test/irc/message.rb +30 -0
- data/test/irc/messages.txt +64 -0
- data/test/irc/parser.rb +13 -0
- data/test/irc/profile_parser.rb +12 -0
- data/test/irc/users.rb +28 -0
- metadata +256 -0
data/lib/event/at.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2007 by Stefan Rusterholz.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#++
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
require 'event'
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
class Event
|
14
|
+
class At < Event
|
15
|
+
class <<self
|
16
|
+
public :new
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_reader :index
|
20
|
+
|
21
|
+
# A string representation. Just nice for printing.
|
22
|
+
def inspect
|
23
|
+
string = if off? then
|
24
|
+
"Off"
|
25
|
+
elsif finished? then
|
26
|
+
"Finished"
|
27
|
+
elsif left = seconds_left then
|
28
|
+
"Due: %s (%.2fs)" % [@next.strftime("%H:%M:%S"), left]
|
29
|
+
else
|
30
|
+
"Error"
|
31
|
+
end
|
32
|
+
|
33
|
+
datetimes = (@previous ? @datetimes.select { |dt| dt > @previous } : @datetimes)
|
34
|
+
"#<%s %s, %s done, due at %s%s>" % [
|
35
|
+
self.class,
|
36
|
+
string,
|
37
|
+
@times ? "#{@count}/#{@times}" : @count,
|
38
|
+
datetimes.first(5).join(', '),
|
39
|
+
datetimes.length > 5 ? "..." : ""
|
40
|
+
]
|
41
|
+
end
|
42
|
+
|
43
|
+
def initialize(*datetimes, &block)
|
44
|
+
super(datetimes.last.kind_of?(Hash) ? datetimes.pop : {}, &block)
|
45
|
+
@datetimes = datetimes.sort
|
46
|
+
#@start = @datetimes.first
|
47
|
+
#@stop = @datetimes.last
|
48
|
+
@index = nil
|
49
|
+
@next = calculate_first(@start)
|
50
|
+
end
|
51
|
+
|
52
|
+
protected
|
53
|
+
def calculate_first(with_start)
|
54
|
+
found = @datetimes.find { |compare| compare >= with_start }
|
55
|
+
@index = found && @datetimes.index(found)
|
56
|
+
return found
|
57
|
+
end
|
58
|
+
|
59
|
+
def calculate_next(withLast)
|
60
|
+
@index += 1
|
61
|
+
@datetimes[@index]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/event/every.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2007 by Stefan Rusterholz.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#++
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
require 'event'
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
class Event
|
14
|
+
class Every < Event
|
15
|
+
class <<self
|
16
|
+
public :new
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_reader :interval
|
20
|
+
|
21
|
+
# A string representation. Just nice for printing.
|
22
|
+
def inspect
|
23
|
+
string = if off? then
|
24
|
+
"Off"
|
25
|
+
elsif finished? then
|
26
|
+
"Finished"
|
27
|
+
elsif left = seconds_left then
|
28
|
+
"Due: %s (%.2fs)" % [@next.strftime("%H:%M:%S"), left]
|
29
|
+
else
|
30
|
+
"Error"
|
31
|
+
end
|
32
|
+
|
33
|
+
"#<%s %s, %s done, scheduled every %.1fs>" % [
|
34
|
+
self.class,
|
35
|
+
string,
|
36
|
+
@times ? "#{@count}/#{@times}" : @count,
|
37
|
+
@interval
|
38
|
+
]
|
39
|
+
end
|
40
|
+
|
41
|
+
protected
|
42
|
+
def initialize(seconds, options={}, &block)
|
43
|
+
super(options, &block)
|
44
|
+
@interval = seconds
|
45
|
+
@next = calculate_first(@start)
|
46
|
+
end
|
47
|
+
|
48
|
+
def calculate_first(with_start)
|
49
|
+
with_start+@interval
|
50
|
+
end
|
51
|
+
|
52
|
+
def calculate_next(with_last)
|
53
|
+
with_last+@interval
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/event/timed.rb
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2007 by Stefan Rusterholz.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#++
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
require 'event'
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
class Event
|
14
|
+
class Timed < Event
|
15
|
+
class <<self
|
16
|
+
public :new
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_reader :original
|
20
|
+
|
21
|
+
# A string representation. Just nice for printing.
|
22
|
+
def inspect
|
23
|
+
string = if off? then
|
24
|
+
"Off"
|
25
|
+
elsif finished? then
|
26
|
+
"Finished"
|
27
|
+
elsif left = seconds_left then
|
28
|
+
"Due: %s (%.2fs)" % [@next.strftime("%H:%M:%S"), left]
|
29
|
+
else
|
30
|
+
"Error"
|
31
|
+
end
|
32
|
+
|
33
|
+
"#<%s %s, %s done, timed for %s, %s, %s>" % [
|
34
|
+
self.class,
|
35
|
+
string,
|
36
|
+
@times ? "#{@count}/#{@times}" : @count,
|
37
|
+
*@original
|
38
|
+
]
|
39
|
+
end
|
40
|
+
|
41
|
+
def initialize(hours=[0], minutes=[0], seconds=[0], options={}, &block)
|
42
|
+
super(options, &block)
|
43
|
+
@original = [hours.inspect, minutes.inspect, seconds.inspect]
|
44
|
+
@indices = [0,0,0]
|
45
|
+
@hours = extract_time_range(hours, 23, HOUR_DIVISORS).sort
|
46
|
+
@minutes = extract_time_range(minutes, 59, MINUTE_DIVISORS).sort
|
47
|
+
@seconds = extract_time_range(seconds, 59, SECOND_DIVISORS).sort
|
48
|
+
@next = calculate_first(@start)
|
49
|
+
end
|
50
|
+
|
51
|
+
def hours
|
52
|
+
@hours.dup
|
53
|
+
end
|
54
|
+
|
55
|
+
def minutes
|
56
|
+
@minutes.dup
|
57
|
+
end
|
58
|
+
|
59
|
+
def seconds
|
60
|
+
@seconds.dup
|
61
|
+
end
|
62
|
+
|
63
|
+
protected
|
64
|
+
def calculate_first(with_start)
|
65
|
+
start_sec = with_start.sec
|
66
|
+
start_min = with_start.min
|
67
|
+
start_hour = with_start.hour
|
68
|
+
|
69
|
+
sec = @seconds.find { |s| s > start_sec } || @seconds.first
|
70
|
+
|
71
|
+
# if second is smaller than start time's second, it can't be in the same minute
|
72
|
+
min = if (sec <= start_sec) then
|
73
|
+
@minutes.find { |m| m > start_min } || @minutes.first
|
74
|
+
else
|
75
|
+
@minutes.find { |m| m >= start_min } || @minutes.first
|
76
|
+
end
|
77
|
+
|
78
|
+
# if minute is smaller than start time's minute, it can't be in the same hour
|
79
|
+
hour = if (min < start_min) then
|
80
|
+
@hours.find { |h| h > start_hour } || @hours.first
|
81
|
+
else
|
82
|
+
@hours.find { |h| h >= start_hour } || @hours.first
|
83
|
+
end
|
84
|
+
|
85
|
+
@indices = [@hours.index(hour), @minutes.index(min), @seconds.index(sec)]
|
86
|
+
first = Time.mktime(with_start.year, with_start.month, with_start.day, hour, min, sec)
|
87
|
+
first += 86400 if first < with_start # happens if hour was nil (e.g. it's 23.00 and next timer is 01.00)
|
88
|
+
|
89
|
+
first
|
90
|
+
end
|
91
|
+
|
92
|
+
def calculate_next(with_last)
|
93
|
+
overflow = 0
|
94
|
+
2.downto(0) { |i|
|
95
|
+
@indices[i] += 1
|
96
|
+
@indices[i], overflow = *@indices[i].divmod(@seconds.length)
|
97
|
+
}
|
98
|
+
hour = @hours[@indices[0]]
|
99
|
+
minute = @minutes[@indices[1]]
|
100
|
+
second = @seconds[@indices[2]]
|
101
|
+
|
102
|
+
Time.mktime(
|
103
|
+
with_last.year,
|
104
|
+
with_last.month,
|
105
|
+
with_last.day,
|
106
|
+
hour,
|
107
|
+
minute,
|
108
|
+
second
|
109
|
+
)+overflow*86400
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
data/lib/installer.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'rbconfig'
|
2
|
+
|
3
|
+
class Installer
|
4
|
+
def initialize(app_name)
|
5
|
+
@app_name = app_name
|
6
|
+
end
|
7
|
+
|
8
|
+
def os_class
|
9
|
+
@os_class ||= case Config::CONFIG["target_os"]
|
10
|
+
when /^darwin/: :osx
|
11
|
+
when /^win/: :windows
|
12
|
+
else :nix
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def user_data_suggestions
|
17
|
+
{
|
18
|
+
:osx => ["#{ENV['HOME']}/Library/Application Support/#{@app_name}", "#{ENV['HOME']}/.#{@app_name}"],
|
19
|
+
:windows => ["#{ENV['HOME']}/.#{@app_name}"],
|
20
|
+
:nix => ["#{ENV['HOME']}/.#{@app_name}"],
|
21
|
+
}[os_class]
|
22
|
+
end
|
23
|
+
|
24
|
+
def user_config_suggestions
|
25
|
+
{
|
26
|
+
:osx => ["#{ENV['HOME']}/Library/Preferences/#{@app_name}", "#{ENV['HOME']}/.#{@app_name}/etc"],
|
27
|
+
:windows => ["#{ENV['HOME']}/.#{@app_name}/etc"],
|
28
|
+
:nix => ["#{ENV['HOME']}/.#{@app_name}/etc"],
|
29
|
+
}[os_class]
|
30
|
+
end
|
31
|
+
|
32
|
+
def user_documents_suggestions
|
33
|
+
{
|
34
|
+
:osx => ["#{ENV['HOME']}/Documents"],
|
35
|
+
:windows => [
|
36
|
+
"#{ENV['HOME']}/My Documents",
|
37
|
+
"#{ENV['HOME']}/#{ENV['USER']}'s Documents",
|
38
|
+
"#{ENV['HOME']}/#{ENV['USER'].downcase}'s documents"
|
39
|
+
].select { |path| File.directory?(path) },
|
40
|
+
:nix => ["#{ENV['HOME']}/"],
|
41
|
+
}[os_class]
|
42
|
+
end
|
43
|
+
|
44
|
+
def user_pid_suggestions
|
45
|
+
{
|
46
|
+
:osx => ["#{ENV['HOME']}/Library/Application Support/#{@app_name}/run", "#{ENV['HOME']}/.#{@app_name}/run"],
|
47
|
+
:windows => ["#{ENV['HOME']}/.#{@app_name}/run"],
|
48
|
+
:nix => ["#{ENV['HOME']}/.#{@app_name}/run"],
|
49
|
+
}[os_class]
|
50
|
+
end
|
51
|
+
|
52
|
+
def shared_data_suggestions
|
53
|
+
{
|
54
|
+
:osx => ["/Library/Application Support/#{@app_name}", "#{Config::CONFIG['datadir']}/#{@app_name}"],
|
55
|
+
:windows => ["#{Config::CONFIG['datadir']}/#{@app_name}"],
|
56
|
+
:nix => ["#{Config::CONFIG['datadir']}/#{@app_name}"],
|
57
|
+
}[os_class]
|
58
|
+
end
|
59
|
+
|
60
|
+
def cli_binary_suggestions
|
61
|
+
{
|
62
|
+
:osx => [Config::CONFIG['bindir']],
|
63
|
+
:windows => [Config::CONFIG['bindir']],
|
64
|
+
:nix => [Config::CONFIG['bindir'], "#{ENV['HOME']}/bin"],
|
65
|
+
}[os_class]
|
66
|
+
end
|
67
|
+
|
68
|
+
def gui_binary_suggestions
|
69
|
+
{
|
70
|
+
:osx => ["/Applications", ENV['HOME']+"/Applications"],
|
71
|
+
:windows => [Config::CONFIG['bindir']],
|
72
|
+
:nix => [Config::CONFIG['bindir'], "#{ENV['HOME']}/bin"],
|
73
|
+
}[os_class]
|
74
|
+
end
|
75
|
+
end
|
data/lib/iterator.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2007 by Stefan Rusterholz.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#++
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
class Iterator
|
10
|
+
include Enumerable
|
11
|
+
|
12
|
+
class Iteration
|
13
|
+
def initialize(&block)
|
14
|
+
@block = block
|
15
|
+
end
|
16
|
+
def yield(*args)
|
17
|
+
@block.call(*args)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(&iterator)
|
22
|
+
@iterator = iterator
|
23
|
+
end
|
24
|
+
|
25
|
+
def each(&block)
|
26
|
+
@iterator.call(Iteration.new(&block))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
if __FILE__ == $0 then
|
31
|
+
#Iterator.new { |iter| File.open(path) { |fh| while buf = fh.read(8192); iter.yield(buf); end } }
|
32
|
+
x = Iterator.new { |iter| [1,2,3].each { |e| iter.yield(e) } }
|
33
|
+
p x.map { |e| e*2 }
|
34
|
+
end
|
data/lib/log.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2007 by Stefan Rusterholz.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#++
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
# == Synopsis
|
10
|
+
# Logfile = Log::File.new("foo.log")
|
11
|
+
# $stderr = Log::Forward(Logfile, :warn) # capture everything that prints to $stderr and treat it as :warn level message
|
12
|
+
# $stdout = Log::Forward(Logfile, :info)
|
13
|
+
# $stderr.puts "foo" # same as Log::File#log("foo", :warn)
|
14
|
+
# $stdout.puts "bar" # same as Log::File#log("bar", :info)
|
15
|
+
# begin
|
16
|
+
# raise "baz"
|
17
|
+
# rescue => exception
|
18
|
+
# $stdout.puts(exception) # same as Log::File#log(exception)
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# == Notes
|
22
|
+
# require 'log/kernel' to get convenience methods in Kernel
|
23
|
+
# it isn't required via 'log' alone to avoid accidental method name clashes.
|
24
|
+
# notice that log/kernel will override Kernel#warn
|
25
|
+
#
|
26
|
+
module Log
|
27
|
+
GroupSeparator = "\x1d"
|
28
|
+
RecordSeparator = "\x1e"
|
29
|
+
UnitSeparator = "\x1f"
|
30
|
+
RecordTerminator = "\n"
|
31
|
+
|
32
|
+
# escape binary data, the data will contain no \n, \r or \t's after escaping, but
|
33
|
+
# still contain binary characters, but all of them preceeded by \e
|
34
|
+
def self.escape(data)
|
35
|
+
data.
|
36
|
+
gsub(/\e/, "\e\e").
|
37
|
+
gsub(/\n/, "\en").
|
38
|
+
gsub(/\r/, "\er").
|
39
|
+
gsub(/\t/, "\et").
|
40
|
+
gsub(/[\x00-\x1a\x1c-\x1f]/, "\e\\0")
|
41
|
+
end
|
42
|
+
|
43
|
+
# unescapes data escaped by Log.escape
|
44
|
+
def self.unescape(data)
|
45
|
+
data.
|
46
|
+
gsub(/\en/, "\n").
|
47
|
+
gsub(/\er/, "\r").
|
48
|
+
gsub(/\et/, "\t").
|
49
|
+
gsub(/\e(.)/, '\1')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
require 'log/comfort'
|
54
|
+
require 'log/converter'
|
55
|
+
require 'log/entry'
|
56
|
+
require 'log/forward'
|
57
|
+
require 'log/fakeio'
|
58
|
+
require 'log/file'
|
59
|
+
require 'log/nolog'
|
60
|
+
|
61
|
+
|
62
|
+
if __FILE__ == $0 then
|
63
|
+
lf = StringIO.new
|
64
|
+
log = Log::File.new(lf)
|
65
|
+
$stderr = Log::Forward.new(log, :warn)
|
66
|
+
warn "foo"
|
67
|
+
Log::Entry.deserialize(lf.string.split("\n").first)
|
68
|
+
end
|
data/lib/log/comfort.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2007 by Stefan Rusterholz.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#++
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
require 'log/entry'
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
# == Description
|
14
|
+
# log/entry.rb provides some convenience methods in Log.
|
15
|
+
#
|
16
|
+
# == Synopsis
|
17
|
+
# log("Some info")
|
18
|
+
# log("Danger!", :warn)
|
19
|
+
# warn("Danger!")
|
20
|
+
# debug("mecode was here")
|
21
|
+
#
|
22
|
+
module Log
|
23
|
+
module Comfort
|
24
|
+
# where data is logged to
|
25
|
+
attr_accessor :log_device
|
26
|
+
|
27
|
+
# See Log::Message.new
|
28
|
+
# Module::log(*args) is simply: $stderr.puts(Log::Message.new(*args))
|
29
|
+
def log(text, severity=:info, *args)
|
30
|
+
(@log_device || $stderr).puts(Log::Entry.new(text.to_str, severity, *args))
|
31
|
+
end
|
32
|
+
|
33
|
+
# See Log::Entry.new to see what arguments are valid.
|
34
|
+
# Module::debug(text, *args) is the same as:
|
35
|
+
# $stderr.puts(Log::Message.new(text, :debug, *args))
|
36
|
+
def debug(text, *args)
|
37
|
+
(@log_device || $stderr).puts(Log::Entry.new(text.to_str, :debug, *args))
|
38
|
+
end
|
39
|
+
|
40
|
+
# See Log::Entry.new to see what arguments are valid.
|
41
|
+
# Module::info(text, *args) is the same as:
|
42
|
+
# $stderr.puts(Log::Message.new(text, :info, *args))
|
43
|
+
def info(text, *args)
|
44
|
+
(@log_device || $stderr).puts(Log::Entry.new(text.to_str, :info, *args))
|
45
|
+
end
|
46
|
+
|
47
|
+
# See Log::Entry.new to see what arguments are valid.
|
48
|
+
# Module::warn(text, *args) is the same as:
|
49
|
+
# $stderr.puts(Log::Message.new(text, :warn, *args))
|
50
|
+
def warn(text, *args)
|
51
|
+
(@log_device || $stderr).puts(Log::Entry.new(text.to_str, :warn, *args))
|
52
|
+
end
|
53
|
+
|
54
|
+
# See Log::Entry.new to see what arguments are valid.
|
55
|
+
# Module::error(text, *args) is the same as:
|
56
|
+
# $stderr.puts(Log::Message.new(text, :error, *args))
|
57
|
+
def error(text, *args)
|
58
|
+
(@log_device || $stderr).puts(Log::Entry.new(text.to_str, :error, *args))
|
59
|
+
end
|
60
|
+
|
61
|
+
# See Log::Entry.new to see what arguments are valid.
|
62
|
+
# Module::fail(text, *args) is the same as:
|
63
|
+
# $stderr.puts(Log::Message.new(text, :fail, *args))
|
64
|
+
def fail(text, *args)
|
65
|
+
(@log_device || $stderr).puts(Log::Entry.new(text.to_str, :fail, *args))
|
66
|
+
end
|
67
|
+
|
68
|
+
#
|
69
|
+
def exception(e)
|
70
|
+
log = @log_device || $stderr
|
71
|
+
if log.respond_to?(:exception) then
|
72
|
+
log.exception(e)
|
73
|
+
else
|
74
|
+
log.puts("#{Time.now.strftime('%FT%T')} [exception]: #{e} (#{e.class})")
|
75
|
+
if $VERBOSE then
|
76
|
+
prefix = "--> "
|
77
|
+
log.puts(*e.backtrace.map { |l| prefix+l })
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# enable Log.log etc.
|
84
|
+
extend Comfort
|
85
|
+
end
|