butler 1.8.0
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/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
|