picky 4.10.0 → 4.11.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/lib/picky/backends/memory/json.rb +6 -3
- data/lib/picky/categories.rb +12 -0
- data/lib/picky/categories_indexed.rb +3 -1
- data/lib/picky/extensions/array.rb +1 -11
- data/lib/picky/extensions/class.rb +5 -3
- data/lib/picky/extensions/object.rb +13 -1
- data/lib/picky/generators/similarity/phonetic.rb +0 -2
- data/lib/picky/index.rb +33 -0
- data/lib/picky/index_facets.rb +9 -5
- data/lib/picky/loader.rb +4 -7
- data/lib/picky/pool.rb +10 -7
- data/lib/picky/qualifier_mapper.rb +51 -0
- data/lib/picky/query/boosts.rb +2 -2
- data/lib/picky/query/indexes.rb +1 -29
- data/lib/picky/query/token.rb +7 -3
- data/lib/picky/query/tokens.rb +0 -6
- data/lib/picky/search_facets.rb +45 -9
- data/lib/picky/sinatra.rb +2 -0
- data/lib/picky/tokenizer.rb +19 -11
- data/lib/picky.rb +3 -1
- data/spec/functional/facets_spec.rb +9 -13
- data/spec/functional/multi_index_qualifier_spec.rb +30 -0
- data/spec/functional/only_spec.rb +34 -32
- data/spec/functional/pool_spec.rb +82 -0
- data/spec/functional/remap_qualifiers_spec.rb +1 -9
- data/spec/lib/categories_indexed_spec.rb +2 -2
- data/spec/lib/extensions/array_spec.rb +19 -19
- data/spec/lib/extensions/object_spec.rb +14 -11
- data/spec/lib/extensions/symbol_spec.rb +1 -1
- data/spec/lib/generators/similarity/phonetic_spec.rb +14 -7
- data/spec/lib/picky_spec.rb +1 -1
- data/spec/lib/pool_spec.rb +17 -17
- data/spec/lib/{query/qualifier_category_mapper_spec.rb → qualifier_mapper_spec.rb} +8 -8
- data/spec/lib/query/token_spec.rb +17 -12
- data/spec/lib/rack/harakiri_spec.rb +5 -0
- data/spec/lib/tokenizer_spec.rb +44 -3
- metadata +11 -8
- data/lib/picky/migrations/from_30_to_31.rb +0 -61
- data/lib/picky/query/qualifier_category_mapper.rb +0 -61
| @@ -89,7 +89,7 @@ describe 'facets' do | |
| 89 89 | 
             
                  index = Picky::Index.new :facets do
         | 
| 90 90 | 
             
                    category :name
         | 
| 91 91 | 
             
                    category :surname
         | 
| 92 | 
            -
                    category :age_category
         | 
| 92 | 
            +
                    category :age_category, :qualifier => :age
         | 
| 93 93 | 
             
                  end
         | 
| 94 94 |  | 
| 95 95 | 
             
                  thing = Struct.new :id, :name, :surname, :age_category
         | 
| @@ -139,29 +139,27 @@ describe 'facets' do | |
| 139 139 | 
             
                  it 'is fast enough' do
         | 
| 140 140 | 
             
                    performance_of {
         | 
| 141 141 | 
             
                      10.times { finder.facets(:age_category, filter: 'surname:meier name:peter') }
         | 
| 142 | 
            -
                    }.should < 0. | 
| 142 | 
            +
                    }.should < 0.0032
         | 
| 143 143 | 
             
                  end
         | 
| 144 144 | 
             
                  it 'has one filtered facet' do
         | 
| 145 | 
            -
                    # TODO Fix problems with alternative qualifiers (like :age).
         | 
| 146 | 
            -
                    #
         | 
| 147 145 | 
             
                    finder.facets(:age_category, filter: 'surname:meier name:peter').should == {
         | 
| 148 146 | 
             
                      '45' => 1
         | 
| 149 147 | 
             
                    }
         | 
| 150 148 | 
             
                  end
         | 
| 151 149 | 
             
                  it 'has two filtered facets' do
         | 
| 152 | 
            -
                    finder.facets(:surname, filter: ' | 
| 150 | 
            +
                    finder.facets(:surname, filter: 'age:40 name:peter').should == {
         | 
| 153 151 | 
             
                      'kunz' => 1,
         | 
| 154 152 | 
             
                      'hanke' => 1 # Not 2 since it is filtered.
         | 
| 155 153 | 
             
                    }
         | 
| 156 154 | 
             
                  end
         | 
| 157 155 | 
             
                  it 'has 2 facets >= count 1' do
         | 
| 158 | 
            -
                    finder.facets(:surname, filter: ' | 
| 156 | 
            +
                    finder.facets(:surname, filter: 'age:40 name:peter', at_least: 1).should == {
         | 
| 159 157 | 
             
                      'kunz' => 1,
         | 
| 160 158 | 
             
                      'hanke' => 1
         | 
| 161 159 | 
             
                    }
         | 
| 162 160 | 
             
                  end
         | 
| 163 161 | 
             
                  it 'has 0 facets >= counts 2' do
         | 
| 164 | 
            -
                    finder.facets(:surname, filter: ' | 
| 162 | 
            +
                    finder.facets(:surname, filter: 'age:40 name:peter', at_least: 2).should == {}
         | 
| 165 163 | 
             
                  end
         | 
| 166 164 | 
             
                end
         | 
| 167 165 |  | 
| @@ -169,27 +167,25 @@ describe 'facets' do | |
| 169 167 | 
             
                  it 'is fast enough' do
         | 
| 170 168 | 
             
                    performance_of {
         | 
| 171 169 | 
             
                      10.times { finder.facets(:age_category, filter: 'surname:meier name:peter', counts: false) }
         | 
| 172 | 
            -
                    }.should < 0. | 
| 170 | 
            +
                    }.should < 0.003
         | 
| 173 171 | 
             
                  end
         | 
| 174 172 | 
             
                  it 'has one filtered facet' do
         | 
| 175 | 
            -
                    # TODO Fix problems with alternative qualifiers (like :age).
         | 
| 176 | 
            -
                    #
         | 
| 177 173 | 
             
                    finder.facets(:age_category, filter: 'surname:meier name:peter', counts: false).should == ['45']
         | 
| 178 174 | 
             
                  end
         | 
| 179 175 | 
             
                  it 'has two filtered facets' do
         | 
| 180 | 
            -
                    finder.facets(:surname, filter: ' | 
| 176 | 
            +
                    finder.facets(:surname, filter: 'age:40 name:peter', counts: false).should == [
         | 
| 181 177 | 
             
                      'kunz',
         | 
| 182 178 | 
             
                      'hanke'
         | 
| 183 179 | 
             
                    ]
         | 
| 184 180 | 
             
                  end
         | 
| 185 181 | 
             
                  it 'has 2 facets >= count 1' do
         | 
| 186 | 
            -
                    finder.facets(:surname, filter: ' | 
| 182 | 
            +
                    finder.facets(:surname, filter: 'age:40 name:peter', at_least: 1, counts: false).should == [
         | 
| 187 183 | 
             
                      'kunz',
         | 
| 188 184 | 
             
                      'hanke'
         | 
| 189 185 | 
             
                    ]
         | 
| 190 186 | 
             
                  end
         | 
| 191 187 | 
             
                  it 'has 0 facets >= counts 2' do
         | 
| 192 | 
            -
                    finder.facets(:surname, filter: ' | 
| 188 | 
            +
                    finder.facets(:surname, filter: 'age:40 name:peter', at_least: 2, counts: false).should == []
         | 
| 193 189 | 
             
                  end
         | 
| 194 190 | 
             
                end
         | 
| 195 191 |  | 
| @@ -0,0 +1,30 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
| 2 | 
            +
            #
         | 
| 3 | 
            +
            require 'spec_helper'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            describe 'Multi Index Qualifiers' do
         | 
| 6 | 
            +
              
         | 
| 7 | 
            +
              it 'resolves the same qualifier to different categories on each index' do
         | 
| 8 | 
            +
                people = Picky::Index.new :people do
         | 
| 9 | 
            +
                  category :title
         | 
| 10 | 
            +
                  category :name, qualifiers: [:name, :last_name]
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
                books = Picky::Index.new :books do
         | 
| 13 | 
            +
                  category :title, qualifiers: [:title, :name]
         | 
| 14 | 
            +
                  category :subtitle
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                person = Struct.new :id, :title, :name
         | 
| 18 | 
            +
                book   = Struct.new :id, :title, :subtitle
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                people.add person.new(1, 'mister', 'pedro maria alhambra madrugada')
         | 
| 21 | 
            +
                
         | 
| 22 | 
            +
                books.add book.new(2, 'the mister madrugada affair', 'the story of seventeen madrugada family members')
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                try = Picky::Search.new people, books
         | 
| 25 | 
            +
                
         | 
| 26 | 
            +
                try.search('title:mister').ids.should == [1, 2]
         | 
| 27 | 
            +
                try.search('name:madrugada').ids.should == [1, 2]
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
              
         | 
| 30 | 
            +
            end
         | 
| @@ -17,46 +17,48 @@ describe 'Search#only' do | |
| 17 17 | 
             
                try.search('text1').ids.should == [1]
         | 
| 18 18 | 
             
                try.search('text2').ids.should == [1]
         | 
| 19 19 | 
             
                try.search('text3').ids.should == [1]
         | 
| 20 | 
            +
                
         | 
| 21 | 
            +
                expect do
         | 
| 22 | 
            +
                  try_again = Picky::Search.new index do
         | 
| 23 | 
            +
                    only :category1
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
                  try_again.search('text1').ids.should == [1]
         | 
| 26 | 
            +
                  try_again.search('text2').ids.should == []
         | 
| 27 | 
            +
                  try_again.search('text3').ids.should == []
         | 
| 20 28 |  | 
| 21 | 
            -
             | 
| 22 | 
            -
                  only :category1
         | 
| 23 | 
            -
                end
         | 
| 24 | 
            -
                try_again.search('text1').ids.should == [1]
         | 
| 25 | 
            -
                try_again.search('text2').ids.should == []
         | 
| 26 | 
            -
                try_again.search('text3').ids.should == []
         | 
| 27 | 
            -
             | 
| 28 | 
            -
                try_again.only :category2, :category3
         | 
| 29 | 
            +
                  try_again.only :category2, :category3
         | 
| 29 30 |  | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 31 | 
            +
                  try_again.search('text1').ids.should == []
         | 
| 32 | 
            +
                  try_again.search('text2').ids.should == [1]
         | 
| 33 | 
            +
                  try_again.search('text3').ids.should == [1]
         | 
| 33 34 |  | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 35 | 
            +
                  try_again.search('category1:text1').ids.should == []
         | 
| 36 | 
            +
                  try_again.search('category1:text2').ids.should == []
         | 
| 37 | 
            +
                  try_again.search('category1:text3').ids.should == []
         | 
| 37 38 |  | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 39 | 
            +
                  try_again.search('category2:text1').ids.should == []
         | 
| 40 | 
            +
                  try_again.search('category2:text2').ids.should == [1]
         | 
| 41 | 
            +
                  try_again.search('category2:text3').ids.should == []
         | 
| 41 42 |  | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 44 | 
            -
             | 
| 43 | 
            +
                  try_again.search('category3:text1').ids.should == []
         | 
| 44 | 
            +
                  try_again.search('category3:text2').ids.should == []
         | 
| 45 | 
            +
                  try_again.search('category3:text3').ids.should == [1]
         | 
| 45 46 |  | 
| 46 | 
            -
             | 
| 47 | 
            -
             | 
| 48 | 
            -
             | 
| 47 | 
            +
                  try_again.search('category1,category2:text1').ids.should == []
         | 
| 48 | 
            +
                  try_again.search('category1,category2:text2').ids.should == [1]
         | 
| 49 | 
            +
                  try_again.search('category1,category2:text3').ids.should == []
         | 
| 49 50 |  | 
| 50 | 
            -
             | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 51 | 
            +
                  try_again.search('category1,category3:text1').ids.should == []
         | 
| 52 | 
            +
                  try_again.search('category1,category3:text2').ids.should == []
         | 
| 53 | 
            +
                  try_again.search('category1,category3:text3').ids.should == [1]
         | 
| 53 54 |  | 
| 54 | 
            -
             | 
| 55 | 
            -
             | 
| 56 | 
            -
             | 
| 55 | 
            +
                  try_again.search('category2,category3:text1').ids.should == []
         | 
| 56 | 
            +
                  try_again.search('category2,category3:text2').ids.should == [1]
         | 
| 57 | 
            +
                  try_again.search('category2,category3:text3').ids.should == [1]
         | 
| 57 58 |  | 
| 58 | 
            -
             | 
| 59 | 
            -
             | 
| 60 | 
            -
             | 
| 59 | 
            +
                  try_again.search('category1,category2,category3:text1').ids.should == []
         | 
| 60 | 
            +
                  try_again.search('category1,category2,category3:text2').ids.should == [1]
         | 
| 61 | 
            +
                  try_again.search('category1,category2,category3:text3').ids.should == [1]
         | 
| 62 | 
            +
                end.to raise_error
         | 
| 61 63 | 
             
              end
         | 
| 62 64 | 
             
            end
         | 
| @@ -0,0 +1,82 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
| 2 | 
            +
            #
         | 
| 3 | 
            +
            require 'spec_helper'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            require 'ostruct'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            describe 'GC stats: searching' do
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              PoolSpecThing = Struct.new :id, :first, :last, :other
         | 
| 10 | 
            +
              
         | 
| 11 | 
            +
              before(:each) do
         | 
| 12 | 
            +
                Picky::Indexes.clear_indexes
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
              
         | 
| 15 | 
            +
              let(:amount) { 5_000 }
         | 
| 16 | 
            +
              let(:data) do
         | 
| 17 | 
            +
                index = Picky::Index.new :sorted do
         | 
| 18 | 
            +
                  category :first
         | 
| 19 | 
            +
                  category :last
         | 
| 20 | 
            +
                  category :other
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
                3.times do |i|
         | 
| 23 | 
            +
                  index.add PoolSpecThing.new(i+1, 'Abracadabra', 'Mirgel',  'whatever it')
         | 
| 24 | 
            +
                  index.add PoolSpecThing.new(i+2, 'Abraham',     'Minder',  'is not too')
         | 
| 25 | 
            +
                  index.add PoolSpecThing.new(i+3, 'Azzie',       'Mueller', 'unimportant')
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
                index
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
              let(:search) { Picky::Search.new data }
         | 
| 30 | 
            +
             | 
| 31 | 
            +
              # TODO Study what the problem is.
         | 
| 32 | 
            +
              #
         | 
| 33 | 
            +
              context 'without pool' do
         | 
| 34 | 
            +
                it 'runs the GC more' do
         | 
| 35 | 
            +
                  # Quickly check if the pool is removed.
         | 
| 36 | 
            +
                  #
         | 
| 37 | 
            +
                  fail 'object pool still installed' if Picky::Query::Token.respond_to? :release_all
         | 
| 38 | 
            +
                  
         | 
| 39 | 
            +
                  try = search
         | 
| 40 | 
            +
                  query = 'abracadabra mirgel'
         | 
| 41 | 
            +
                  gc_runs_of do
         | 
| 42 | 
            +
                    amount.times { try.search query }
         | 
| 43 | 
            +
                  end.should <= 13
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
                it 'is less (?) performant' do
         | 
| 46 | 
            +
                  try = search
         | 
| 47 | 
            +
                  query = 'abracadabra mirgel'
         | 
| 48 | 
            +
                  performance_of do
         | 
| 49 | 
            +
                    amount.times { try.search query }
         | 
| 50 | 
            +
                  end.should <= 0.42
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
              end
         | 
| 53 | 
            +
              context 'with pool' do
         | 
| 54 | 
            +
                before(:each) do
         | 
| 55 | 
            +
                  Picky::Pool.install
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
                after(:each) do
         | 
| 58 | 
            +
                  # Reload since installing the Pool taints the classes.
         | 
| 59 | 
            +
                  #
         | 
| 60 | 
            +
                  Picky::Loader.load_framework
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
                it 'runs the GC less' do
         | 
| 63 | 
            +
                  # Quickly check that the pool is added.
         | 
| 64 | 
            +
                  #
         | 
| 65 | 
            +
                  fail 'object pool not installed' unless Picky::Query::Token.respond_to? :release_all
         | 
| 66 | 
            +
                  
         | 
| 67 | 
            +
                  try = search
         | 
| 68 | 
            +
                  query = 'abracadabra mirgel'
         | 
| 69 | 
            +
                  gc_runs_of do
         | 
| 70 | 
            +
                    amount.times { try.search query; Picky::Pool.release_all }
         | 
| 71 | 
            +
                  end.should <= 1 # Definitely less GC runs.
         | 
| 72 | 
            +
                end
         | 
| 73 | 
            +
                it 'is more (?) performant' do
         | 
| 74 | 
            +
                  try = search
         | 
| 75 | 
            +
                  query = 'abracadabra mirgel'
         | 
| 76 | 
            +
                  performance_of do
         | 
| 77 | 
            +
                    amount.times { try.search query }
         | 
| 78 | 
            +
                  end.should <= 0.42
         | 
| 79 | 
            +
                end
         | 
| 80 | 
            +
              end
         | 
| 81 | 
            +
              
         | 
| 82 | 
            +
            end
         | 
| @@ -28,15 +28,7 @@ describe 'qualifier remapping' do | |
| 28 28 | 
             
                #
         | 
| 29 29 | 
             
                try.search('b').ids.should == [2]
         | 
| 30 30 |  | 
| 31 | 
            -
                #  | 
| 32 | 
            -
                #
         | 
| 33 | 
            -
                try.search('b:b').ids.should == []
         | 
| 34 | 
            -
                
         | 
| 35 | 
            -
                # So remap the qualifiers.
         | 
| 36 | 
            -
                #
         | 
| 37 | 
            -
                try.remap_qualifiers
         | 
| 38 | 
            -
                
         | 
| 39 | 
            -
                # Now it works!
         | 
| 31 | 
            +
                # It already also finds it with a qualifier!
         | 
| 40 32 | 
             
                #
         | 
| 41 33 | 
             
                try.search('b:b').ids.should == [2]
         | 
| 42 34 | 
             
              end
         | 
| @@ -83,7 +83,7 @@ describe Picky::Categories do | |
| 83 83 | 
             
                  end
         | 
| 84 84 | 
             
                  context "with similar token" do
         | 
| 85 85 | 
             
                    before(:each) do
         | 
| 86 | 
            -
                      @token.stub :similar? => true
         | 
| 86 | 
            +
                      @token.stub :similar? => true, :categorize => nil
         | 
| 87 87 | 
             
                    end
         | 
| 88 88 | 
             
                    it "calls the right method" do
         | 
| 89 89 | 
             
                      @categories.should_receive(:similar_possible_for).once.with @token
         | 
| @@ -93,7 +93,7 @@ describe Picky::Categories do | |
| 93 93 | 
             
                  end
         | 
| 94 94 | 
             
                  context "with non-similar token" do
         | 
| 95 95 | 
             
                    before(:each) do
         | 
| 96 | 
            -
                      @token.stub :similar? => false
         | 
| 96 | 
            +
                      @token.stub :similar? => false, :categorize => nil
         | 
| 97 97 | 
             
                    end
         | 
| 98 98 | 
             
                    it "calls the right method" do
         | 
| 99 99 | 
             
                      @categories.should_receive(:possible_for).once.with @token
         | 
| @@ -8,24 +8,6 @@ describe Array do | |
| 8 8 | 
             
                end
         | 
| 9 9 | 
             
              end
         | 
| 10 10 |  | 
| 11 | 
            -
              describe "clustered_uniq_fast" do
         | 
| 12 | 
            -
                it "should generate a new array" do
         | 
| 13 | 
            -
                  ary = [:test1, :test2, :test1]
         | 
| 14 | 
            -
                  ary.clustered_uniq_fast.object_id.should_not == ary.object_id
         | 
| 15 | 
            -
                end
         | 
| 16 | 
            -
                it "should not change clusteredly unique arrays" do
         | 
| 17 | 
            -
                  [:test1, :test2, :test1].clustered_uniq_fast.should == [:test1, :test2, :test1]
         | 
| 18 | 
            -
                end
         | 
| 19 | 
            -
                it "should not skip interspersed elements" do
         | 
| 20 | 
            -
                  [:test1, :test1, :test2, :test1].clustered_uniq_fast.should == [:test1, :test2, :test1]
         | 
| 21 | 
            -
                end
         | 
| 22 | 
            -
                it "should work like uniq if no interspersed elements exist" do
         | 
| 23 | 
            -
                  [:test1, :test1, :test2, :test2, :test3].clustered_uniq_fast.should == [:test1, :test2, :test3]
         | 
| 24 | 
            -
                end
         | 
| 25 | 
            -
                it "is fast" do
         | 
| 26 | 
            -
                  performance_of { [:test1, :test1, :test2, :test2, :test3].clustered_uniq_fast }.should < 0.00001
         | 
| 27 | 
            -
                end
         | 
| 28 | 
            -
              end
         | 
| 29 11 | 
             
              describe "clustered_uniq" do
         | 
| 30 12 | 
             
                it "should generate a new array" do
         | 
| 31 13 | 
             
                  ary = [:test1, :test2, :test1]
         | 
| @@ -41,8 +23,26 @@ describe Array do | |
| 41 23 | 
             
                  [:test1, :test1, :test2, :test2, :test3].clustered_uniq.should == [:test1, :test2, :test3]
         | 
| 42 24 | 
             
                end
         | 
| 43 25 | 
             
                it "is fast" do
         | 
| 44 | 
            -
                  performance_of { [:test1, :test1, :test2, :test2, :test3].clustered_uniq }.should < 0. | 
| 26 | 
            +
                  performance_of { [:test1, :test1, :test2, :test2, :test3].clustered_uniq }.should < 0.00001
         | 
| 45 27 | 
             
                end
         | 
| 46 28 | 
             
              end
         | 
| 29 | 
            +
              # describe "clustered_uniq" do
         | 
| 30 | 
            +
              #   it "should generate a new array" do
         | 
| 31 | 
            +
              #     ary = [:test1, :test2, :test1]
         | 
| 32 | 
            +
              #     ary.clustered_uniq.object_id.should_not == ary.object_id
         | 
| 33 | 
            +
              #   end
         | 
| 34 | 
            +
              #   it "should not change clusteredly unique arrays" do
         | 
| 35 | 
            +
              #     [:test1, :test2, :test1].clustered_uniq.should == [:test1, :test2, :test1]
         | 
| 36 | 
            +
              #   end
         | 
| 37 | 
            +
              #   it "should not skip interspersed elements" do
         | 
| 38 | 
            +
              #     [:test1, :test1, :test2, :test1].clustered_uniq.should == [:test1, :test2, :test1]
         | 
| 39 | 
            +
              #   end
         | 
| 40 | 
            +
              #   it "should work like uniq if no interspersed elements exist" do
         | 
| 41 | 
            +
              #     [:test1, :test1, :test2, :test2, :test3].clustered_uniq.should == [:test1, :test2, :test3]
         | 
| 42 | 
            +
              #   end
         | 
| 43 | 
            +
              #   it "is fast" do
         | 
| 44 | 
            +
              #     performance_of { [:test1, :test1, :test2, :test2, :test3].clustered_uniq }.should < 0.000012
         | 
| 45 | 
            +
              #   end
         | 
| 46 | 
            +
              # end
         | 
| 47 47 |  | 
| 48 48 | 
             
            end
         | 
| @@ -1,19 +1,12 @@ | |
| 1 1 | 
             
            require 'spec_helper'
         | 
| 2 2 |  | 
| 3 | 
            +
            require 'time'
         | 
| 4 | 
            +
             | 
| 3 5 | 
             
            describe Object do
         | 
| 4 6 |  | 
| 5 7 | 
             
              context 'basic object' do
         | 
| 6 8 | 
             
                let(:object) { described_class.new }
         | 
| 7 9 |  | 
| 8 | 
            -
                # describe "exclaim" do
         | 
| 9 | 
            -
                #   it "delegates to puts" do
         | 
| 10 | 
            -
                #     STDOUT.should_receive(:puts).once.with :bla
         | 
| 11 | 
            -
                #     STDOUT.should_receive(:flush).once.with
         | 
| 12 | 
            -
                #
         | 
| 13 | 
            -
                #     object.exclaim :bla
         | 
| 14 | 
            -
                #   end
         | 
| 15 | 
            -
                # end
         | 
| 16 | 
            -
             | 
| 17 10 | 
             
                describe "timed_exclaim" do
         | 
| 18 11 | 
             
                  it "should exclaim right" do
         | 
| 19 12 | 
             
                    Time.stub! :now => Time.parse('07-03-1977 12:34:56')
         | 
| @@ -25,8 +18,18 @@ describe Object do | |
| 25 18 |  | 
| 26 19 | 
             
                describe 'warn_gem_missing' do
         | 
| 27 20 | 
             
                  it 'should warn right' do
         | 
| 28 | 
            -
                     | 
| 29 | 
            -
             | 
| 21 | 
            +
                    Picky.logger.should_receive(:warn).once.with <<-EXPECTED
         | 
| 22 | 
            +
            Warning: gnorf gem missing!
         | 
| 23 | 
            +
            To use gnarble gnarf, you need to:
         | 
| 24 | 
            +
              1. Add the following line to Gemfile:
         | 
| 25 | 
            +
                 gem 'gnorf'
         | 
| 26 | 
            +
                 or
         | 
| 27 | 
            +
                 require 'gnorf'
         | 
| 28 | 
            +
                 for example at the top of your app.rb file.
         | 
| 29 | 
            +
              2. Then, run:
         | 
| 30 | 
            +
                 bundle update
         | 
| 31 | 
            +
            EXPECTED
         | 
| 32 | 
            +
                    
         | 
| 30 33 | 
             
                    object.warn_gem_missing 'gnorf', 'gnarble gnarf'
         | 
| 31 34 | 
             
                  end
         | 
| 32 35 | 
             
                end
         | 
| @@ -13,7 +13,7 @@ describe Symbol do | |
| 13 13 | 
             
                  performance_of { @token.each_subtoken { |subtoken| } }.should < 0.00065
         | 
| 14 14 | 
             
                end
         | 
| 15 15 | 
             
                it 'is fast enough' do
         | 
| 16 | 
            -
                  performance_of { @token.each_intoken { |intoken| } }.should < 0. | 
| 16 | 
            +
                  performance_of { @token.each_intoken { |intoken| } }.should < 0.0375
         | 
| 17 17 | 
             
                end
         | 
| 18 18 | 
             
              end
         | 
| 19 19 |  | 
| @@ -2,20 +2,27 @@ | |
| 2 2 | 
             
            #
         | 
| 3 3 | 
             
            require 'spec_helper'
         | 
| 4 4 |  | 
| 5 | 
            -
             | 
| 5 | 
            +
            require 'text'
         | 
| 6 6 |  | 
| 7 | 
            -
             | 
| 8 | 
            -
                expect {
         | 
| 9 | 
            -
                  described_class.new
         | 
| 10 | 
            -
                }.to raise_error("In Picky 2.0+, the Similarity::Phonetic has been renamed to Similarity::DoubleMetaphone. Please use that one. Thanks!")
         | 
| 11 | 
            -
              end
         | 
| 7 | 
            +
            describe Picky::Generators::Similarity::Phonetic do
         | 
| 12 8 |  | 
| 13 9 | 
             
              it "raises when you don't have the text gem" do
         | 
| 14 10 | 
             
                instance = Class.new(described_class).allocate
         | 
| 15 11 |  | 
| 16 12 | 
             
                instance.should_receive(:require).any_number_of_times.and_raise LoadError
         | 
| 13 | 
            +
                
         | 
| 14 | 
            +
                Picky.logger.should_receive(:warn).once.with <<-EXPECTED
         | 
| 15 | 
            +
            Warning: text gem missing!
         | 
| 16 | 
            +
            To use a phonetic Similarity, you need to:
         | 
| 17 | 
            +
              1. Add the following line to Gemfile:
         | 
| 18 | 
            +
                 gem 'text'
         | 
| 19 | 
            +
                 or
         | 
| 20 | 
            +
                 require 'text'
         | 
| 21 | 
            +
                 for example at the top of your app.rb file.
         | 
| 22 | 
            +
              2. Then, run:
         | 
| 23 | 
            +
                 bundle update
         | 
| 24 | 
            +
            EXPECTED
         | 
| 17 25 |  | 
| 18 | 
            -
                instance.should_receive(:warn).once.with "text gem missing!\nTo use a phonetic Similarity, you need to:\n  1. Add the following line to Gemfile:\n     gem 'text'\n  2. Then, run:\n     bundle update\n"
         | 
| 19 26 | 
             
                instance.should_receive(:exit).once.with 1
         | 
| 20 27 |  | 
| 21 28 | 
             
                instance.send :initialize
         | 
    
        data/spec/lib/picky_spec.rb
    CHANGED
    
    | @@ -5,7 +5,7 @@ describe Picky do | |
| 5 5 | 
             
              it 'sets the right internal encoding' do
         | 
| 6 6 | 
             
                Encoding.default_external.should == Encoding::UTF_8
         | 
| 7 7 | 
             
              end
         | 
| 8 | 
            -
              #  | 
| 8 | 
            +
              # THINK What to set default external encoding to?
         | 
| 9 9 | 
             
              #
         | 
| 10 10 | 
             
              # it 'sets the right external encoding' do
         | 
| 11 11 | 
             
              #   Encoding.default_internal.should == Encoding::UTF_8
         | 
    
        data/spec/lib/pool_spec.rb
    CHANGED
    
    | @@ -4,7 +4,7 @@ require 'spec_helper' | |
| 4 4 |  | 
| 5 5 | 
             
            describe Picky::Pool do
         | 
| 6 6 |  | 
| 7 | 
            -
              let(: | 
| 7 | 
            +
              let(:pool_klass) do
         | 
| 8 8 | 
             
                Class.new do
         | 
| 9 9 | 
             
                  extend Picky::Pool
         | 
| 10 10 |  | 
| @@ -30,50 +30,50 @@ describe Picky::Pool do | |
| 30 30 | 
             
              context 'functional' do
         | 
| 31 31 | 
             
                before(:each) do
         | 
| 32 32 | 
             
                  described_class.clear
         | 
| 33 | 
            -
                   | 
| 33 | 
            +
                  pool_klass.clear
         | 
| 34 34 | 
             
                  other.clear
         | 
| 35 35 | 
             
                end
         | 
| 36 36 | 
             
                it 'lets me get an instance' do
         | 
| 37 | 
            -
                   | 
| 37 | 
            +
                  pool_klass.new(1).should be_kind_of(pool_klass)
         | 
| 38 38 | 
             
                end
         | 
| 39 39 | 
             
                it 'does not create a new reference if it has free ones' do
         | 
| 40 | 
            -
                  p1 =  | 
| 41 | 
            -
                  p2 =  | 
| 40 | 
            +
                  p1 = pool_klass.new 1
         | 
| 41 | 
            +
                  p2 = pool_klass.new 2
         | 
| 42 42 | 
             
                  p1.release
         | 
| 43 43 |  | 
| 44 | 
            -
                   | 
| 44 | 
            +
                  pool_klass.free_size.should == 1
         | 
| 45 45 | 
             
                end
         | 
| 46 46 | 
             
                it 'gives me the released reference if I try to new' do
         | 
| 47 | 
            -
                  p1 =  | 
| 48 | 
            -
                  p2 =  | 
| 47 | 
            +
                  p1 = pool_klass.new 1
         | 
| 48 | 
            +
                  p2 = pool_klass.new 2
         | 
| 49 49 | 
             
                  p1.release
         | 
| 50 50 |  | 
| 51 | 
            -
                   | 
| 51 | 
            +
                  pool_klass.new(3).number.should == 3
         | 
| 52 52 | 
             
                end
         | 
| 53 53 | 
             
                it 'releases all PoolTests if called on PoolTest' do
         | 
| 54 | 
            -
                  p1 =  | 
| 55 | 
            -
                   | 
| 54 | 
            +
                  p1 = pool_klass.new 1
         | 
| 55 | 
            +
                  pool_klass.new 2
         | 
| 56 56 | 
             
                  other.new 1
         | 
| 57 57 | 
             
                  other.new 2
         | 
| 58 58 |  | 
| 59 59 | 
             
                  other.free_size.should == 0 
         | 
| 60 60 |  | 
| 61 | 
            -
                   | 
| 61 | 
            +
                  pool_klass.release_all
         | 
| 62 62 |  | 
| 63 | 
            -
                   | 
| 63 | 
            +
                  pool_klass.new(3).should == p1
         | 
| 64 64 | 
             
                  other.free_size.should == 0
         | 
| 65 65 | 
             
                end
         | 
| 66 66 | 
             
                it 'releases all if called on Pool' do
         | 
| 67 | 
            -
                   | 
| 68 | 
            -
                   | 
| 67 | 
            +
                  pool_klass.new 1
         | 
| 68 | 
            +
                  pool_klass.new 2
         | 
| 69 69 | 
             
                  other.new 1
         | 
| 70 70 | 
             
                  other.new 2
         | 
| 71 71 |  | 
| 72 | 
            -
                   | 
| 72 | 
            +
                  pool_klass.free_size.should == 0
         | 
| 73 73 |  | 
| 74 74 | 
             
                  described_class.release_all
         | 
| 75 75 |  | 
| 76 | 
            -
                   | 
| 76 | 
            +
                  pool_klass.free_size.should == 2
         | 
| 77 77 | 
             
                end
         | 
| 78 78 | 
             
              end
         | 
| 79 79 |  | 
| @@ -1,16 +1,16 @@ | |
| 1 1 | 
             
            require 'spec_helper'
         | 
| 2 2 |  | 
| 3 | 
            -
            describe Picky:: | 
| 3 | 
            +
            describe Picky::QualifierMapper do
         | 
| 4 4 |  | 
| 5 | 
            -
              let(: | 
| 6 | 
            -
                 | 
| 7 | 
            -
                 | 
| 8 | 
            -
                @ | 
| 9 | 
            -
                @ | 
| 5 | 
            +
              let(:categories) do
         | 
| 6 | 
            +
                index      = Picky::Index.new :test
         | 
| 7 | 
            +
                categories = Picky::Categories.new
         | 
| 8 | 
            +
                @category1 = categories << Picky::Category.new(:category1, index, :qualifiers => ['t1', 'tt1', 'ttt1'])
         | 
| 9 | 
            +
                @category2 = categories << Picky::Category.new(:category2, index, :qualifiers => [:t2, :tt2, :ttt2])
         | 
| 10 | 
            +
                @category3 = categories << Picky::Category.new(:category3, index, :qualifiers => [:t3, :tt3, :ttt3])
         | 
| 10 11 | 
             
                categories
         | 
| 11 12 | 
             
              end
         | 
| 12 | 
            -
              let(: | 
| 13 | 
            -
              let(:mapper) { described_class.new indexes }
         | 
| 13 | 
            +
              let(:mapper) { described_class.new categories }
         | 
| 14 14 |  | 
| 15 15 | 
             
              def self.it_should_map(qualifier, expected)
         | 
| 16 16 | 
             
                it "should map #{qualifier} to #{expected}" do
         | 
| @@ -14,17 +14,20 @@ describe Picky::Query::Token do | |
| 14 14 |  | 
| 15 15 | 
             
              describe 'categorize' do
         | 
| 16 16 | 
             
                let(:mapper) do
         | 
| 17 | 
            -
                   | 
| 18 | 
            -
                   | 
| 19 | 
            -
                   | 
| 20 | 
            -
                   | 
| 21 | 
            -
                  Picky:: | 
| 17 | 
            +
                  # TODO Can we remove the index?
         | 
| 18 | 
            +
                  #
         | 
| 19 | 
            +
                  index      = Picky::Index.new :mapper
         | 
| 20 | 
            +
                  categories = Picky::Categories.new
         | 
| 21 | 
            +
                  @category1 = categories << Picky::Category.new(:category1, index)
         | 
| 22 | 
            +
                  @category2 = categories << Picky::Category.new(:category2, index)
         | 
| 23 | 
            +
                  @category3 = categories << Picky::Category.new(:category3, index)
         | 
| 24 | 
            +
                  Picky::QualifierMapper.new categories
         | 
| 22 25 | 
             
                end
         | 
| 23 26 | 
             
                context 'with qualifiers' do
         | 
| 24 27 | 
             
                  let(:token) { described_class.processed 'category1:qualifier', 'category1:Qualifier' }
         | 
| 25 28 | 
             
                  context 'unrestricted' do
         | 
| 26 29 | 
             
                    it 'categorizes correctly' do
         | 
| 27 | 
            -
                      token. | 
| 30 | 
            +
                      token.predefined_categories(mapper).should == [@category1]
         | 
| 28 31 | 
             
                    end
         | 
| 29 32 | 
             
                  end
         | 
| 30 33 | 
             
                  context 'restricted' do
         | 
| @@ -32,7 +35,7 @@ describe Picky::Query::Token do | |
| 32 35 | 
             
                      mapper.restrict_to :category1
         | 
| 33 36 | 
             
                    end
         | 
| 34 37 | 
             
                    it 'categorizes correctly' do
         | 
| 35 | 
            -
                      token. | 
| 38 | 
            +
                      token.predefined_categories(mapper).should == [@category1]
         | 
| 36 39 | 
             
                    end
         | 
| 37 40 | 
             
                  end
         | 
| 38 41 | 
             
                  context 'restricted' do
         | 
| @@ -40,7 +43,7 @@ describe Picky::Query::Token do | |
| 40 43 | 
             
                      mapper.restrict_to :category2, :category3
         | 
| 41 44 | 
             
                    end
         | 
| 42 45 | 
             
                    it 'categorizes correctly' do
         | 
| 43 | 
            -
                      token. | 
| 46 | 
            +
                      token.predefined_categories(mapper).should == []
         | 
| 44 47 | 
             
                    end
         | 
| 45 48 | 
             
                  end
         | 
| 46 49 | 
             
                end
         | 
| @@ -48,7 +51,7 @@ describe Picky::Query::Token do | |
| 48 51 | 
             
                  let(:token) { described_class.processed 'noqualifier', 'NoQualifier' }
         | 
| 49 52 | 
             
                  context 'unrestricted' do
         | 
| 50 53 | 
             
                    it 'categorizes correctly' do
         | 
| 51 | 
            -
                      token. | 
| 54 | 
            +
                      token.predefined_categories(mapper).should == nil
         | 
| 52 55 | 
             
                    end
         | 
| 53 56 | 
             
                  end
         | 
| 54 57 | 
             
                  context 'restricted' do
         | 
| @@ -56,7 +59,7 @@ describe Picky::Query::Token do | |
| 56 59 | 
             
                      mapper.restrict_to :category1
         | 
| 57 60 | 
             
                    end
         | 
| 58 61 | 
             
                    it 'categorizes correctly' do
         | 
| 59 | 
            -
                      token. | 
| 62 | 
            +
                      token.predefined_categories(mapper).should == [@category1]
         | 
| 60 63 | 
             
                    end
         | 
| 61 64 | 
             
                  end
         | 
| 62 65 | 
             
                  context 'restricted' do
         | 
| @@ -64,7 +67,7 @@ describe Picky::Query::Token do | |
| 64 67 | 
             
                      mapper.restrict_to :category2, :category3
         | 
| 65 68 | 
             
                    end
         | 
| 66 69 | 
             
                    it 'categorizes correctly' do
         | 
| 67 | 
            -
                      token. | 
| 70 | 
            +
                      token.predefined_categories(mapper).should == [@category2, @category3]
         | 
| 68 71 | 
             
                    end
         | 
| 69 72 | 
             
                  end
         | 
| 70 73 | 
             
                end
         | 
| @@ -94,7 +97,9 @@ describe Picky::Query::Token do | |
| 94 97 | 
             
                    token.similar_tokens_for(@category).map(&:original).should == ['array', 'of', 'similar']
         | 
| 95 98 | 
             
                  end
         | 
| 96 99 | 
             
                  it 'returns a list of tokens with the right categorization' do
         | 
| 97 | 
            -
                    token.similar_tokens_for(@category).map | 
| 100 | 
            +
                    token.similar_tokens_for(@category).map do |token|
         | 
| 101 | 
            +
                      token.predefined_categories nil # TODO Clean this up.
         | 
| 102 | 
            +
                    end.should == [[@category], [@category], [@category]]
         | 
| 98 103 | 
             
                  end
         | 
| 99 104 | 
             
                end
         | 
| 100 105 | 
             
                context 'without similar' do
         |