]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/blob - data/rbot/plugins/salut.rb
Plugin header boilerplating.
[user/henk/code/ruby/rbot.git] / data / rbot / plugins / salut.rb
1 #-- vim:sw=2:et\r
2 #++\r
3 #\r
4 # :title: Salutations plugin for rbot\r
5 #\r
6 # Author:: Giuseppe "Oblomov" Bilotta <giuseppe.bilotta@gmail.com>\r
7 # Copyright:: (C) 2006-2007 Giuseppe Bilotta\r
8 # License:: GPL v2\r
9 #\r
10 # Salutations plugin: respond to salutations\r
11 #\r
12 # TODO:: allow online editing of salutations\r
13 #\r
14 # TODO:: *REMEMBER* to set @changed to true after edit or changes won't be saved\r
15 \r
16 class SalutPlugin < Plugin\r
17   BotConfig.register BotConfigBooleanValue.new('salut.all_languages',\r
18     :default => true, \r
19     :desc => "Check for a salutation in all languages and not just in the one defined by core.language",\r
20     :on_change => Proc.new {|bot, v| bot.plugins['salut'].reload}\r
21   )\r
22   BotConfig.register BotConfigBooleanValue.new('salut.address_only',\r
23     :default => true, \r
24     :desc => "When set to true, the bot will only reply to salutations directed at him",\r
25     :on_change => Proc.new {|bot, v| bot.plugins['salut'].reload}\r
26   )\r
27 \r
28 \r
29   def initialize\r
30     @salutations = Hash.new\r
31     @match = Hash.new\r
32     @match_langs = Array.new\r
33     @main_lang_str = nil\r
34     @main_lang = nil\r
35     @all_langs = true\r
36     @changed = false\r
37     super\r
38     reload\r
39   end\r
40 \r
41   def set_language(what)\r
42     reload\r
43   end\r
44 \r
45   def create_match\r
46     @match.clear\r
47     ar_dest = Array.new\r
48     ar_in = Array.new\r
49     ar_out = Array.new\r
50     ar_both = Array.new\r
51     @salutations.each { |lang, hash|\r
52       ar_dest.clear\r
53       ar_in.clear\r
54       ar_out.clear\r
55       ar_both.clear\r
56       hash.each { |situation, array|\r
57         case situation.to_s\r
58         when /^generic-dest$/\r
59           ar_dest += array\r
60         when /in$/\r
61           ar_in += array\r
62         when /out$/\r
63           ar_out += array\r
64         else\r
65           ar_both += array\r
66         end\r
67       }\r
68       @match[lang] = Hash.new\r
69       @match[lang][:in] = Regexp.new("\\b(?:" + ar_in.uniq.map { |txt|\r
70         Regexp.escape(txt)\r
71       }.join('|') + ")\\b", Regexp::IGNORECASE) unless ar_in.empty?\r
72       @match[lang][:out] = Regexp.new("\\b(?:" + ar_out.uniq.map { |txt|\r
73         Regexp.escape(txt)\r
74       }.join('|') + ")\\b", Regexp::IGNORECASE) unless ar_out.empty?\r
75       @match[lang][:both] = Regexp.new("\\b(?:" + ar_both.uniq.map { |txt|\r
76         Regexp.escape(txt)\r
77       }.join('|') + ")\\b", Regexp::IGNORECASE) unless ar_both.empty?\r
78       @match[lang][:dest] = Regexp.new("\\b(?:" + ar_dest.uniq.map { |txt|\r
79         Regexp.escape(txt)\r
80       }.join('|') + ")\\b", Regexp::IGNORECASE) unless ar_dest.empty?\r
81     }\r
82     @punct = /\s*[.,:!;?]?\s*/ # Punctuation\r
83 \r
84     # Languages to match for, in order\r
85     @match_langs.clear\r
86     @match_langs << @main_lang if @match.key?(@main_lang)\r
87     @match_langs << :english if @match.key?(:english)\r
88     @match.each_key { |key|\r
89       @match_langs << key\r
90     }\r
91     @match_langs.uniq!\r
92   end\r
93 \r
94   def listen(m)\r
95     return if @match.empty?\r
96     return unless m.kind_of?(PrivMessage)\r
97     return if m.address? and m.plugin == 'config'\r
98     to_me = m.address? || m.message =~ /#{Regexp.escape(@bot.nick)}/i\r
99     if @bot.config['salut.address_only']\r
100       return unless to_me\r
101     end\r
102     salut = nil\r
103     @match_langs.each { |lang|\r
104       [:both, :in, :out].each { |k|\r
105         next unless @match[lang][k]\r
106         if m.message =~ @match[lang][k]\r
107           salut = [@match[lang][k], lang, k]\r
108           break\r
109         end\r
110       }\r
111       break if salut\r
112     }\r
113     return unless salut\r
114     # If the bot wasn't addressed, we continue only if the match was exact\r
115     # (apart from space and punctuation) or if @match[:dest] matches too\r
116     return unless to_me or m.message =~ /^#{@punct}#{salut.first}#{@punct}$/ or m.message =~ @match[salut[1]][:dest] \r
117     h = Time.new.hour\r
118     case h\r
119     when 4...12\r
120       salut_reply(m, salut, :morning)\r
121     when 12...18\r
122       salut_reply(m, salut, :afternoon)\r
123     else\r
124       salut_reply(m, salut, :evening)\r
125     end\r
126   end\r
127 \r
128   def salut_reply(m, salut, time)\r
129     lang = salut[1]\r
130     k = salut[2]\r
131     debug "Replying to #{salut.first} (#{lang} #{k}) in the #{time}"\r
132     # salut_ar = @salutations[@main_lang].update @salutations[:english].update @salutations[lang]\r
133     salut_ar = @salutations[lang]\r
134     case k\r
135     when :both\r
136       sfx = ""\r
137     else\r
138       sfx = "-#{k}"\r
139     end\r
140     debug "Building array ..."\r
141     rep_ar = Array.new\r
142     rep_ar += salut_ar.fetch("#{time}#{sfx}".to_sym, [])\r
143     rep_ar += salut_ar.fetch("#{time}".to_sym, []) unless sfx.empty?\r
144     rep_ar += salut_ar.fetch("generic#{sfx}".to_sym, [])\r
145     rep_ar += salut_ar.fetch("generic".to_sym, []) unless sfx.empty?\r
146     debug "Choosing reply in #{rep_ar.inspect} ..."\r
147     if rep_ar.empty?\r
148       if m.public? # and (m.address? or m =~ /#{Regexp.escape(@bot.nick)}/)\r
149         choice = @bot.lang.get("hello_X") % m.sourcenick\r
150       else\r
151         choice = @bot.lang.get("hello") % m.sourcenick\r
152       end\r
153     else\r
154       choice = rep_ar.pick_one\r
155       if m.public? and (m.address? or m.message =~ /#{Regexp.escape(@bot.nick)}/)\r
156         choice += "#{[',',''].pick_one} #{m.sourcenick}"\r
157         choice += [" :)", " :D", "!", "", "", ""].pick_one\r
158       end\r
159     end\r
160     debug "Replying #{choice}"\r
161     m.plainreply choice\r
162   end\r
163 \r
164   def reload\r
165     save\r
166     @main_lang_str = @bot.config['core.language']\r
167     @main_lang = @main_lang_str.to_sym\r
168     @all_langs = @bot.config['salut.all_languages']\r
169     if @all_langs\r
170       # Get all available languages\r
171       langs = Dir.new("#{@bot.botclass}/salut").collect {|f|\r
172         f =~ /salut-([^.]+)/ ? $1 : nil\r
173       }.compact\r
174       langs.each { |lang|\r
175         @salutations[lang.to_sym] = load_lang(lang)\r
176       }\r
177     else\r
178       @salutations.clear\r
179       @salutations[@main_lang] = load_lang(@main_lang_str)\r
180     end\r
181     create_match\r
182     @changed = false\r
183   end\r
184 \r
185   def load_lang(lang)\r
186     dir = "#{@bot.botclass}/salut"\r
187     if not File.exist?(dir)\r
188       Dir.mkdir(dir)\r
189     end\r
190     file = "#{@bot.botclass}/salut/salut-#{lang}"\r
191     if File.exist?(file)\r
192       begin\r
193         salutations = Hash.new\r
194         content = YAML::load_file(file)\r
195         content.each { |key, val|\r
196           salutations[key.to_sym] = val\r
197         }\r
198         return salutations\r
199       rescue\r
200         error "failed to read salutations in #{lang}: #{$!}"\r
201       end\r
202     end\r
203     return nil\r
204   end\r
205 \r
206   def save\r
207     return if @salutations.empty?\r
208     return unless @changed\r
209     @salutations.each { |lang, val|\r
210       l = lang.to_s\r
211       save_lang(lang, val)\r
212     }\r
213     @changed = false\r
214   end\r
215 \r
216   def save_lang(lang, val)\r
217     fn = "#{@bot.botclass}/salut/salut-#{lang}"\r
218     Utils.safe_save(fn) { |file|\r
219       file.puts val.to_yaml\r
220     }\r
221   end\r
222 \r
223 end\r
224 \r
225 plugin = SalutPlugin.new\r
226 \r