]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/blob - data/rbot/plugins/salut.rb
Fix a horrendous String leak
[user/henk/code/ruby/rbot.git] / data / rbot / plugins / salut.rb
1 # vim: set sw=2 et:\r
2 # Salutations plugin: respond to salutations\r
3 \r
4 unless Array.respond_to?(:pick_one)\r
5   debug "Defining the pick_one method for Array"\r
6   class ::Array\r
7     def pick_one\r
8       return nil if self.empty?\r
9       self[rand(self.length)]\r
10     end\r
11   end\r
12 end\r
13 \r
14 \r
15 class SalutPlugin < Plugin\r
16   BotConfig.register BotConfigBooleanValue.new('salut.all_languages',\r
17     :default => true, \r
18     :desc => "Check for a salutation in all languages and not just in the one defined by core.language",\r
19     :on_change => Proc.new {|bot, v| bot.plugins['salut'].reload}\r
20   )\r
21   BotConfig.register BotConfigBooleanValue.new('salut.address_only',\r
22     :default => true, \r
23     :desc => "When set to true, the bot will only reply to salutations directed at him",\r
24     :on_change => Proc.new {|bot, v| bot.plugins['salut'].reload}\r
25   )\r
26 \r
27 \r
28   def initialize\r
29     @salutations = Hash.new\r
30     @match = nil\r
31     @main_lang_str = nil\r
32     @main_lang = nil\r
33     @all_langs = true\r
34     super\r
35     reload\r
36   end\r
37 \r
38   def set_language(what)\r
39     reload\r
40   end\r
41 \r
42   def create_match\r
43     @match = Hash.new\r
44     ar_in = Array.new\r
45     ar_out = Array.new\r
46     ar_both = Array.new\r
47     @salutations.each { |lang, hash|\r
48       hash.each { |situation, array|\r
49         case situation.to_s\r
50         when /in$/\r
51           ar_in += array\r
52         when /out$/\r
53           ar_out += array\r
54         else\r
55           ar_both += array\r
56         end\r
57       }\r
58     }\r
59     @match[:in] = Regexp.new("\\b(?:" + ar_in.uniq.map { |txt|\r
60       Regexp.escape(txt)\r
61     }.join('|') + ")\\b", Regexp::IGNORECASE) unless ar_in.empty?\r
62     @match[:out] = Regexp.new("\\b(?:" + ar_out.uniq.map { |txt|\r
63       Regexp.escape(txt)\r
64     }.join('|') + ")\\b", Regexp::IGNORECASE) unless ar_out.empty?\r
65     @match[:both] = Regexp.new("\\b(?:" + ar_both.uniq.map { |txt|\r
66       Regexp.escape(txt)\r
67     }.join('|') + ")\\b", Regexp::IGNORECASE) unless ar_both.empty?\r
68     debug "Matches: #{@match.inspect}"\r
69   end\r
70 \r
71   def listen(m)\r
72     if @bot.config['salut.address_only']\r
73       return unless m.address? or m.message =~ /#{Regexp.escape(@bot.nick)}/\r
74     end\r
75     salut = nil\r
76     [:both, :in, :out].each { |k|\r
77       next unless @match[k]\r
78       debug "Checking salutations #{k} (#{@match[k].inspect})"\r
79       if m.message =~ /^#{@match[k]}/\r
80         salut = k\r
81         break\r
82       end\r
83     }\r
84     return unless salut\r
85     h = Time.new.hour\r
86     case h\r
87     when 4...12\r
88       salut_reply(m, salut, :morning)\r
89     when 12...18\r
90       salut_reply(m, salut, :afternoon)\r
91     else\r
92       salut_reply(m, salut, :evening)\r
93     end\r
94   end\r
95 \r
96   def salut_reply(m, k, time)\r
97     debug "Replying to #{k} in the #{time}"\r
98     case k\r
99     when :both\r
100       sfx = ""\r
101     else\r
102       sfx = "-#{k}"\r
103     end\r
104     debug "Building array ..."\r
105     rep_ar = Array.new\r
106     rep_ar += @salutations[@main_lang].fetch("#{time}#{sfx}".to_sym, [])\r
107     rep_ar += @salutations[@main_lang].fetch("#{time}".to_sym, []) unless sfx.empty?\r
108     rep_ar += @salutations[@main_lang].fetch("generic#{sfx}".to_sym, [])\r
109     rep_ar += @salutations[@main_lang].fetch("generic".to_sym, []) unless sfx.empty?\r
110     debug "Choosing reply in #{rep_ar.inspect} ..."\r
111     if rep_ar.empty?\r
112       if m.public? and (m.address? or m =~ /#{Regexp.escape(@bot.nick)}/)\r
113         choice = @bot.lang.get("hello_X") % m.sourcenick\r
114       else\r
115         choice = @bot.lang.get("hello") % m.sourcenick\r
116       end\r
117     else\r
118       choice = rep_ar.pick_one\r
119       if m.public? and (m.address? or m.message =~ /#{Regexp.escape(@bot.nick)}/)\r
120         choice += "#{[',',''].pick_one} #{m.sourcenick}"\r
121         choice += [" :)", " :D", "!", "", "", ""].pick_one\r
122       end\r
123     end\r
124     debug "Replying #{choice}"\r
125     m.plainreply choice\r
126   end\r
127 \r
128   def reload\r
129     save\r
130     @main_lang_str = @bot.config['core.language']\r
131     @main_lang = @main_lang_str.to_sym\r
132     @all_langs = @bot.config['salut.all_languages']\r
133     if @all_langs\r
134       # Get all available languages\r
135       langs = Dir.new("#{@bot.botclass}/salut").collect {|f|\r
136         f =~ /salut-([^.]+)/ ? $1 : nil\r
137       }.compact\r
138       langs.each { |lang|\r
139         @salutations[lang.to_sym] = load_lang(lang)\r
140       }\r
141     else\r
142       @salutations.clear\r
143       @salutations[@main_lang] = load_lang(@main_lang_str)\r
144     end\r
145     create_match\r
146   end\r
147 \r
148   def load_lang(lang)\r
149     dir = "#{@bot.botclass}/salut"\r
150     if not File.exist?(dir)\r
151       Dir.mkdir(dir)\r
152     end\r
153     file = "#{@bot.botclass}/salut/salut-#{lang}"\r
154     if File.exist?(file)\r
155       begin\r
156         salutations = Hash.new\r
157         content = YAML::load_file(file)\r
158         content.each { |key, val|\r
159           salutations[key.to_sym] = val\r
160         }\r
161         return salutations\r
162       rescue\r
163         error "failed to read salutations in #{lang}: #{$!}"\r
164       end\r
165     end\r
166     return nil\r
167   end\r
168 \r
169   def save\r
170     return if @salutations.empty?\r
171     @salutations.each { |lang, val|\r
172       l = lang.to_s\r
173       save_lang(lang, val)\r
174     }\r
175   end\r
176 \r
177   def save_lang(lang, val)\r
178     fn = "#{@bot.botclass}/salut/salut-#{lang}"\r
179     Utils.safe_save(fn) { |file|\r
180       file.puts val.to_yaml\r
181     }\r
182   end\r
183 \r
184 end\r
185 \r
186 plugin = SalutPlugin.new\r
187 \r