Handling of results for queries such as "time in japan", where the time is returned
[six.git] / plugins / phrases.rb
blob2834da5cbb686cd8566e15291f726b2976e08a5f
2 # Phrases plugin for CyBot.
3 # CiarĂ¡n Walsh 13/5/07
5 # Recognises patterns and responds with a stored phrase
7 class Phrases < PluginBase
8   def initialize(*args)
9     @brief_help = 'Repeats stored phrases'
10     super(*args)
11   end
13   # Check a message against the phrase list
14   # Returns nil, or an array of the matching pattern and response text if one is found
15   def find_matching_phrase(msg)
16     return nil if msg[0] == ?$ # Ignore commands
17     @phrases.each do |(pattern, text)|
18       return [pattern, text.dup] if pattern === msg
19     end
20     return nil
21   end
23   # Called for all incoming channel messages
24   # Checks the message for a phrase match and replies
25   def hook_privmsg_chan(irc, msg)
26     pattern, text = find_matching_phrase(msg)
27     return unless pattern and text
29     # The hash of replacement variables that can be used in a response phrase
30     vars = {}
31     # Add the matches from the pattern to the replacement hash if applicable
32     if pattern.is_a? Regexp
33       pattern =~ msg # Why is this necessary??
34       Regexp.last_match.captures.each_with_index { |cap, index| vars['$' + (index+1).to_s] = cap }
35     end
36     vars['me']  = irc.server.nick
37     vars['you'] = irc.from.nick
39     vars.each_pair { |name, val| text.gsub!('[' + name + ']', val.to_s) }
40     irc.puts text#.gsub(/\[(.+?)\]/) { |match| vars.has_key?($1) ? vars[$1] : $1 }
41   end
43   # Checks whether the user is allowed to use this plugin
44   # Informs them and returns false if not 
45   def authed?(irc)
46     if !$user.caps(irc, 'phrases', 'op', 'owner').any?
47       irc.reply "You aren't allowed to use this command"
48       return false
49     end
50     true
51   end
53   # Display a phrase for a given pattern
54   # Usage: $get <pattern>
55   def cmd_get(irc, phrase)
56     return unless authed?(irc)
57     
58     if phrase.nil? or phrase.strip.empty?
59       irc.reply 'USAGE: get <phrase>'
60       return
61     end
62     pattern, text = find_matching_phrase(phrase)
64     if pattern
65       irc.reply "#{pattern.inspect} => #{text}"
66     else
67       irc.reply "No phrase matched '#{phrase}'"
68     end
69   end
70         help :get, "Display a phrase for a given pattern.  To set phrases use 'set'"
72   # Set the phrase for a pattern
73   # Usage: $set <pattern> => <phrase>
74   def cmd_set(irc, line)
75     return unless authed?(irc)
76     (pattern, text) = line.strip.split(/\s*=>\s*/, 2)
78     if !pattern || !text || pattern.empty? || text.empty?
79       irc.reply 'Usage: set <pattern> => <response phrase>'
80       irc.reply 'Pattern can be a constant phrase or a /rege/x'
81       irc.reply 'Response phrase can contain [variables]: me, you, $1+'
82       return
83     end
85     if pattern =~ %r{\A/(.*)/([imx]*)\z}
86       transform = {
87         'i' => Regexp::IGNORECASE,
88         'x' => Regexp::EXTENDED,
89       }
90       begin
91         ptrn, flags = $1, $2.split(//)
92         f = flags.inject(0) { |flags, letter| flags += transform[letter] if transform.has_key? letter }
93         re = Regexp.new(ptrn, f)
94         @phrases[re] = text
95       rescue
96         irc.reply "Error compiling pattern (note: only flags i & x are allowed)"
97         return
98       end
99     else
100       @phrases[pattern] = text
101     end
102     irc.puts 'Phrase stored'
103   end
104         help :set, "Set the phrase for a pattern.Usage: set <pattern> => <response phrase>. Pattern can be a constant phrase or a /rege/x./ Response phrase can contain [variables]: me, you, $1+."
106   def cmd_del(irc, pattern)
107     return unless authed?(irc)
109     if pattern.nil? or pattern.strip.empty?
110       irc.reply 'USAGE: del <pattern>'
111       return
112     end
114     if pattern =~ %r{\A/(.*)/([imx]*)\z}
115       transform = {
116         'i' => Regexp::IGNORECASE,
117         'x' => Regexp::EXTENDED,
118       }
119       begin
120         ptrn, flags = $1, $2.split(//)
121         f = flags.inject(0) { |flags, letter| flags += transform[letter] if transform.has_key? letter }
122         pattern = Regexp.new(ptrn, f)
123       rescue
124         irc.reply "Error compiling pattern (note: only flags i & x are allowed)"
125         return
126       end
127     end
128     if @phrases.delete(pattern)
129       irc.reply "Phrase #{pattern.inspect} deleted"
130     else
131       irc.reply "Phrase #{pattern.inspect} not found"
132     end
133   end
134   
135   def cmd_reload(irc, line)
136     return unless authed?(irc)
137     load
138     irc.reply 'Phrases reloaded from disk'
139   end
140         help :reload, "Reloads all phrases from disk.  Make sure to save any changes you've made first."
142   def cmd_save(irc, line)
143     return unless authed?(irc)
144     if save
145       irc.reply 'Phrases saved to disk'
146     else
147       irc.reply "Couldn't write phrases to disk"
148     end
149   end
150         help :save, "Save phrases to disk."
152   # Load/save the phrases data
153   # These seem to be called automatically at (un)load
154   def load
155     begin
156       @phrases = YAML.load_file(file_name('phrases.yml'))
157     rescue Exception => e
158       @phrases = {}
159     end
160     @phrases = {} unless @phrases.is_a? Hash
161   end
162   def save
163     begin
164       open_file("phrases.yml", 'w') do |f|
165         f.puts "# CyBot phrases plugin"
166         YAML.dump(@phrases, f)
167         f.puts
168       end
169       return true
170     rescue Exception => e
171       $log.puts e.message
172       $log.puts e.backtrace.join("\n")
173     end
174     false
175   end