ambitious-sphinx 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +18 -0
- data/Manifest +16 -0
- data/README +82 -0
- data/ambitious-sphinx.gemspec +60 -0
- data/config/ultrasphinx/default.base +77 -0
- data/config/ultrasphinx/development.conf +62 -0
- data/lib/ambition/adapters/ambitious_sphinx.rb +15 -0
- data/lib/ambition/adapters/ambitious_sphinx/base.rb +33 -0
- data/lib/ambition/adapters/ambitious_sphinx/query.rb +52 -0
- data/lib/ambition/adapters/ambitious_sphinx/select.rb +108 -0
- data/lib/ambition/adapters/ambitious_sphinx/slice.rb +13 -0
- data/lib/ambition/adapters/ambitious_sphinx/sort.rb +38 -0
- data/test/helper.rb +9 -0
- data/test/select_test.rb +80 -0
- data/test/slice_test.rb +12 -0
- data/test/sort_test.rb +26 -0
- metadata +87 -0
data/LICENSE
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Copyright (c) 2007 Josh Nichols and Dan Croak
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
4
|
+
this software and associated documentation files (the "Software"), to deal in
|
5
|
+
the Software without restriction, including without limitation the rights to
|
6
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
7
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
8
|
+
subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
15
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
16
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
17
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
18
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Manifest
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
ambitious-sphinx.gemspec
|
2
|
+
config/ultrasphinx/default.base
|
3
|
+
config/ultrasphinx/development.conf
|
4
|
+
lib/ambition/adapters/ambitious_sphinx/base.rb
|
5
|
+
lib/ambition/adapters/ambitious_sphinx/query.rb
|
6
|
+
lib/ambition/adapters/ambitious_sphinx/select.rb
|
7
|
+
lib/ambition/adapters/ambitious_sphinx/slice.rb
|
8
|
+
lib/ambition/adapters/ambitious_sphinx/sort.rb
|
9
|
+
lib/ambition/adapters/ambitious_sphinx.rb
|
10
|
+
LICENSE
|
11
|
+
Manifest
|
12
|
+
README
|
13
|
+
test/helper.rb
|
14
|
+
test/select_test.rb
|
15
|
+
test/slice_test.rb
|
16
|
+
test/sort_test.rb
|
data/README
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
= An Ambitious Sphinx Adapter
|
2
|
+
|
3
|
+
I don't know about you, but I like me some sexy full-text searching.
|
4
|
+
|
5
|
+
== The basics
|
6
|
+
|
7
|
+
Want to find all meals that mention bacon?
|
8
|
+
|
9
|
+
Meal.select {'bacon'}
|
10
|
+
|
11
|
+
What about bacon bits and sour cream?
|
12
|
+
|
13
|
+
Meal.select {'bacon bits' && 'sour cream'}
|
14
|
+
|
15
|
+
Maybe with bacon in the name, or cheese in the recipe?
|
16
|
+
|
17
|
+
Meal.select {|m| m.name =~ 'bacon' || m.recipe =~ 'cheese'}
|
18
|
+
|
19
|
+
Cheese in the name, but not grilled?
|
20
|
+
|
21
|
+
Meal.select {|m| m.name =~ 'bacon' && m.name !~ 'grilled'}
|
22
|
+
|
23
|
+
== Pagination
|
24
|
+
|
25
|
+
You're going to want to use pagination. Ultrasphinx, the underlying library, only supports it, as in, you can't just get all the objects matching your query. You _have_ to use paging.
|
26
|
+
|
27
|
+
It's pretty simple:
|
28
|
+
|
29
|
+
Meal.select {'bacon'}.page(2)
|
30
|
+
Meal.select {'bacon'}.page(3)
|
31
|
+
|
32
|
+
== Big honking disclaimer
|
33
|
+
|
34
|
+
We're still learning a lot about how sphinx and ambition work, so things are likely to change a lot, and features are likely to be missing.
|
35
|
+
|
36
|
+
== Getting Started
|
37
|
+
|
38
|
+
|
39
|
+
=== Installing
|
40
|
+
|
41
|
+
sudo gem install ambitious-sphinx
|
42
|
+
|
43
|
+
=== Add it to your app
|
44
|
+
|
45
|
+
Require our files somewhere, like at the end of config/environment.rb, maybe create config/initializers/sphinx.rb
|
46
|
+
|
47
|
+
require 'ultrasphinx'
|
48
|
+
require 'ambition/adapters/ambitious_sphinx'
|
49
|
+
|
50
|
+
=== Sphinx and Ultrasphinx
|
51
|
+
|
52
|
+
You will also need to go through the motions of setting up ultrasphinx.
|
53
|
+
|
54
|
+
This includes:
|
55
|
+
|
56
|
+
* Configuring/installing sphinx
|
57
|
+
* Modifying your model to indicate what's to be indexed
|
58
|
+
* Bootstrapping ultrasphinx
|
59
|
+
|
60
|
+
All this is discussed in detail in ultrasphinx's README
|
61
|
+
|
62
|
+
== Playing with the code base
|
63
|
+
|
64
|
+
In addition to the other dependencies, you'll need to:
|
65
|
+
|
66
|
+
gem install echoe redgreen mocha test-spec
|
67
|
+
|
68
|
+
Run the tests with:
|
69
|
+
|
70
|
+
rake test
|
71
|
+
|
72
|
+
|
73
|
+
== More information on Sphinx:
|
74
|
+
|
75
|
+
-> http://www.sphinxsearch.com/
|
76
|
+
-> http://blog.evanweaver.com/articles/2007/07/09/ultrasphinx-searching-the-world-in-231-seconds/
|
77
|
+
-> http://blog.evanweaver.com/files/doc/fauna/ultrasphinx/files/README.html
|
78
|
+
|
79
|
+
== More information on Ambition:
|
80
|
+
|
81
|
+
-> http://ambition.rubyforge.org
|
82
|
+
-> http://groups.google.com/group/ambition-rb/
|
@@ -0,0 +1,60 @@
|
|
1
|
+
|
2
|
+
# Gem::Specification for Ambitious-sphinx-0.1.0
|
3
|
+
# Originally generated by Echoe
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = %q{ambitious-sphinx}
|
7
|
+
s.version = "0.1.0"
|
8
|
+
|
9
|
+
s.specification_version = 2 if s.respond_to? :specification_version=
|
10
|
+
|
11
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
|
+
s.authors = ["Josh Nichols"]
|
13
|
+
s.date = %q{2008-02-29}
|
14
|
+
s.description = %q{An ambitious adapter for sphinx}
|
15
|
+
s.email = %q{josh@technicalpickles.com}
|
16
|
+
s.files = ["ambitious-sphinx.gemspec", "config/ultrasphinx/default.base", "config/ultrasphinx/development.conf", "lib/ambition/adapters/ambitious_sphinx/base.rb", "lib/ambition/adapters/ambitious_sphinx/query.rb", "lib/ambition/adapters/ambitious_sphinx/select.rb", "lib/ambition/adapters/ambitious_sphinx/slice.rb", "lib/ambition/adapters/ambitious_sphinx/sort.rb", "lib/ambition/adapters/ambitious_sphinx.rb", "LICENSE", "Manifest", "README", "test/helper.rb", "test/select_test.rb", "test/slice_test.rb", "test/sort_test.rb"]
|
17
|
+
s.has_rdoc = true
|
18
|
+
s.homepage = %q{http://ambitioussphinx.rubyforge.org/}
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
s.rubyforge_project = %q{ambitioussphinx}
|
21
|
+
s.rubygems_version = %q{1.0.0}
|
22
|
+
s.summary = %q{An ambitious adapter for sphinx}
|
23
|
+
s.test_files = ["test/select_test.rb", "test/slice_test.rb", "test/sort_test.rb"]
|
24
|
+
|
25
|
+
s.add_dependency(%q<ultrasphinx>, [">= 1.7"])
|
26
|
+
s.add_dependency(%q<ambition>, [">= 0.5.0"])
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
# # Original Rakefile source (requires the Echoe gem):
|
31
|
+
#
|
32
|
+
# require 'rake'
|
33
|
+
#
|
34
|
+
# begin
|
35
|
+
# require 'rubygems'
|
36
|
+
# gem 'echoe', '>=2.7'
|
37
|
+
# ENV['RUBY_FLAGS'] = ""
|
38
|
+
# require 'echoe'
|
39
|
+
#
|
40
|
+
# Echoe.new('ambitious-sphinx') do |p|
|
41
|
+
# p.dependencies << 'ultrasphinx >=1.7'
|
42
|
+
# p.summary = 'An ambitious adapter for sphinx'
|
43
|
+
# p.author = 'Josh Nichols'
|
44
|
+
# p.email = 'josh@technicalpickles.com'
|
45
|
+
#
|
46
|
+
# p.project = 'ambitioussphinx'
|
47
|
+
# p.url = 'http://ambitioussphinx.rubyforge.org/'
|
48
|
+
# p.test_pattern = 'test/*_test.rb'
|
49
|
+
# p.version = '0.1.0'
|
50
|
+
# p.dependencies << 'ambition >=0.5.0'
|
51
|
+
# end
|
52
|
+
#
|
53
|
+
# rescue LoadError
|
54
|
+
# puts "Not doing any of the Echoe gemmy stuff, because you don't have the specified gem versions"
|
55
|
+
# end
|
56
|
+
#
|
57
|
+
# desc 'Install as a gem'
|
58
|
+
# task :install_gem do
|
59
|
+
# puts `rake manifest package && gem install pkg/ambitious-sphinx-#{Version}.gem`
|
60
|
+
# end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# Sphinx/Ultrasphinx user-configurable options.
|
4
|
+
#
|
5
|
+
# Copy this file to RAILS_ROOT/config/ultrasphinx. You can use individual
|
6
|
+
# namespaces if you want (e.g. development.base, production.base,
|
7
|
+
# test.base).
|
8
|
+
#
|
9
|
+
# This file should not be handed directly to Sphinx. Use the rake task
|
10
|
+
#
|
11
|
+
# rake ultrasphinx::configure
|
12
|
+
#
|
13
|
+
# to generate a parallel default.conf file. This is the file that Sphinx itself will
|
14
|
+
# use. The Ultrasphinx rake tasks automatically pass the correct file to
|
15
|
+
# to Sphinx.
|
16
|
+
#
|
17
|
+
# It is safe to edit .base files by hand. It is not safe to edit the generated
|
18
|
+
# .conf files. Do not symlink the .conf file to the .base file! I don't know why
|
19
|
+
# people think they need to do that. It's wrong.
|
20
|
+
#
|
21
|
+
|
22
|
+
indexer
|
23
|
+
{
|
24
|
+
# Indexer running options
|
25
|
+
mem_limit = 256M
|
26
|
+
}
|
27
|
+
|
28
|
+
searchd
|
29
|
+
{
|
30
|
+
# Daemon options
|
31
|
+
# What interface the search daemon should listen on and where to store its logs
|
32
|
+
address = 0.0.0.0
|
33
|
+
port = 3312
|
34
|
+
seamless_rotate = 1
|
35
|
+
log = /tmp/sphinx/log/searchd.log
|
36
|
+
query_log = /tmp/sphinx/log/query.log
|
37
|
+
read_timeout = 5
|
38
|
+
max_children = 300
|
39
|
+
pid_file = /tmp/sphinx/log/searchd.pid
|
40
|
+
max_matches = 100000
|
41
|
+
}
|
42
|
+
|
43
|
+
client
|
44
|
+
{
|
45
|
+
# Client options
|
46
|
+
# Name of the Aspell dictionary (two letters max)
|
47
|
+
dictionary_name = ap
|
48
|
+
# How your application connects to the search daemon (not necessarily the same as above)
|
49
|
+
server_host = localhost
|
50
|
+
server_port = 3312
|
51
|
+
}
|
52
|
+
|
53
|
+
source
|
54
|
+
{
|
55
|
+
# Individual SQL source options
|
56
|
+
sql_range_step = 5000
|
57
|
+
strip_html = 0
|
58
|
+
index_html_attrs =
|
59
|
+
sql_query_post =
|
60
|
+
}
|
61
|
+
|
62
|
+
index
|
63
|
+
{
|
64
|
+
# Index building options
|
65
|
+
path = db/sphinx
|
66
|
+
docinfo = extern # just leave this alone
|
67
|
+
morphology = stem_en
|
68
|
+
stopwords = # /path/to/stopwords.txt
|
69
|
+
min_word_len = 1
|
70
|
+
|
71
|
+
# Enable these if you need wildcard searching. They will slow down indexing significantly.
|
72
|
+
# min_infix_len = 1
|
73
|
+
# enable_star = 1
|
74
|
+
|
75
|
+
charset_type = utf-8 # or sbcs (Single Byte Character Set)
|
76
|
+
charset_table = 0..9, A..Z->a..z, -, _, ., &, a..z, U+410..U+42F->U+430..U+44F, U+430..U+44F,U+C5->U+E5, U+E5, U+C4->U+E4, U+E4, U+D6->U+F6, U+F6, U+16B, U+0c1->a, U+0c4->a, U+0c9->e, U+0cd->i, U+0d3->o, U+0d4->o, U+0da->u, U+0dd->y, U+0e1->a, U+0e4->a, U+0e9->e, U+0ed->i, U+0f3->o, U+0f4->o, U+0fa->u, U+0fd->y, U+104->U+105, U+105, U+106->U+107, U+10c->c, U+10d->c, U+10e->d, U+10f->d, U+116->U+117, U+117, U+118->U+119, U+11a->e, U+11b->e, U+12E->U+12F, U+12F, U+139->l, U+13a->l, U+13d->l, U+13e->l, U+141->U+142, U+142, U+143->U+144, U+144,U+147->n, U+148->n, U+154->r, U+155->r, U+158->r, U+159->r, U+15A->U+15B, U+15B, U+160->s, U+160->U+161, U+161->s, U+164->t, U+165->t, U+16A->U+16B, U+16B, U+16e->u, U+16f->u, U+172->U+173, U+173, U+179->U+17A, U+17A, U+17B->U+17C, U+17C, U+17d->z, U+17e->z,
|
77
|
+
}
|
@@ -0,0 +1,62 @@
|
|
1
|
+
|
2
|
+
# Auto-generated at Tue Jan 15 21:29:08 -0500 2008.
|
3
|
+
# Hand modifications will be overwritten.
|
4
|
+
# /Users/nichoj/Projects/ambitious_sphinx/config/ultrasphinx/default.base
|
5
|
+
indexer {
|
6
|
+
mem_limit = 256M
|
7
|
+
}
|
8
|
+
searchd {
|
9
|
+
read_timeout = 5
|
10
|
+
max_children = 300
|
11
|
+
log = /tmp/sphinx/log/searchd.log
|
12
|
+
port = 3312
|
13
|
+
max_matches = 100000
|
14
|
+
query_log = /tmp/sphinx/log/query.log
|
15
|
+
seamless_rotate = 1
|
16
|
+
pid_file = /tmp/sphinx/log/searchd.pid
|
17
|
+
address = 0.0.0.0
|
18
|
+
}
|
19
|
+
|
20
|
+
# Source configuration
|
21
|
+
|
22
|
+
source tweets
|
23
|
+
{
|
24
|
+
strip_html = 0
|
25
|
+
sql_range_step = 5000
|
26
|
+
index_html_attrs =
|
27
|
+
sql_query_post =
|
28
|
+
|
29
|
+
type = mysql
|
30
|
+
sql_query_pre = SET SESSION group_concat_max_len = 65535
|
31
|
+
sql_query_pre = SET NAMES utf8
|
32
|
+
|
33
|
+
sql_db = ambitious_sphinx_development
|
34
|
+
sql_host = localhost
|
35
|
+
sql_pass =
|
36
|
+
sql_sock = /tmp/mysql.sock
|
37
|
+
sql_user = root
|
38
|
+
sql_query_range = SELECT MIN(id) , MAX(id) FROM tweets
|
39
|
+
sql_query = SELECT (tweets.id * 1 + 0) AS id, tweets.body AS body, 'Tweet' AS class, 0 AS class_id, UNIX_TIMESTAMP(tweets.created_at) AS created_at, tweets.user_name AS user_name FROM tweets WHERE tweets.id >= $start AND tweets.id <= $end GROUP BY tweets.id
|
40
|
+
|
41
|
+
sql_group_column = class_id
|
42
|
+
sql_date_column = created_at
|
43
|
+
sql_query_info = SELECT * FROM tweets WHERE tweets.id = (($id - 0) / 1)
|
44
|
+
}
|
45
|
+
|
46
|
+
|
47
|
+
# Index configuration
|
48
|
+
|
49
|
+
index complete
|
50
|
+
{
|
51
|
+
source = tweets
|
52
|
+
charset_type = utf-8
|
53
|
+
charset_table = 0..9, A..Z->a..z, -, _, ., &, a..z, U+410..U+42F->U+430..U+44F, U+430..U+44F,U+C5->U+E5, U+E5, U+C4->U+E4, U+E4, U+D6->U+F6, U+F6, U+16B, U+0c1->a, U+0c4->a, U+0c9->e, U+0cd->i, U+0d3->o, U+0d4->o, U+0da->u, U+0dd->y, U+0e1->a, U+0e4->a, U+0e9->e, U+0ed->i, U+0f3->o, U+0f4->o, U+0fa->u, U+0fd->y, U+104->U+105, U+105, U+106->U+107, U+10c->c, U+10d->c, U+10e->d, U+10f->d, U+116->U+117, U+117, U+118->U+119, U+11a->e, U+11b->e, U+12E->U+12F, U+12F, U+139->l, U+13a->l, U+13d->l, U+13e->l, U+141->U+142, U+142, U+143->U+144, U+144,U+147->n, U+148->n, U+154->r, U+155->r, U+158->r, U+159->r, U+15A->U+15B, U+15B, U+160->s, U+160->U+161, U+161->s, U+164->t, U+165->t, U+16A->U+16B, U+16B, U+16e->u, U+16f->u, U+172->U+173, U+173, U+179->U+17A, U+17A, U+17B->U+17C, U+17C, U+17d->z, U+17e->z,
|
54
|
+
min_word_len = 1
|
55
|
+
# enable_star = 1
|
56
|
+
stopwords =
|
57
|
+
path = db/sphinx//sphinx_index_complete
|
58
|
+
docinfo = extern
|
59
|
+
morphology = stem_en
|
60
|
+
# min_infix_len = 1
|
61
|
+
}
|
62
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'ambition'
|
2
|
+
|
3
|
+
# stub out rails stuff enough so that ultrasphinx will be happy
|
4
|
+
RAILS_ROOT = './' unless defined? RAILS_ROOT
|
5
|
+
RAILS_ENV = 'development' unless defined? RAILS_ENV
|
6
|
+
|
7
|
+
require 'active_record'
|
8
|
+
require 'ultrasphinx'
|
9
|
+
|
10
|
+
%w(base page query select sort slice).each do |f|
|
11
|
+
require "ambition/adapters/ambitious_sphinx/#{f}"
|
12
|
+
end
|
13
|
+
|
14
|
+
ActiveRecord::Base.extend Ambition::API
|
15
|
+
ActiveRecord::Base.ambition_adapter = Ambition::Adapters::AmbitiousSphinx
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Ambition # :nodoc:
|
2
|
+
module Adapters # :nodoc:
|
3
|
+
module AmbitiousSphinx # :nodoc:
|
4
|
+
# Helper for the other
|
5
|
+
class Base
|
6
|
+
# Does the string have an Ultrasphinx field?
|
7
|
+
def has_field? str
|
8
|
+
str =~ /:/
|
9
|
+
end
|
10
|
+
|
11
|
+
# Does the string have any Ultrasphinx operators?
|
12
|
+
def has_operator? str
|
13
|
+
str =~ /(AND|OR|NOT)/
|
14
|
+
end
|
15
|
+
|
16
|
+
# Should this string be quotified? It needs to happen if the string doesn't
|
17
|
+
# have an operator or a field.
|
18
|
+
def needs_quoting? str
|
19
|
+
not (has_operator?(str) or has_field?(str))
|
20
|
+
end
|
21
|
+
|
22
|
+
# Quote the string if it needs it.
|
23
|
+
def quotify str
|
24
|
+
if needs_quoting?(str)
|
25
|
+
%Q("#{str}")
|
26
|
+
else
|
27
|
+
str
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Ambition
|
2
|
+
module Adapters
|
3
|
+
module AmbitiousSphinx
|
4
|
+
# Responsible for taking the clauses that Ambition has generated, and ultimately doing a
|
5
|
+
# Ultrasphinx::Search based on them
|
6
|
+
class Query < Base
|
7
|
+
def kick
|
8
|
+
Ultrasphinx::Search.new(to_hash).results
|
9
|
+
end
|
10
|
+
|
11
|
+
# Some magic to add pagination. This gets called if you were to do:
|
12
|
+
#
|
13
|
+
# Meal.select {'bacon'}.page(5)
|
14
|
+
#
|
15
|
+
# When +page+ is invoked, it's actually being invoked on +Ambition::Context+.
|
16
|
+
# It has +method_missing+? voodoo which will try to pass the method onto
|
17
|
+
# the +Query+. That's this class.
|
18
|
+
def page(number)
|
19
|
+
stash[:page] = number
|
20
|
+
context
|
21
|
+
end
|
22
|
+
|
23
|
+
# Not entirely sure when this is used, so unimplemented so far.
|
24
|
+
def size
|
25
|
+
raise "Not implemented yet."
|
26
|
+
end
|
27
|
+
|
28
|
+
# Builds a hash of options for Ultrasphinx::Search based on the clauses Ambition has generated.
|
29
|
+
def to_hash
|
30
|
+
hash = {}
|
31
|
+
|
32
|
+
unless (query = clauses[:select]).blank?
|
33
|
+
query_s = query.join(' ').squeeze(' ').strip
|
34
|
+
hash[:query] = quotify(query_s)
|
35
|
+
end
|
36
|
+
|
37
|
+
unless (page = stash[:page]).blank?
|
38
|
+
hash[:page] = page
|
39
|
+
end
|
40
|
+
|
41
|
+
hash
|
42
|
+
end
|
43
|
+
|
44
|
+
# Prints out the query that would be executed.
|
45
|
+
def to_s
|
46
|
+
hash = to_hash
|
47
|
+
hash[:query]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module Ambition
|
2
|
+
module Adapters
|
3
|
+
module AmbitiousSphinx
|
4
|
+
# Select is responsible for taking pure Ruby, and mangling it until it resembles
|
5
|
+
# the syntax that Ultrasphinx[http://blog.evanweaver.com/files/doc/fauna/ultrasphinx/files/README.html] uses.
|
6
|
+
class Select < Base
|
7
|
+
# Handles method calls, like
|
8
|
+
#
|
9
|
+
# u.name
|
10
|
+
def call(method)
|
11
|
+
"#{method.to_s}:"
|
12
|
+
end
|
13
|
+
|
14
|
+
# Should we be supporting chained calls like:
|
15
|
+
#
|
16
|
+
# u.name.downcase
|
17
|
+
#
|
18
|
+
# ?
|
19
|
+
#
|
20
|
+
# I don't think Sphinx would be able to handle this.
|
21
|
+
def chained_call(*methods)
|
22
|
+
raise "Not implemented yet."
|
23
|
+
end
|
24
|
+
|
25
|
+
# Handles generating an Ultrasphinx query for code like:
|
26
|
+
#
|
27
|
+
# 'foo' && 'bar'
|
28
|
+
def both(left, right)
|
29
|
+
"#{quotify left} AND #{quotify right}"
|
30
|
+
end
|
31
|
+
|
32
|
+
# Handles generating an Ultrasphinx query for code like:
|
33
|
+
#
|
34
|
+
# 'foo' || 'bar'
|
35
|
+
def either(left, right)
|
36
|
+
"#{quotify left} OR #{quotify right}"
|
37
|
+
end
|
38
|
+
|
39
|
+
# Sphinx doesn't support equality.
|
40
|
+
def ==(left, right)
|
41
|
+
raise "Not applicable to sphinx."
|
42
|
+
end
|
43
|
+
|
44
|
+
# Sphinx doesn't support inequality.
|
45
|
+
def not_equal(left, right)
|
46
|
+
raise "Not applicable to sphinx."
|
47
|
+
end
|
48
|
+
|
49
|
+
# Handles generating an Ultrasphinx query for code like:
|
50
|
+
#
|
51
|
+
# u.name =~ 'bob'
|
52
|
+
#
|
53
|
+
# Some cavaets:
|
54
|
+
# * left hand side _must_ be a field, like u.name
|
55
|
+
# * right hand side _must not_ be a regular expression. Pattern matching is generally not
|
56
|
+
# supported by full text search engines
|
57
|
+
def =~(left, right)
|
58
|
+
raise if right.is_a? Regexp
|
59
|
+
"#{left}#{quotify right}"
|
60
|
+
end
|
61
|
+
|
62
|
+
# Handles generating an Ultrasphinx query for code like:
|
63
|
+
#
|
64
|
+
# u.name !~ 'bob'
|
65
|
+
#
|
66
|
+
# Some cavaets:
|
67
|
+
# * left hand side _must_ be a field, like u.name
|
68
|
+
# * right hand side _must not_ be a regular expression. Pattern matching is generally not
|
69
|
+
# supported by full text search engines
|
70
|
+
def not_regexp(left, right)
|
71
|
+
# could be DRYer, but this is more readable than: "NOT #{self.=~(left,right)}"
|
72
|
+
raise if right.is_a? Regexp
|
73
|
+
"NOT #{left}#{quotify right}"
|
74
|
+
end
|
75
|
+
|
76
|
+
# Not supported by Sphinx. If you need this kind of comparison, you probably should be
|
77
|
+
# using ambitious-activerecord.
|
78
|
+
def <(left, right)
|
79
|
+
raise "Not applicable to sphinx."
|
80
|
+
end
|
81
|
+
|
82
|
+
# Not supported by Sphinx. If you need this kind of comparison, you probably should be
|
83
|
+
# using ambitious-activerecord.
|
84
|
+
def >(left, right)
|
85
|
+
raise "Not applicable to sphinx."
|
86
|
+
end
|
87
|
+
|
88
|
+
# Not supported by Sphinx. If you need this kind of comparison, you probably should be
|
89
|
+
# using ambitious-activerecord.
|
90
|
+
def >=(left, right)
|
91
|
+
raise "Not applicable to sphinx."
|
92
|
+
end
|
93
|
+
|
94
|
+
# Not supported by Sphinx. If you need this kind of comparison, you probably should be
|
95
|
+
# using ambitious-activerecord.
|
96
|
+
def <=(left, right)
|
97
|
+
raise "Not applicable to sphinx."
|
98
|
+
end
|
99
|
+
|
100
|
+
# Not supported by Sphinx. If you need this kind of comparison, you probably should be
|
101
|
+
# using ambitious-activerecord.
|
102
|
+
def include?(left, right)
|
103
|
+
raise "Not applicable to sphinx."
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Ambition
|
2
|
+
module Adapters
|
3
|
+
module AmbitiousSphinx
|
4
|
+
# Slice would normally handle slicing, but we don't support it yet.
|
5
|
+
class Slice < Base
|
6
|
+
# Not implemented
|
7
|
+
def slice(start, length)
|
8
|
+
raise "Not implemented."
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Ambition
|
2
|
+
module Adapters
|
3
|
+
module AmbitiousSphinx
|
4
|
+
# +Sort+ would normally handle sorting, but we don't support it yet.
|
5
|
+
class Sort < Base
|
6
|
+
# Not implemented
|
7
|
+
def sort_by(method)
|
8
|
+
raise "Not implemented."
|
9
|
+
end
|
10
|
+
|
11
|
+
# Not implemented
|
12
|
+
def reverse_sort_by(method)
|
13
|
+
raise "Not implemented."
|
14
|
+
end
|
15
|
+
|
16
|
+
# Not implemented
|
17
|
+
def chained_sort_by(receiver, method)
|
18
|
+
raise "Not implemented."
|
19
|
+
end
|
20
|
+
|
21
|
+
# Not implemented
|
22
|
+
def chained_reverse_sort_by(receiver, method)
|
23
|
+
raise "Not implemented."
|
24
|
+
end
|
25
|
+
|
26
|
+
# Not implemented
|
27
|
+
def to_proc(symbol)
|
28
|
+
raise "Not implemented."
|
29
|
+
end
|
30
|
+
|
31
|
+
# Not implemented
|
32
|
+
def rand
|
33
|
+
raise "Not implemented."
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/test/helper.rb
ADDED
data/test/select_test.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/helper'
|
2
|
+
|
3
|
+
context 'AmbitiousSphinx Adapter :: Select' do
|
4
|
+
|
5
|
+
specify 'Ruby attributes become Sphinx fields prefixed with @' do
|
6
|
+
query = User.select {|m| m.name}.to_hash[:query]
|
7
|
+
query.should == "name:"
|
8
|
+
end
|
9
|
+
|
10
|
+
specify 'Ruby string becomes Sphinx string' do
|
11
|
+
query = User.select {'jon'}.to_hash[:query]
|
12
|
+
query.should == %Q("jon")
|
13
|
+
end
|
14
|
+
|
15
|
+
specify 'Ruby string becomes Sphinx phrase search' do
|
16
|
+
query = User.select {'jon doe'}.to_hash[:query]
|
17
|
+
query.should == "\"jon doe\""
|
18
|
+
end
|
19
|
+
|
20
|
+
specify 'Ruby == should not be supported' do
|
21
|
+
should.raise do User.select {|m| m.name == 'jon'} end
|
22
|
+
end
|
23
|
+
|
24
|
+
specify 'Ruby != becomes Sphinx NOT operator' do
|
25
|
+
should.raise do User.select {|m| m.name != 'jon'} end
|
26
|
+
end
|
27
|
+
|
28
|
+
specify 'Ruby && becomes Sphinx AND operator' do
|
29
|
+
query = User.select {'jon' && 'blarg'}.to_hash[:query]
|
30
|
+
query.should == %Q("jon" AND "blarg")
|
31
|
+
end
|
32
|
+
|
33
|
+
specify 'Ruby || becomes Sphinx OR operator' do
|
34
|
+
query = User.select { 'jon' || 'chris'}.to_hash[:query]
|
35
|
+
query.should == %Q("jon" OR "chris")
|
36
|
+
end
|
37
|
+
|
38
|
+
specify 'Ruby =~ with string' do
|
39
|
+
query = User.select {|m| m.name =~ 'chris'}.to_hash[:query]
|
40
|
+
query.should == %Q(name:"chris")
|
41
|
+
end
|
42
|
+
|
43
|
+
specify 'Ruby =~ with string' do
|
44
|
+
query = User.select {|m| m.name =~ 'chris' && m.name =~ 'jon'}.to_hash[:query]
|
45
|
+
query.should == %Q(name:"chris" AND name:"jon")
|
46
|
+
end
|
47
|
+
|
48
|
+
specify 'Ruby =~ with Regexp' do
|
49
|
+
should.raise do User.select {|m| m.name =~ /chris/} end
|
50
|
+
end
|
51
|
+
|
52
|
+
specify 'Ruby !~ with string' do
|
53
|
+
query = User.select {|m| m.name =~ 'chris' && m.name !~ 'jon'}.to_hash[:query]
|
54
|
+
query.should == %Q(name:"chris" AND NOT name:"jon")
|
55
|
+
end
|
56
|
+
|
57
|
+
specify 'Ruby !~ with Regexp is not supported' do
|
58
|
+
should.raise do User.select {|m| m.name !~ /chris/} end
|
59
|
+
end
|
60
|
+
|
61
|
+
specify 'Ruby > should not be supported' do
|
62
|
+
should.raise do User.select {|m| m.age > 21} end
|
63
|
+
end
|
64
|
+
|
65
|
+
specify 'Ruby >= should not be supported' do
|
66
|
+
should.raise do User.select {|m| m.age >= 21} end
|
67
|
+
end
|
68
|
+
|
69
|
+
specify 'Ruby < should not be supported' do
|
70
|
+
should.raise do User.select {|m| m.age < 21} end
|
71
|
+
end
|
72
|
+
|
73
|
+
specify 'Ruby <= should not be supported' do
|
74
|
+
should.raise do User.select {|m| m.age <= 21} end
|
75
|
+
end
|
76
|
+
|
77
|
+
xspecify 'inspect' do
|
78
|
+
User.select { |u| u.name }.inspect.should.match %r(call #to_s or #to_hash)
|
79
|
+
end
|
80
|
+
end
|
data/test/slice_test.rb
ADDED
data/test/sort_test.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/helper'
|
2
|
+
|
3
|
+
context "AmbitiousSphinx Adapter :: Sort" do
|
4
|
+
setup do
|
5
|
+
@klass = User
|
6
|
+
@block = @klass.select { |m| m.name =~ 'jon' }
|
7
|
+
end
|
8
|
+
|
9
|
+
specify "order" do
|
10
|
+
should.raise do
|
11
|
+
@block.sort_by {|m| m.name}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
specify "reverse order with -" do
|
16
|
+
should.raise do
|
17
|
+
@block.sort_by { |m| -m.age }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
specify "random order" do
|
22
|
+
should.raise do
|
23
|
+
@block.sort_by { rand }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ambitious-sphinx
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Josh Nichols
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-02-29 00:00:00 -05:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: ultrasphinx
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: "1.7"
|
23
|
+
version:
|
24
|
+
- !ruby/object:Gem::Dependency
|
25
|
+
name: ambition
|
26
|
+
version_requirement:
|
27
|
+
version_requirements: !ruby/object:Gem::Requirement
|
28
|
+
requirements:
|
29
|
+
- - ">="
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
version: 0.5.0
|
32
|
+
version:
|
33
|
+
description: An ambitious adapter for sphinx
|
34
|
+
email: josh@technicalpickles.com
|
35
|
+
executables: []
|
36
|
+
|
37
|
+
extensions: []
|
38
|
+
|
39
|
+
extra_rdoc_files: []
|
40
|
+
|
41
|
+
files:
|
42
|
+
- ambitious-sphinx.gemspec
|
43
|
+
- config/ultrasphinx/default.base
|
44
|
+
- config/ultrasphinx/development.conf
|
45
|
+
- lib/ambition/adapters/ambitious_sphinx/base.rb
|
46
|
+
- lib/ambition/adapters/ambitious_sphinx/query.rb
|
47
|
+
- lib/ambition/adapters/ambitious_sphinx/select.rb
|
48
|
+
- lib/ambition/adapters/ambitious_sphinx/slice.rb
|
49
|
+
- lib/ambition/adapters/ambitious_sphinx/sort.rb
|
50
|
+
- lib/ambition/adapters/ambitious_sphinx.rb
|
51
|
+
- LICENSE
|
52
|
+
- Manifest
|
53
|
+
- README
|
54
|
+
- test/helper.rb
|
55
|
+
- test/select_test.rb
|
56
|
+
- test/slice_test.rb
|
57
|
+
- test/sort_test.rb
|
58
|
+
has_rdoc: true
|
59
|
+
homepage: http://ambitioussphinx.rubyforge.org/
|
60
|
+
post_install_message:
|
61
|
+
rdoc_options: []
|
62
|
+
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: "0"
|
70
|
+
version:
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: "0"
|
76
|
+
version:
|
77
|
+
requirements: []
|
78
|
+
|
79
|
+
rubyforge_project: ambitioussphinx
|
80
|
+
rubygems_version: 1.0.0
|
81
|
+
signing_key:
|
82
|
+
specification_version: 2
|
83
|
+
summary: An ambitious adapter for sphinx
|
84
|
+
test_files:
|
85
|
+
- test/select_test.rb
|
86
|
+
- test/slice_test.rb
|
87
|
+
- test/sort_test.rb
|