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