sphinx_for_dm 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README ADDED
@@ -0,0 +1,10 @@
1
+ SphinxForDM
2
+ ===========
3
+
4
+ Introduction
5
+ ------------
6
+
7
+ Complete rip-off of acts_as_sphinx by Kent Sibilev.
8
+
9
+ Please submit patches to foysavas@gmail.com.
10
+
data/lib/sphinx.rb ADDED
@@ -0,0 +1,460 @@
1
+ require "socket"
2
+ # = sphinx.rb - Sphinx Client Library
3
+ #
4
+ # Author:: Dmytro Shteflyuk <mailto:kpumuk@kpumuk.info>.
5
+ # Copyright:: Copyright (c) 2006 Wildbit, LLC
6
+ # License:: Distributes under the same terms as Ruby
7
+ #
8
+ # This library is distributed under the terms of the Ruby license.
9
+ # You can freely distribute/modify this library.
10
+
11
+ # ==Sphinx Client Library
12
+ #
13
+ # The Sphinx Client Library is used to communicate with <tt>searchd</tt>
14
+ # daemon and get search results from Sphinx.
15
+ #
16
+ # ===Usage
17
+ #
18
+ # sphinx = Sphinx.new
19
+ # result = sphinx.query('test')
20
+ # ids = result[:matches].map { |id, value| id }.join(',')
21
+ # posts = Post.find :all, :conditions => "id IN (#{ids})"
22
+ #
23
+ # docs = posts.map { |post| post.body }
24
+ # excerpts = sphinx.build_excerpts(docs, 'index', 'test')
25
+ #
26
+ class Sphinx
27
+
28
+ # :stopdoc:
29
+ class SphinxError < StandardError; end
30
+ class SphinxConnectError < SphinxError; end
31
+ class SphinxResponseError < SphinxError; end
32
+ class SphinxInternalError < SphinxError; end
33
+ class SphinxTemporaryError < SphinxError; end
34
+ class SphinxUnknownError < SphinxError; end
35
+ # :startdoc:
36
+
37
+ # known searchd commands
38
+ SEARCHD_COMMAND_SEARCH = 0
39
+ SEARCHD_COMMAND_EXCERPT = 1
40
+
41
+ # current client-side command implementation versions
42
+ VER_COMMAND_SEARCH = 0x104
43
+ VER_COMMAND_EXCERPT = 0x100
44
+
45
+ # known searchd status codes
46
+ SEARCHD_OK = 0
47
+ SEARCHD_ERROR = 1
48
+ SEARCHD_RETRY = 2
49
+
50
+ # known match modes
51
+ SPH_MATCH_ALL = 0
52
+ SPH_MATCH_ANY = 1
53
+ SPH_MATCH_PHRASE = 2
54
+ SPH_MATCH_BOOLEAN = 3
55
+ SPH_MATCH_EXTENDED = 4
56
+
57
+ # known sort modes
58
+ SPH_SORT_RELEVANCE = 0
59
+ SPH_SORT_ATTR_DESC = 1
60
+ SPH_SORT_ATTR_ASC = 2
61
+ SPH_SORT_TIME_SEGMENTS = 3
62
+ SPH_SORT_EXTENDED = 4
63
+
64
+ # known attribute types
65
+ SPH_ATTR_INTEGER = 1
66
+ SPH_ATTR_TIMESTAMP = 2
67
+
68
+ # known grouping functions
69
+ SPH_GROUPBY_DAY = 0
70
+ SPH_GROUPBY_WEEK = 1
71
+ SPH_GROUPBY_MONTH = 2
72
+ SPH_GROUPBY_YEAR = 3
73
+ SPH_GROUPBY_ATTR = 4
74
+
75
+ # Constructs the Sphinx object and sets options to their default values.
76
+ def initialize
77
+ @host = 'localhost' # searchd host (default is "localhost")
78
+ @port = 3312 # searchd port (default is 3312)
79
+ @offset = 0 # how much records to seek from result-set start (default is 0)
80
+ @limit = 20 # how much records to return from result-set starting at offset (default is 20)
81
+ @mode = SPH_MATCH_ALL # query matching mode (default is SPH_MATCH_ALL)
82
+ @weights = [] # per-field weights (default is 1 for all fields)
83
+ @sort = SPH_SORT_RELEVANCE # match sorting mode (default is SPH_SORT_RELEVANCE)
84
+ @sortby = '' # attribute to sort by (defualt is "")
85
+ @min_id = 0 # min ID to match (default is 0)
86
+ @max_id = 0xFFFFFFFF # max ID to match (default is UINT_MAX)
87
+ @min = {} # attribute name to min-value hash (for range filters)
88
+ @max = {} # attribute name to max-value hash (for range filters)
89
+ @filter = {} # attribute name to values set hash (for values-set filters)
90
+ @groupby = '' # group-by attribute name
91
+ @groupfunc = SPH_GROUPBY_DAY # function to pre-process group-by attribute value with
92
+ @maxmatches = 1000 # max matches to retrieve
93
+
94
+ @error = '' # last error message
95
+ @warning = '' # last warning message
96
+ end
97
+
98
+ # Get last error message.
99
+ def last_error
100
+ @error
101
+ end
102
+
103
+ # Get last warning message.
104
+ def last_warning
105
+ @warning
106
+ end
107
+
108
+ # Set searchd server.
109
+ def set_server(host, port)
110
+ @host = host
111
+ @port = port
112
+ end
113
+
114
+ # Set match offset, count, and max number to retrieve.
115
+ def set_limits(offset, limit, max = 0)
116
+ @offset = offset
117
+ @limit = limit
118
+ @maxmatches = max if max > 0
119
+ end
120
+
121
+ # Set match mode.
122
+ def set_match_mode(mode)
123
+ @mode = mode
124
+ end
125
+
126
+ # Set sort mode.
127
+ def set_sort_mode(mode, sortby = '')
128
+ @sort = mode
129
+ @sortby = sortby
130
+ end
131
+
132
+ # Set per-field weights.
133
+ def set_weights(weights)
134
+ @weights = weights
135
+ end
136
+
137
+ # Set IDs range to match.
138
+ #
139
+ # Only match those records where document ID is beetwen <tt>min_id</tt> and <tt>max_id</tt>
140
+ # (including <tt>min_id</tt> and <tt>max_id</tt>).
141
+ def set_id_range(min_id, max_id)
142
+ @min_id = min_id
143
+ @max_id = max_id
144
+ end
145
+
146
+ # Set values filter.
147
+ #
148
+ # Only match those records where <tt>attr</tt> column values
149
+ # are in specified set.
150
+ def set_filter(attr, values)
151
+ @filter[attr] = values
152
+ end
153
+
154
+ # Set range filter.
155
+ #
156
+ # Only match those records where <tt>attr</tt> column value
157
+ # is beetwen <tt>min</tt> and <tt>max</tt> (including <tt>min</tt> and <tt>max</tt>).
158
+ def set_filter_range(attr, min, max)
159
+ @min[attr] = min
160
+ @max[attr] = max
161
+ end
162
+
163
+ # Set grouping.
164
+ #
165
+ # if grouping
166
+ def set_group_by(attr, func)
167
+ @groupby = attr
168
+ @groupfunc = func
169
+ end
170
+
171
+ # Connect to searchd server and run given search query.
172
+ #
173
+ # * <tt>query</tt> -- query string
174
+ # * <tt>index</tt> -- index name to query, default is "*" which means to query all indexes
175
+ #
176
+ # returns hash which has the following keys on success:
177
+ #
178
+ # * <tt>:matches</tt> -- hash which maps found document_id to ( "weight", "group" ) hash
179
+ # * <tt>:total</tt> -- total amount of matches retrieved (upto SPH_MAX_MATCHES, see sphinx.h)
180
+ # * <tt>:total_found</tt> -- total amount of matching documents in index
181
+ # * <tt>:time</tt> -- search time
182
+ # * <tt>:words</tt> -- hash which maps query terms (stemmed!) to ( :docs, :hits ) hash
183
+ def query(query, index = '*')
184
+ sock = connect
185
+
186
+ # build request
187
+
188
+ # mode and limits
189
+ req = [@offset, @limit, @mode, @sort].pack('NNNN')
190
+ req << [@sortby.length].pack('N')
191
+ req << @sortby
192
+ # query itself
193
+ req << [query.length].pack('N')
194
+ req << query
195
+ # weights
196
+ req << [@weights.length].pack('N')
197
+ req << @weights.pack('N' * @weights.length)
198
+ # indexes
199
+ req << [index.length].pack('N')
200
+ req << index
201
+ # id range
202
+ req << [@min_id.to_i, @max_id.to_i].pack('NN')
203
+
204
+ # filters
205
+ req << [@min.length + @filter.length].pack('N')
206
+ @min.each do |attribute, min|
207
+ req << [attribute.length].pack('N')
208
+ req << attribute
209
+ req << [0, min, @max[attribute]].pack('NNN')
210
+ end
211
+
212
+ @filter.each do |attribute, values|
213
+ req << [attribute.length].pack('N')
214
+ req << attribute
215
+ req << [values.length].pack('N')
216
+ req << values.pack('N' * values.length)
217
+ end
218
+
219
+ # group-by
220
+ req << [@groupfunc, @groupby.length].pack('NN')
221
+ req << @groupby
222
+
223
+ # max matches to retrieve
224
+ req << [@maxmatches].pack('N')
225
+
226
+ # send query, get response
227
+ len = req.length
228
+ # add header
229
+ req = [SEARCHD_COMMAND_SEARCH, VER_COMMAND_SEARCH, len].pack('nnN') + req
230
+ sock.send(req, 0)
231
+
232
+ response = get_response(sock, VER_COMMAND_SEARCH)
233
+
234
+ # parse response
235
+ result = {}
236
+ max = response.length # protection from broken response
237
+
238
+ #read schema
239
+ p = 0
240
+ fields = []
241
+ attrs = {}
242
+
243
+ nfields = response[p, 4].unpack('N*').first
244
+ p += 4
245
+ while nfields > 0 and p < max
246
+ nfields -= 1
247
+ len = response[p, 4].unpack('N*').first
248
+ p += 4
249
+ fields << response[p, len]
250
+ p += len
251
+ end
252
+ result[:fields] = fields
253
+
254
+ nattrs = response[p, 4].unpack('N*').first
255
+ p += 4
256
+ while nattrs > 0 && p < max
257
+ nattrs -= 1
258
+ len = response[p, 4].unpack('N*').first
259
+ p += 4
260
+ attr = response[p, len]
261
+ p += len
262
+ type = response[p, 4].unpack('N*').first
263
+ p += 4
264
+ attrs[attr.to_sym] = type;
265
+ end
266
+ result[:attrs] = attrs
267
+
268
+ # read match count
269
+ count = response[p, 4].unpack('N*').first
270
+ p += 4
271
+
272
+ # read matches
273
+ result[:matches] = {}
274
+ while count > 0 and p < max
275
+ count -= 1
276
+ doc, weight = response[p, 8].unpack('N*N*')
277
+ p += 8
278
+
279
+ result[:matches][doc] ||= {}
280
+ result[:matches][doc][:weight] = weight
281
+ attrs.each do |attr, type|
282
+ val = response[p, 4].unpack('N*').first
283
+ p += 4
284
+ result[:matches][doc][:attrs] ||= {}
285
+ result[:matches][doc][:attrs][attr] = val
286
+ end
287
+ end
288
+ result[:total], result[:total_found], result[:time], words = \
289
+ response[p, 16].unpack('N*N*N*N*')
290
+ result[:time] = '%.3f' % (result[:time] / 1000)
291
+ p += 16
292
+
293
+ result[:words] = {}
294
+ while words > 0 and p < max
295
+ words -= 1
296
+ len = response[p, 4].unpack('N*').first
297
+ p += 4
298
+ word = response[p, len]
299
+ p += len
300
+ docs, hits = response[p, 8].unpack('N*N*')
301
+ p += 8
302
+ result[:words][word] = {:docs => docs, :hits => hits}
303
+ end
304
+
305
+ result
306
+ end
307
+
308
+ # Connect to searchd server and generate exceprts from given documents.
309
+ #
310
+ # * <tt>index</tt> -- a string specifiying the index which settings will be used
311
+ # for stemming, lexing and case folding
312
+ # * <tt>docs</tt> -- an array of strings which represent the documents' contents
313
+ # * <tt>words</tt> -- a string which contains the words to highlight
314
+ # * <tt>opts</tt> is a hash which contains additional optional highlighting parameters.
315
+ #
316
+ # You can use following parameters:
317
+ # * <tt>:before_match</tt> -- a string to insert before a set of matching words, default is "<b>"
318
+ # * <tt>:after_match</tt> -- a string to insert after a set of matching words, default is "<b>"
319
+ # * <tt>:chunk_separator</tt> -- a string to insert between excerpts chunks, default is " ... "
320
+ # * <tt>:limit</tt> -- max excerpt size in symbols (codepoints), default is 256
321
+ # * <tt>:around</tt> -- how much words to highlight around each match, default is 5
322
+ #
323
+ # Returns an array of string excerpts on success.
324
+ def build_excerpts(docs, index, words, opts = {})
325
+ sock = connect
326
+
327
+ # fixup options
328
+ opts[:before_match] ||= '<b>';
329
+ opts[:after_match] ||= '</b>';
330
+ opts[:chunk_separator] ||= ' ... ';
331
+ opts[:limit] ||= 256;
332
+ opts[:around] ||= 5;
333
+
334
+ # build request
335
+
336
+ # v.1.0 req
337
+ req = [0, 1].pack('N2'); # mode=0, flags=1 (remove spaces)
338
+ # req index
339
+ req << [index.length].pack('N')
340
+ req << index
341
+ # req words
342
+ req << [words.length].pack('N')
343
+ req << words
344
+
345
+ # options
346
+ req << [opts[:before_match].length].pack('N')
347
+ req << opts[:before_match]
348
+ req << [opts[:after_match].length].pack('N')
349
+ req << opts[:after_match]
350
+ req << [opts[:chunk_separator].length].pack('N')
351
+ req << opts[:chunk_separator]
352
+ req << [opts[:limit].to_i, opts[:around].to_i].pack('NN')
353
+
354
+ # documents
355
+ req << [docs.size].pack('N');
356
+ docs.each do |doc|
357
+ req << [doc.length].pack('N')
358
+ req << doc
359
+ end
360
+
361
+ # send query, get response
362
+ len = req.length
363
+ # add header
364
+ req = [SEARCHD_COMMAND_EXCERPT, VER_COMMAND_EXCERPT, len].pack('nnN') + req
365
+ sock.send(req, 0)
366
+
367
+ response = get_response(sock, VER_COMMAND_EXCERPT)
368
+
369
+ # parse response
370
+ p = 0
371
+ res = []
372
+ rlen = response.length
373
+ docs.each do |doc|
374
+ len = response[p, 4].unpack('N*').first;
375
+ p += 4
376
+ if p + len > rlen
377
+ @error = 'incomplete reply'
378
+ raise SphinxResponseError, @error
379
+ end
380
+ res << response[p, len]
381
+ p += len
382
+ end
383
+ return res;
384
+ end
385
+
386
+ # Connect to searchd server.
387
+ def connect
388
+ begin
389
+ sock = TCPSocket.new(@host, @port)
390
+ rescue
391
+ @error = "connection to #{@host}:#{@port} failed"
392
+ raise SphinxConnectError, @error
393
+ end
394
+
395
+ v = sock.recv(4).unpack('N*').first
396
+ if v < 1
397
+ sock.close
398
+ @error = "expected searchd protocol version 1+, got version '#{v}'"
399
+ raise SphinxConnectError, @error
400
+ end
401
+
402
+ sock.send([1].pack('N'), 0)
403
+ sock
404
+ end
405
+ private :connect
406
+
407
+ # get and check response packet from searchd server
408
+ def get_response(sock, client_version)
409
+ header = sock.recv(8)
410
+ status, ver, len = header.unpack('n2N')
411
+ response = ''
412
+ left = len
413
+ while left > 0 do
414
+ begin
415
+ chunk = sock.recv(left)
416
+ if chunk
417
+ response << chunk
418
+ left -= chunk.length
419
+ end
420
+ rescue EOFError
421
+ end
422
+ end if left
423
+ sock.close
424
+
425
+ # check response
426
+ read = response.length
427
+ if not response or read != len
428
+ @error = len \
429
+ ? "failed to read searchd response (status=#{status}, ver=#{ver}, len=#{len}, read=#{read})" \
430
+ : "received zero-sized searchd response"
431
+ raise SphinxResponseError, @error
432
+ end
433
+
434
+ # check status
435
+ if status == SEARCHD_ERROR
436
+ @error = "searchd error: " + response[4,].to_s
437
+ raise SphinxInternalError, @error
438
+ end
439
+
440
+ if status == SEARCHD_RETRY
441
+ @error = "temporary searchd error: " + response[4,]
442
+ raise SphinxTemporaryError, @error
443
+ end
444
+
445
+ unless status == SEARCHD_OK
446
+ @error = "unknown status code '#{status}'"
447
+ raise SphinxUnknownError, @error
448
+ end
449
+
450
+ # check version
451
+ if ver < client_version
452
+ @warning = "searchd command v.%d.%d older than client's v.%d.%d, some options might not work" % \
453
+ ver >> 8, ver & 0xff, client_ver >> 8, client_ver & 0xff
454
+ end
455
+
456
+ return response
457
+ end
458
+ private :get_response
459
+
460
+ end
@@ -0,0 +1,88 @@
1
+ require "sphinx"
2
+
3
+ module SphinxForDataMapper
4
+ module ClassMethods
5
+ def acts_as_sphinx(options = {})
6
+ default_options = {:host => 'localhost', :port => 3312, :index => name.tableize}
7
+ write_inheritable_attribute 'sphinx_options', default_options.merge(options)
8
+ extend SphinxClassMethods
9
+ end
10
+ end
11
+
12
+ def self.included(receiver)
13
+ receiver.extend(ClassMethods)
14
+ end
15
+
16
+ module SphinxClassMethods
17
+ VALID_OPTIONS = %w[mode offset page limit index weights host
18
+ port range filter filter_range group_by sort_mode].map(&:to_sym)
19
+
20
+ def sphinx_index
21
+ read_inheritable_attribute('sphinx_options')[:index]
22
+ end
23
+
24
+ def sphinx_options
25
+ read_inheritable_attribute 'sphinx_options'
26
+ end
27
+
28
+ def ask_sphinx(query, options = {})
29
+ default_options = {:offset => 0, :limit => 20}
30
+ default_options.merge! sphinx_options
31
+ default_options.merge! options
32
+
33
+ if options[:page] && options[:limit]
34
+ options[:offset] = options[:limit] * (options[:page].to_i - 1)
35
+ options[:offset] = 0 if options[:offset] < 0
36
+ end
37
+
38
+ sphinx = Sphinx.new
39
+ sphinx.set_server options[:host], options[:port]
40
+ sphinx.set_limits options[:offset], options[:limit]
41
+ sphinx.set_weights options[:weights] if options[:weights]
42
+ sphinx.set_id_range options[:range] if options[:range]
43
+
44
+ options[:filter].each do |attr, values|
45
+ sphinx.set_filter attr, [*values]
46
+ end if options[:filter]
47
+
48
+ options[:filter_range].each do |attr, (min, max)|
49
+ sphinx.set_filter_range attr, min, max
50
+ end if options[:filter_range]
51
+
52
+ options[:group_by].each do |attr, func|
53
+ funcion = Sphinx.const_get("SPH_GROUPBY_#{func.to_s.upcase}") \
54
+ rescue raise("Unknown group by function #{func}")
55
+ sphinx.set_group_by attr, funcion
56
+ end if options[:group_by]
57
+
58
+ if options[:mode]
59
+ match_mode = Sphinx.const_get("SPH_MATCH_#{options[:mode].to_s.upcase}") \
60
+ rescue raise("Unknown search mode #{options[:mode]}")
61
+ sphinx.set_match_mode match_mode
62
+ end
63
+
64
+ if options[:sort_mode]
65
+ sort_mode, sort_expr = options[:sort_mode]
66
+ sort_mode = Sphinx.const_get("SPH_SORT_#{sort_mode.to_s.upcase}") \
67
+ rescue raise("Unknown sort mode #{sort_mode}")
68
+ sphinx.set_sort_mode sort_mode, sort_expr
69
+ end
70
+
71
+ sphinx.query query, options[:index]
72
+ end
73
+
74
+ def all_with_sphinx(query, options = {})
75
+ result = ask_sphinx(query, options.delete(:sphinx) || {})
76
+ records = result[:matches].empty? ? [] : all(({ :id.in => result[:matches].keys }).merge(options))
77
+ records = records.sort_by{|r| -result[:matches][r.id][:weight] }
78
+ %w[total total_found time].map(&:to_sym).each do |method|
79
+ class << records; self end.send(:define_method, method) {result[method]}
80
+ end
81
+ records
82
+ end
83
+ end
84
+ end
85
+
86
+ class DataMapper::Base
87
+ include SphinxForDataMapper
88
+ end
data/scripts/sphinx.sh ADDED
@@ -0,0 +1,47 @@
1
+ #!/bin/sh
2
+ #
3
+ # start/stop searchd server.
4
+
5
+ if ! [ -x /usr/local/bin/searchd ]; then
6
+ exit 0
7
+ fi
8
+
9
+ case "$1" in
10
+ start)
11
+ echo -n "Starting sphinx searchd server:"
12
+ echo -n " searchd" ;
13
+ /sbin/start-stop-daemon --start --quiet --pidfile /var/run/searchd.pid --chdir /etc --exec /usr/local/bin/searchd
14
+ echo "."
15
+ ;;
16
+ stop)
17
+ echo -n "Stopping sphinx searchd server:"
18
+ echo -n " searchd" ;
19
+ /sbin/start-stop-daemon --stop --quiet --oknodo --pidfile /var/run/searchd.pid --exec /usr/local/bin/searchd
20
+ echo "."
21
+ ;;
22
+ reload)
23
+ echo -n "Reloading sphinx searchd server:"
24
+ echo -n " searchd"
25
+ /sbin/start-stop-daemon --stop --quiet --oknodo --pidfile /var/run/searchd.pid --signal 1
26
+ echo "."
27
+ ;;
28
+ force-reload)
29
+ $0 reload
30
+ ;;
31
+ reindex)
32
+ cd /etc
33
+ /usr/local/bin/indexer --rotate --quiet --all
34
+ ;;
35
+ restart)
36
+ echo -n "Restarting sphinx searchd server:"
37
+ echo -n " searchd"
38
+ /sbin/start-stop-daemon --stop --quiet --oknodo --pidfile /var/run/searchd.pid --exec /usr/local/bin/searchd
39
+ /sbin/start-stop-daemon --start --quiet --pidfile /var/run/searchd.pid --chdir /etc --exec /usr/local/bin/searchd
40
+ echo "."
41
+ ;;
42
+ *)
43
+ echo "Usage: /etc/init.d/searchd {start|stop|reload|restart|reindex}"
44
+ exit 1
45
+ ;;
46
+ esac
47
+ exit 0
@@ -0,0 +1,43 @@
1
+ namespace :dm do
2
+ namespace :sphinx do
3
+ desc "Run indexer"
4
+ task :index do
5
+ cd 'config' do
6
+ system 'indexer --all'
7
+ end
8
+ end
9
+
10
+ desc "Rotate idendexes and restart searchd server"
11
+ task :rotate do
12
+ cd 'config' do
13
+ system 'indexer --rotate --all'
14
+ end
15
+ end
16
+
17
+ desc "Start searchd server"
18
+ task :start do
19
+ if File.exists?('/var/run/searchd.pid')
20
+ puts 'Sphinx searchd server is already started.'
21
+ else
22
+ cd 'config' do
23
+ system 'searchd'
24
+ puts 'Sphinx searchd server started.'
25
+ end
26
+ end
27
+ end
28
+
29
+ desc "Stop searchd server"
30
+ task :stop do
31
+ unless File.exists?('/var/run/searchd.pid')
32
+ puts 'Sphinx searchd server is not running.'
33
+ else
34
+ pid = File.read('/var/run/searchd.pid').chomp
35
+ system "kill #{pid}"
36
+ puts 'Sphinx searchd server stopped.'
37
+ end
38
+ end
39
+
40
+ desc "Restart searchd server"
41
+ task :restart => [:stop, :start]
42
+ end
43
+ end
metadata ADDED
@@ -0,0 +1,50 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.4
3
+ specification_version: 1
4
+ name: sphinx_for_dm
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.0.1
7
+ date: 2008-02-24 00:00:00 -05:00
8
+ summary: Acts_as_sphinx for DataMapper
9
+ require_paths:
10
+ - lib
11
+ email: foysavas@gmail.com
12
+ homepage: http://www.foysavas.com
13
+ rubyforge_project:
14
+ description:
15
+ autorequire: sphinx_for_dm
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Foy Savas
31
+ files:
32
+ - lib/sphinx_for_dm.rb
33
+ - lib/sphinx.rb
34
+ - scripts/sphinx.sh
35
+ - tasks/sphinx_for_dm_tasks.rake
36
+ - README
37
+ test_files: []
38
+
39
+ rdoc_options: []
40
+
41
+ extra_rdoc_files:
42
+ - README
43
+ executables: []
44
+
45
+ extensions: []
46
+
47
+ requirements: []
48
+
49
+ dependencies: []
50
+