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