picky 4.3.0 → 4.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
| @@ -1,6 +1,8 @@ | |
| 1 1 | 
             
            module Picky
         | 
| 2 2 |  | 
| 3 3 | 
             
              class Category
         | 
| 4 | 
            +
                
         | 
| 5 | 
            +
                class Picky::IdNotGivenException < StandardError; end
         | 
| 4 6 |  | 
| 5 7 | 
             
                # Removes an indexed object with the
         | 
| 6 8 | 
             
                # given id.
         | 
| @@ -31,11 +33,9 @@ module Picky | |
| 31 33 | 
             
                # Note: Takes a hash as opposed to the add/replace method.
         | 
| 32 34 | 
             
                #
         | 
| 33 35 | 
             
                def replace_from hash
         | 
| 34 | 
            -
                  # TODO Decide on a format.
         | 
| 35 | 
            -
                  #
         | 
| 36 36 | 
             
                  return unless text = hash[from] || hash[from.to_s]
         | 
| 37 37 |  | 
| 38 | 
            -
                  id = hash[:id] || hash['id']
         | 
| 38 | 
            +
                  raise IdNotGivenException.new unless id = hash[:id] || hash['id']
         | 
| 39 39 | 
             
                  id = id.send key_format
         | 
| 40 40 |  | 
| 41 41 | 
             
                  remove id
         | 
| @@ -4,18 +4,44 @@ module Picky | |
| 4 4 | 
             
                module IndexActions
         | 
| 5 5 |  | 
| 6 6 | 
             
                  def self.extended base
         | 
| 7 | 
            +
                    # Updates the given item and returns HTTP codes:
         | 
| 8 | 
            +
                    #  * 200 if the index has been updated or no error case has occurred.
         | 
| 9 | 
            +
                    #  * 404 if the index cannot be found.
         | 
| 10 | 
            +
                    #  * 400 if no data or item id has been provided in the data.
         | 
| 11 | 
            +
                    #
         | 
| 12 | 
            +
                    # Note: 200 returns no data yet.
         | 
| 13 | 
            +
                    #
         | 
| 7 14 | 
             
                    base.post '/' do
         | 
| 8 15 | 
             
                      index_name = params['index']
         | 
| 9 | 
            -
                       | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 16 | 
            +
                      begin
         | 
| 17 | 
            +
                        index = Picky::Indexes[index_name.to_sym]
         | 
| 18 | 
            +
                        data = params['data']
         | 
| 19 | 
            +
                        return 400 unless data
         | 
| 20 | 
            +
                        data && index.replace_from(Yajl::Parser.parse data) && 200
         | 
| 21 | 
            +
                      rescue IdNotGivenException
         | 
| 22 | 
            +
                        400
         | 
| 23 | 
            +
                      rescue StandardError
         | 
| 24 | 
            +
                        404
         | 
| 25 | 
            +
                      end
         | 
| 12 26 | 
             
                    end
         | 
| 27 | 
            +
                    
         | 
| 28 | 
            +
                    # Deletes the given item and returns:
         | 
| 29 | 
            +
                    #  * 200 if the index has been updated or no error case has occurred.
         | 
| 30 | 
            +
                    #  * 404 if the index cannot be found.
         | 
| 31 | 
            +
                    #  * 400 if no data or item id has been provided in the data.
         | 
| 32 | 
            +
                    #
         | 
| 33 | 
            +
                    # Note: 200 returns no data yet.
         | 
| 34 | 
            +
                    #
         | 
| 13 35 | 
             
                    base.delete '/' do
         | 
| 14 36 | 
             
                      index_name = params['index']
         | 
| 15 | 
            -
                       | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 37 | 
            +
                      begin
         | 
| 38 | 
            +
                        index = Picky::Indexes[index_name.to_sym]
         | 
| 39 | 
            +
                        data = Yajl::Parser.parse params['data']
         | 
| 40 | 
            +
                        id = data['id']
         | 
| 41 | 
            +
                        id ? index.remove(id) && 200 : 400
         | 
| 42 | 
            +
                      rescue StandardError
         | 
| 43 | 
            +
                        404
         | 
| 44 | 
            +
                      end
         | 
| 19 45 | 
             
                    end
         | 
| 20 46 | 
             
                  end
         | 
| 21 47 |  | 
| @@ -29,5 +29,16 @@ describe Picky::Category, "Realtime API" do | |
| 29 29 | 
             
              it 'offers an unshift method' do
         | 
| 30 30 | 
             
                category.unshift Thing.new(1, 'text')
         | 
| 31 31 | 
             
              end
         | 
| 32 | 
            +
              it 'offers a replace_from method' do
         | 
| 33 | 
            +
                category.replace_from id: 1, text: "some text"
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
              it 'raises on no id given' do
         | 
| 36 | 
            +
                expect {
         | 
| 37 | 
            +
                  category.replace_from text: "some text"
         | 
| 38 | 
            +
                }.to raise_error
         | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
              it 'shrugs off no data given' do
         | 
| 41 | 
            +
                category.replace_from id: 1
         | 
| 42 | 
            +
              end
         | 
| 32 43 |  | 
| 33 44 | 
             
            end
         | 
| @@ -0,0 +1,72 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
| 2 | 
            +
            #
         | 
| 3 | 
            +
            require 'spec_helper'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            describe Picky::Tokenizer do
         | 
| 6 | 
            +
              describe 'examples' do
         | 
| 7 | 
            +
                it 'works correctly' do
         | 
| 8 | 
            +
                  tokenizer = described_class.new(split_words_on: /\&/, normalizes_words: [[/\&/, 'and']])
         | 
| 9 | 
            +
                  
         | 
| 10 | 
            +
                  # TODO Is this really correct? Shouldn't we split after normalizing? 
         | 
| 11 | 
            +
                  #
         | 
| 12 | 
            +
                  tokenizer.tokenize('M & M').should == [['m', 'and', 'm'], ['m', 'and', 'm']]
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
                it 'works correctly' do
         | 
| 15 | 
            +
                  tokenizer = described_class.new(stopwords: /\b(and)\b/, normalizes_words: [[/\&/, 'and']])
         | 
| 16 | 
            +
                  
         | 
| 17 | 
            +
                  # TODO Is this really correct? Shouldn't we stop words after normalizing? 
         | 
| 18 | 
            +
                  #
         | 
| 19 | 
            +
                  tokenizer.tokenize('M & M').should == [['m', 'and', 'm'], ['m', 'and', 'm']]
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
                it 'removes all stopwords if they do not occur alone' do
         | 
| 22 | 
            +
                  tokenizer = described_class.new(stopwords: /\b(and|then)\b/)
         | 
| 23 | 
            +
                  tokenizer.tokenize('and then').should == [[], []]
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
                it 'does not remove a stopword if it occurs alone' do
         | 
| 26 | 
            +
                  tokenizer = described_class.new(stopwords: /\b(and|then)\b/)
         | 
| 27 | 
            +
                  tokenizer.tokenize('and').should == [['and'], ['and']]
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
                it 'does not remove a stopword if it occurs alone (even with qualifier)' do
         | 
| 30 | 
            +
                  tokenizer = described_class.new(stopwords: /\b(and|then)\b/)
         | 
| 31 | 
            +
                  tokenizer.tokenize('title:and').should == [['title:and'], ['title:and']]
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
                it 'does not remove a stopword if it occurs alone (even with qualifier)' do
         | 
| 34 | 
            +
                  tokenizer = described_class.new(stopwords: /\b(and|then)\b/)
         | 
| 35 | 
            +
                  tokenizer.tokenize('title:and').should == [['title:and'], ['title:and']]
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
                it 'removes stopwords, then only lets through max words words' do
         | 
| 38 | 
            +
                  tokenizer = described_class.new(stopwords: /\b(and|then|to|the)\b/, max_words: 2)
         | 
| 39 | 
            +
                  tokenizer.tokenize('and then they went to the house').should == [['they', 'went'], ['they', 'went']]
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
                it 'can take freaky splits_text_on options' do
         | 
| 42 | 
            +
                  tokenizer = described_class.new(splits_text_on: /([A-Z]?[a-z]+)/, case_sensitive: false) # Explicit case, is false by default.
         | 
| 43 | 
            +
                  tokenizer.tokenize('TOTALCamelCaseExample').should == [
         | 
| 44 | 
            +
                    ["total", "camel", "case", "example"],
         | 
| 45 | 
            +
                    ["total", "camel", "case", "example"]
         | 
| 46 | 
            +
                  ]
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
                it 'substitutes and removes in the right order' do
         | 
| 49 | 
            +
                  tokenizer = described_class.new(
         | 
| 50 | 
            +
                    substitutes_characters_with: Picky::CharacterSubstituters::WestEuropean.new,
         | 
| 51 | 
            +
                    removes_characters: /e/
         | 
| 52 | 
            +
                  )
         | 
| 53 | 
            +
                  
         | 
| 54 | 
            +
                  # Ä -> Ae -> A
         | 
| 55 | 
            +
                  #
         | 
| 56 | 
            +
                  tokenizer.tokenize('Ä ä').should == [['a', 'a'], ['a', 'a']]
         | 
| 57 | 
            +
                end
         | 
| 58 | 
            +
                it 'removes characters, then only lets through an ok sized token' do
         | 
| 59 | 
            +
                  tokenizer = described_class.new(rejects_token_if: ->(token){ token.size >= 5 }, removes_characters: /e/)
         | 
| 60 | 
            +
                  tokenizer.tokenize('hullo').should == [[], []]
         | 
| 61 | 
            +
                  tokenizer.tokenize('hello').should == [['hllo'], ['hllo']]
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
                it 'is case sensitive' do
         | 
| 64 | 
            +
                  tokenizer = described_class.new(case_sensitive: true)
         | 
| 65 | 
            +
                  tokenizer.tokenize('Kaspar codes').should == [['Kaspar', 'codes'], ['Kaspar', 'codes']]
         | 
| 66 | 
            +
                end
         | 
| 67 | 
            +
                it 'is case sensitive, also for removing characters' do
         | 
| 68 | 
            +
                  tokenizer = described_class.new(case_sensitive: true, removes_characters: /K/)
         | 
| 69 | 
            +
                  tokenizer.tokenize('Kaspar codes').should == [['aspar', 'codes'], ['aspar', 'codes']]
         | 
| 70 | 
            +
                end
         | 
| 71 | 
            +
              end
         | 
| 72 | 
            +
            end
         | 
| @@ -1,61 +1,196 @@ | |
| 1 1 | 
             
            require 'yajl'
         | 
| 2 2 | 
             
            require 'sinatra'
         | 
| 3 | 
            -
             | 
| 3 | 
            +
            require_relative '../../../client/lib/picky-client'
         | 
| 4 | 
            +
            require_relative '../../../client/lib/picky-client/spec'
         | 
| 4 5 | 
             
            require 'spec_helper'
         | 
| 5 6 |  | 
| 6 7 | 
             
            describe 'Sinatra Index Actions' do
         | 
| 7 8 |  | 
| 8 | 
            -
               | 
| 9 | 
            -
              #
         | 
| 10 | 
            -
              class MyPickyServer < Sinatra::Base
         | 
| 11 | 
            -
                extend Picky::Sinatra::IndexActions
         | 
| 9 | 
            +
              before(:all) do
         | 
| 12 10 |  | 
| 13 | 
            -
                 | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 11 | 
            +
                # This is the application that is tested.
         | 
| 12 | 
            +
                #
         | 
| 13 | 
            +
                class MyIndexActionsPickyServer < Sinatra::Base
         | 
| 14 | 
            +
                  extend Picky::Sinatra::IndexActions
         | 
| 15 | 
            +
                
         | 
| 16 | 
            +
                  data = Picky::Index.new :some_index do
         | 
| 17 | 
            +
                    category :name
         | 
| 18 | 
            +
                    category :surname
         | 
| 19 | 
            +
                  end
         | 
| 17 20 |  | 
| 18 | 
            -
             | 
| 21 | 
            +
                  people = Picky::Search.new data
         | 
| 19 22 |  | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            +
                  get '/people' do
         | 
| 24 | 
            +
                    results = people.search params[:query], params[:ids] || 20, params[:offset] || 0
         | 
| 25 | 
            +
                    results.to_json
         | 
| 26 | 
            +
                  end
         | 
| 23 27 | 
             
                end
         | 
| 28 | 
            +
                
         | 
| 24 29 | 
             
              end
         | 
| 25 30 |  | 
| 26 31 | 
             
              describe 'updating' do
         | 
| 27 32 | 
             
                before(:each) do
         | 
| 28 33 | 
             
                  Picky::Indexes.clear
         | 
| 29 34 | 
             
                end
         | 
| 30 | 
            -
                let(:request) { ::Rack::MockRequest.new  | 
| 31 | 
            -
                 | 
| 32 | 
            -
                   | 
| 35 | 
            +
                let(:request) { ::Rack::MockRequest.new MyIndexActionsPickyServer }
         | 
| 36 | 
            +
                context 'return values' do
         | 
| 37 | 
            +
                  describe 'update' do
         | 
| 38 | 
            +
                    it 'returns a correct code after updating without problems' do
         | 
| 39 | 
            +
                      result = request.post('/', params: {
         | 
| 40 | 
            +
                        index: 'some_index',
         | 
| 41 | 
            +
                        data: %Q{{ "id":"1", "name":"Florian", "surname":"Hanke" }}
         | 
| 42 | 
            +
                      })
         | 
| 43 | 
            +
                      result.status.should == 200
         | 
| 44 | 
            +
                    end
         | 
| 45 | 
            +
                    it 'returns a correct code after updating with just the id' do
         | 
| 46 | 
            +
                      result = request.post('/', params: {
         | 
| 47 | 
            +
                        index: 'some_index',
         | 
| 48 | 
            +
                        data: %Q{{ "id":"1" }}
         | 
| 49 | 
            +
                      })
         | 
| 50 | 
            +
                      result.status.should == 200
         | 
| 51 | 
            +
                    end
         | 
| 52 | 
            +
                    it 'returns a correct code after updating without id' do
         | 
| 53 | 
            +
                      result = request.post('/', params: {
         | 
| 54 | 
            +
                        index: 'some_index',
         | 
| 55 | 
            +
                        data: %Q{{ "name":"Florian", "surname":"Hanke" }}
         | 
| 56 | 
            +
                      })
         | 
| 57 | 
            +
                      result.status.should == 400
         | 
| 58 | 
            +
                    end
         | 
| 59 | 
            +
                    it 'returns a correct code after updating with the wrong index' do
         | 
| 60 | 
            +
                      result = request.post('/', params: {
         | 
| 61 | 
            +
                        index: 'some_wrong_index',
         | 
| 62 | 
            +
                        data: %Q{{ "id":"1", "name":"Florian", "surname":"Hanke" }}
         | 
| 63 | 
            +
                      })
         | 
| 64 | 
            +
                      result.status.should == 404
         | 
| 65 | 
            +
                    end
         | 
| 66 | 
            +
                  end
         | 
| 67 | 
            +
                  describe 'delete' do
         | 
| 68 | 
            +
                    before(:each) do
         | 
| 69 | 
            +
                      request.post('/', params: {
         | 
| 70 | 
            +
                        index: 'some_index',
         | 
| 71 | 
            +
                        data: %Q{{ "id":"1", "name":"Florian", "surname":"Hanke" }}
         | 
| 72 | 
            +
                      })
         | 
| 73 | 
            +
                    end
         | 
| 74 | 
            +
                    it 'returns a correct code after deleting without problems' do
         | 
| 75 | 
            +
                      result = request.delete('/', params: {
         | 
| 76 | 
            +
                        index: 'some_index',
         | 
| 77 | 
            +
                        data: %Q{{ "id":"1" }}
         | 
| 78 | 
            +
                      })
         | 
| 79 | 
            +
                      result.status.should == 200
         | 
| 80 | 
            +
                    end
         | 
| 81 | 
            +
                    it 'returns a correct code after deleting twice' do
         | 
| 82 | 
            +
                      result = request.delete('/', params: {
         | 
| 83 | 
            +
                        index: 'some_index',
         | 
| 84 | 
            +
                        data: %Q{{ "id":"1" }}
         | 
| 85 | 
            +
                      })
         | 
| 86 | 
            +
                      result = request.delete('/', params: {
         | 
| 87 | 
            +
                        index: 'some_index',
         | 
| 88 | 
            +
                        data: %Q{{ "id":"1" }}
         | 
| 89 | 
            +
                      })
         | 
| 90 | 
            +
                      result.status.should == 200
         | 
| 91 | 
            +
                    end
         | 
| 92 | 
            +
                    it 'returns a correct code after deleting without id' do
         | 
| 93 | 
            +
                      result = request.delete('/', params: {
         | 
| 94 | 
            +
                        index: 'some_index',
         | 
| 95 | 
            +
                        data: %Q{{}}
         | 
| 96 | 
            +
                      })
         | 
| 97 | 
            +
                      result.status.should == 400
         | 
| 98 | 
            +
                    end
         | 
| 99 | 
            +
                    it 'returns a correct code after deleting with the wrong index' do
         | 
| 100 | 
            +
                      result = request.delete('/', params: {
         | 
| 101 | 
            +
                        index: 'some_wrong_index',
         | 
| 102 | 
            +
                        data: %Q{{ "id":"1" }}
         | 
| 103 | 
            +
                      })
         | 
| 104 | 
            +
                      result.status.should == 404
         | 
| 105 | 
            +
                    end        
         | 
| 106 | 
            +
                  end
         | 
| 107 | 
            +
                end
         | 
| 108 | 
            +
                context '' do
         | 
| 109 | 
            +
                  it 'updates the index correctly' do
         | 
| 110 | 
            +
                    request.post('/', params: {
         | 
| 111 | 
            +
                      index: 'some_index',
         | 
| 112 | 
            +
                      data: %Q{{ "id":"1", "name":"Florian", "surname":"Hanke" }}
         | 
| 113 | 
            +
                    })
         | 
| 33 114 |  | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 115 | 
            +
                    results = Yajl::Parser.parse request.get('/people', params: { query: 'florian' }).body
         | 
| 116 | 
            +
                    results['total'].should == 1
         | 
| 36 117 |  | 
| 37 | 
            -
             | 
| 118 | 
            +
                    request.post('/', params: {
         | 
| 119 | 
            +
                      index: 'some_index',
         | 
| 120 | 
            +
                      data: %Q{{ "id":"2", "name":"Florian", "surname":"Meier" }}
         | 
| 121 | 
            +
                    })
         | 
| 38 122 |  | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 44 | 
            -
             | 
| 123 | 
            +
                    results = Yajl::Parser.parse request.get('/people', params: { query: 'florian' }).body
         | 
| 124 | 
            +
                    results['total'].should == 2
         | 
| 125 | 
            +
                  end
         | 
| 126 | 
            +
                  it 'updates the index correctly' do
         | 
| 127 | 
            +
                    request.post('/', params: {
         | 
| 128 | 
            +
                      index: 'some_index',
         | 
| 129 | 
            +
                      data: %Q{{ "id":"1", "name":"Flarian", "surname":"Hanke" }}
         | 
| 130 | 
            +
                    })
         | 
| 45 131 |  | 
| 46 | 
            -
             | 
| 47 | 
            -
             | 
| 132 | 
            +
                    results = Yajl::Parser.parse request.get('/people', params: { query: 'hanke' }).body
         | 
| 133 | 
            +
                    results['total'].should == 1
         | 
| 48 134 |  | 
| 49 | 
            -
             | 
| 135 | 
            +
                    results = Yajl::Parser.parse request.get('/people', params: { query: 'florian' }).body
         | 
| 136 | 
            +
                    results['total'].should == 0
         | 
| 50 137 |  | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 53 | 
            -
             | 
| 54 | 
            -
             | 
| 55 | 
            -
             | 
| 138 | 
            +
                    # Whoops, typo. Let's fix it.
         | 
| 139 | 
            +
                    #
         | 
| 140 | 
            +
                    request.post('/', params: {
         | 
| 141 | 
            +
                      index: 'some_index',
         | 
| 142 | 
            +
                      data: %Q{{ "id":"1", "name":"Florian", "surname":"Hanke" }}
         | 
| 143 | 
            +
                    })
         | 
| 144 | 
            +
                  
         | 
| 145 | 
            +
                    results = Yajl::Parser.parse request.get('/people', params: { query: 'hanke' }).body
         | 
| 146 | 
            +
                    results['total'].should == 1
         | 
| 147 | 
            +
                  
         | 
| 148 | 
            +
                    results = Yajl::Parser.parse request.get('/people', params: { query: 'flarian' }).body
         | 
| 149 | 
            +
                    results['total'].should == 0
         | 
| 150 | 
            +
                  
         | 
| 151 | 
            +
                    results = Yajl::Parser.parse request.get('/people', params: { query: 'florian' }).body
         | 
| 152 | 
            +
                    results['total'].should == 1
         | 
| 153 | 
            +
                  end
         | 
| 154 | 
            +
                  it 'deletes entries from the index correctly' do
         | 
| 155 | 
            +
                    request.post('/', params: {
         | 
| 156 | 
            +
                      index: 'some_index',
         | 
| 157 | 
            +
                      data: %Q{{ "id":"1", "name":"Florian", "surname":"Hanke" }}
         | 
| 158 | 
            +
                    })
         | 
| 159 | 
            +
                    request.post('/', params: {
         | 
| 160 | 
            +
                      index: 'some_index',
         | 
| 161 | 
            +
                      data: %Q{{ "id":"2", "name":"Florian", "surname":"Meier" }}
         | 
| 162 | 
            +
                    })
         | 
| 163 | 
            +
                  
         | 
| 164 | 
            +
                    results = Yajl::Parser.parse request.get('/people', params: { query: 'florian' }).body
         | 
| 165 | 
            +
                    results['total'].should == 2
         | 
| 166 | 
            +
                  
         | 
| 167 | 
            +
                    request.delete('/', params: {
         | 
| 168 | 
            +
                      index: 'some_index',
         | 
| 169 | 
            +
                      data: %Q{{ "id":"1" }}
         | 
| 170 | 
            +
                    })
         | 
| 171 | 
            +
                  
         | 
| 172 | 
            +
                    results = Yajl::Parser.parse request.get('/people', params: { query: 'florian' }).body
         | 
| 173 | 
            +
                    results['total'].should == 1
         | 
| 174 | 
            +
                  end
         | 
| 175 | 
            +
                  it 'has no problem with a superfluous delete' do
         | 
| 176 | 
            +
                    request.delete('/', params: {
         | 
| 177 | 
            +
                      index: 'some_index',
         | 
| 178 | 
            +
                      data: %Q{{ "id":"1" }}
         | 
| 179 | 
            +
                    })
         | 
| 180 | 
            +
                  
         | 
| 181 | 
            +
                    results = Yajl::Parser.parse request.get('/people', params: { query: 'florian' }).body
         | 
| 182 | 
            +
                    results['total'].should == 0
         | 
| 183 | 
            +
                  end
         | 
| 184 | 
            +
                  it 'works with the (test) client' do
         | 
| 185 | 
            +
                    client = Picky::TestClient.new MyIndexActionsPickyServer, :path => '/people'
         | 
| 186 | 
            +
                  
         | 
| 187 | 
            +
                    request.post('/', params: {
         | 
| 188 | 
            +
                      index: 'some_index',
         | 
| 189 | 
            +
                      data: %Q{{ "id":"1", "name":"Florian", "surname":"Hanke" }}
         | 
| 190 | 
            +
                    })
         | 
| 56 191 |  | 
| 57 | 
            -
             | 
| 58 | 
            -
                   | 
| 192 | 
            +
                    client.search('florian').total.should == 1
         | 
| 193 | 
            +
                  end
         | 
| 59 194 | 
             
                end
         | 
| 60 195 | 
             
              end
         | 
| 61 196 |  | 
    
        data/spec/lib/tokenizer_spec.rb
    CHANGED
    
    | @@ -96,7 +96,9 @@ ERROR | |
| 96 96 | 
             
                    before(:each) do
         | 
| 97 97 | 
             
                      tokenizer.normalizes_words([
         | 
| 98 98 | 
             
                        [/st\./, 'sankt'],
         | 
| 99 | 
            -
                        [/stras?s?e?/, 'str']
         | 
| 99 | 
            +
                        [/stras?s?e?/, 'str'],
         | 
| 100 | 
            +
                        [/\+/, 'plus'],
         | 
| 101 | 
            +
                        [/\&/, 'and']
         | 
| 100 102 | 
             
                      ])
         | 
| 101 103 | 
             
                    end
         | 
| 102 104 | 
             
                    it "has normalize_with_patterns" do
         | 
| @@ -105,6 +107,12 @@ ERROR | |
| 105 107 | 
             
                    it "normalizes, but just the first one" do
         | 
| 106 108 | 
             
                      tokenizer.normalize_with_patterns('st. wegstrasse').should == 'sankt wegstrasse'
         | 
| 107 109 | 
             
                    end
         | 
| 110 | 
            +
                    it "works correctly" do
         | 
| 111 | 
            +
                      tokenizer.normalize_with_patterns('camera +').should == 'camera plus'
         | 
| 112 | 
            +
                    end
         | 
| 113 | 
            +
                    it "works correctly" do
         | 
| 114 | 
            +
                      tokenizer.normalize_with_patterns('alice & bob').should == 'alice and bob'
         | 
| 115 | 
            +
                    end
         | 
| 108 116 | 
             
                  end
         | 
| 109 117 | 
             
                end
         | 
| 110 118 |  | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: picky
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 4.3. | 
| 4 | 
            +
              version: 4.3.1
         | 
| 5 5 | 
             
              prerelease: 
         | 
| 6 6 | 
             
            platform: ruby
         | 
| 7 7 | 
             
            authors:
         | 
| @@ -9,11 +9,11 @@ authors: | |
| 9 9 | 
             
            autorequire: 
         | 
| 10 10 | 
             
            bindir: bin
         | 
| 11 11 | 
             
            cert_chain: []
         | 
| 12 | 
            -
            date: 2012-03- | 
| 12 | 
            +
            date: 2012-03-24 00:00:00.000000000 Z
         | 
| 13 13 | 
             
            dependencies:
         | 
| 14 14 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 15 15 | 
             
              name: rspec
         | 
| 16 | 
            -
              requirement: & | 
| 16 | 
            +
              requirement: &70193563400740 !ruby/object:Gem::Requirement
         | 
| 17 17 | 
             
                none: false
         | 
| 18 18 | 
             
                requirements:
         | 
| 19 19 | 
             
                - - ! '>='
         | 
| @@ -21,21 +21,21 @@ dependencies: | |
| 21 21 | 
             
                    version: '0'
         | 
| 22 22 | 
             
              type: :development
         | 
| 23 23 | 
             
              prerelease: false
         | 
| 24 | 
            -
              version_requirements: * | 
| 24 | 
            +
              version_requirements: *70193563400740
         | 
| 25 25 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 26 26 | 
             
              name: picky-client
         | 
| 27 | 
            -
              requirement: & | 
| 27 | 
            +
              requirement: &70193563400240 !ruby/object:Gem::Requirement
         | 
| 28 28 | 
             
                none: false
         | 
| 29 29 | 
             
                requirements:
         | 
| 30 30 | 
             
                - - ~>
         | 
| 31 31 | 
             
                  - !ruby/object:Gem::Version
         | 
| 32 | 
            -
                    version: 4.3. | 
| 32 | 
            +
                    version: 4.3.1
         | 
| 33 33 | 
             
              type: :development
         | 
| 34 34 | 
             
              prerelease: false
         | 
| 35 | 
            -
              version_requirements: * | 
| 35 | 
            +
              version_requirements: *70193563400240
         | 
| 36 36 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 37 37 | 
             
              name: text
         | 
| 38 | 
            -
              requirement: & | 
| 38 | 
            +
              requirement: &70193563399820 !ruby/object:Gem::Requirement
         | 
| 39 39 | 
             
                none: false
         | 
| 40 40 | 
             
                requirements:
         | 
| 41 41 | 
             
                - - ! '>='
         | 
| @@ -43,10 +43,10 @@ dependencies: | |
| 43 43 | 
             
                    version: '0'
         | 
| 44 44 | 
             
              type: :runtime
         | 
| 45 45 | 
             
              prerelease: false
         | 
| 46 | 
            -
              version_requirements: * | 
| 46 | 
            +
              version_requirements: *70193563399820
         | 
| 47 47 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 48 48 | 
             
              name: yajl-ruby
         | 
| 49 | 
            -
              requirement: & | 
| 49 | 
            +
              requirement: &70193563399360 !ruby/object:Gem::Requirement
         | 
| 50 50 | 
             
                none: false
         | 
| 51 51 | 
             
                requirements:
         | 
| 52 52 | 
             
                - - ! '>='
         | 
| @@ -54,10 +54,10 @@ dependencies: | |
| 54 54 | 
             
                    version: '0'
         | 
| 55 55 | 
             
              type: :runtime
         | 
| 56 56 | 
             
              prerelease: false
         | 
| 57 | 
            -
              version_requirements: * | 
| 57 | 
            +
              version_requirements: *70193563399360
         | 
| 58 58 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 59 59 | 
             
              name: activesupport
         | 
| 60 | 
            -
              requirement: & | 
| 60 | 
            +
              requirement: &70193563415200 !ruby/object:Gem::Requirement
         | 
| 61 61 | 
             
                none: false
         | 
| 62 62 | 
             
                requirements:
         | 
| 63 63 | 
             
                - - ~>
         | 
| @@ -65,10 +65,10 @@ dependencies: | |
| 65 65 | 
             
                    version: '3.0'
         | 
| 66 66 | 
             
              type: :runtime
         | 
| 67 67 | 
             
              prerelease: false
         | 
| 68 | 
            -
              version_requirements: * | 
| 68 | 
            +
              version_requirements: *70193563415200
         | 
| 69 69 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 70 70 | 
             
              name: procrastinate
         | 
| 71 | 
            -
              requirement: & | 
| 71 | 
            +
              requirement: &70193563414580 !ruby/object:Gem::Requirement
         | 
| 72 72 | 
             
                none: false
         | 
| 73 73 | 
             
                requirements:
         | 
| 74 74 | 
             
                - - ~>
         | 
| @@ -76,10 +76,10 @@ dependencies: | |
| 76 76 | 
             
                    version: '0.4'
         | 
| 77 77 | 
             
              type: :runtime
         | 
| 78 78 | 
             
              prerelease: false
         | 
| 79 | 
            -
              version_requirements: * | 
| 79 | 
            +
              version_requirements: *70193563414580
         | 
| 80 80 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 81 81 | 
             
              name: rack_fast_escape
         | 
| 82 | 
            -
              requirement: & | 
| 82 | 
            +
              requirement: &70193563414120 !ruby/object:Gem::Requirement
         | 
| 83 83 | 
             
                none: false
         | 
| 84 84 | 
             
                requirements:
         | 
| 85 85 | 
             
                - - ! '>='
         | 
| @@ -87,7 +87,7 @@ dependencies: | |
| 87 87 | 
             
                    version: '0'
         | 
| 88 88 | 
             
              type: :runtime
         | 
| 89 89 | 
             
              prerelease: false
         | 
| 90 | 
            -
              version_requirements: * | 
| 90 | 
            +
              version_requirements: *70193563414120
         | 
| 91 91 | 
             
            description: Fast Ruby semantic text search engine with comfortable single field interface.
         | 
| 92 92 | 
             
            email: florian.hanke+picky@gmail.com
         | 
| 93 93 | 
             
            executables:
         | 
| @@ -259,6 +259,7 @@ files: | |
| 259 259 | 
             
            - spec/functional/regression_spec.rb
         | 
| 260 260 | 
             
            - spec/functional/speed_spec.rb
         | 
| 261 261 | 
             
            - spec/functional/terminate_early_spec.rb
         | 
| 262 | 
            +
            - spec/functional/tokenizer_spec.rb
         | 
| 262 263 | 
             
            - spec/integration/sinatra_index_actions_spec.rb
         | 
| 263 264 | 
             
            - spec/lib/analytics_spec.rb
         | 
| 264 265 | 
             
            - spec/lib/analyzer_spec.rb
         | 
| @@ -408,6 +409,7 @@ test_files: | |
| 408 409 | 
             
            - spec/functional/regression_spec.rb
         | 
| 409 410 | 
             
            - spec/functional/speed_spec.rb
         | 
| 410 411 | 
             
            - spec/functional/terminate_early_spec.rb
         | 
| 412 | 
            +
            - spec/functional/tokenizer_spec.rb
         | 
| 411 413 | 
             
            - spec/integration/sinatra_index_actions_spec.rb
         | 
| 412 414 | 
             
            - spec/lib/analytics_spec.rb
         | 
| 413 415 | 
             
            - spec/lib/analyzer_spec.rb
         |