butler 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (164) hide show
  1. data/CHANGELOG +4 -0
  2. data/GPL.txt +340 -0
  3. data/LICENSE.txt +52 -0
  4. data/README +37 -0
  5. data/Rakefile +334 -0
  6. data/bin/botcontrol +230 -0
  7. data/data/butler/config_template.yaml +4 -0
  8. data/data/butler/dialogs/backup.rb +19 -0
  9. data/data/butler/dialogs/botcontrol.rb +4 -0
  10. data/data/butler/dialogs/config.rb +1 -0
  11. data/data/butler/dialogs/create.rb +53 -0
  12. data/data/butler/dialogs/delete.rb +3 -0
  13. data/data/butler/dialogs/en/backup.yaml +6 -0
  14. data/data/butler/dialogs/en/botcontrol.yaml +5 -0
  15. data/data/butler/dialogs/en/create.yaml +11 -0
  16. data/data/butler/dialogs/en/delete.yaml +2 -0
  17. data/data/butler/dialogs/en/help.yaml +17 -0
  18. data/data/butler/dialogs/en/info.yaml +13 -0
  19. data/data/butler/dialogs/en/list.yaml +4 -0
  20. data/data/butler/dialogs/en/notyetimplemented.yaml +2 -0
  21. data/data/butler/dialogs/en/rename.yaml +3 -0
  22. data/data/butler/dialogs/en/start.yaml +3 -0
  23. data/data/butler/dialogs/en/sync_plugins.yaml +3 -0
  24. data/data/butler/dialogs/en/uninstall.yaml +5 -0
  25. data/data/butler/dialogs/en/unknown_command.yaml +2 -0
  26. data/data/butler/dialogs/help.rb +11 -0
  27. data/data/butler/dialogs/info.rb +27 -0
  28. data/data/butler/dialogs/interactive.rb +1 -0
  29. data/data/butler/dialogs/list.rb +10 -0
  30. data/data/butler/dialogs/notyetimplemented.rb +1 -0
  31. data/data/butler/dialogs/rename.rb +4 -0
  32. data/data/butler/dialogs/selectbot.rb +2 -0
  33. data/data/butler/dialogs/start.rb +5 -0
  34. data/data/butler/dialogs/sync_plugins.rb +30 -0
  35. data/data/butler/dialogs/uninstall.rb +17 -0
  36. data/data/butler/dialogs/unknown_command.rb +1 -0
  37. data/data/butler/plugins/core/logout.rb +41 -0
  38. data/data/butler/plugins/core/plugins.rb +134 -0
  39. data/data/butler/plugins/core/privilege.rb +103 -0
  40. data/data/butler/plugins/core/user.rb +166 -0
  41. data/data/butler/plugins/dev/eval.rb +64 -0
  42. data/data/butler/plugins/dev/nometa.rb +14 -0
  43. data/data/butler/plugins/dev/onhandlers.rb +93 -0
  44. data/data/butler/plugins/dev/raw.rb +36 -0
  45. data/data/butler/plugins/dev/rawlog.rb +77 -0
  46. data/data/butler/plugins/games/eightball.rb +54 -0
  47. data/data/butler/plugins/games/mastermind.rb +174 -0
  48. data/data/butler/plugins/irc/action.rb +36 -0
  49. data/data/butler/plugins/irc/join.rb +38 -0
  50. data/data/butler/plugins/irc/notice.rb +36 -0
  51. data/data/butler/plugins/irc/part.rb +38 -0
  52. data/data/butler/plugins/irc/privmsg.rb +36 -0
  53. data/data/butler/plugins/irc/quit.rb +36 -0
  54. data/data/butler/plugins/operator/deop.rb +41 -0
  55. data/data/butler/plugins/operator/devoice.rb +41 -0
  56. data/data/butler/plugins/operator/limit.rb +47 -0
  57. data/data/butler/plugins/operator/op.rb +41 -0
  58. data/data/butler/plugins/operator/voice.rb +41 -0
  59. data/data/butler/plugins/public/help.rb +69 -0
  60. data/data/butler/plugins/public/login.rb +72 -0
  61. data/data/butler/plugins/public/usage.rb +49 -0
  62. data/data/butler/plugins/service/clones.rb +56 -0
  63. data/data/butler/plugins/service/define.rb +47 -0
  64. data/data/butler/plugins/service/log.rb +183 -0
  65. data/data/butler/plugins/service/svn.rb +91 -0
  66. data/data/butler/plugins/util/cycle.rb +98 -0
  67. data/data/butler/plugins/util/load.rb +41 -0
  68. data/data/butler/plugins/util/pong.rb +29 -0
  69. data/data/butler/strings/random/acknowledge.en.yaml +5 -0
  70. data/data/butler/strings/random/gratitude.en.yaml +3 -0
  71. data/data/butler/strings/random/hello.en.yaml +4 -0
  72. data/data/butler/strings/random/ignorance.en.yaml +7 -0
  73. data/data/butler/strings/random/ignorance_about.en.yaml +3 -0
  74. data/data/butler/strings/random/insult.en.yaml +3 -0
  75. data/data/butler/strings/random/rejection.en.yaml +12 -0
  76. data/data/man/botcontrol.1 +17 -0
  77. data/lib/access.rb +187 -0
  78. data/lib/access/admin.rb +16 -0
  79. data/lib/access/privilege.rb +122 -0
  80. data/lib/access/role.rb +102 -0
  81. data/lib/access/savable.rb +18 -0
  82. data/lib/access/user.rb +180 -0
  83. data/lib/access/yamlbase.rb +126 -0
  84. data/lib/butler.rb +188 -0
  85. data/lib/butler/bot.rb +247 -0
  86. data/lib/butler/control.rb +93 -0
  87. data/lib/butler/dialog.rb +64 -0
  88. data/lib/butler/initialvalues.rb +40 -0
  89. data/lib/butler/irc/channel.rb +135 -0
  90. data/lib/butler/irc/channels.rb +96 -0
  91. data/lib/butler/irc/client.rb +351 -0
  92. data/lib/butler/irc/hostmask.rb +53 -0
  93. data/lib/butler/irc/message.rb +184 -0
  94. data/lib/butler/irc/parser.rb +125 -0
  95. data/lib/butler/irc/parser/commands.rb +83 -0
  96. data/lib/butler/irc/parser/generic.rb +343 -0
  97. data/lib/butler/irc/socket.rb +378 -0
  98. data/lib/butler/irc/string.rb +186 -0
  99. data/lib/butler/irc/topic.rb +15 -0
  100. data/lib/butler/irc/user.rb +265 -0
  101. data/lib/butler/irc/users.rb +112 -0
  102. data/lib/butler/plugin.rb +249 -0
  103. data/lib/butler/plugin/configproxy.rb +35 -0
  104. data/lib/butler/plugin/mapper.rb +85 -0
  105. data/lib/butler/plugin/matcher.rb +55 -0
  106. data/lib/butler/plugin/onhandlers.rb +70 -0
  107. data/lib/butler/plugin/trigger.rb +58 -0
  108. data/lib/butler/plugins.rb +147 -0
  109. data/lib/butler/version.rb +17 -0
  110. data/lib/cloptions.rb +217 -0
  111. data/lib/cloptions/adapters.rb +24 -0
  112. data/lib/cloptions/switch.rb +132 -0
  113. data/lib/configuration.rb +223 -0
  114. data/lib/dialogline.rb +296 -0
  115. data/lib/dialogline/localizations.rb +24 -0
  116. data/lib/durations.rb +57 -0
  117. data/lib/event.rb +295 -0
  118. data/lib/event/at.rb +64 -0
  119. data/lib/event/every.rb +56 -0
  120. data/lib/event/timed.rb +112 -0
  121. data/lib/installer.rb +75 -0
  122. data/lib/iterator.rb +34 -0
  123. data/lib/log.rb +68 -0
  124. data/lib/log/comfort.rb +85 -0
  125. data/lib/log/converter.rb +23 -0
  126. data/lib/log/entry.rb +152 -0
  127. data/lib/log/fakeio.rb +55 -0
  128. data/lib/log/file.rb +54 -0
  129. data/lib/log/filereader.rb +81 -0
  130. data/lib/log/forward.rb +49 -0
  131. data/lib/log/methods.rb +39 -0
  132. data/lib/log/nolog.rb +18 -0
  133. data/lib/log/splitter.rb +26 -0
  134. data/lib/ostructfixed.rb +26 -0
  135. data/lib/ruby/array/columnize.rb +38 -0
  136. data/lib/ruby/dir/mktree.rb +28 -0
  137. data/lib/ruby/enumerable/join.rb +13 -0
  138. data/lib/ruby/exception/detailed.rb +24 -0
  139. data/lib/ruby/file/append.rb +11 -0
  140. data/lib/ruby/file/write.rb +11 -0
  141. data/lib/ruby/hash/zip.rb +15 -0
  142. data/lib/ruby/kernel/bench.rb +15 -0
  143. data/lib/ruby/kernel/daemonize.rb +42 -0
  144. data/lib/ruby/kernel/non_verbose.rb +17 -0
  145. data/lib/ruby/kernel/safe_fork.rb +18 -0
  146. data/lib/ruby/range/stepped.rb +11 -0
  147. data/lib/ruby/string/arguments.rb +72 -0
  148. data/lib/ruby/string/chunks.rb +15 -0
  149. data/lib/ruby/string/post_arguments.rb +44 -0
  150. data/lib/ruby/string/unescaped.rb +17 -0
  151. data/lib/scheduler.rb +164 -0
  152. data/lib/scriptfile.rb +101 -0
  153. data/lib/templater.rb +86 -0
  154. data/test/cloptions.rb +134 -0
  155. data/test/cv.rb +28 -0
  156. data/test/irc/client.rb +85 -0
  157. data/test/irc/client_login.txt +53 -0
  158. data/test/irc/client_subscribe.txt +8 -0
  159. data/test/irc/message.rb +30 -0
  160. data/test/irc/messages.txt +64 -0
  161. data/test/irc/parser.rb +13 -0
  162. data/test/irc/profile_parser.rb +12 -0
  163. data/test/irc/users.rb +28 -0
  164. metadata +256 -0
@@ -0,0 +1,23 @@
1
+ #--
2
+ # Copyright 2007 by Stefan Rusterholz.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #++
6
+
7
+
8
+
9
+ module Log
10
+ module Converter
11
+ def default_type
12
+ :info
13
+ end
14
+
15
+ def convert(obj)
16
+ case obj
17
+ when Entry: obj
18
+ when Exception: Entry.new(obj.message.chomp, :error, obj.backtrace)
19
+ else Entry.new(obj.to_str.chomp, default_type)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,152 @@
1
+ #--
2
+ # Copyright 2007 by Stefan Rusterholz.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #++
6
+
7
+
8
+
9
+ require 'enumerator'
10
+ require 'log'
11
+
12
+
13
+
14
+ module Log
15
+ # currently unused
16
+ Printable = "%d#{RecordSeparator}%s#{RecordSeparator}%s#{RecordSeparator}%s"
17
+ # currently *only* used by Entry#serialize, but not by Entry::deserialize
18
+ Serialized =
19
+ "%d#{RecordSeparator}" \
20
+ "%s#{RecordSeparator}" \
21
+ "%s#{RecordSeparator}" \
22
+ "%s#{RecordSeparator}" \
23
+ "%s"
24
+
25
+ class Entry
26
+ class <<self
27
+ attr_accessor :time_format
28
+
29
+ def deserialize(line)
30
+ time, severity, text, flagstr, data = line.chomp(RecordTerminator).split(RecordSeparator)
31
+ flags = {}
32
+ flagstr.split(UnitSeparator).each_cons(2) { |key, value|
33
+ flagstr[key] = value
34
+ }
35
+ severity = Integer(severity) rescue severity
36
+ new(text, InvSeverity[severity], Marshal.load(Log.unescape(data)), Time.at(time.to_i), flags)
37
+ end
38
+
39
+ def formatter_for(entity, &formatter)
40
+ @formatter[entity] = formatter
41
+ end
42
+
43
+ def format(entity, value, *args)
44
+ @formatter[entity].call(value, *args)
45
+ end
46
+
47
+ def format_time(entry, time, format=nil)
48
+ entry.time.strftime(format || @time_format)
49
+ end
50
+
51
+ def format_severity(entry)
52
+ entry.severity.to_s
53
+ end
54
+
55
+ def format_flags(entry, flags)
56
+ entry.flags.map{ |k,v| "#{k}: #{v}"}.join(", ")
57
+ end
58
+
59
+ def format_text(entry)
60
+ entry.text.chomp.gsub(/[\r\n]+/, '; ').gsub(/[\x00-\x1f\x7f]/, '.')
61
+ end
62
+ end
63
+
64
+ Severity = Hash.new{|h,k|k}.merge({
65
+ :debug => 1,
66
+ :info => 2,
67
+ :warn => 4,
68
+ :error => 8,
69
+ :fail => 16,
70
+ })
71
+ InvSeverity = Severity.invert
72
+ @formatter = {
73
+ "time" => method(:format_time),
74
+ "severity" => method(:format_severity),
75
+ "flags" => method(:format_flags),
76
+ "text" => method(:format_text), #Log.method(:escape),
77
+ }
78
+ @time_format = "%FT%T"
79
+
80
+ attr_reader :time
81
+ attr_reader :severity
82
+ attr_reader :text
83
+ attr_reader :flags
84
+ attr_reader :data
85
+ def initialize(text, severity=:info, data=nil, *flags)
86
+ @time = flags.first.kind_of?(Time) ? flags.shift : Time.now
87
+ @severity = severity
88
+ @text = text
89
+ @data = data
90
+ @flags = flags.last.kind_of?(Hash) ? flags.pop : {}
91
+ @flags.each_key { |k,v| @flags[k.to_s] = @flags.delete(k) }
92
+ flags.each { |flag| @flags[flag.to_s] = true }
93
+ end
94
+
95
+ def [](key)
96
+ @flags[key]
97
+ end
98
+
99
+ def debug?
100
+ @severity == Severity[:debug]
101
+ end
102
+
103
+ def info?
104
+ @severity == Severity[:info]
105
+ end
106
+
107
+ def warn?
108
+ @severity == Severity[:warn]
109
+ end
110
+
111
+ def error?
112
+ @severity == Severity[:error]
113
+ end
114
+
115
+ def fail?
116
+ @severity == Severity[:fail]
117
+ end
118
+
119
+ def serialize
120
+ Serialized % [
121
+ @time,
122
+ Severity[@severity],
123
+ Log.escape(@text),
124
+ @flags.map.join(UnitSeparator),
125
+ Log.escape(Marshal.dump(@data))
126
+ ]
127
+ end
128
+
129
+ def to_s(format=nil)
130
+ format ||= "%{time:%FT%T} [%{severity}]: %{text}"
131
+ format.gsub(/%(%|\{[^}]+\})/) { |match|
132
+ if match == "%%" then
133
+ "%"
134
+ else
135
+ entity, *args = match[2..-2].split(/:/)
136
+ Entry.format(entity, self, *args)
137
+ end
138
+ }
139
+ end
140
+
141
+ def inspect
142
+ "#<%s %s %s %s flags=%s data=%s>" % [
143
+ self.class,
144
+ @time.strftime("%FT%T"),
145
+ @severity,
146
+ @text.inspect,
147
+ @flags.inspect,
148
+ @data.inspect
149
+ ]
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,55 @@
1
+ #--
2
+ # Copyright 2007 by Stefan Rusterholz.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #++
6
+
7
+
8
+
9
+ module Log
10
+ # == Description
11
+ # Fakes most IO methods and forwards the converted data to #process
12
+ #
13
+ # == Requisites
14
+ # * @buffer initialized to ""
15
+ # * #process method present (this should write to the storage)
16
+ # * #convert method present (see Log::Converter)
17
+ #
18
+ # == Notes
19
+ # Following methods might be useful to be implemented:
20
+ # binmode, fcntl, fileno, flush, fsync, isatty, lineno, lineno=, pid, pos,
21
+ # pos=, , scanf, seek, soak_up_spaces, stat, sync, sync=, sysread, tell, to_i,
22
+ # to_io, tty?
23
+ #
24
+ # Following write methods are NOT implemented:
25
+ # puts, syswrite, write_nonblock
26
+ #
27
+ # All read methods must be implemented by the including class
28
+ #
29
+ module FakeIO
30
+ def process_buffer
31
+ while line = @buffer.slice!(/.*?\n/)
32
+ process(convert(line))
33
+ end
34
+ end
35
+
36
+ def <<(obj)
37
+ process(convert(obj))
38
+ end
39
+
40
+ def puts(*objs)
41
+ objs.each { |obj| process(convert(obj)) }
42
+ end
43
+
44
+ def write(*objs)
45
+ @buffer << objs.join("")
46
+ process_buffer
47
+ end
48
+ alias print write
49
+
50
+ def printf(*args)
51
+ @buffer << sprintf(*args)
52
+ process_buffer
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,54 @@
1
+ #--
2
+ # Copyright 2007 by Stefan Rusterholz.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #++
6
+
7
+
8
+
9
+ require 'log/converter'
10
+ require 'log/fakeio'
11
+ require 'log/methods'
12
+
13
+
14
+
15
+ module Log
16
+ # Log.file is equivalent to Log::File.new
17
+ def self.file(*args)
18
+ Log::File.new(*args)
19
+ end
20
+
21
+ class File
22
+ include Converter
23
+ include FakeIO
24
+ include Methods
25
+
26
+ def initialize(out)
27
+ @out = nil
28
+ @default_type = :error
29
+ @buffer = ""
30
+ reopen(out)
31
+ end
32
+
33
+ def process(obj)
34
+ @out.puts(obj.serialize)
35
+ @out.flush
36
+ end
37
+
38
+ def reopen(out)
39
+ close
40
+ @out = out.respond_to?(:to_str) ? ::File.open(out, "a") : out
41
+ raise TypeError, "out #{@out} does not respond to 'puts'." unless @out.respond_to?(:puts)
42
+ self
43
+ end
44
+
45
+ def close
46
+ @out.close if @out.respond_to?(:close)
47
+ self
48
+ end
49
+
50
+ def closed?
51
+ @out.respond_to?(:close) ? @out.closed? : true
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,81 @@
1
+ module Log
2
+ class FileReader
3
+ include Enumerable
4
+ class Filter
5
+ module Grep; def =~(entry); entry.text =~ @arg1; end; end
6
+ module NoGrep; def =~(entry); entry.text !~ @arg1; end; end
7
+ module Find; def =~(entry); entry.text.include?(@arg1); end; end
8
+ module NoFind; def =~(entry); !entry.text.include?(@arg1); end; end
9
+ module StartDate; def =~(entry); entry.time > @arg1; end; end
10
+ module EndDate; def =~(entry); entry.time < @arg1; end; end
11
+ module OneOfLevels; def =~(entry); @arg1.include?(entry.severity); end; end
12
+ module NoneOfLevels; def =~(entry); !@arg1.include?(entry.severity); end; end
13
+
14
+ Types = {
15
+ :grep => Grep,
16
+ :no_grep => NoGrep,
17
+ :find => Find,
18
+ :no_find => NoFind,
19
+ :start_date => StartDate,
20
+ :end_date => EndDate,
21
+ :one_of_levels => OneOfLevels,
22
+ :none_of_levels => NoneOfLevels,
23
+ }
24
+
25
+ def initialize(type, *args)
26
+ extend Types[type]
27
+ @arg1 = args.first
28
+ @args = args
29
+ end
30
+ end
31
+
32
+ def initialize(file)
33
+ @file = ::File.open(file, "r")
34
+ @pos = 0
35
+ @cache = {}
36
+ @filters = []
37
+ end
38
+
39
+ def add_filter(type, *args)
40
+ @filters << Filter.new(type, *args)
41
+ end
42
+
43
+ def matches(entry)
44
+ @filters.all? { |filter| filter =~ entry }
45
+ end
46
+
47
+ def head(n)
48
+ i = 0
49
+ while line = @file.gets and i < n
50
+ entry = Log::Entry.deserialize(line)
51
+ if matches(entry) then
52
+ yield(entry)
53
+ i+=1
54
+ end
55
+ end
56
+ entries
57
+ end
58
+
59
+ def tail(n, &block)
60
+ entries = []
61
+ while line = @file.gets and entries.length < n
62
+ entry = Log::Entry.deserialize(line)
63
+ entries.push entry if matches(entry)
64
+ end
65
+ while line = @file.gets
66
+ entry = Log::Entry.deserialize(line)
67
+ entries.push entry if matches(entry)
68
+ entries.shift
69
+ end
70
+ entries.compact
71
+ entries.each(&block)
72
+ end
73
+
74
+ def each
75
+ while line = @file.gets
76
+ entry = Log::Entry.deserialize(line)
77
+ yield(entry) if matches(entry)
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,49 @@
1
+ #--
2
+ # Copyright 2007 by Stefan Rusterholz.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #++
6
+
7
+
8
+
9
+ require 'log/fakeio'
10
+ require 'log/converter'
11
+
12
+
13
+
14
+ module Log
15
+ # Log.forward is equivalent to Log::Forward.new
16
+ def self.forward(*args)
17
+ Forward.new(*args)
18
+ end
19
+
20
+ # Forward an IO to an object (object must respond to #puts)
21
+ # Will convert all puts/prints etc. to Log::Entry's using
22
+ # Log::Converter#convert
23
+ # Example:
24
+ # $stderr = Log.forward(your_logfile)
25
+ class Forward
26
+ include FakeIO
27
+ include Converter
28
+
29
+ def initialize(to, type=:info)
30
+ raise ArgumentError, "Target must respond to 'puts'" unless to.respond_to?(:puts)
31
+ @to = to
32
+ @default_type = type
33
+ @buffer = ""
34
+ end
35
+
36
+ def process(obj)
37
+ @to.puts(obj)
38
+ end
39
+
40
+ def inspect
41
+ "#<%s:%08x %s %s>" % [
42
+ self.class,
43
+ object_id,
44
+ @default_type,
45
+ @to.inspect
46
+ ]
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,39 @@
1
+ #--
2
+ # Copyright 2007 by Stefan Rusterholz.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #++
6
+
7
+
8
+
9
+ module Log
10
+ # Provides convenience mappings to #process
11
+ # Map debug, info, warn, error, fail to log, log itself uses process with
12
+ # Entry.new
13
+ # See Log::File for an example.
14
+ module Methods
15
+ def log(*args)
16
+ process(Entry.new(*args))
17
+ end
18
+
19
+ def debug(text, *args)
20
+ log(text, :debug, *args)
21
+ end
22
+
23
+ def info(text, *args)
24
+ log(text, :info, *args)
25
+ end
26
+
27
+ def warn(text, *args)
28
+ log(text, :warn, *args)
29
+ end
30
+
31
+ def error(text, *args)
32
+ log(text, :error, *args)
33
+ end
34
+
35
+ def fail(text, *args)
36
+ log(text, :fail, *args)
37
+ end
38
+ end
39
+ end