xapit 0.1.0
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/LICENSE +20 -0
- data/Manifest +178 -0
- data/README.rdoc +183 -0
- data/Rakefile +15 -0
- data/TODO +23 -0
- data/features/facets.feature +51 -0
- data/features/finding.feature +119 -0
- data/features/indexing.feature +41 -0
- data/features/step_definitions/common_steps.rb +7 -0
- data/features/step_definitions/xapit_steps.rb +117 -0
- data/features/support/env.rb +7 -0
- data/features/support/xapit_helpers.rb +27 -0
- data/init.rb +3 -0
- data/install.rb +9 -0
- data/lib/xapit.rb +39 -0
- data/lib/xapit/collection.rb +165 -0
- data/lib/xapit/config.rb +83 -0
- data/lib/xapit/facet.rb +59 -0
- data/lib/xapit/facet_blueprint.rb +59 -0
- data/lib/xapit/facet_option.rb +56 -0
- data/lib/xapit/index_blueprint.rb +117 -0
- data/lib/xapit/indexers/abstract_indexer.rb +101 -0
- data/lib/xapit/indexers/classic_indexer.rb +27 -0
- data/lib/xapit/indexers/simple_indexer.rb +31 -0
- data/lib/xapit/membership.rb +103 -0
- data/lib/xapit/query.rb +62 -0
- data/lib/xapit/query_parsers/abstract_query_parser.rb +115 -0
- data/lib/xapit/query_parsers/classic_query_parser.rb +19 -0
- data/lib/xapit/query_parsers/simple_query_parser.rb +75 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/tmp/xapdb/flintlock +0 -0
- data/spec/tmp/xapdb/iamflint +0 -0
- data/spec/tmp/xapdb/postlist.DB +0 -0
- data/spec/tmp/xapdb/postlist.baseA +0 -0
- data/spec/tmp/xapdb/postlist.baseB +0 -0
- data/spec/tmp/xapdb/record.DB +0 -0
- data/spec/tmp/xapdb/record.baseA +0 -0
- data/spec/tmp/xapdb/record.baseB +0 -0
- data/spec/tmp/xapdb/spelling.DB +0 -0
- data/spec/tmp/xapdb/spelling.baseA +0 -0
- data/spec/tmp/xapdb/spelling.baseB +0 -0
- data/spec/tmp/xapdb/termlist.DB +0 -0
- data/spec/tmp/xapdb/termlist.baseA +0 -0
- data/spec/tmp/xapdb/termlist.baseB +0 -0
- data/spec/tmp/xapian_db/flintlock +0 -0
- data/spec/tmp/xapian_db/iamflint +0 -0
- data/spec/tmp/xapian_db/postlist.DB +0 -0
- data/spec/tmp/xapian_db/postlist.baseA +0 -0
- data/spec/tmp/xapian_db/record.DB +0 -0
- data/spec/tmp/xapian_db/record.baseA +0 -0
- data/spec/tmp/xapian_db/termlist.DB +0 -0
- data/spec/tmp/xapian_db/termlist.baseA +0 -0
- data/spec/tmp/xapiandab/flintlock +0 -0
- data/spec/tmp/xapiandab/iamflint +0 -0
- data/spec/tmp/xapiandab/postlist.DB +0 -0
- data/spec/tmp/xapiandab/postlist.baseA +0 -0
- data/spec/tmp/xapiandab/postlist.baseB +0 -0
- data/spec/tmp/xapiandab/record.DB +0 -0
- data/spec/tmp/xapiandab/record.baseA +0 -0
- data/spec/tmp/xapiandab/record.baseB +0 -0
- data/spec/tmp/xapiandab/spelling.DB +0 -0
- data/spec/tmp/xapiandab/spelling.baseA +0 -0
- data/spec/tmp/xapiandab/spelling.baseB +0 -0
- data/spec/tmp/xapiandab/termlist.DB +0 -0
- data/spec/tmp/xapiandab/termlist.baseA +0 -0
- data/spec/tmp/xapiandab/termlist.baseB +0 -0
- data/spec/tmp/xapiandatab/flintlock +0 -0
- data/spec/tmp/xapiandatab/iamflint +0 -0
- data/spec/tmp/xapiandatab/postlist.DB +0 -0
- data/spec/tmp/xapiandatab/postlist.baseA +0 -0
- data/spec/tmp/xapiandatab/postlist.baseB +0 -0
- data/spec/tmp/xapiandatab/record.DB +0 -0
- data/spec/tmp/xapiandatab/record.baseA +0 -0
- data/spec/tmp/xapiandatab/record.baseB +0 -0
- data/spec/tmp/xapiandatab/spelling.DB +0 -0
- data/spec/tmp/xapiandatab/spelling.baseA +0 -0
- data/spec/tmp/xapiandatab/spelling.baseB +0 -0
- data/spec/tmp/xapiandatab/termlist.DB +0 -0
- data/spec/tmp/xapiandatab/termlist.baseA +0 -0
- data/spec/tmp/xapiandatab/termlist.baseB +0 -0
- data/spec/tmp/xapiandataba/flintlock +0 -0
- data/spec/tmp/xapiandataba/iamflint +0 -0
- data/spec/tmp/xapiandataba/postlist.DB +0 -0
- data/spec/tmp/xapiandataba/postlist.baseA +0 -0
- data/spec/tmp/xapiandataba/postlist.baseB +0 -0
- data/spec/tmp/xapiandataba/record.DB +0 -0
- data/spec/tmp/xapiandataba/record.baseA +0 -0
- data/spec/tmp/xapiandataba/record.baseB +0 -0
- data/spec/tmp/xapiandataba/spelling.DB +0 -0
- data/spec/tmp/xapiandataba/spelling.baseA +0 -0
- data/spec/tmp/xapiandataba/spelling.baseB +0 -0
- data/spec/tmp/xapiandataba/termlist.DB +0 -0
- data/spec/tmp/xapiandataba/termlist.baseA +0 -0
- data/spec/tmp/xapiandataba/termlist.baseB +0 -0
- data/spec/tmp/xapiandatabas/flintlock +0 -0
- data/spec/tmp/xapiandatabas/iamflint +0 -0
- data/spec/tmp/xapiandatabas/postlist.DB +0 -0
- data/spec/tmp/xapiandatabas/postlist.baseA +0 -0
- data/spec/tmp/xapiandatabas/record.DB +0 -0
- data/spec/tmp/xapiandatabas/record.baseA +0 -0
- data/spec/tmp/xapiandatabas/termlist.DB +0 -0
- data/spec/tmp/xapiandatabas/termlist.baseA +0 -0
- data/spec/tmp/xapiandatb/flintlock +0 -0
- data/spec/tmp/xapiandatb/iamflint +0 -0
- data/spec/tmp/xapiandatb/postlist.DB +0 -0
- data/spec/tmp/xapiandatb/postlist.baseA +0 -0
- data/spec/tmp/xapiandatb/postlist.baseB +0 -0
- data/spec/tmp/xapiandatb/record.DB +0 -0
- data/spec/tmp/xapiandatb/record.baseA +0 -0
- data/spec/tmp/xapiandatb/record.baseB +0 -0
- data/spec/tmp/xapiandatb/spelling.DB +0 -0
- data/spec/tmp/xapiandatb/spelling.baseA +0 -0
- data/spec/tmp/xapiandatb/spelling.baseB +0 -0
- data/spec/tmp/xapiandatb/termlist.DB +0 -0
- data/spec/tmp/xapiandatb/termlist.baseA +0 -0
- data/spec/tmp/xapiandatb/termlist.baseB +0 -0
- data/spec/tmp/xapiandbase/flintlock +0 -0
- data/spec/tmp/xapiandbase/iamflint +0 -0
- data/spec/tmp/xapiandbase/postlist.DB +0 -0
- data/spec/tmp/xapiandbase/postlist.baseA +0 -0
- data/spec/tmp/xapiandbase/postlist.baseB +0 -0
- data/spec/tmp/xapiandbase/record.DB +0 -0
- data/spec/tmp/xapiandbase/record.baseA +0 -0
- data/spec/tmp/xapiandbase/record.baseB +0 -0
- data/spec/tmp/xapiandbase/spelling.DB +0 -0
- data/spec/tmp/xapiandbase/spelling.baseA +0 -0
- data/spec/tmp/xapiandbase/spelling.baseB +0 -0
- data/spec/tmp/xapiandbase/termlist.DB +0 -0
- data/spec/tmp/xapiandbase/termlist.baseA +0 -0
- data/spec/tmp/xapiandbase/termlist.baseB +0 -0
- data/spec/xapit/collection_spec.rb +153 -0
- data/spec/xapit/config_spec.rb +48 -0
- data/spec/xapit/facet_blueprint_spec.rb +29 -0
- data/spec/xapit/facet_option_spec.rb +80 -0
- data/spec/xapit/facet_spec.rb +73 -0
- data/spec/xapit/index_blueprint_spec.rb +60 -0
- data/spec/xapit/indexers/abstract_indexer_spec.rb +74 -0
- data/spec/xapit/indexers/classic_indexer_spec.rb +26 -0
- data/spec/xapit/indexers/simple_indexer_spec.rb +53 -0
- data/spec/xapit/membership_spec.rb +39 -0
- data/spec/xapit/query_parsers/abstract_query_parser_spec.rb +23 -0
- data/spec/xapit/query_parsers/classic_query_parser_spec.rb +15 -0
- data/spec/xapit/query_parsers/simple_query_parser_spec.rb +86 -0
- data/spec/xapit/query_spec.rb +41 -0
- data/spec/xapit_member.rb +32 -0
- data/tasks/spec.rb +9 -0
- data/tasks/xapit.rake +9 -0
- data/tmp/xapiandatabase/flintlock +0 -0
- data/tmp/xapiandatabase/iamflint +0 -0
- data/tmp/xapiandatabase/postlist.DB +0 -0
- data/tmp/xapiandatabase/postlist.baseA +0 -0
- data/tmp/xapiandatabase/postlist.baseB +0 -0
- data/tmp/xapiandatabase/record.DB +0 -0
- data/tmp/xapiandatabase/record.baseA +0 -0
- data/tmp/xapiandatabase/record.baseB +0 -0
- data/tmp/xapiandatabase/spelling.DB +0 -0
- data/tmp/xapiandatabase/spelling.baseA +0 -0
- data/tmp/xapiandatabase/spelling.baseB +0 -0
- data/tmp/xapiandatabase/termlist.DB +0 -0
- data/tmp/xapiandatabase/termlist.baseA +0 -0
- data/tmp/xapiandatabase/termlist.baseB +0 -0
- data/tmp/xapiandatabase/value.baseB +0 -0
- data/tmp/xapiandb/flintlock +0 -0
- data/tmp/xapiandb/iamflint +0 -0
- data/tmp/xapiandb/postlist.DB +0 -0
- data/tmp/xapiandb/postlist.baseA +0 -0
- data/tmp/xapiandb/postlist.baseB +0 -0
- data/tmp/xapiandb/record.DB +0 -0
- data/tmp/xapiandb/record.baseA +0 -0
- data/tmp/xapiandb/record.baseB +0 -0
- data/tmp/xapiandb/spelling.DB +0 -0
- data/tmp/xapiandb/spelling.baseA +0 -0
- data/tmp/xapiandb/spelling.baseB +0 -0
- data/tmp/xapiandb/termlist.DB +0 -0
- data/tmp/xapiandb/termlist.baseA +0 -0
- data/tmp/xapiandb/termlist.baseB +0 -0
- data/tmp/xapiandb/value.baseB +0 -0
- data/uninstall.rb +5 -0
- data/xapit.gemspec +30 -0
- metadata +257 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
|
2
|
+
|
|
3
|
+
describe Xapit::Facet do
|
|
4
|
+
describe "with database" do
|
|
5
|
+
before(:each) do
|
|
6
|
+
XapitMember.xapit do |index|
|
|
7
|
+
index.facet :visible
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe "indexed" do
|
|
12
|
+
before(:each) do
|
|
13
|
+
@visible1 = XapitMember.new(:visible => true)
|
|
14
|
+
@visible2 = XapitMember.new(:visible => true)
|
|
15
|
+
@invisible = XapitMember.new(:visible => false)
|
|
16
|
+
Xapit.index_all
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
describe "facet from empty search" do
|
|
20
|
+
before(:each) do
|
|
21
|
+
@facet = XapitMember.search("").facets.first
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "should have the name of 'Visible'" do
|
|
25
|
+
@facet.name.should == 'Visible'
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "should have true and false options" do
|
|
29
|
+
@facet.options.map(&:name).sort.should == %w[false true]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "should have record count" do
|
|
33
|
+
@facet.options.detect { |o| o.name == 'true' }.count.should == 2
|
|
34
|
+
@facet.options.detect { |o| o.name == 'false' }.count.should == 1
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "should have identifier for options" do
|
|
38
|
+
blueprint = Xapit::FacetBlueprint.new(XapitMember, 0, :visible)
|
|
39
|
+
@facet.options.detect { |o| o.name == 'true' }.identifier.should == blueprint.identifiers_for(@visible1).first
|
|
40
|
+
@facet.options.detect { |o| o.name == 'false' }.identifier.should == blueprint.identifiers_for(@invisible).first
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "should have matching identifiers" do
|
|
44
|
+
blueprint = Xapit::FacetBlueprint.new(XapitMember, 0, :visible)
|
|
45
|
+
hash = { blueprint.identifiers_for(@visible1).first => 2, blueprint.identifiers_for(@invisible).first => 1 }
|
|
46
|
+
@facet.matching_identifiers.should == hash
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "should not include matching identifiers that are current" do
|
|
50
|
+
blueprint = Xapit::FacetBlueprint.new(XapitMember, 0, :visible)
|
|
51
|
+
@facet.existing_facet_identifiers = blueprint.identifiers_for(@visible1)
|
|
52
|
+
@facet.matching_identifiers.should == { blueprint.identifiers_for(@invisible).first => 1 }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "should return identifier on to_param" do
|
|
56
|
+
blueprint = Xapit::FacetBlueprint.new(XapitMember, 0, :visible)
|
|
57
|
+
@facet.options.detect { |o| o.name == 'true' }.to_param.should == blueprint.identifiers_for(@visible1).first
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it "should sort options in alphabetical order" do
|
|
61
|
+
@facet.options.first.name.should == 'false'
|
|
62
|
+
@facet.options.last.name.should == 'true'
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it "should not list facets if only one option is found" do
|
|
67
|
+
blueprint = Xapit::FacetBlueprint.new(XapitMember, 0, :visible)
|
|
68
|
+
facets = XapitMember.search("", :facets => blueprint.identifiers_for(@visible1)).facets
|
|
69
|
+
facets.should be_empty
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
|
2
|
+
|
|
3
|
+
describe Xapit::IndexBlueprint do
|
|
4
|
+
before(:each) do
|
|
5
|
+
@index = Xapit::IndexBlueprint.new(XapitMember)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
it "should remember text attributes" do
|
|
9
|
+
@index.text(:foo)
|
|
10
|
+
@index.text(:bar, :blah)
|
|
11
|
+
@index.text(:custom) { |t| t*t }
|
|
12
|
+
@index.text_attributes.keys.should include(:foo, :bar, :blah, :custom)
|
|
13
|
+
@index.text_attributes[:foo][:proc].should be_nil
|
|
14
|
+
@index.text_attributes[:custom][:proc].should be_kind_of(Proc)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "should remember field attributes" do
|
|
18
|
+
@index.field(:foo)
|
|
19
|
+
@index.field(:bar, :blah)
|
|
20
|
+
@index.field_attributes.should include(:foo, :bar, :blah)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "should remember facets" do
|
|
24
|
+
@index.facet(:foo)
|
|
25
|
+
@index.facet(:bar, "Baz")
|
|
26
|
+
@index.facets.map(&:name).should == ["Foo", "Baz"]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "should remember sortable attributes" do
|
|
30
|
+
@index.sortable(:foo)
|
|
31
|
+
@index.sortable(:bar, :blah)
|
|
32
|
+
@index.sortable_attributes.should include(:foo, :bar, :blah)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it "should have a sortable position offset by facets" do
|
|
36
|
+
@index.facet(:foo)
|
|
37
|
+
@index.facet(:test)
|
|
38
|
+
@index.sortable(:bar, :blah)
|
|
39
|
+
@index.sortable_position_for(:blah).should == 3
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "should index member document into database" do
|
|
43
|
+
XapitMember.new
|
|
44
|
+
@index.index_all
|
|
45
|
+
Xapit::Config.writable_database.doccount.should >= 1
|
|
46
|
+
Xapit::Config.writable_database.flush
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "should remember all blueprints and index each of them" do
|
|
50
|
+
stub(Xapit::Config.writable_database).add_document
|
|
51
|
+
mock(@index).index_all
|
|
52
|
+
Xapit::IndexBlueprint.index_all
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "should pass in extra arguments to each method" do
|
|
56
|
+
index = Xapit::IndexBlueprint.new(Object, :foo, :bar => :blah)
|
|
57
|
+
mock(Object).find_each(:foo, :bar => :blah)
|
|
58
|
+
index.index_all
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
|
2
|
+
|
|
3
|
+
describe Xapit::AbstractIndexer do
|
|
4
|
+
before(:each) do
|
|
5
|
+
XapitMember.xapit { } # to ensure methods are included
|
|
6
|
+
@index = Xapit::IndexBlueprint.new(XapitMember)
|
|
7
|
+
@indexer = Xapit::SimpleIndexer.new(@index)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "should map field to term with 'X' prefix" do
|
|
11
|
+
member = Object.new
|
|
12
|
+
stub(member).category { "Water" }
|
|
13
|
+
@index.field(:category)
|
|
14
|
+
@indexer.field_terms(member).should == %w[Xcategory-water]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "should add terms separately when array is returned" do
|
|
18
|
+
member = Object.new
|
|
19
|
+
stub(member).category { ["Water", "Liquid"] }
|
|
20
|
+
@index.field(:category)
|
|
21
|
+
@indexer.field_terms(member).should == %w[Xcategory-water Xcategory-liquid]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "should have base terms with class name and id" do
|
|
25
|
+
member = Object.new
|
|
26
|
+
stub(member).id { 123 }
|
|
27
|
+
@indexer.base_terms(member).should == %w[CObject QObject-123]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "should add terms, values and options for facets" do
|
|
31
|
+
Xapit::Config.writable_database # force xapit to use a writable database at the beginning
|
|
32
|
+
stub(XapitMember).xapit_index_blueprint { @index }
|
|
33
|
+
member = XapitMember.new(:foo => ["ABC", "DEF"])
|
|
34
|
+
ids = Xapit::FacetBlueprint.new(XapitMember, 0, :foo).identifiers_for(member)
|
|
35
|
+
@index.facet(:foo)
|
|
36
|
+
@indexer.facet_terms(member).should == ids.map { |id| "F#{id}" }
|
|
37
|
+
@indexer.values(member).should == [ids.join('-')]
|
|
38
|
+
@indexer.save_facet_options_for(member)
|
|
39
|
+
ids.map { |id| Xapit::FacetOption.find(id).name }.should == ["ABC", "DEF"]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "should add values for sortable fields" do
|
|
43
|
+
member = Object.new
|
|
44
|
+
stub(member).name { "Foo" }
|
|
45
|
+
@index.sortable(:name)
|
|
46
|
+
@indexer.values(member).should == ["foo"]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "should add terms and values to xapian document" do
|
|
50
|
+
member = Object.new
|
|
51
|
+
stub(member).id { 123 }
|
|
52
|
+
stub(@indexer).values.returns(%w[value list])
|
|
53
|
+
stub(@indexer).other_terms { %w[term list] }
|
|
54
|
+
doc = @indexer.document_for(member)
|
|
55
|
+
doc.should be_kind_of(Xapian::Document)
|
|
56
|
+
doc.data.should == "Object-123"
|
|
57
|
+
doc.values.map(&:value).sort.should == %w[value list].sort
|
|
58
|
+
doc.terms.map(&:term).sort.should == %w[term list].sort
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it "should convert time to integer before saving as field term" do
|
|
62
|
+
member = Object.new
|
|
63
|
+
stub(member).created_at { Time.now }
|
|
64
|
+
@index.field(:created_at)
|
|
65
|
+
@indexer.field_terms(member).should == ["Xcreated_at-#{member.created_at.to_i}"]
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it "should convert date to time then integer before saving as field term" do
|
|
69
|
+
member = Object.new
|
|
70
|
+
stub(member).created_on { Date.today }
|
|
71
|
+
@index.field(:created_on)
|
|
72
|
+
@indexer.field_terms(member).should == ["Xcreated_on-#{member.created_on.to_time.to_i}"]
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
|
2
|
+
|
|
3
|
+
describe Xapit::ClassicIndexer do
|
|
4
|
+
before(:each) do
|
|
5
|
+
@index = Xapit::IndexBlueprint.new(XapitMember)
|
|
6
|
+
@indexer = Xapit::ClassicIndexer.new(@index)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "should add text terms to document when indexing attributes" do
|
|
10
|
+
member = Object.new
|
|
11
|
+
stub(member).name { "jumping high" }
|
|
12
|
+
@index.text(:name)
|
|
13
|
+
document = Xapian::Document.new
|
|
14
|
+
@indexer.index_text_attributes(member, document)
|
|
15
|
+
document.terms.map(&:term).sort.should == %w[Zjump Zhigh jumping high].sort
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "should use given block to generate text terms" do
|
|
19
|
+
member = Object.new
|
|
20
|
+
stub(member).name { "foobar" }
|
|
21
|
+
@index.text(:name) { |t| [t.length] }
|
|
22
|
+
document = Xapian::Document.new
|
|
23
|
+
@indexer.index_text_attributes(member, document)
|
|
24
|
+
document.terms.map(&:term).sort.should == %w[6].sort
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
|
2
|
+
|
|
3
|
+
describe Xapit::SimpleIndexer do
|
|
4
|
+
before(:each) do
|
|
5
|
+
@index = Xapit::IndexBlueprint.new(XapitMember)
|
|
6
|
+
@indexer = Xapit::SimpleIndexer.new(@index)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "should return terms for text attributes" do
|
|
10
|
+
member = Object.new
|
|
11
|
+
stub(member).description { "This is a test" }
|
|
12
|
+
@index.text(:description)
|
|
13
|
+
@indexer.terms_for_attribute_without_stemming(member, :description, {}).should == %w[this is a test]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "should return text term with stemming added" do
|
|
17
|
+
member = Object.new
|
|
18
|
+
stub(member).description { "jumping high" }
|
|
19
|
+
@index.text(:description)
|
|
20
|
+
@indexer.terms_for_attribute(member, :description, {}).should == %w[jumping Zjump high Zhigh]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "should convert attribute to string when converting text to terms" do
|
|
24
|
+
member = Object.new
|
|
25
|
+
stub(member).num { 123 }
|
|
26
|
+
@index.text(:num)
|
|
27
|
+
@indexer.terms_for_attribute_without_stemming(member, :num, {}).should == %w[123]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "should add text terms to document when indexing attributes" do
|
|
31
|
+
@index.text(:description)
|
|
32
|
+
stub(@indexer).terms_for_attribute { %w[term list] }
|
|
33
|
+
document = Xapian::Document.new
|
|
34
|
+
@indexer.index_text_attributes(nil, document)
|
|
35
|
+
document.terms.map(&:term).sort.should == %w[term list].sort
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "should use given block to generate text terms" do
|
|
39
|
+
member = Object.new
|
|
40
|
+
stub(member).name { "foobar" }
|
|
41
|
+
proc = lambda { |t| [t.length] }
|
|
42
|
+
@indexer.terms_for_attribute_without_stemming(member, :name, { :proc => proc }).should == ["6"]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "should increment term frequency by weight option" do
|
|
46
|
+
member = Object.new
|
|
47
|
+
stub(member).description { "This is a test" }
|
|
48
|
+
@index.text(:description, :weight => 10)
|
|
49
|
+
document = Xapian::Document.new
|
|
50
|
+
@indexer.index_text_attributes(member, document)
|
|
51
|
+
document.terms.first.wdf.should == 10
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
|
2
|
+
|
|
3
|
+
class OtherMember
|
|
4
|
+
include Xapit::Membership
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
describe XapitMember do
|
|
8
|
+
it "should have xapit method" do
|
|
9
|
+
OtherMember.should respond_to(:xapit)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "should not respond to xapit_index_blueprint if xapit isn't called" do
|
|
13
|
+
OtherMember.should_not respond_to(:xapit_index_blueprint)
|
|
14
|
+
OtherMember.should_not respond_to(:search)
|
|
15
|
+
OtherMember.new.should_not respond_to(:search_similar)
|
|
16
|
+
OtherMember.new.should_not respond_to(:xapit_relevance)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
describe "with description indexed" do
|
|
20
|
+
before(:each) do
|
|
21
|
+
XapitMember.xapit do |index|
|
|
22
|
+
index.text :description
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "should have xapit index blueprint" do
|
|
27
|
+
XapitMember.xapit_index_blueprint.should be_kind_of(Xapit::IndexBlueprint)
|
|
28
|
+
end
|
|
29
|
+
it "should return collection from search" do
|
|
30
|
+
XapitMember.search("foo").class.should == Xapit::Collection
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "should store xapit_relevance" do
|
|
34
|
+
member = XapitMember.new
|
|
35
|
+
member.xapit_relevance = 123
|
|
36
|
+
member.xapit_relevance.should == 123
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
|
2
|
+
|
|
3
|
+
describe Xapit::AbstractQueryParser do
|
|
4
|
+
before(:each) do
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
it "parse conditions hash into terms" do
|
|
8
|
+
parser = Xapit::AbstractQueryParser.new(:conditions => { :foo => 'bar', 'hello' => :world })
|
|
9
|
+
parser.condition_terms.sort.should == ["Xfoo-bar", "Xhello-world"].sort
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "convert time into integer before placing in condition term" do
|
|
13
|
+
time = Time.now
|
|
14
|
+
parser = Xapit::AbstractQueryParser.new(:conditions => { :time => time })
|
|
15
|
+
parser.condition_terms.should == ["Xtime-#{time.to_i}"]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "convert date into time then integer before placing in condition term" do
|
|
19
|
+
date = Date.today
|
|
20
|
+
parser = Xapit::AbstractQueryParser.new(:conditions => { :date => date })
|
|
21
|
+
parser.condition_terms.should == ["Xdate-#{date.to_time.to_i}"]
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
|
2
|
+
|
|
3
|
+
describe Xapit::ClassicQueryParser do
|
|
4
|
+
before(:each) do
|
|
5
|
+
@parser = Xapit::ClassicQueryParser.new(nil, nil)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
it "should have an initial xapian parser with stemming and default operator support" do
|
|
9
|
+
expected = Xapian::QueryParser.new
|
|
10
|
+
expected.stemmer = Xapian::Stem.new("english")
|
|
11
|
+
expected.stemming_strategy = Xapian::QueryParser::STEM_SOME
|
|
12
|
+
expected.default_op = Xapian::Query::OP_AND
|
|
13
|
+
@parser.xapian_query_from_text("foo bar").description.should == expected.parse_query("foo bar").description
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
|
2
|
+
|
|
3
|
+
describe Xapit::SimpleQueryParser do
|
|
4
|
+
describe "with stemming" do
|
|
5
|
+
it "should include stemmed variation for single word" do
|
|
6
|
+
Xapit::SimpleQueryParser.new(nil, "jumping").parsed.should == "Zjump"
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "should include stemmed variations for multiple words" do
|
|
10
|
+
Xapit::SimpleQueryParser.new(nil, "jumping high").parsed.should == [:and, "Zjump", "Zhigh"]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "should add stemmed variation for 'not' option" do
|
|
14
|
+
Xapit::SimpleQueryParser.new(nil, "jumping not high").parsed.should == [:and, "Zjump", [:not, "Zhigh"]]
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
describe "without stemming" do
|
|
19
|
+
before(:each) do
|
|
20
|
+
Xapit::Config.options[:stemming] = false
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "should parse nothing for simple string" do
|
|
24
|
+
Xapit::SimpleQueryParser.new(nil, "foobar").parsed.should == "foobar"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "should parse empty string as blank string" do
|
|
28
|
+
Xapit::SimpleQueryParser.new(nil, "").parsed.should == ""
|
|
29
|
+
Xapit::SimpleQueryParser.new(nil, " \t ").parsed.should == ""
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "should parse white space as AND" do
|
|
33
|
+
Xapit::SimpleQueryParser.new(nil, "foo bar").parsed.should == [:and, "foo", "bar"]
|
|
34
|
+
Xapit::SimpleQueryParser.new(nil, "\t foo \t bar ").parsed.should == [:and, "foo", "bar"]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "should parse simple 'or' query" do
|
|
38
|
+
Xapit::SimpleQueryParser.new(nil, "foo or bar").parsed.should == [:or, "foo", "bar"]
|
|
39
|
+
Xapit::SimpleQueryParser.new(nil, " foo or\t bar \t ").parsed.should == [:or, "foo", "bar"]
|
|
40
|
+
Xapit::SimpleQueryParser.new(nil, "foo OR bar").parsed.should == [:or, "foo", "bar"]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "should parse 'and' within 'or' giving 'or' presedence" do
|
|
44
|
+
Xapit::SimpleQueryParser.new(nil, "foo or bar blah").parsed.should == [:or, "foo", [:and, "bar", "blah"]]
|
|
45
|
+
Xapit::SimpleQueryParser.new(nil, "foo bar or blah").parsed.should == [:or, [:and, "foo", "bar"], "blah"]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it "should parse simple 'not' query" do
|
|
49
|
+
Xapit::SimpleQueryParser.new(nil, "foo not bar").parsed.should == [:and, "foo", [:not, "bar"]]
|
|
50
|
+
Xapit::SimpleQueryParser.new(nil, "foo NOT bar blah").parsed.should == [:and, "foo", [:not, "bar"], "blah"]
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it "should convert simple query to xapian query" do
|
|
54
|
+
Xapit::SimpleQueryParser.new(nil, "foo bar").xapian_query.description.should == Xapian::Query.new(Xapian::Query::OP_AND, "foo", "bar").description
|
|
55
|
+
Xapit::SimpleQueryParser.new(nil, "foo OR bar").xapian_query.description.should == Xapian::Query.new(Xapian::Query::OP_OR, "foo", "bar").description
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "should convert deep query to xapian query" do
|
|
59
|
+
query = Xapian::Query.new(Xapian::Query::OP_OR,
|
|
60
|
+
Xapian::Query.new(Xapian::Query::OP_OR, ["foo"]),
|
|
61
|
+
Xapian::Query.new(Xapian::Query::OP_AND, ["bar", "blah"])
|
|
62
|
+
)
|
|
63
|
+
Xapit::SimpleQueryParser.new(nil, "foo or bar blah").xapian_query.description.should == query.description
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it "should convert multi-deep query to xapian query" do
|
|
67
|
+
query = Xapian::Query.new(Xapian::Query::OP_OR,
|
|
68
|
+
Xapian::Query.new(Xapian::Query::OP_AND, ["foo", "bar"]),
|
|
69
|
+
Xapian::Query.new(Xapian::Query::OP_AND, ["test", "blah"])
|
|
70
|
+
)
|
|
71
|
+
Xapit::SimpleQueryParser.new(nil, "foo bar or test blah").xapian_query.description.should == query.description
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it "should convert single word query to xapian query" do
|
|
75
|
+
Xapit::SimpleQueryParser.new(nil, "foo").xapian_query.description.should == Xapian::Query.new(Xapian::Query::OP_AND, ["foo"]).description
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it "should convert negative query to xapian query" do
|
|
79
|
+
query = Xapian::Query.new(Xapian::Query::OP_AND_NOT,
|
|
80
|
+
Xapian::Query.new(Xapian::Query::OP_AND, ["foo"]),
|
|
81
|
+
Xapian::Query.new(Xapian::Query::OP_AND, ["bar"])
|
|
82
|
+
)
|
|
83
|
+
Xapit::SimpleQueryParser.new(nil, "foo not bar").xapian_query.description.should == query.description
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|