4 # :title: Dictionary lookup plugin for rbot
6 # Author:: Giuseppe "Oblomov" Bilotta <giuseppe.bilotta@gmail.com>
7 # Copyright:: (C) 2006-2007 Giuseppe Bilotta
10 # Provides a link to the definition of a word in one of the supported
11 # dictionaries. Currently available are
12 # * the Oxford dictionary for (British) English
13 # * the De Mauro/Paravia dictionary for Italian
14 # * the Chambers dictionary for English (accepts both US and UK)
15 # * the Littré dictionary for French
17 # Other plugins can use this one to check if a given word is valid in italian
18 # or english or french by using the is_italian?, is_british?, is_english?,
21 # TODO: cache results and reuse them if get_cached returns a cache copy
23 DEMAURO_LEMMA = /<anchor>(.*?)(?: - (.*?))<go href="lemma.php\?ID=(\d+)"\/><\/anchor>/
24 CHAMBERS_LEMMA = /<p><span class="hwd">(.*?)<\/span> <span class="psa">(.*?)<\/span>(.*?)<\/p>/
26 class DictPlugin < Plugin
27 Config.register Config::IntegerValue.new('dict.hits',
29 :desc => "Number of hits to return from a dictionary lookup")
30 Config.register Config::IntegerValue.new('dict.first_par',
32 :desc => "When set to n > 0, the bot will return the first paragraph from the first n dictionary hits")
36 @dmurl = "http://www.demauroparavia.it/"
37 @dmwapurl = "http://wap.demauroparavia.it/index.php?lemma=%s"
38 @dmwaplemma = "http://wap.demauroparavia.it/lemma.php?ID=%s"
39 @oxurl = "http://www.askoxford.com/concise_oed/%s"
40 @chambersurl = "http://www.chambersharrap.co.uk/chambers/features/chref/chref.py/main?query=%s&title=21st"
41 @littreurl = "http://francois.gannaz.free.fr/Littre/xmlittre.php?requete=%s"
45 def help(plugin, topic="")
48 return "demauro <word> => provides a link to the definition of <word> from the De Mauro/Paravia dictionary"
50 return "oxford <word> => provides a link to the definition of <word> (it can also be an expression) from the Concise Oxford dictionary"
52 return "chambers <word> => provides a link to the definition of <word> (it can also be an expression) from the Chambers 21st Century Dictionary"
54 return "littre <word> => provides a link to the definition of <word> (it can also be an expression) from the Littré online dictionary"
56 return "<dictionary> <word>: check for <word> on <dictionary> where <dictionary> can be one of: demauro, oxford, chambers, littre"
59 def demauro(m, params)
60 justcheck = params[:justcheck]
62 word = params[:word].downcase
63 url = @dmwapurl % CGI.escape(word)
65 info = @bot.httputil.get_response(url) rescue nil
66 xml = info.body if info
68 info = info ? " (#{info.code} - #{info.message})" : ""
69 return false if justcheck
70 m.reply "An error occurred while looking for #{word}#{info}"
73 if xml=~ /Non ho trovato occorrenze per/
74 return false if justcheck
75 m.reply "Nothing found for #{word}"
78 entries = xml.scan(DEMAURO_LEMMA)
81 if not entries.transpose.first.grep(/\b#{word}\b/)
82 return false if justcheck
83 text += " not found. Similar words"
85 return true if justcheck
88 hits = @bot.config['dict.hits']
89 text += entries[0...hits].map { |ar|
91 urls << @dmwaplemma % ar[2]
92 "#{n}. #{Bold}#{ar[0]}#{Bold} - #{ar[1].gsub(/<\/?em>/,'')}: #{@dmurl}#{ar[2]}"
96 first_pars = @bot.config['dict.first_par']
98 return unless first_pars > 0
100 Utils.get_first_pars urls, first_pars, :message => m,
101 :strip => /^.+?\s+-\s+/
105 def is_italian?(word)
106 return demauro(nil, :word => word, :justcheck => true)
110 def oxford(m, params)
111 justcheck = params[:justcheck]
113 word = params[:word].join
114 [word, word + "_1"].each { |check|
115 url = @oxurl % CGI.escape(check)
119 h = @bot.httputil.get(url, :max_redir => 5)
120 if h and h.match(%r!<h2>#{word}(?:<sup>1</sup>)?</h2>!)
121 m.reply("#{word} : #{url}") unless justcheck
123 m.reply("#{Bold}%s#{Bold}: %s" % [word, defn.ircify_html(:nbsp => :space)], :overlong => :truncate)
127 return false if justcheck
128 m.reply "#{word} not found"
131 def is_british?(word)
132 return oxford(nil, :word => word, :justcheck => true, :british => true)
136 def chambers(m, params)
137 justcheck = params[:justcheck]
139 word = params[:word].to_s.downcase
140 url = @chambersurl % CGI.escape(word)
142 info = @bot.httputil.get_response(url) rescue nil
143 xml = info.body if info
146 info = info ? " (#{info.code} - #{info.message})" : ""
147 return false if justcheck
148 m.reply "An error occurred while looking for #{word}#{info}"
150 when /Sorry, no entries for <b>.*?<\/b> were found./
151 return false if justcheck
152 m.reply "Nothing found for #{word}"
154 when /No exact matches for <b>.*?<\/b>, but the following may be helpful./
155 return false if justcheck
156 m.reply "Nothing found for #{word}, but see #{url} for possible suggestions"
159 # Else, we have a hit
160 return true if justcheck
161 m.reply "#{word}: #{url}"
162 entries = xml.scan(CHAMBERS_LEMMA)
163 hits = @bot.config['dict.hits']
164 entries[0...hits].map { |ar|
165 m.reply(("#{Bold}%s#{Bold} #{Underline}%s#{Underline}%s" % ar).ircify_html, :overlong => :truncate)
169 def is_english?(word)
170 return chambers(nil, :word => word, :justcheck => true)
173 def littre(m, params)
174 justcheck = params[:justcheck]
176 word = params[:word].to_s.downcase
177 url = @littreurl % CGI.escape(word)
179 info = @bot.httputil.get_response(url) rescue nil
180 xml = info.body if info
181 head ||= xml.match(/<div class="entree">(.*?)<\/div>/)[1] rescue nil
184 info = info ? " (#{info.code} - #{info.message})" : ""
185 return false if justcheck
186 m.reply "An error occurred while looking for #{word}#{info}"
188 when /Erreur : le mot <STRONG>.*?<\/STRONG> n'a pas./
189 return false if justcheck
191 m.reply "Nothing found for #{word}, I'll assume you meant #{head}"
193 m.reply "Nothing found for #{word}"
197 return true if justcheck
198 entete = xml.match(/<div class="entete">(.*?)<\/div>/m)[1] rescue nil
199 m.reply "#{head}: #{url} : #{entete.ircify_html rescue nil}"
200 entries = xml.scan(/<span class="variante">(.*?)<\!--variante-->/m)
201 hits = @bot.config['dict.hits']
203 entries[0...hits].map { |ar|
205 m.reply(("#{Bold}#{n}#{Bold} %s" % ar).ircify_html, :overlong => :truncate)
210 return littre(nil, :word => word, :justcheck => true)
215 plugin = DictPlugin.new
216 plugin.map 'demauro :word', :action => 'demauro', :thread => true
217 plugin.map 'oxford *word', :action => 'oxford', :thread => true
218 plugin.map 'chambers *word', :action => 'chambers', :thread => true
219 plugin.map 'littre *word', :action => 'littre', :thread => true