X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=data%2Frbot%2Fplugins%2Fsalut.rb;h=6c6f3bc11b928676522b710b9b374421c0eb17bf;hb=e5ff70eece675e05e6cdd1e2740f1f7a1316c697;hp=feff2dd63c9efe880d5acf0b3f2d0129cf143e99;hpb=edd1cf77be07ae507014574141e920ad23eb164d;p=user%2Fhenk%2Fcode%2Fruby%2Frbot.git diff --git a/data/rbot/plugins/salut.rb b/data/rbot/plugins/salut.rb index feff2dd6..6c6f3bc1 100644 --- a/data/rbot/plugins/salut.rb +++ b/data/rbot/plugins/salut.rb @@ -1,226 +1,208 @@ -#-- vim:sw=2:et -#++ -# -# :title: Salutations plugin for rbot -# -# Author:: Giuseppe "Oblomov" Bilotta -# Copyright:: (C) 2006-2007 Giuseppe Bilotta -# License:: GPL v2 -# -# Salutations plugin: respond to salutations -# -# TODO:: allow online editing of salutations -# -# TODO:: *REMEMBER* to set @changed to true after edit or changes won't be saved - -class SalutPlugin < Plugin - BotConfig.register BotConfigBooleanValue.new('salut.all_languages', - :default => true, - :desc => "Check for a salutation in all languages and not just in the one defined by core.language", - :on_change => Proc.new {|bot, v| bot.plugins['salut'].reload} - ) - BotConfig.register BotConfigBooleanValue.new('salut.address_only', - :default => true, - :desc => "When set to true, the bot will only reply to salutations directed at him", - :on_change => Proc.new {|bot, v| bot.plugins['salut'].reload} - ) - - - def initialize - @salutations = Hash.new - @match = Hash.new - @match_langs = Array.new - @main_lang_str = nil - @main_lang = nil - @all_langs = true - @changed = false - super - reload - end - - def set_language(what) - reload - end - - def create_match - @match.clear - ar_dest = Array.new - ar_in = Array.new - ar_out = Array.new - ar_both = Array.new - @salutations.each { |lang, hash| - ar_dest.clear - ar_in.clear - ar_out.clear - ar_both.clear - hash.each { |situation, array| - case situation.to_s - when /^generic-dest$/ - ar_dest += array - when /in$/ - ar_in += array - when /out$/ - ar_out += array - else - ar_both += array - end - } - @match[lang] = Hash.new - @match[lang][:in] = Regexp.new("\\b(?:" + ar_in.uniq.map { |txt| - Regexp.escape(txt) - }.join('|') + ")\\b", Regexp::IGNORECASE) unless ar_in.empty? - @match[lang][:out] = Regexp.new("\\b(?:" + ar_out.uniq.map { |txt| - Regexp.escape(txt) - }.join('|') + ")\\b", Regexp::IGNORECASE) unless ar_out.empty? - @match[lang][:both] = Regexp.new("\\b(?:" + ar_both.uniq.map { |txt| - Regexp.escape(txt) - }.join('|') + ")\\b", Regexp::IGNORECASE) unless ar_both.empty? - @match[lang][:dest] = Regexp.new("\\b(?:" + ar_dest.uniq.map { |txt| - Regexp.escape(txt) - }.join('|') + ")\\b", Regexp::IGNORECASE) unless ar_dest.empty? - } - @punct = /\s*[.,:!;?]?\s*/ # Punctuation - - # Languages to match for, in order - @match_langs.clear - @match_langs << @main_lang if @match.key?(@main_lang) - @match_langs << :english if @match.key?(:english) - @match.each_key { |key| - @match_langs << key - } - @match_langs.uniq! - end - - def listen(m) - return if @match.empty? - return unless m.kind_of?(PrivMessage) - return if m.address? and m.plugin == 'config' - to_me = m.address? || m.message =~ /#{Regexp.escape(@bot.nick)}/i - if @bot.config['salut.address_only'] - return unless to_me - end - salut = nil - @match_langs.each { |lang| - [:both, :in, :out].each { |k| - next unless @match[lang][k] - if m.message =~ @match[lang][k] - salut = [@match[lang][k], lang, k] - break - end - } - break if salut - } - return unless salut - # If the bot wasn't addressed, we continue only if the match was exact - # (apart from space and punctuation) or if @match[:dest] matches too - return unless to_me or m.message =~ /^#{@punct}#{salut.first}#{@punct}$/ or m.message =~ @match[salut[1]][:dest] - h = Time.new.hour - case h - when 4...12 - salut_reply(m, salut, :morning) - when 12...18 - salut_reply(m, salut, :afternoon) - else - salut_reply(m, salut, :evening) - end - end - - def salut_reply(m, salut, time) - lang = salut[1] - k = salut[2] - debug "Replying to #{salut.first} (#{lang} #{k}) in the #{time}" - # salut_ar = @salutations[@main_lang].update @salutations[:english].update @salutations[lang] - salut_ar = @salutations[lang] - case k - when :both - sfx = "" - else - sfx = "-#{k}" - end - debug "Building array ..." - rep_ar = Array.new - rep_ar += salut_ar.fetch("#{time}#{sfx}".to_sym, []) - rep_ar += salut_ar.fetch("#{time}".to_sym, []) unless sfx.empty? - rep_ar += salut_ar.fetch("generic#{sfx}".to_sym, []) - rep_ar += salut_ar.fetch("generic".to_sym, []) unless sfx.empty? - debug "Choosing reply in #{rep_ar.inspect} ..." - if rep_ar.empty? - if m.public? # and (m.address? or m =~ /#{Regexp.escape(@bot.nick)}/) - choice = @bot.lang.get("hello_X") % m.sourcenick - else - choice = @bot.lang.get("hello") % m.sourcenick - end - else - choice = rep_ar.pick_one - if m.public? and (m.address? or m.message =~ /#{Regexp.escape(@bot.nick)}/) - choice += "#{[',',''].pick_one} #{m.sourcenick}" - choice += [" :)", " :D", "!", "", "", ""].pick_one - end - end - debug "Replying #{choice}" - m.plainreply choice - end - - def reload - save - @main_lang_str = @bot.config['core.language'] - @main_lang = @main_lang_str.to_sym - @all_langs = @bot.config['salut.all_languages'] - if @all_langs - # Get all available languages - langs = Dir.new("#{@bot.botclass}/salut").collect {|f| - f =~ /salut-([^.]+)/ ? $1 : nil - }.compact - langs.each { |lang| - @salutations[lang.to_sym] = load_lang(lang) - } - else - @salutations.clear - @salutations[@main_lang] = load_lang(@main_lang_str) - end - create_match - @changed = false - end - - def load_lang(lang) - dir = "#{@bot.botclass}/salut" - if not File.exist?(dir) - Dir.mkdir(dir) - end - file = "#{@bot.botclass}/salut/salut-#{lang}" - if File.exist?(file) - begin - salutations = Hash.new - content = YAML::load_file(file) - content.each { |key, val| - salutations[key.to_sym] = val - } - return salutations - rescue - error "failed to read salutations in #{lang}: #{$!}" - end - end - return nil - end - - def save - return if @salutations.empty? - return unless @changed - @salutations.each { |lang, val| - l = lang.to_s - save_lang(lang, val) - } - @changed = false - end - - def save_lang(lang, val) - fn = "#{@bot.botclass}/salut/salut-#{lang}" - Utils.safe_save(fn) { |file| - file.puts val.to_yaml - } - end - -end - -plugin = SalutPlugin.new - +#-- vim:sw=2:et +#++ +# +# :title: Salutations plugin for rbot +# +# Author:: Giuseppe "Oblomov" Bilotta +# Copyright:: (C) 2006-2007 Giuseppe Bilotta +# License:: GPL v2 +# +# Salutations plugin: respond to salutations +# +# TODO:: allow online editing of salutations + +class SalutPlugin < Plugin + Config.register Config::BooleanValue.new('salut.all_languages', + :default => true, + :desc => "Check for a salutation in all languages and not just in the one defined by core.language", + :on_change => Proc.new {|bot, v| bot.plugins['salut'].reload}) + + Config.register Config::BooleanValue.new('salut.address_only', + :default => true, + :desc => "When set to true, the bot will only reply to salutations directed at him", + :on_change => Proc.new {|bot, v| bot.plugins['salut'].reload}) + + def initialize + super + + @match = Hash.new + @match_langs = Array.new + + reload + end + + def set_language(language) + @language = language + end + + def load_static_files(path) + debug "loading salutation rules from #{path}" + Dir.glob("#{path}/*").map { |filename| + language = filename[filename.rindex('-')+1..-1] + begin + salutations = {} + content = YAML::load_file(filename) + content.each { |key, val| + salutations[key.to_sym] = val + } + rescue + error "failed to read salutations in #{filename}: #{$!}" + end + [language, salutations] + }.to_h + end + + def reload + @salutations = @registry[:salutations] + + # migrate existing data files + if not @salutations and Dir.exists? datafile + log "migrate existing salutations from #{datafile}" + + @salutations = load_static_files(datafile) + end + + # load initial salutations from plugin directory + unless @salutations + log "load initial salutations from #{plugin_path}" + + initial_path = File.join(plugin_path, 'salut') + @salutations = load_static_files(initial_path) + end + + debug @salutations.inspect + + create_match + end + + def save + return unless @salutations + + @registry[:salutations] = @salutations + + @registry.flush + end + + def create_match + use_all_languages = @bot.config['salut.all_languages'] + + @match.clear + ar_dest = Array.new + ar_in = Array.new + ar_out = Array.new + ar_both = Array.new + @salutations.each { |lang, hash| + next if lang != @language and not use_all_languages + ar_dest.clear + ar_in.clear + ar_out.clear + ar_both.clear + hash.each { |situation, array| + case situation.to_s + when /^generic-dest$/ + ar_dest += array + when /in$/ + ar_in += array + when /out$/ + ar_out += array + else + ar_both += array + end + } + @match[lang] = Hash.new + @match[lang][:in] = Regexp.new("\\b(?:" + ar_in.uniq.map { |txt| + Regexp.escape(txt) + }.join('|') + ")\\b", Regexp::IGNORECASE) unless ar_in.empty? + @match[lang][:out] = Regexp.new("\\b(?:" + ar_out.uniq.map { |txt| + Regexp.escape(txt) + }.join('|') + ")\\b", Regexp::IGNORECASE) unless ar_out.empty? + @match[lang][:both] = Regexp.new("\\b(?:" + ar_both.uniq.map { |txt| + Regexp.escape(txt) + }.join('|') + ")\\b", Regexp::IGNORECASE) unless ar_both.empty? + @match[lang][:dest] = Regexp.new("\\b(?:" + ar_dest.uniq.map { |txt| + Regexp.escape(txt) + }.join('|') + ")\\b", Regexp::IGNORECASE) unless ar_dest.empty? + } + @punct = /\s*[.,:!;?]?\s*/ # Punctuation + + # Languages to match for, in order + @match_langs.clear + @match_langs << @language if @match.key?(@language) + @match_langs << 'english' if @match.key?('english') + @match.each_key { |key| + @match_langs << key + } + @match_langs.uniq! + end + + def unreplied(m) + return if @match.empty? + return unless m.kind_of?(PrivMessage) + return if m.address? and m.plugin == 'config' + to_me = m.address? || m.message =~ /#{Regexp.escape(@bot.nick)}/i + if @bot.config['salut.address_only'] + return unless to_me + end + salut = nil + @match_langs.each { |lang| + [:both, :in, :out].each { |k| + next unless @match[lang][k] + if m.message =~ @match[lang][k] + salut = [@match[lang][k], lang, k] + break + end + } + break if salut + } + return unless salut + # If the bot wasn't addressed, we continue only if the match was exact + # (apart from space and punctuation) or if @match[:dest] matches too + return unless to_me or m.message =~ /^#{@punct}#{salut.first}#{@punct}$/ or m.message =~ @match[salut[1]][:dest] + h = Time.new.hour + case h + when 4...12 + salut_reply(m, salut, :morning) + when 12...18 + salut_reply(m, salut, :afternoon) + else + salut_reply(m, salut, :evening) + end + end + + def salut_reply(m, salut, time) + lang = salut[1] + k = salut[2] + debug "Replying to #{salut.first} (#{lang} #{k}) in the #{time}" + salut_ar = @salutations[lang] + case k + when :both + sfx = "" + else + sfx = "-#{k}" + end + debug "Building array ..." + rep_ar = Array.new + rep_ar += salut_ar.fetch("#{time}#{sfx}".to_sym, []) + rep_ar += salut_ar.fetch("#{time}".to_sym, []) unless sfx.empty? + rep_ar += salut_ar.fetch("generic#{sfx}".to_sym, []) + rep_ar += salut_ar.fetch("generic".to_sym, []) unless sfx.empty? + debug "Choosing reply in #{rep_ar.inspect} ..." + if rep_ar.empty? + if m.public? # and (m.address? or m =~ /#{Regexp.escape(@bot.nick)}/) + choice = @bot.lang.get("hello_X") % m.sourcenick + else + choice = @bot.lang.get("hello") % m.sourcenick + end + else + choice = rep_ar.pick_one + if m.public? and (m.address? or m.message =~ /#{Regexp.escape(@bot.nick)}/) + choice += "#{[',',''].pick_one} #{m.sourcenick}" + choice += [" :)", " :D", "!", "", "", ""].pick_one + end + end + debug "Replying #{choice}" + m.reply choice, :nick => false, :to => :public + end +end + +SalutPlugin.new