Fix whitespace irregularities in code
[xapian.git] / xapian-bindings / ruby / xapian.rb
blob8280809dfe421c601be0060236845edd038bfb66
1 # :title:Ruby Xapian bindings
2 # =Ruby Xapian bindings
4 # Original version by Paul Legato (plegato@nks.net), 4/20/06.
6 # Copyright (C) 2006 Networked Knowledge Systems, Inc.
7 # Copyright (C) 2008,2011 Olly Betts
8 # Copyright (C) 2010 Richard Boulton
10 # This program is free software; you can redistribute it and/or
11 # modify it under the terms of the GNU General Public License as
12 # published by the Free Software Foundation; either version 2 of the
13 # License, or (at your option) any later version.
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 # GNU General Public License for more details.
20 # You should have received a copy of the GNU General Public License
21 # along with this program; if not, write to the Free Software
22 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
23 # USA
25 # ==Underscore methods
26 # Note: Methods whose names start with an underscore character _ are internal
27 # methods from the C++ API. Their functionality is not accessible in a
28 # Ruby-friendly way, so this file provides wrapper code to make it easier to
29 # use them from a Ruby programming idiom.  Most are also dangerous insofar as
30 # misusing them can cause your program to segfault.  In particular, all of
31 # Xapian's *Iterator classes are wrapped into nice Ruby-friendly Arrays.
33 # It should never be necessary to use any method whose name starts with an
34 # underscore from user-level code. Make sure you are _VERY_ certain that you
35 # know exactly what you're doing if you do use one of these methods. Beware.
36 # You've been warned...
40 module Xapian
41   ######## load the SWIG-generated library
42   require '_xapian'
45   # iterate over two dangerous iterators (i.e. those that can cause segfaults
46   # if used improperly.)
47   # Return the results as an Array.
48   # Users should never need to use this method.
49   #
50   # Takes a block that returns some appropriate Ruby object to wrap the
51   # underlying Iterator
52   def _safelyIterate(dangerousStart, dangerousEnd) #:nodoc:
53     retval = Array.new
55     item = dangerousStart
56     lastTerm = dangerousEnd
58     return retval if dangerousStart.equals(dangerousEnd)
60     begin
61       retval.push(yield(item))
62       item.next()
63     end while not item.equals(lastTerm) # must use primitive C++ comparator
65     return retval
66   end # _safelyIterate
67   module_function :_safelyIterate
69   #--
70   ### safe Ruby wrapper for the dangerous C++ Xapian::TermIterator class
71   class Xapian::Term
72     attr_accessor :term, :wdf, :termfreq
74     def initialize(term, wdf=nil, termfreq=nil)
75       @term = term
76       @wdf = wdf
77       @termfreq = termfreq
78     end
80     def ==(other)
81       return other.is_a?(Xapian::Term) && other.term == @term && other.wdf == @wdf && other.termfreq == @termfreq
82     end
83   end # class Term
85   ### Ruby wrapper for a Match, i.e. a Xapian::MSetIterator (Match Set) in C++.
86   # it's no longer an iterator in the Ruby version, but we want to preserve its
87   # non-iterative data.
88   # (MSetIterator is not dangerous, but it is inconvenient to use from a Ruby
89   # idiom, so we wrap it..)
90   class Xapian::Match
91     attr_accessor :docid, :document, :rank, :weight, :collapse_count, :percent
93     def initialize(docid, document, rank, weight, collapse_count, percent)
94       @docid = docid
95       @document = document
96       @rank = rank
97       @weight = weight
98       @collapse_count = collapse_count
99       @percent = percent
100     end # initialize
102     def ==(other)
103       return other.is_a?(Xapian::Match) && other.docid == @docid && other.rank == @rank &&
104         other.weight == @weight && other.collapse_count == @collapse_count && other.percent == @percent
105     end
106   end # class Xapian::Match
108   # Ruby wrapper for an ExpandTerm, i.e. a Xapian::ESetIterator in C++
109   # Not dangerous, but inconvenient to use from a Ruby programming idiom, so we
110   # wrap it.
111   class Xapian::ExpandTerm
112     attr_accessor :name, :weight
114     def initialize(name, weight)
115       @name = name
116       @weight = weight
117     end # initialize
119     def ==(other)
120       return other.is_a?(Xapian::ExpandTerm) && other.name == @name && other.weight == @weight
121     end
123   end # Xapian::ExpandTerm
125   # Ruby wrapper for Xapian::ValueIterator
126   class Xapian::Value
127     attr_accessor :value, :valueno, :docid
129     def initialize(value, valueno, docid)
130       @value = value
131       @valueno = valueno
132       @docid = docid
133     end # initialize
135     def ==(other)
136       return other.is_a?(Xapian::Value) && other.value == @value && other.valueno == @valueno && other.docid == @docid
137     end
138   end # Xapian::Value
140   # Refer to the
141   # {Xapian::Document C++ API documentation}[https://xapian.org/docs/apidoc/html/classXapian_1_1Document.html]
142   # for methods not specific to Ruby.
143   #--
144   # Extend Xapian::Document with a nice wrapper for its nasty input_iterators
145   class Xapian::Document
146     def terms
147       Xapian._safelyIterate(self._dangerous_termlist_begin(), self._dangerous_termlist_end()) { |item|
148         Xapian::Term.new(item.term, item.wdf)
149       }
150     end # terms
152     def values
153       Xapian._safelyIterate(self._dangerous_values_begin(), self._dangerous_values_end()) { |item|
154         Xapian::Value.new(item.value, item.valueno, 0)
155       }
156     end # values
158   end # class Xapian::Document
160   # Refer to the
161   # {Xapian::Query C++ API documentation}[https://xapian.org/docs/apidoc/html/classXapian_1_1Query.html]
162   # for methods not specific to Ruby.
163   #--
164   # Extend Xapian::Query with a nice wrapper for its dangerous iterators
165   class Xapian::Query
166     def terms
167       Xapian._safelyIterate(self._dangerous_terms_begin(), self._dangerous_terms_end()) { |item|
168         Xapian::Term.new(item.term, item.wdf)
169         # termfreq is not supported by TermIterators from Queries
170       }
171     end # terms
172   end # Xapian::Query
174   # Refer to the
175   # {Xapian::Enquire C++ API documentation}[https://xapian.org/docs/apidoc/html/classXapian_1_1Enquire.html]
176   # for methods not specific to Ruby.
177   #--
178   # Extend Xapian::Enquire with a nice wrapper for its dangerous iterators
179   class Xapian::Enquire
180     # Get matching terms for some document.
181     # document can be either a Xapian::DocID or a Xapian::MSetIterator
182     def matching_terms(document)
183       Xapian._safelyIterate(self._dangerous_matching_terms_begin(document),
184                             self._dangerous_matching_terms_end(document)) { |item|
185         Xapian::Term.new(item.term, item.wdf)
186       }
187     end # matching_terms
188   end # Xapian::Enquire
190   # Refer to the
191   # {Xapian::MSet C++ API documentation}[https://xapian.org/docs/apidoc/html/classXapian_1_1MSet.html]
192   # for methods not specific to Ruby.
193   #--
194   # MSetIterators are not dangerous, just inconvenient to use within a Ruby
195   # programming idiom. So we wrap them.
196   class Xapian::MSet
197     def matches
198       Xapian._safelyIterate(self._begin(),
199                             self._end()) { |item|
200         Xapian::Match.new(item.docid, item.document, item.rank, item.weight, item.collapse_count, item.percent)
201       }
203     end # matches
204   end # Xapian::MSet
206   # Refer to the
207   # {Xapian::ESet C++ API documentation}[https://xapian.org/docs/apidoc/html/classXapian_1_1ESet.html]
208   # for methods not specific to Ruby.
209   #--
210   # ESetIterators are not dangerous, just inconvenient to use within a Ruby
211   # programming idiom. So we wrap them.
212   class Xapian::ESet
213     def terms
214       Xapian._safelyIterate(self._begin(),
215                             self._end()) { |item|
216         # note: in the ExpandTerm wrapper, we implicitly rename
217         # ESetIterator#term() (defined in xapian-headers.i) to ExpandTerm#term()
218         Xapian::ExpandTerm.new(item.term, item.weight)
219       }
221     end # terms
222   end # Xapian::ESet
225   #--
226   # Wrapper for the C++ class Xapian::PostingIterator
227   class Xapian::Posting
228     attr_accessor :docid, :doclength, :wdf
230     def initialize(docid, doclength, wdf)
231       @docid = docid
232       @doclength = doclength
233       @wdf = wdf
234     end
236     def ==(other)
237       return other.is_a?(Xapian::Posting) && other.docid == @docid && other.doclength == @doclength &&
238         other.wdf == @wdf
239     end
240   end # Xapian::Posting
242   # Refer to the
243   # {Xapian::Database C++ API documentation}[https://xapian.org/docs/apidoc/html/classXapian_1_1Database.html]
244   # for methods not specific to Ruby.
245   #--
246   # Wrap some dangerous iterators.
247   class Xapian::Database
248     # Returns an Array of all Xapian::Terms for this database.
249     def allterms(pref = '')
250       Xapian._safelyIterate(self._dangerous_allterms_begin(pref),
251                             self._dangerous_allterms_end(pref)) { |item|
252         Xapian::Term.new(item.term, 0, item.termfreq)
253       }
254     end # allterms
256     # Returns an Array of Xapian::Postings for the given term.
257     # term is a string.
258     def postlist(term)
259       Xapian._safelyIterate(self._dangerous_postlist_begin(term),
260                             self._dangerous_postlist_end(term)) { |item|
261         Xapian::Posting.new(item.docid, item.doclength, item.wdf)
262       }
263     end # postlist(term)
265     # Returns an Array of Terms for the given docid.
266     def termlist(docid)
267       Xapian._safelyIterate(self._dangerous_termlist_begin(docid),
268                             self._dangerous_termlist_end(docid)) { |item|
269         Xapian::Term.new(item.term, item.wdf, item.termfreq)
270       }
271     end # termlist(docid)
273     # Returns an Array of Xapian::Termpos objects for the given term (a String)
274     # in the given docid.
275     def positionlist(docid, term)
276       Xapian._safelyIterate(self._dangerous_positionlist_begin(docid, term),
277                             self._dangerous_positionlist_end(docid, term)) { |item|
278         item.termpos
279       }
280     end # positionlist
282     # Returns an Array of Xapian::Value objects for the given slot in the
283     # database.
284     def valuestream(slot)
285       Xapian._safelyIterate(self._dangerous_valuestream_begin(slot),
286                             self._dangerous_valuestream_end(slot)) { |item|
287         Xapian::Value.new(item.value, slot, item.docid)
288       }
289     end # valuestream(slot)
290   end # Xapian::Database
292   # Refer to the
293   # {Xapian::ValueCountMatchSpy C++ API documentation}[https://xapian.org/docs/apidoc/html/classXapian_1_1ValueCountMatchSpy.html]
294   # for methods not specific to Ruby.
295   #--
296   # Wrap some dangerous iterators.
297   class Xapian::ValueCountMatchSpy
298     # Returns an Array of all the values seen, in alphabetical order
299     def values()
300       Xapian._safelyIterate(self._dangerous_values_begin(),
301                             self._dangerous_values_end()) { |item|
302         Xapian::Term.new(item.term, 0, item.termfreq)
303       }
304     end # values
306     # Returns an Array of the top values seen, by frequency
307     def top_values(maxvalues)
308       Xapian._safelyIterate(self._dangerous_top_values_begin(maxvalues),
309                             self._dangerous_top_values_end(maxvalues)) { |item|
310         Xapian::Term.new(item.term, 0, item.termfreq)
311       }
312     end # top_values
313   end # Xapian::Database
315   # Refer to the
316   # {Xapian::LatLongCoords C++ API documentation}[https://xapian.org/docs/apidoc/html/classXapian_1_1LatLongCoords.html]
317   # for methods not specific to Ruby.
318   #--
319   # Wrap some dangerous iterators.
320   class Xapian::LatLongCoords
321     # Returns an Array of all the values seen, in alphabetical order
322     def all()
323       Xapian._safelyIterate(self._begin(),
324                             self._end()) { |item|
325         item.get_coord()
326       }
327     end # allterms
328   end # Xapian::LatLongCoords
330 end # Xapian module