]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/blob - data/rbot/plugins/salut.rb
plugin(salut): use registry for storage see #42
[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 class SalutPlugin < Plugin
15   Config.register Config::BooleanValue.new('salut.all_languages',
16     :default => true,
17     :desc => "Check for a salutation in all languages and not just in the one defined by core.language",
18     :on_change => Proc.new {|bot, v| bot.plugins['salut'].reload})
19
20   Config.register Config::BooleanValue.new('salut.address_only',
21     :default => true,
22     :desc => "When set to true, the bot will only reply to salutations directed at him",
23     :on_change => Proc.new {|bot, v| bot.plugins['salut'].reload})
24
25   def initialize
26     super
27
28     @match = Hash.new
29     @match_langs = Array.new
30
31     reload
32   end
33
34   def set_language(language)
35     @language = language
36   end
37
38   def load_static_files(path)
39     debug "loading salutation rules from #{path}"
40     Dir.glob("#{path}/*").map { |filename|
41       language = filename[filename.rindex('-')+1..-1]
42       begin
43         salutations = {}
44         content = YAML::load_file(filename)
45         content.each { |key, val|
46           salutations[key.to_sym] = val
47         }
48       rescue
49         error "failed to read salutations in #{filename}: #{$!}"
50       end
51       [language, salutations]
52     }.to_h
53   end
54
55   def reload
56     @salutations = @registry[:salutations]
57
58     # migrate existing data files
59     if not @salutations and Dir.exists? datafile
60       log "migrate existing salutations from #{datafile}"
61
62       @salutations = load_static_files(datafile)
63     end
64
65     # load initial salutations from plugin directory
66     unless @salutations
67       log "load initial salutations from #{plugin_path}"
68
69       initial_path = File.join(plugin_path, 'salut')
70       @salutations = load_static_files(initial_path)
71     end
72
73     debug @salutations.inspect
74
75     create_match
76   end
77
78   def save
79     return unless @salutations
80
81     @registry[:salutations] = @salutations
82
83     @registry.flush
84   end
85
86   def create_match
87     use_all_languages = @bot.config['salut.all_languages']
88
89     @match.clear
90     ar_dest = Array.new
91     ar_in = Array.new
92     ar_out = Array.new
93     ar_both = Array.new
94     @salutations.each { |lang, hash|
95       next if lang != @language and not use_all_languages
96       ar_dest.clear
97       ar_in.clear
98       ar_out.clear
99       ar_both.clear
100       hash.each { |situation, array|
101         case situation.to_s
102         when /^generic-dest$/
103           ar_dest += array
104         when /in$/
105           ar_in += array
106         when /out$/
107           ar_out += array
108         else
109           ar_both += array
110         end
111       }
112       @match[lang] = Hash.new
113       @match[lang][:in] = Regexp.new("\\b(?:" + ar_in.uniq.map { |txt|
114         Regexp.escape(txt)
115       }.join('|') + ")\\b", Regexp::IGNORECASE) unless ar_in.empty?
116       @match[lang][:out] = Regexp.new("\\b(?:" + ar_out.uniq.map { |txt|
117         Regexp.escape(txt)
118       }.join('|') + ")\\b", Regexp::IGNORECASE) unless ar_out.empty?
119       @match[lang][:both] = Regexp.new("\\b(?:" + ar_both.uniq.map { |txt|
120         Regexp.escape(txt)
121       }.join('|') + ")\\b", Regexp::IGNORECASE) unless ar_both.empty?
122       @match[lang][:dest] = Regexp.new("\\b(?:" + ar_dest.uniq.map { |txt|
123         Regexp.escape(txt)
124       }.join('|') + ")\\b", Regexp::IGNORECASE) unless ar_dest.empty?
125     }
126     @punct = /\s*[.,:!;?]?\s*/ # Punctuation
127
128     # Languages to match for, in order
129     @match_langs.clear
130     @match_langs << @language if @match.key?(@language)
131     @match_langs << 'english' if @match.key?('english')
132     @match.each_key { |key|
133       @match_langs << key
134     }
135     @match_langs.uniq!
136   end
137
138   def unreplied(m)
139     return if @match.empty?
140     return unless m.kind_of?(PrivMessage)
141     return if m.address? and m.plugin == 'config'
142     to_me = m.address? || m.message =~ /#{Regexp.escape(@bot.nick)}/i
143     if @bot.config['salut.address_only']
144       return unless to_me
145     end
146     salut = nil
147     @match_langs.each { |lang|
148       [:both, :in, :out].each { |k|
149         next unless @match[lang][k]
150         if m.message =~ @match[lang][k]
151           salut = [@match[lang][k], lang, k]
152           break
153         end
154       }
155       break if salut
156     }
157     return unless salut
158     # If the bot wasn't addressed, we continue only if the match was exact
159     # (apart from space and punctuation) or if @match[:dest] matches too
160     return unless to_me or m.message =~ /^#{@punct}#{salut.first}#{@punct}$/ or m.message =~ @match[salut[1]][:dest]
161     h = Time.new.hour
162     case h
163     when 4...12
164       salut_reply(m, salut, :morning)
165     when 12...18
166       salut_reply(m, salut, :afternoon)
167     else
168       salut_reply(m, salut, :evening)
169     end
170   end
171
172   def salut_reply(m, salut, time)
173     lang = salut[1]
174     k = salut[2]
175     debug "Replying to #{salut.first} (#{lang} #{k}) in the #{time}"
176     salut_ar = @salutations[lang]
177     case k
178     when :both
179       sfx = ""
180     else
181       sfx = "-#{k}"
182     end
183     debug "Building array ..."
184     rep_ar = Array.new
185     rep_ar += salut_ar.fetch("#{time}#{sfx}".to_sym, [])
186     rep_ar += salut_ar.fetch("#{time}".to_sym, []) unless sfx.empty?
187     rep_ar += salut_ar.fetch("generic#{sfx}".to_sym, [])
188     rep_ar += salut_ar.fetch("generic".to_sym, []) unless sfx.empty?
189     debug "Choosing reply in #{rep_ar.inspect} ..."
190     if rep_ar.empty?
191       if m.public? # and (m.address? or m =~ /#{Regexp.escape(@bot.nick)}/)
192         choice = @bot.lang.get("hello_X") % m.sourcenick
193       else
194         choice = @bot.lang.get("hello") % m.sourcenick
195       end
196     else
197       choice = rep_ar.pick_one
198       if m.public? and (m.address? or m.message =~ /#{Regexp.escape(@bot.nick)}/)
199         choice += "#{[',',''].pick_one} #{m.sourcenick}"
200         choice += [" :)", " :D", "!", "", "", ""].pick_one
201       end
202     end
203     debug "Replying #{choice}"
204     m.reply choice, :nick => false, :to => :public
205   end
206 end
207
208 SalutPlugin.new