xapit 0.1.0 → 0.2.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/CHANGELOG +27 -0
 - data/Manifest +16 -1
 - data/README.rdoc +29 -15
 - data/Rakefile +1 -1
 - data/features/facets.feature +40 -1
 - data/features/finding.feature +15 -59
 - data/features/sorting.feature +29 -0
 - data/features/step_definitions/xapit_steps.rb +11 -3
 - data/features/suggestions.feature +17 -0
 - data/features/support/xapit_helpers.rb +1 -1
 - data/install.rb +7 -8
 - data/lib/xapit.rb +34 -2
 - data/lib/xapit/adapters/abstract_adapter.rb +46 -0
 - data/lib/xapit/adapters/active_record_adapter.rb +20 -0
 - data/lib/xapit/adapters/data_mapper_adapter.rb +10 -0
 - data/lib/xapit/collection.rb +17 -5
 - data/lib/xapit/config.rb +1 -9
 - data/lib/xapit/facet.rb +11 -8
 - data/lib/xapit/index_blueprint.rb +9 -3
 - data/lib/xapit/indexers/abstract_indexer.rb +13 -2
 - data/lib/xapit/indexers/classic_indexer.rb +5 -3
 - data/lib/xapit/indexers/simple_indexer.rb +15 -8
 - data/lib/xapit/membership.rb +19 -1
 - data/lib/xapit/query.rb +40 -15
 - data/lib/xapit/query_parsers/abstract_query_parser.rb +46 -24
 - data/lib/xapit/rake_tasks.rb +13 -0
 - data/rails_generators/xapit/USAGE +13 -0
 - data/rails_generators/xapit/templates/setup_xapit.rb +1 -0
 - data/rails_generators/xapit/templates/xapit.rake +4 -0
 - data/rails_generators/xapit/xapit_generator.rb +20 -0
 - data/spec/spec_helper.rb +2 -2
 - data/spec/xapit/adapters/active_record_adapter_spec.rb +31 -0
 - data/spec/xapit/adapters/data_mapper_adapter_spec.rb +10 -0
 - data/spec/xapit/facet_option_spec.rb +2 -2
 - data/spec/xapit/index_blueprint_spec.rb +11 -3
 - data/spec/xapit/indexers/abstract_indexer_spec.rb +37 -0
 - data/spec/xapit/indexers/classic_indexer_spec.rb +9 -0
 - data/spec/xapit/indexers/simple_indexer_spec.rb +22 -6
 - data/spec/xapit/membership_spec.rb +16 -0
 - data/spec/xapit/query_parsers/abstract_query_parser_spec.rb +21 -3
 - data/spec/xapit/query_spec.rb +21 -0
 - data/spec/xapit_member.rb +13 -2
 - data/tasks/xapit.rake +1 -9
 - data/tmp/xapiandatabase/postlist.DB +0 -0
 - data/tmp/xapiandatabase/postlist.baseB +0 -0
 - data/tmp/xapiandatabase/record.DB +0 -0
 - data/tmp/xapiandatabase/record.baseB +0 -0
 - data/tmp/xapiandatabase/spelling.DB +0 -0
 - data/tmp/xapiandatabase/spelling.baseB +0 -0
 - data/tmp/xapiandatabase/termlist.DB +0 -0
 - data/tmp/xapiandatabase/termlist.baseB +0 -0
 - data/tmp/xapiandatabase/value.DB +0 -0
 - data/tmp/xapiandatabase/value.baseA +0 -0
 - data/tmp/xapiandb/spelling.DB +0 -0
 - data/tmp/xapiandb/spelling.baseB +0 -0
 - data/xapit.gemspec +4 -4
 - metadata +23 -3
 
| 
         @@ -0,0 +1,13 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # TODO investigate why this is needed to ensure it doesn't load twice
         
     | 
| 
      
 2 
     | 
    
         
            +
            unless @xapit_rake_loaded
         
     | 
| 
      
 3 
     | 
    
         
            +
              @xapit_rake_loaded = true
         
     | 
| 
      
 4 
     | 
    
         
            +
              namespace :xapit do
         
     | 
| 
      
 5 
     | 
    
         
            +
                desc "Index all xapit models."
         
     | 
| 
      
 6 
     | 
    
         
            +
                task :index => :environment do
         
     | 
| 
      
 7 
     | 
    
         
            +
                  Xapit.remove_database
         
     | 
| 
      
 8 
     | 
    
         
            +
                  Xapit.index_all do |member_class|
         
     | 
| 
      
 9 
     | 
    
         
            +
                    puts "Indexing #{member_class.name}"
         
     | 
| 
      
 10 
     | 
    
         
            +
                  end
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,13 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            Description:
         
     | 
| 
      
 2 
     | 
    
         
            +
                Generates files necessary to setup Xapit. This includes an initializer
         
     | 
| 
      
 3 
     | 
    
         
            +
                to specify the configuration (setup_xapit.rb) and a rake file to load
         
     | 
| 
      
 4 
     | 
    
         
            +
                the rake tasks (xapit.rake).
         
     | 
| 
      
 5 
     | 
    
         
            +
                
         
     | 
| 
      
 6 
     | 
    
         
            +
                IMPORTANT: Only use this generator if you are using the gem version of
         
     | 
| 
      
 7 
     | 
    
         
            +
                Xapit, it is not needed if you are installing via Rails plugin.
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            Examples:
         
     | 
| 
      
 10 
     | 
    
         
            +
                script/generate xapit
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                    Initializer: config/initializers/setup_xapit.rb
         
     | 
| 
      
 13 
     | 
    
         
            +
                    Rake Tasks:  lib/tasks/xapit.rake
         
     | 
| 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            Xapit.setup(:database_path => "#{Rails.root}/db/xapiandb")
         
     | 
| 
         @@ -0,0 +1,20 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class XapitGenerator < Rails::Generator::Base
         
     | 
| 
      
 2 
     | 
    
         
            +
              def manifest
         
     | 
| 
      
 3 
     | 
    
         
            +
                record do |m|
         
     | 
| 
      
 4 
     | 
    
         
            +
                  m.directory "config/initializers"
         
     | 
| 
      
 5 
     | 
    
         
            +
                  m.file "setup_xapit.rb", "config/initializers/setup_xapit.rb"
         
     | 
| 
      
 6 
     | 
    
         
            +
                  
         
     | 
| 
      
 7 
     | 
    
         
            +
                  m.directory "lib/tasks"
         
     | 
| 
      
 8 
     | 
    
         
            +
                  m.file "xapit.rake", "lib/tasks/xapit.rake"
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
              end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              protected
         
     | 
| 
      
 13 
     | 
    
         
            +
                def banner
         
     | 
| 
      
 14 
     | 
    
         
            +
                  <<-EOS
         
     | 
| 
      
 15 
     | 
    
         
            +
            Generates files necessary to setup Xapit.
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            USAGE: #{$0} #{spec.name}
         
     | 
| 
      
 18 
     | 
    
         
            +
            EOS
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
            end
         
     | 
    
        data/spec/spec_helper.rb
    CHANGED
    
    | 
         @@ -8,8 +8,8 @@ require File.dirname(__FILE__) + '/xapit_member' 
     | 
|
| 
       8 
8 
     | 
    
         
             
            Spec::Runner.configure do |config|
         
     | 
| 
       9 
9 
     | 
    
         
             
              config.mock_with :rr
         
     | 
| 
       10 
10 
     | 
    
         
             
              config.before(:each) do
         
     | 
| 
       11 
     | 
    
         
            -
                Xapit 
     | 
| 
       12 
     | 
    
         
            -
                Xapit 
     | 
| 
      
 11 
     | 
    
         
            +
                Xapit.setup(:database_path => File.dirname(__FILE__) + '/tmp/xapiandb')
         
     | 
| 
      
 12 
     | 
    
         
            +
                Xapit.remove_database
         
     | 
| 
       13 
13 
     | 
    
         
             
                XapitMember.delete_all
         
     | 
| 
       14 
14 
     | 
    
         
             
              end
         
     | 
| 
       15 
15 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,31 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            describe Xapit::ActiveRecordAdapter do
         
     | 
| 
      
 4 
     | 
    
         
            +
              it "should be used for ActiveRecord::Base subclasses" do
         
     | 
| 
      
 5 
     | 
    
         
            +
                Xapit::ActiveRecordAdapter.should_not be_for_class(Object)
         
     | 
| 
      
 6 
     | 
    
         
            +
                klass = Object.new
         
     | 
| 
      
 7 
     | 
    
         
            +
                stub(klass).ancestors { ["ActiveRecord::Base"] }
         
     | 
| 
      
 8 
     | 
    
         
            +
                Xapit::ActiveRecordAdapter.should be_for_class(klass)
         
     | 
| 
      
 9 
     | 
    
         
            +
              end
         
     | 
| 
      
 10 
     | 
    
         
            +
              
         
     | 
| 
      
 11 
     | 
    
         
            +
              it "should pass find_single to find method to target" do
         
     | 
| 
      
 12 
     | 
    
         
            +
                target = Object.new
         
     | 
| 
      
 13 
     | 
    
         
            +
                mock(target).find(1) { :record }
         
     | 
| 
      
 14 
     | 
    
         
            +
                adapter = Xapit::ActiveRecordAdapter.new(target)
         
     | 
| 
      
 15 
     | 
    
         
            +
                adapter.find_single(1).should == :record
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
              
         
     | 
| 
      
 18 
     | 
    
         
            +
              it "should pass find_multiple to find method to target" do
         
     | 
| 
      
 19 
     | 
    
         
            +
                target = Object.new
         
     | 
| 
      
 20 
     | 
    
         
            +
                mock(target).find([1, 2]) { :record }
         
     | 
| 
      
 21 
     | 
    
         
            +
                adapter = Xapit::ActiveRecordAdapter.new(target)
         
     | 
| 
      
 22 
     | 
    
         
            +
                adapter.find_multiple([1, 2]).should == :record
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
              
         
     | 
| 
      
 25 
     | 
    
         
            +
              it "should pass find_each to target" do
         
     | 
| 
      
 26 
     | 
    
         
            +
                target = Object.new
         
     | 
| 
      
 27 
     | 
    
         
            +
                mock(target).find_each(:args) { 5 }
         
     | 
| 
      
 28 
     | 
    
         
            +
                adapter = Xapit::ActiveRecordAdapter.new(target)
         
     | 
| 
      
 29 
     | 
    
         
            +
                adapter.find_each(:args).should == 5
         
     | 
| 
      
 30 
     | 
    
         
            +
              end
         
     | 
| 
      
 31 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,10 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            describe Xapit::DataMapperAdapter do
         
     | 
| 
      
 4 
     | 
    
         
            +
              it "should be used for DataMapper::Resource model" do
         
     | 
| 
      
 5 
     | 
    
         
            +
                Xapit::DataMapperAdapter.should_not be_for_class(Object)
         
     | 
| 
      
 6 
     | 
    
         
            +
                klass = Object.new
         
     | 
| 
      
 7 
     | 
    
         
            +
                stub(klass).ancestors { ["DataMapper::Resource"] }
         
     | 
| 
      
 8 
     | 
    
         
            +
                Xapit::DataMapperAdapter.should be_for_class(klass)
         
     | 
| 
      
 9 
     | 
    
         
            +
              end
         
     | 
| 
      
 10 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -9,7 +9,7 @@ describe Xapit::FacetOption do 
     | 
|
| 
       9 
9 
     | 
    
         
             
              end
         
     | 
| 
       10 
10 
     | 
    
         | 
| 
       11 
11 
     | 
    
         
             
              it "should remove current identifier from previous identifiers if it exists" do
         
     | 
| 
       12 
     | 
    
         
            -
                Xapit 
     | 
| 
      
 12 
     | 
    
         
            +
                Xapit.setup(:breadcrumb_facets => false)
         
     | 
| 
       13 
13 
     | 
    
         
             
                option = Xapit::FacetOption.new(nil, nil, nil)
         
     | 
| 
       14 
14 
     | 
    
         
             
                option.existing_facet_identifiers = ["abc", "123", "foo"]
         
     | 
| 
       15 
15 
     | 
    
         
             
                stub(option).identifier { "foo" }
         
     | 
| 
         @@ -17,7 +17,7 @@ describe Xapit::FacetOption do 
     | 
|
| 
       17 
17 
     | 
    
         
             
              end
         
     | 
| 
       18 
18 
     | 
    
         | 
| 
       19 
19 
     | 
    
         
             
              it "should support breadcrumb style facets" do
         
     | 
| 
       20 
     | 
    
         
            -
                Xapit 
     | 
| 
      
 20 
     | 
    
         
            +
                Xapit.setup(:breadcrumb_facets => true)
         
     | 
| 
       21 
21 
     | 
    
         
             
                option = Xapit::FacetOption.new(nil, nil, nil)
         
     | 
| 
       22 
22 
     | 
    
         
             
                option.existing_facet_identifiers = ["abc", "123", "foo"]
         
     | 
| 
       23 
23 
     | 
    
         
             
                stub(option).identifier { "123" }
         
     | 
| 
         @@ -2,6 +2,7 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            describe Xapit::IndexBlueprint do
         
     | 
| 
       4 
4 
     | 
    
         
             
              before(:each) do
         
     | 
| 
      
 5 
     | 
    
         
            +
                XapitMember.xapit { } # call so methods are generated
         
     | 
| 
       5 
6 
     | 
    
         
             
                @index = Xapit::IndexBlueprint.new(XapitMember)
         
     | 
| 
       6 
7 
     | 
    
         
             
              end
         
     | 
| 
       7 
8 
     | 
    
         | 
| 
         @@ -36,7 +37,14 @@ describe Xapit::IndexBlueprint do 
     | 
|
| 
       36 
37 
     | 
    
         
             
                @index.facet(:foo)
         
     | 
| 
       37 
38 
     | 
    
         
             
                @index.facet(:test)
         
     | 
| 
       38 
39 
     | 
    
         
             
                @index.sortable(:bar, :blah)
         
     | 
| 
       39 
     | 
    
         
            -
                @index. 
     | 
| 
      
 40 
     | 
    
         
            +
                @index.position_of_sortable(:blah).should == 3
         
     | 
| 
      
 41 
     | 
    
         
            +
              end
         
     | 
| 
      
 42 
     | 
    
         
            +
              
         
     | 
| 
      
 43 
     | 
    
         
            +
              it "should have a field position offset by facets + sortable" do
         
     | 
| 
      
 44 
     | 
    
         
            +
                @index.facet(:foo)
         
     | 
| 
      
 45 
     | 
    
         
            +
                @index.sortable(:bar, :blah)
         
     | 
| 
      
 46 
     | 
    
         
            +
                @index.field(:bar, :blah)
         
     | 
| 
      
 47 
     | 
    
         
            +
                @index.position_of_field(:blah).should == 4
         
     | 
| 
       40 
48 
     | 
    
         
             
              end
         
     | 
| 
       41 
49 
     | 
    
         | 
| 
       42 
50 
     | 
    
         
             
              it "should index member document into database" do
         
     | 
| 
         @@ -53,8 +61,8 @@ describe Xapit::IndexBlueprint do 
     | 
|
| 
       53 
61 
     | 
    
         
             
              end
         
     | 
| 
       54 
62 
     | 
    
         | 
| 
       55 
63 
     | 
    
         
             
              it "should pass in extra arguments to each method" do
         
     | 
| 
       56 
     | 
    
         
            -
                index = Xapit::IndexBlueprint.new( 
     | 
| 
       57 
     | 
    
         
            -
                mock( 
     | 
| 
      
 64 
     | 
    
         
            +
                index = Xapit::IndexBlueprint.new(XapitMember, :foo, :bar => :blah)
         
     | 
| 
      
 65 
     | 
    
         
            +
                mock(XapitMember).find_each(:foo, :bar => :blah)
         
     | 
| 
       58 
66 
     | 
    
         
             
                index.index_all
         
     | 
| 
       59 
67 
     | 
    
         
             
              end
         
     | 
| 
       60 
68 
     | 
    
         
             
            end
         
     | 
| 
         @@ -71,4 +71,41 @@ describe Xapit::AbstractIndexer do 
     | 
|
| 
       71 
71 
     | 
    
         
             
                @index.field(:created_on)
         
     | 
| 
       72 
72 
     | 
    
         
             
                @indexer.field_terms(member).should == ["Xcreated_on-#{member.created_on.to_time.to_i}"]
         
     | 
| 
       73 
73 
     | 
    
         
             
              end
         
     | 
| 
      
 74 
     | 
    
         
            +
              
         
     | 
| 
      
 75 
     | 
    
         
            +
              it "should use sortable_serialze for numeric sortable" do
         
     | 
| 
      
 76 
     | 
    
         
            +
                member = Object.new
         
     | 
| 
      
 77 
     | 
    
         
            +
                stub(member).age { 7.89 }
         
     | 
| 
      
 78 
     | 
    
         
            +
                @index.sortable(:age)
         
     | 
| 
      
 79 
     | 
    
         
            +
                @indexer.values(member).should == [Xapian.sortable_serialise(7.89)]
         
     | 
| 
      
 80 
     | 
    
         
            +
              end
         
     | 
| 
      
 81 
     | 
    
         
            +
              
         
     | 
| 
      
 82 
     | 
    
         
            +
              it "should only use first value if sortable attribute is an array" do
         
     | 
| 
      
 83 
     | 
    
         
            +
                member = Object.new
         
     | 
| 
      
 84 
     | 
    
         
            +
                stub(member).age { [1, 2] }
         
     | 
| 
      
 85 
     | 
    
         
            +
                @index.sortable(:age)
         
     | 
| 
      
 86 
     | 
    
         
            +
                @indexer.values(member).should == [Xapian.sortable_serialise(1)]
         
     | 
| 
      
 87 
     | 
    
         
            +
              end
         
     | 
| 
      
 88 
     | 
    
         
            +
              
         
     | 
| 
      
 89 
     | 
    
         
            +
              it "should add sortable_serialze value for numeric field" do
         
     | 
| 
      
 90 
     | 
    
         
            +
                member = Object.new
         
     | 
| 
      
 91 
     | 
    
         
            +
                stub(member).age { [1, 2] }
         
     | 
| 
      
 92 
     | 
    
         
            +
                @index.field(:age)
         
     | 
| 
      
 93 
     | 
    
         
            +
                @indexer.values(member).should == [Xapian.sortable_serialise(1)]
         
     | 
| 
      
 94 
     | 
    
         
            +
              end
         
     | 
| 
      
 95 
     | 
    
         
            +
              
         
     | 
| 
      
 96 
     | 
    
         
            +
              it "should use sortable_serialze for date field" do
         
     | 
| 
      
 97 
     | 
    
         
            +
                date = Date.today
         
     | 
| 
      
 98 
     | 
    
         
            +
                member = Object.new
         
     | 
| 
      
 99 
     | 
    
         
            +
                stub(member).age { date }
         
     | 
| 
      
 100 
     | 
    
         
            +
                @index.field(:age)
         
     | 
| 
      
 101 
     | 
    
         
            +
                @indexer.values(member).should == [Xapian.sortable_serialise(date.to_time.to_i)]
         
     | 
| 
      
 102 
     | 
    
         
            +
              end
         
     | 
| 
      
 103 
     | 
    
         
            +
              
         
     | 
| 
      
 104 
     | 
    
         
            +
              it "should use sortable_serialze for time field" do
         
     | 
| 
      
 105 
     | 
    
         
            +
                time = Time.now
         
     | 
| 
      
 106 
     | 
    
         
            +
                member = Object.new
         
     | 
| 
      
 107 
     | 
    
         
            +
                stub(member).age { time }
         
     | 
| 
      
 108 
     | 
    
         
            +
                @index.field(:age)
         
     | 
| 
      
 109 
     | 
    
         
            +
                @indexer.values(member).should == [Xapian.sortable_serialise(time.to_i)]
         
     | 
| 
      
 110 
     | 
    
         
            +
              end
         
     | 
| 
       74 
111 
     | 
    
         
             
            end
         
     | 
| 
         @@ -23,4 +23,13 @@ describe Xapit::ClassicIndexer do 
     | 
|
| 
       23 
23 
     | 
    
         
             
                @indexer.index_text_attributes(member, document)
         
     | 
| 
       24 
24 
     | 
    
         
             
                document.terms.map(&:term).sort.should == %w[6].sort
         
     | 
| 
       25 
25 
     | 
    
         
             
              end
         
     | 
| 
      
 26 
     | 
    
         
            +
              
         
     | 
| 
      
 27 
     | 
    
         
            +
              it "should return terms separated by array" do
         
     | 
| 
      
 28 
     | 
    
         
            +
                member = Object.new
         
     | 
| 
      
 29 
     | 
    
         
            +
                stub(member).description { ["foo bar", 6, "", nil] }
         
     | 
| 
      
 30 
     | 
    
         
            +
                @index.text(:description)
         
     | 
| 
      
 31 
     | 
    
         
            +
                document = Xapian::Document.new
         
     | 
| 
      
 32 
     | 
    
         
            +
                @indexer.index_text_attributes(member, document)
         
     | 
| 
      
 33 
     | 
    
         
            +
                document.terms.map(&:term).sort.should == ["foo bar", "6"].sort
         
     | 
| 
      
 34 
     | 
    
         
            +
              end
         
     | 
| 
       26 
35 
     | 
    
         
             
            end
         
     | 
| 
         @@ -10,21 +10,21 @@ describe Xapit::SimpleIndexer do 
     | 
|
| 
       10 
10 
     | 
    
         
             
                member = Object.new
         
     | 
| 
       11 
11 
     | 
    
         
             
                stub(member).description { "This is a test" }
         
     | 
| 
       12 
12 
     | 
    
         
             
                @index.text(:description)
         
     | 
| 
       13 
     | 
    
         
            -
                @indexer. 
     | 
| 
      
 13 
     | 
    
         
            +
                @indexer.terms_for_attribute(member, :description, {}).should == %w[this is a test]
         
     | 
| 
       14 
14 
     | 
    
         
             
              end
         
     | 
| 
       15 
15 
     | 
    
         | 
| 
       16 
     | 
    
         
            -
              it "should return text  
     | 
| 
      
 16 
     | 
    
         
            +
              it "should return text terms with stemming added" do
         
     | 
| 
       17 
17 
     | 
    
         
             
                member = Object.new
         
     | 
| 
       18 
18 
     | 
    
         
             
                stub(member).description { "jumping high" }
         
     | 
| 
       19 
19 
     | 
    
         
             
                @index.text(:description)
         
     | 
| 
       20 
     | 
    
         
            -
                @indexer. 
     | 
| 
      
 20 
     | 
    
         
            +
                @indexer.stemmed_terms_for_attribute(member, :description, {}).should == %w[Zjump Zhigh]
         
     | 
| 
       21 
21 
     | 
    
         
             
              end
         
     | 
| 
       22 
22 
     | 
    
         | 
| 
       23 
23 
     | 
    
         
             
              it "should convert attribute to string when converting text to terms" do
         
     | 
| 
       24 
24 
     | 
    
         
             
                member = Object.new
         
     | 
| 
       25 
25 
     | 
    
         
             
                stub(member).num { 123 }
         
     | 
| 
       26 
26 
     | 
    
         
             
                @index.text(:num)
         
     | 
| 
       27 
     | 
    
         
            -
                @indexer. 
     | 
| 
      
 27 
     | 
    
         
            +
                @indexer.terms_for_attribute(member, :num, {}).should == %w[123]
         
     | 
| 
       28 
28 
     | 
    
         
             
              end
         
     | 
| 
       29 
29 
     | 
    
         | 
| 
       30 
30 
     | 
    
         
             
              it "should add text terms to document when indexing attributes" do
         
     | 
| 
         @@ -32,14 +32,14 @@ describe Xapit::SimpleIndexer do 
     | 
|
| 
       32 
32 
     | 
    
         
             
                stub(@indexer).terms_for_attribute { %w[term list] }
         
     | 
| 
       33 
33 
     | 
    
         
             
                document = Xapian::Document.new
         
     | 
| 
       34 
34 
     | 
    
         
             
                @indexer.index_text_attributes(nil, document)
         
     | 
| 
       35 
     | 
    
         
            -
                document.terms.map(&:term).sort.should == %w[ 
     | 
| 
      
 35 
     | 
    
         
            +
                document.terms.map(&:term).sort.should == %w[Zlist Zterm list term].sort
         
     | 
| 
       36 
36 
     | 
    
         
             
              end
         
     | 
| 
       37 
37 
     | 
    
         | 
| 
       38 
38 
     | 
    
         
             
              it "should use given block to generate text terms" do
         
     | 
| 
       39 
39 
     | 
    
         
             
                member = Object.new
         
     | 
| 
       40 
40 
     | 
    
         
             
                stub(member).name { "foobar" }
         
     | 
| 
       41 
41 
     | 
    
         
             
                proc = lambda { |t| [t.length] }
         
     | 
| 
       42 
     | 
    
         
            -
                @indexer. 
     | 
| 
      
 42 
     | 
    
         
            +
                @indexer.terms_for_attribute(member, :name, { :proc => proc }).should == ["6"]
         
     | 
| 
       43 
43 
     | 
    
         
             
              end
         
     | 
| 
       44 
44 
     | 
    
         | 
| 
       45 
45 
     | 
    
         
             
              it "should increment term frequency by weight option" do
         
     | 
| 
         @@ -50,4 +50,20 @@ describe Xapit::SimpleIndexer do 
     | 
|
| 
       50 
50 
     | 
    
         
             
                @indexer.index_text_attributes(member, document)
         
     | 
| 
       51 
51 
     | 
    
         
             
                document.terms.first.wdf.should == 10
         
     | 
| 
       52 
52 
     | 
    
         
             
              end
         
     | 
| 
      
 53 
     | 
    
         
            +
              
         
     | 
| 
      
 54 
     | 
    
         
            +
              it "should increment term frequency by weight option" do
         
     | 
| 
      
 55 
     | 
    
         
            +
                member = Object.new
         
     | 
| 
      
 56 
     | 
    
         
            +
                stub(member).description { "This is a test" }
         
     | 
| 
      
 57 
     | 
    
         
            +
                @index.text(:description, :weight => 10)
         
     | 
| 
      
 58 
     | 
    
         
            +
                document = Xapian::Document.new
         
     | 
| 
      
 59 
     | 
    
         
            +
                @indexer.index_text_attributes(member, document)
         
     | 
| 
      
 60 
     | 
    
         
            +
                document.terms.first.wdf.should == 10
         
     | 
| 
      
 61 
     | 
    
         
            +
              end
         
     | 
| 
      
 62 
     | 
    
         
            +
              
         
     | 
| 
      
 63 
     | 
    
         
            +
              it "should return terms separated by array" do
         
     | 
| 
      
 64 
     | 
    
         
            +
                member = Object.new
         
     | 
| 
      
 65 
     | 
    
         
            +
                stub(member).description { ["foo bar", 6, "", nil] }
         
     | 
| 
      
 66 
     | 
    
         
            +
                @index.text(:description)
         
     | 
| 
      
 67 
     | 
    
         
            +
                @indexer.terms_for_attribute(member, :description, {}).should == ["foo bar", "6"]
         
     | 
| 
      
 68 
     | 
    
         
            +
              end
         
     | 
| 
       53 
69 
     | 
    
         
             
            end
         
     | 
| 
         @@ -21,11 +21,13 @@ describe XapitMember do 
     | 
|
| 
       21 
21 
     | 
    
         
             
                  XapitMember.xapit do |index|
         
     | 
| 
       22 
22 
     | 
    
         
             
                    index.text :description
         
     | 
| 
       23 
23 
     | 
    
         
             
                  end
         
     | 
| 
      
 24 
     | 
    
         
            +
                  XapitMember.instance_variable_set("@xapit_adapter", nil)
         
     | 
| 
       24 
25 
     | 
    
         
             
                end
         
     | 
| 
       25 
26 
     | 
    
         | 
| 
       26 
27 
     | 
    
         
             
                it "should have xapit index blueprint" do
         
     | 
| 
       27 
28 
     | 
    
         
             
                  XapitMember.xapit_index_blueprint.should be_kind_of(Xapit::IndexBlueprint)
         
     | 
| 
       28 
29 
     | 
    
         
             
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
                
         
     | 
| 
       29 
31 
     | 
    
         
             
                it "should return collection from search" do
         
     | 
| 
       30 
32 
     | 
    
         
             
                  XapitMember.search("foo").class.should == Xapit::Collection
         
     | 
| 
       31 
33 
     | 
    
         
             
                end
         
     | 
| 
         @@ -35,5 +37,19 @@ describe XapitMember do 
     | 
|
| 
       35 
37 
     | 
    
         
             
                  member.xapit_relevance = 123
         
     | 
| 
       36 
38 
     | 
    
         
             
                  member.xapit_relevance.should == 123
         
     | 
| 
       37 
39 
     | 
    
         
             
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
                
         
     | 
| 
      
 41 
     | 
    
         
            +
                it "should have an adapter" do
         
     | 
| 
      
 42 
     | 
    
         
            +
                  XapitMember.xapit_adapter.class.should == Xapit::ActiveRecordAdapter
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
                
         
     | 
| 
      
 45 
     | 
    
         
            +
                it "should use DataMapper adapter if that is ancestor" do
         
     | 
| 
      
 46 
     | 
    
         
            +
                  stub(XapitMember).ancestors { ["DataMapper::Resource"] }
         
     | 
| 
      
 47 
     | 
    
         
            +
                  XapitMember.xapit_adapter.class.should == Xapit::DataMapperAdapter
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
                
         
     | 
| 
      
 50 
     | 
    
         
            +
                it "should raise an exception when no adapter is found" do
         
     | 
| 
      
 51 
     | 
    
         
            +
                  stub(XapitMember).ancestors { [] }
         
     | 
| 
      
 52 
     | 
    
         
            +
                  lambda { XapitMember.xapit_adapter }.should raise_error
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
       38 
54 
     | 
    
         
             
              end
         
     | 
| 
       39 
55 
     | 
    
         
             
            end
         
     | 
| 
         @@ -4,20 +4,38 @@ describe Xapit::AbstractQueryParser do 
     | 
|
| 
       4 
4 
     | 
    
         
             
              before(:each) do
         
     | 
| 
       5 
5 
     | 
    
         
             
              end
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
       7 
     | 
    
         
            -
              it "parse conditions hash into terms" do
         
     | 
| 
      
 7 
     | 
    
         
            +
              it "should parse conditions hash into terms" do
         
     | 
| 
       8 
8 
     | 
    
         
             
                parser = Xapit::AbstractQueryParser.new(:conditions => { :foo => 'bar', 'hello' => :world })
         
     | 
| 
       9 
9 
     | 
    
         
             
                parser.condition_terms.sort.should == ["Xfoo-bar", "Xhello-world"].sort
         
     | 
| 
       10 
10 
     | 
    
         
             
              end
         
     | 
| 
       11 
11 
     | 
    
         | 
| 
       12 
     | 
    
         
            -
              it "convert time into integer before placing in condition term" do
         
     | 
| 
      
 12 
     | 
    
         
            +
              it "should convert time into integer before placing in condition term" do
         
     | 
| 
       13 
13 
     | 
    
         
             
                time = Time.now
         
     | 
| 
       14 
14 
     | 
    
         
             
                parser = Xapit::AbstractQueryParser.new(:conditions => { :time => time })
         
     | 
| 
       15 
15 
     | 
    
         
             
                parser.condition_terms.should == ["Xtime-#{time.to_i}"]
         
     | 
| 
       16 
16 
     | 
    
         
             
              end
         
     | 
| 
       17 
17 
     | 
    
         | 
| 
       18 
     | 
    
         
            -
              it "convert date into time then integer before placing in condition term" do
         
     | 
| 
      
 18 
     | 
    
         
            +
              it "should convert date into time then integer before placing in condition term" do
         
     | 
| 
       19 
19 
     | 
    
         
             
                date = Date.today
         
     | 
| 
       20 
20 
     | 
    
         
             
                parser = Xapit::AbstractQueryParser.new(:conditions => { :date => date })
         
     | 
| 
       21 
21 
     | 
    
         
             
                parser.condition_terms.should == ["Xdate-#{date.to_time.to_i}"]
         
     | 
| 
       22 
22 
     | 
    
         
             
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
                
         
     | 
| 
      
 24 
     | 
    
         
            +
              it "should give spelling suggestion on full term" do
         
     | 
| 
      
 25 
     | 
    
         
            +
                Xapit::Config.writable_database.add_spelling("foo bar")
         
     | 
| 
      
 26 
     | 
    
         
            +
                parser = Xapit::AbstractQueryParser.new(nil, "foo barr")
         
     | 
| 
      
 27 
     | 
    
         
            +
                parser.spelling_suggestion.should == "foo bar"
         
     | 
| 
      
 28 
     | 
    
         
            +
              end
         
     | 
| 
      
 29 
     | 
    
         
            +
                
         
     | 
| 
      
 30 
     | 
    
         
            +
              it "should allow an array of conditions to be specified and use OR xapian query." do
         
     | 
| 
      
 31 
     | 
    
         
            +
                parser = Xapit::AbstractQueryParser.new(:not_conditions => { :foo => %w[hello world]})
         
     | 
| 
      
 32 
     | 
    
         
            +
                parser.not_condition_terms.first.xapian_query.description.should == Xapit::Query.new(%w[Xfoo-hello Xfoo-world], :or).xapian_query.description
         
     | 
| 
      
 33 
     | 
    
         
            +
              end
         
     | 
| 
      
 34 
     | 
    
         
            +
                
         
     | 
| 
      
 35 
     | 
    
         
            +
              it "should allow range condition to be specified and use VALUE_RANGE xapian query." do
         
     | 
| 
      
 36 
     | 
    
         
            +
                XapitMember.xapit { |i| i.field :foo }
         
     | 
| 
      
 37 
     | 
    
         
            +
                expected = Xapian::Query.new(Xapian::Query::OP_VALUE_RANGE, 0, Xapian.sortable_serialise(2), Xapian.sortable_serialise(5))
         
     | 
| 
      
 38 
     | 
    
         
            +
                parser = Xapit::AbstractQueryParser.new(XapitMember, :conditions => { :foo => 2..5 })
         
     | 
| 
      
 39 
     | 
    
         
            +
                parser.condition_terms.first.description.should == expected.description
         
     | 
| 
      
 40 
     | 
    
         
            +
              end
         
     | 
| 
       23 
41 
     | 
    
         
             
            end
         
     | 
    
        data/spec/xapit/query_spec.rb
    CHANGED
    
    | 
         @@ -19,6 +19,12 @@ describe Xapit::Query do 
     | 
|
| 
       19 
19 
     | 
    
         
             
                query.xapian_query.description.should == expected.description
         
     | 
| 
       20 
20 
     | 
    
         
             
              end
         
     | 
| 
       21 
21 
     | 
    
         | 
| 
      
 22 
     | 
    
         
            +
              it "should build a query from an array of strings with :or operator" do
         
     | 
| 
      
 23 
     | 
    
         
            +
                expected = Xapian::Query.new(Xapian::Query::OP_OR, %w[foo bar])
         
     | 
| 
      
 24 
     | 
    
         
            +
                query = Xapit::Query.new(%w[foo bar], :or)
         
     | 
| 
      
 25 
     | 
    
         
            +
                query.xapian_query.description.should == expected.description
         
     | 
| 
      
 26 
     | 
    
         
            +
              end
         
     | 
| 
      
 27 
     | 
    
         
            +
              
         
     | 
| 
       22 
28 
     | 
    
         
             
              it "should AND two queries together" do
         
     | 
| 
       23 
29 
     | 
    
         
             
                expected = Xapian::Query.new(Xapian::Query::OP_AND,
         
     | 
| 
       24 
30 
     | 
    
         
             
                  Xapian::Query.new(Xapian::Query::OP_AND, ["foo"]),
         
     | 
| 
         @@ -38,4 +44,19 @@ describe Xapit::Query do 
     | 
|
| 
       38 
44 
     | 
    
         
             
                query.or_query("bar")
         
     | 
| 
       39 
45 
     | 
    
         
             
                query.xapian_query.description.should == expected.description
         
     | 
| 
       40 
46 
     | 
    
         
             
              end
         
     | 
| 
      
 47 
     | 
    
         
            +
              
         
     | 
| 
      
 48 
     | 
    
         
            +
              it "should build a query from an array of mixed strings and queries" do
         
     | 
| 
      
 49 
     | 
    
         
            +
                expected = Xapian::Query.new(Xapian::Query::OP_AND,
         
     | 
| 
      
 50 
     | 
    
         
            +
                  Xapian::Query.new(Xapian::Query::OP_AND, ["foo"]),
         
     | 
| 
      
 51 
     | 
    
         
            +
                  Xapian::Query.new(Xapian::Query::OP_AND, ["bar"])
         
     | 
| 
      
 52 
     | 
    
         
            +
                )
         
     | 
| 
      
 53 
     | 
    
         
            +
                query = Xapit::Query.new([Xapit::Query.new("foo"), Xapian::Query.new(Xapian::Query::OP_AND, ["bar"])])
         
     | 
| 
      
 54 
     | 
    
         
            +
                query.xapian_query.description.should == expected.description
         
     | 
| 
      
 55 
     | 
    
         
            +
              end
         
     | 
| 
      
 56 
     | 
    
         
            +
              
         
     | 
| 
      
 57 
     | 
    
         
            +
              it "should use xapit query passed in" do
         
     | 
| 
      
 58 
     | 
    
         
            +
                expected = Xapian::Query.new(Xapian::Query::OP_AND, ["foo bar"])
         
     | 
| 
      
 59 
     | 
    
         
            +
                query = Xapit::Query.new(Xapit::Query.new("foo bar"))
         
     | 
| 
      
 60 
     | 
    
         
            +
                query.xapian_query.description.should == expected.description
         
     | 
| 
      
 61 
     | 
    
         
            +
              end
         
     | 
| 
       41 
62 
     | 
    
         
             
            end
         
     | 
    
        data/spec/xapit_member.rb
    CHANGED
    
    | 
         @@ -3,6 +3,12 @@ class XapitMember 
     | 
|
| 
       3 
3 
     | 
    
         | 
| 
       4 
4 
     | 
    
         
             
              attr_reader :id
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
      
 6 
     | 
    
         
            +
              # Make it look like this inherits from ActiveRecord::Base
         
     | 
| 
      
 7 
     | 
    
         
            +
              # so it will use the ActiveRecord adapter.
         
     | 
| 
      
 8 
     | 
    
         
            +
              def self.ancestors
         
     | 
| 
      
 9 
     | 
    
         
            +
                ["ActiveRecord::Base"]
         
     | 
| 
      
 10 
     | 
    
         
            +
              end
         
     | 
| 
      
 11 
     | 
    
         
            +
              
         
     | 
| 
       6 
12 
     | 
    
         
             
              def self.find_each(&block)
         
     | 
| 
       7 
13 
     | 
    
         
             
                @@records.each(&block) if @@records
         
     | 
| 
       8 
14 
     | 
    
         
             
              end
         
     | 
| 
         @@ -11,8 +17,13 @@ class XapitMember 
     | 
|
| 
       11 
17 
     | 
    
         
             
                @@records = []
         
     | 
| 
       12 
18 
     | 
    
         
             
              end
         
     | 
| 
       13 
19 
     | 
    
         | 
| 
       14 
     | 
    
         
            -
              def self.find( 
     | 
| 
       15 
     | 
    
         
            -
                 
     | 
| 
      
 20 
     | 
    
         
            +
              def self.find(ids)
         
     | 
| 
      
 21 
     | 
    
         
            +
                if ids.kind_of? Array
         
     | 
| 
      
 22 
     | 
    
         
            +
                  # change the order to mimic database where we can't predict the order
         
     | 
| 
      
 23 
     | 
    
         
            +
                  ids.sort.map { |id| @@records.detect { |r| r.id == id.to_i } }
         
     | 
| 
      
 24 
     | 
    
         
            +
                else
         
     | 
| 
      
 25 
     | 
    
         
            +
                  @@records.detect { |r| r.id == ids.to_i }
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
       16 
27 
     | 
    
         
             
              end
         
     | 
| 
       17 
28 
     | 
    
         | 
| 
       18 
29 
     | 
    
         
             
              def initialize(attributes = {})
         
     | 
    
        data/tasks/xapit.rake
    CHANGED
    
    | 
         @@ -1,9 +1 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
             
     | 
| 
       2 
     | 
    
         
            -
              desc "Index all xapit models."
         
     | 
| 
       3 
     | 
    
         
            -
              task :index => :environment do
         
     | 
| 
       4 
     | 
    
         
            -
                Xapit::Config.remove_database
         
     | 
| 
       5 
     | 
    
         
            -
                Xapit.index_all do |member_class|
         
     | 
| 
       6 
     | 
    
         
            -
                  puts "Indexing #{member_class.name}"
         
     | 
| 
       7 
     | 
    
         
            -
                end
         
     | 
| 
       8 
     | 
    
         
            -
              end
         
     | 
| 
       9 
     | 
    
         
            -
            end
         
     | 
| 
      
 1 
     | 
    
         
            +
            require File.join(File.dirname(__FILE__), '/../lib/xapit/rake_tasks')
         
     |