picky 4.0.0pre1 → 4.0.0pre2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. data/aux/picky/cli.rb +6 -2
  2. data/lib/picky.rb +10 -8
  3. data/lib/picky/backends/backend.rb +37 -0
  4. data/lib/picky/backends/file.rb +0 -20
  5. data/lib/picky/backends/memory.rb +0 -29
  6. data/lib/picky/backends/redis.rb +74 -15
  7. data/lib/picky/backends/redis/list.rb +1 -1
  8. data/lib/picky/backends/sqlite.rb +0 -27
  9. data/lib/picky/bundle.rb +2 -2
  10. data/lib/picky/bundle_indexed.rb +1 -1
  11. data/lib/picky/bundle_indexing.rb +1 -1
  12. data/lib/picky/categories_indexed.rb +1 -11
  13. data/lib/picky/category.rb +4 -4
  14. data/lib/picky/category/location.rb +25 -0
  15. data/lib/picky/category_realtime.rb +4 -3
  16. data/lib/picky/console.rb +1 -1
  17. data/lib/picky/constants.rb +1 -1
  18. data/lib/picky/ext/maybe_compile.rb +2 -2
  19. data/lib/picky/extensions/object.rb +3 -2
  20. data/lib/picky/generators/aliases.rb +7 -2
  21. data/lib/picky/generators/partial/default.rb +1 -0
  22. data/lib/picky/generators/similarity/default.rb +1 -0
  23. data/lib/picky/generators/similarity/phonetic.rb +13 -2
  24. data/lib/picky/generators/strategy.rb +0 -2
  25. data/lib/picky/generators/weights/constant.rb +1 -2
  26. data/lib/picky/generators/weights/default.rb +1 -0
  27. data/lib/picky/generators/weights/dynamic.rb +1 -1
  28. data/lib/picky/generators/weights/logarithmic.rb +1 -1
  29. data/lib/picky/generators/weights/{runtime.rb → stub.rb} +1 -3
  30. data/lib/picky/index.rb +3 -3
  31. data/lib/picky/index_indexing.rb +0 -2
  32. data/lib/picky/index_realtime.rb +1 -1
  33. data/lib/picky/indexers/base.rb +7 -0
  34. data/lib/picky/indexers/parallel.rb +2 -4
  35. data/lib/picky/indexers/serial.rb +2 -0
  36. data/lib/picky/indexes_indexing.rb +1 -1
  37. data/lib/picky/interfaces/live_parameters/master_child.rb +175 -0
  38. data/lib/picky/interfaces/live_parameters/unicorn.rb +37 -0
  39. data/lib/picky/loader.rb +238 -259
  40. data/lib/picky/query/allocation.rb +19 -10
  41. data/lib/picky/query/combination.rb +7 -1
  42. data/lib/picky/query/combinations.rb +1 -6
  43. data/lib/picky/query/token.rb +26 -36
  44. data/lib/picky/results.rb +18 -17
  45. data/lib/picky/scheduler.rb +2 -1
  46. data/lib/picky/search.rb +1 -1
  47. data/lib/picky/sinatra.rb +6 -6
  48. data/lib/picky/statistics.rb +2 -0
  49. data/lib/picky/tokenizer.rb +8 -8
  50. data/lib/picky/wrappers/bundle/calculation.rb +4 -4
  51. data/lib/picky/wrappers/bundle/location.rb +1 -2
  52. data/lib/tasks/framework.rake +1 -1
  53. data/lib/tasks/statistics.rake +1 -1
  54. data/lib/tasks/try.rake +1 -1
  55. data/lib/tasks/try.rb +1 -1
  56. data/spec/aux/picky/cli_spec.rb +12 -12
  57. data/spec/ext/performant_spec.rb +16 -16
  58. data/spec/functional/backends/file_spec.rb +78 -7
  59. data/spec/functional/backends/memory_spec.rb +78 -7
  60. data/spec/functional/backends/redis_spec.rb +73 -13
  61. data/spec/functional/dynamic_weights_spec.rb +3 -4
  62. data/spec/functional/realtime_spec.rb +2 -2
  63. data/spec/functional/speed_spec.rb +2 -2
  64. data/spec/functional/terminate_early_spec.rb +3 -3
  65. data/spec/lib/analytics_spec.rb +1 -1
  66. data/spec/lib/analyzer_spec.rb +5 -3
  67. data/spec/lib/categories_indexed_spec.rb +38 -20
  68. data/spec/lib/category/location_spec.rb +30 -0
  69. data/spec/lib/character_substituters/west_european_spec.rb +1 -0
  70. data/spec/lib/extensions/hash_spec.rb +6 -5
  71. data/spec/lib/extensions/module_spec.rb +6 -6
  72. data/spec/lib/extensions/object_spec.rb +9 -8
  73. data/spec/lib/extensions/string_spec.rb +1 -1
  74. data/spec/lib/generators/similarity/phonetic_spec.rb +11 -0
  75. data/spec/lib/index_realtime_spec.rb +5 -5
  76. data/spec/lib/interfaces/{live_parameters_spec.rb → live_parameters/master_child_spec.rb} +26 -26
  77. data/spec/lib/interfaces/live_parameters/unicorn_spec.rb +160 -0
  78. data/spec/lib/loader_spec.rb +65 -25
  79. data/spec/lib/query/allocation_spec.rb +25 -22
  80. data/spec/lib/query/combinations_spec.rb +13 -36
  81. data/spec/lib/query/token_spec.rb +144 -131
  82. data/spec/lib/query/tokens_spec.rb +14 -0
  83. data/spec/lib/results_spec.rb +14 -8
  84. data/spec/lib/search_spec.rb +1 -1
  85. data/spec/lib/sinatra_spec.rb +8 -8
  86. metadata +28 -91
  87. data/lib/picky/adapters/rack.rb +0 -34
  88. data/lib/picky/adapters/rack/base.rb +0 -27
  89. data/lib/picky/adapters/rack/live_parameters.rb +0 -37
  90. data/lib/picky/adapters/rack/search.rb +0 -67
  91. data/lib/picky/application.rb +0 -268
  92. data/lib/picky/frontend_adapters/rack.rb +0 -161
  93. data/lib/picky/interfaces/live_parameters.rb +0 -187
  94. data/lib/picky/sources/base.rb +0 -92
  95. data/lib/picky/sources/couch.rb +0 -76
  96. data/lib/picky/sources/csv.rb +0 -83
  97. data/lib/picky/sources/db.rb +0 -189
  98. data/lib/picky/sources/delicious.rb +0 -63
  99. data/lib/picky/sources/mongo.rb +0 -80
  100. data/lib/picky/wrappers/category/location.rb +0 -38
  101. data/lib/tasks/routes.rake +0 -8
  102. data/spec/lib/adapters/rack/base_spec.rb +0 -24
  103. data/spec/lib/adapters/rack/live_parameters_spec.rb +0 -26
  104. data/spec/lib/adapters/rack/query_spec.rb +0 -39
  105. data/spec/lib/application_spec.rb +0 -155
  106. data/spec/lib/frontend_adapters/rack_spec.rb +0 -294
  107. data/spec/lib/sources/base_spec.rb +0 -53
  108. data/spec/lib/sources/couch_spec.rb +0 -114
  109. data/spec/lib/sources/csv_spec.rb +0 -89
  110. data/spec/lib/sources/db_spec.rb +0 -125
  111. data/spec/lib/sources/delicious_spec.rb +0 -94
  112. data/spec/lib/sources/mongo_spec.rb +0 -50
@@ -1,63 +0,0 @@
1
- module Picky
2
-
3
- module Sources
4
-
5
- # Describes a Delicious (http://deli.cio.us) source.
6
- #
7
- # This source has a fixed set of categories:
8
- # * title
9
- # * tags
10
- # * url
11
- #
12
- # Examples:
13
- # Sources::CSV.new('usrnam', 'paswrd')
14
- #
15
- class Delicious < Base
16
-
17
- def initialize username, password
18
- check_gem
19
- @username = username
20
- @password = password
21
- end
22
- def check_gem # :nodoc:
23
- require 'www/delicious'
24
- rescue LoadError
25
- warn_gem_missing 'www-delicious', 'the delicious source'
26
- exit 1
27
- end
28
-
29
- def to_s
30
- "#{self.class.name}(#{@username})"
31
- end
32
-
33
- # Harvests the data to index.
34
- #
35
- def harvest category
36
- get_data do |indexed_id, data|
37
- text = data[category.from]
38
- next unless text
39
- yield indexed_id, text
40
- end
41
- end
42
-
43
- #
44
- #
45
- def get_data # :nodoc:
46
- @generated_id ||= 0
47
- @posts ||= WWW::Delicious.new(@username, @password).posts_recent(count: 100)
48
- @posts.each do |post|
49
- data = {
50
- title: post.title,
51
- tags: post.tags.join(' '),
52
- url: post.url.to_s
53
- }
54
- @generated_id += 1
55
- yield @generated_id, data
56
- end
57
- end
58
-
59
- end
60
-
61
- end
62
-
63
- end
@@ -1,80 +0,0 @@
1
- module Picky
2
-
3
- module Sources
4
-
5
- # Important note: We're not sure if this works already.
6
- #
7
- # A Mongo database source.
8
- #
9
- # Options:
10
- # * url, db
11
- # Example:
12
- # Sources::Mongo.new(:collection1, :collection2, :url => 'localhost:28017', :db => 'testdatabase')
13
- # Be sure to escape the URL properly, e.g. # => %23 in the databasename if needed
14
- #
15
- # and all the options of a <tt>RestClient::Resource</tt>.
16
- # See http://github.com/archiloque/rest-client.
17
- #
18
- class Mongo < Base
19
-
20
- # Raised when a Mongo source is instantiated without a valid uri.
21
- #
22
- # Important!
23
- # You have to start your mongodb with --rest in order to use
24
- # the rest / http interface
25
- #
26
- class NoDBGiven < StandardError; end
27
-
28
- @@id_key = '_id'
29
- #
30
- #
31
- def initialize *category_names, options
32
- check_gem
33
-
34
- unless options[:url] && options[:db]
35
- raise_no_db_given(category_names)
36
- end
37
-
38
- @db = RestClient::Resource.new options.delete(:url), options
39
- @database = options.delete(:db)
40
- @key_format = options[:key_format] && options[:key_format].intern || :to_s
41
- end
42
-
43
- # Tries to require the rest_client gem.
44
- #
45
- def check_gem # :nodoc:
46
- require 'rest_client'
47
- rescue LoadError
48
- warn_gem_missing 'rest-client', 'the MongoDB source'
49
- exit 1
50
- end
51
-
52
- # Fetches the data, @limit=0 will return all records
53
- #
54
- # Limit is set to 0 by default - all collection entries will be send
55
- # If want to limit the results, set to to any other number, e.g. limit=15
56
- # to return only 15 entries
57
- #
58
- def harvest category
59
- collection = (category.from || category.index_name).to_s
60
- resp = @db["/#{@database}/#{category.index_name}/?@limit=0"].get
61
- JSON.parse(resp)['rows'].each do |row|
62
- text = row[collection].to_s
63
- next unless text
64
- index_key = row.delete @@id_key # Note: I removed .values
65
- yield index_key, text
66
- end
67
- end
68
-
69
- def raise_no_db_given category_names # :nodoc:
70
- raise NoDBGiven.new(category_names.join(', '))
71
- end
72
-
73
- def to_s
74
- self.class.name
75
- end
76
-
77
- end
78
- end
79
-
80
- end
@@ -1,38 +0,0 @@
1
- module Picky
2
- module Wrappers
3
- module Category
4
-
5
- module Location
6
-
7
- # THINK Is this the best way to do this?
8
- #
9
- def self.wrap category, grid, precision = 1, anchor = 0.0
10
- wrapped_exact = Wrappers::Bundle::Location.new category.exact, grid: grid, precision: precision, anchor: anchor
11
-
12
- category.class_eval do
13
-
14
- # Uses a basic tokenizer.
15
- #
16
- def tokenizer
17
- @tokenizer ||= Tokenizer.new
18
- end
19
-
20
- # Both use the exact index.
21
- #
22
- # TODO Necessary to wrap?
23
- #
24
- define_method :exact do
25
- wrapped_exact
26
- end
27
- define_method :partial do
28
- wrapped_exact
29
- end
30
-
31
- end
32
- end
33
-
34
- end
35
-
36
- end
37
- end
38
- end
@@ -1,8 +0,0 @@
1
- # Routing tasks.
2
- #
3
- desc "Shows the available URL paths."
4
- task :routes => :application do
5
- Picky::Application.apps.each do |app|
6
- puts app.to_routes
7
- end
8
- end
@@ -1,24 +0,0 @@
1
- # encoding: utf-8
2
- #
3
- require 'spec_helper'
4
-
5
- describe Picky::Adapters::Rack::Base do
6
-
7
- before(:each) do
8
- @adapter = described_class.new
9
- end
10
-
11
- describe 'respond_with' do
12
- describe 'by default' do
13
- it 'uses json' do
14
- @adapter.respond_with('response').should ==
15
- [200, { 'Content-Type' => 'application/json', 'Content-Length' => '8' }, ['response']]
16
- end
17
- end
18
- it 'adapts the content length' do
19
- @adapter.respond_with('123').should ==
20
- [200, { 'Content-Type' => 'application/json', 'Content-Length' => '3' }, ['123']]
21
- end
22
- end
23
-
24
- end
@@ -1,26 +0,0 @@
1
- # encoding: utf-8
2
- #
3
- require 'spec_helper'
4
-
5
- describe Picky::Adapters::Rack::LiveParameters do
6
-
7
- let(:live_parameters) { stub :live_parameters }
8
- let(:adapter) { described_class.new live_parameters }
9
-
10
- describe 'to_app' do
11
- it 'works' do
12
- lambda { adapter.to_app }.should_not raise_error
13
- end
14
- it 'returns the right thing' do
15
- adapter.to_app.should respond_to(:call)
16
- end
17
- it 'returned lambda should call parameters on the live parameters' do
18
- env = { 'rack.input' => 'some input' }
19
-
20
- live_parameters.should_receive(:parameters).once.with({}).and_return Hash.new
21
-
22
- adapter.to_app.call env
23
- end
24
- end
25
-
26
- end
@@ -1,39 +0,0 @@
1
- # encoding: utf-8
2
- #
3
- require 'spec_helper'
4
-
5
- describe Picky::Adapters::Rack::Search do
6
-
7
- before(:each) do
8
- @query = stub :query
9
- @adapter = described_class.new @query
10
- end
11
-
12
- describe 'to_app' do
13
- it 'works' do
14
- lambda { @adapter.to_app }.should_not raise_error
15
- end
16
- it 'returns the right thing' do
17
- @adapter.to_app.should respond_to(:call)
18
- end
19
- end
20
-
21
- describe 'extracted' do
22
- it 'extracts the query' do
23
- @adapter.extracted('query' => 'some_query')[0].should == 'some_query'
24
- end
25
- it 'extracts the default ids amount' do
26
- @adapter.extracted('query' => 'some_query')[1].should == 20
27
- end
28
- it 'extracts the default offset' do
29
- @adapter.extracted('query' => 'some_query')[2].should == 0
30
- end
31
- it 'extracts a given ids amount' do
32
- @adapter.extracted('query' => 'some_query', 'ids' => '123')[1].should == 123
33
- end
34
- it 'extracts a given offset' do
35
- @adapter.extracted('query' => 'some_query', 'offset' => '123')[2].should == 123
36
- end
37
- end
38
-
39
- end
@@ -1,155 +0,0 @@
1
- # encoding: utf-8
2
- #
3
- require 'spec_helper'
4
-
5
- describe Picky::Application do
6
-
7
- describe "integration" do
8
- it "should run ok" do
9
- lambda {
10
- class MinimalTestApplication < described_class
11
- books = Picky::Index.new :books do
12
- source Picky::Sources::DB.new(
13
- 'SELECT id, title FROM books',
14
- :file => 'app/db.yml'
15
- )
16
- end
17
- books.category :title
18
-
19
- rack_adapter.stub! :exclaim # Stopping it from exclaiming.
20
-
21
- route %r{^/books} => Picky::Search.new(books)
22
- end
23
- Picky::Tokenizer.index_default.tokenize 'some text'
24
- Picky::Tokenizer.query_default.tokenize 'some text'
25
- }.should_not raise_error
26
- end
27
- it "should run ok" do
28
- lambda {
29
- # Here we just test if the API can be called ok.
30
- #
31
- class TestApplication < described_class
32
- indexing removes_characters: /[^a-zA-Z0-9\s\/\-\"\&\.]/,
33
- stopwords: /\b(and|the|of|it|in|for)\b/,
34
- splits_text_on: /[\s\/\-\"\&\.]/,
35
- removes_characters_after_splitting: /[\.]/,
36
- normalizes_words: [[/\$(\w+)/i, '\1 dollars']],
37
- rejects_token_if: lambda { |token| token.blank? || token == :amistad }
38
-
39
- searching removes_characters: /[^a-zA-Z0-9äöü\s\/\-\,\&\"\~\*\:]/,
40
- stopwords: /\b(and|the|of|it|in|for)\b/,
41
- splits_text_on: /[\s\/\-\,\&]+/,
42
- normalizes_words: [[/Deoxyribonucleic Acid/i, 'DNA']],
43
-
44
- substitutes_characters_with: Picky::CharacterSubstituters::WestEuropean.new,
45
- maximum_tokens: 5
46
-
47
- books_index = Picky::Index.new :books do
48
- source Picky::Sources::DB.new(
49
- 'SELECT id, title, author, isbn13 as isbn FROM books',
50
- :file => 'app/db.yml'
51
- )
52
- end
53
-
54
- books_index.category :title,
55
- similarity: Picky::Similarity::DoubleMetaphone.new(3) # Up to three similar title word indexed.
56
- books_index.category :author,
57
- similarity: Picky::Similarity::Soundex.new(2)
58
- books_index.category :isbn,
59
- partial: Picky::Partial::None.new # Partially searching on an ISBN makes not much sense.
60
-
61
- geo_index = Picky::Index.new :geo do
62
- source Picky::Sources::CSV.new(:location, :north, :east, file: 'data/ch.csv', col_sep: ',')
63
- indexing removes_characters: /[^a-z]/
64
- category :location,
65
- similarity: Picky::Similarity::Metaphone.new(4)
66
- ranged_category :north1, 1, precision: 3, from: :north
67
- ranged_category :east1, 1, precision: 3, from: :east
68
- end
69
-
70
- rack_adapter.stub! :exclaim # Stopping it from exclaiming.
71
-
72
- route %r{^/books} => Picky::Search.new(books_index)
73
-
74
- buks_search = Picky::Search.new(books_index) do
75
- searching removes_characters: /[buks]/
76
- ignore :author
77
- end
78
- route %r{^/buks} => buks_search
79
- end
80
- }.should_not raise_error
81
- end
82
- end
83
-
84
- describe 'finalize' do
85
- before(:each) do
86
- described_class.stub! :check
87
- end
88
- it 'checks if all is ok' do
89
- described_class.should_receive(:check).once.with
90
-
91
- described_class.finalize
92
- end
93
- it 'tells the rack adapter to finalize' do
94
- described_class.rack_adapter.should_receive(:finalize).once.with
95
-
96
- described_class.finalize
97
- end
98
- end
99
-
100
- describe 'check' do
101
- it 'does something' do
102
- described_class.should_receive(:warn).once.with "\nWARNING: No routes defined for application configuration in Class.\n\n"
103
-
104
- described_class.check
105
- end
106
- end
107
-
108
- describe 'delegation' do
109
- it "should delegate route" do
110
- described_class.rack_adapter.should_receive(:route).once.with :path => :query
111
-
112
- described_class.route :path => :query
113
- end
114
- end
115
-
116
- describe 'rack_adapter' do
117
- it 'should be there' do
118
- lambda { described_class.rack_adapter }.should_not raise_error
119
- end
120
- it "should return a new FrontendAdapters::Rack instance" do
121
- described_class.rack_adapter.should be_kind_of(Picky::FrontendAdapters::Rack)
122
- end
123
- it "should cache the instance" do
124
- described_class.rack_adapter.should == described_class.rack_adapter
125
- end
126
- end
127
-
128
- describe 'route' do
129
- it 'is delegated' do
130
- described_class.rack_adapter.should_receive(:route).once.with :some_options
131
-
132
- described_class.route(:some_options)
133
- end
134
- it 'raises on block' do
135
- expect {
136
- described_class.route :quack => Hash.new do # Anything with a block.
137
- # do something
138
- end
139
- }.to raise_error("Warning: block passed into #route method, not into Search.new!")
140
- end
141
- end
142
-
143
- describe 'call' do
144
- before(:each) do
145
- @routes = stub :routes
146
- described_class.stub! :rack_adapter => @routes
147
- end
148
- it 'should delegate' do
149
- @routes.should_receive(:call).once.with :env
150
-
151
- described_class.call :env
152
- end
153
- end
154
-
155
- end
@@ -1,294 +0,0 @@
1
- # encoding: utf-8
2
- #
3
- require 'spec_helper'
4
-
5
- describe Picky::FrontendAdapters::Rack do
6
-
7
- before(:each) do
8
- @rack_adapter = described_class.new
9
- @rack_adapter.stub! :exclaim
10
- end
11
-
12
- def rack_defaults_for url
13
- url, query_string = url.split ??
14
-
15
- { "GATEWAY_INTERFACE"=>"CGI/1.1",
16
- "PATH_INFO"=>"#{url}",
17
- "QUERY_STRING"=>"#{query_string}",
18
- "REMOTE_ADDR"=>"127.0.0.1",
19
- "REMOTE_HOST"=>"localhost",
20
- "REQUEST_METHOD"=>"GET",
21
- "REQUEST_URI"=>"http://localhost:3001#{url}",
22
- "SCRIPT_NAME"=>"",
23
- "SERVER_NAME"=>"localhost",
24
- "SERVER_PORT"=>"3001",
25
- "SERVER_PROTOCOL"=>"HTTP/1.1",
26
- "SERVER_SOFTWARE"=>"WEBrick/1.3.1 (Ruby/1.9.2/2010-07-11)",
27
- "HTTP_HOST"=>"localhost:3001",
28
- "HTTP_USER_AGENT"=>"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-us) AppleWebKit/533.16 (KHTML like Gecko) Version/5.0 Safari/533.16",
29
- "HTTP_ACCEPT"=>"application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5",
30
- "HTTP_CACHE_CONTROL"=>"max-age=0",
31
- "HTTP_ACCEPT_LANGUAGE"=>"en-us",
32
- "HTTP_ACCEPT_ENCODING"=>"gzip,
33
- deflate",
34
- "HTTP_COOKIE"=>"__utma=111872281.1536032598.1255697925.1255697925.1255697925.1; _jsuid=8971917605087477351; locale=de",
35
- "HTTP_CONNECTION"=>"keep-alive",
36
- "rack.input"=>'' }
37
- end
38
-
39
- context 'empty?' do
40
- context 'no routes' do
41
- before(:each) do
42
- @rack_adapter.reset_routes
43
- end
44
- it 'returns the right answer' do
45
- @rack_adapter.empty?.should == true
46
- end
47
- end
48
- context 'with routes' do
49
- before(:each) do
50
- @rack_adapter.route %r{something} => Picky::Search.new
51
- end
52
- it 'returns the right answer' do
53
- @rack_adapter.empty?.should == false
54
- end
55
- describe 'to_s' do
56
- it 'outputs correctly' do
57
- @rack_adapter.to_s.should == "Note: Anchored (✓) regexps are faster, e.g. /\\A.*\\Z/ or /^.*$/.\n\n something => Picky::Search(weights: Picky::Query::Weights({}))"
58
- end
59
- end
60
- end
61
- end
62
-
63
- context 'real routes' do
64
- before(:each) do
65
- @rack_adapter.reset_routes
66
- Picky.logger.stub! :info
67
- end
68
- it 'should route correctly' do
69
- env = {}
70
-
71
- @rack_adapter.routes.freeze
72
- @rack_adapter.call(env).should == [404, {"Content-Type" => "text/html", "X-Cascade" => "pass"}, ["Not Found"]]
73
- end
74
- it 'should route correctly' do
75
- env = rack_defaults_for '/'
76
-
77
- @rack_adapter.root 200
78
-
79
- @rack_adapter.routes.freeze
80
- @rack_adapter.call(env).should == [200, {"Content-Type"=>"text/html", "Content-Length"=>"0"}, ['']]
81
- end
82
- it 'should route correctly' do
83
- env = rack_defaults_for '/blarf'
84
-
85
- @rack_adapter.default 200
86
-
87
- @rack_adapter.routes.freeze
88
- @rack_adapter.call(env).should == [200, {"Content-Type"=>"text/html", "Content-Length"=>"0"}, ['']]
89
- end
90
- it 'should route correctly' do
91
- env = rack_defaults_for '/gurk'
92
-
93
- @rack_adapter.answer %r{/gurk}, lambda { |env| [333, {}, ['this is gurk']] }
94
-
95
- @rack_adapter.routes.freeze
96
- @rack_adapter.call(env).should == [333, {}, ['this is gurk']]
97
- end
98
- it 'should route correctly' do
99
- env = rack_defaults_for '/gurk'
100
-
101
- @rack_adapter.answer '/gurk', lambda { |env| [333, {}, ['this is gurk']] }
102
-
103
- @rack_adapter.routes.freeze
104
- @rack_adapter.call(env).should == [333, {}, ['this is gurk']]
105
- end
106
- it 'should route correctly' do
107
- env = rack_defaults_for '/searches/some_route?query=some_query'
108
-
109
- search = stub :search
110
- search.should_receive(:search).once.with(anything, 20, 0).and_return(Picky::Results.new)
111
- Picky::Search.stub! :new => search
112
-
113
- @rack_adapter.route '/searches/some_route' => Picky::Search.new(:some_index, :some_other_index)
114
-
115
- @rack_adapter.routes.freeze
116
- @rack_adapter.call(env).should == [200, {"Content-Type"=>"application/json", "Content-Length"=>"52"}, ["{\"allocations\":[],\"offset\":0,\"duration\":0,\"total\":0}"]]
117
- end
118
- it 'should route correctly' do
119
- env = rack_defaults_for '/searches/some_route?query=some_query&type=some_type'
120
-
121
- search = stub :search
122
- search.should_receive(:search).once.with(anything, 20, 0).and_return(Picky::Results.new)
123
- Picky::Search.stub! :new => search
124
-
125
- @rack_adapter.route '/searches/some_route' => Picky::Search.new(:some_index, :some_other_index), :query => { :type => :some_type }
126
-
127
- @rack_adapter.routes.freeze
128
- @rack_adapter.call(env).should == [200, {"Content-Type"=>"application/json", "Content-Length"=>"52"}, ["{\"allocations\":[],\"offset\":0,\"duration\":0,\"total\":0}"]]
129
- end
130
- it 'should route correctly' do
131
- env = rack_defaults_for '/searches/some_wrong_route?query=some_query'
132
-
133
- search = stub :search
134
- search.should_receive(:search).never
135
- Picky::Search.stub! :new => search
136
-
137
- @rack_adapter.route '/searches/some_route' => Picky::Search.new(:some_index, :some_other_index)
138
-
139
- @rack_adapter.routes.freeze
140
- @rack_adapter.call(env).should == [404, {"Content-Type"=>"text/html", "X-Cascade"=>"pass"}, ["Not Found"]]
141
- end
142
- end
143
-
144
- describe 'to_s' do
145
- context 'no routes' do
146
- it 'outputs correctly' do
147
- @rack_adapter.to_s.should == "Note: Anchored (✓) regexps are faster, e.g. /\\A.*\\Z/ or /^.*$/.\n\n"
148
- end
149
- end
150
- end
151
-
152
- context 'stubbed routes' do
153
- before(:each) do
154
- @routes = stub :routes
155
- @rack_adapter.stub! :routes => @routes
156
- end
157
-
158
- describe 'generate_query_string' do
159
- it 'should not allow an empty query condition' do
160
- lambda {
161
- @rack_adapter.generate_query_string({}).should == 'this=must_be'
162
- }.should raise_error "At least one query string condition is needed."
163
- end
164
- it 'should handle a single condition' do
165
- @rack_adapter.generate_query_string(:this => :must_be).should == 'this=must_be'
166
- end
167
- it 'should not allow multiple query strings' do
168
- lambda {
169
- @rack_adapter.generate_query_string(:this => :must_be, :that => :should_be).should == 'this=must_be|that=should_be'
170
- }.should raise_error "Too many query param conditions (only 1 allowed): {:this=>:must_be, :that=>:should_be}"
171
- end
172
- it 'should be sanity checked' do
173
- '/searches/some_route?query=some_query&type=some_type'.should match(%r{#{"type=some_type"}})
174
- end
175
- end
176
-
177
- describe "route" do
178
- it "should delegate correctly" do
179
- @rack_adapter.should_receive(:route_one).once.with %r{regexp1}, :query1, {}
180
- @rack_adapter.should_receive(:route_one).once.with %r{regexp2}, :query2, {}
181
-
182
- @rack_adapter.route %r{regexp1} => :query1, %r{regexp2} => :query2
183
- end
184
- it "should split options correctly" do
185
- @rack_adapter.should_receive(:route_one).once.with %r{regexp1}, :query1, :some => :option
186
- @rack_adapter.should_receive(:route_one).once.with %r{regexp2}, :query2, :some => :option
187
-
188
- @rack_adapter.route %r{regexp1} => :query1, %r{regexp2} => :query2, :some => :option
189
- end
190
- it 'does not accept nil queries' do
191
- lambda { @rack_adapter.route %r{some/regexp} => nil }.should raise_error(Picky::FrontendAdapters::Rack::RouteTargetNilError, /Routing for \/some\\\/regexp\/ was defined with a nil target object, i.e. \/some\\\/regexp\/ => nil./)
192
- end
193
- end
194
-
195
- describe 'finalize' do
196
- before(:each) do
197
- @rack_adapter.routes.should_receive(:freeze).once.with
198
-
199
- @rack_adapter.finalize
200
- end
201
- end
202
-
203
- describe 'route_one' do
204
- before(:each) do
205
- Picky::Adapters::Rack.stub! :app_for => :some_query_app
206
- end
207
- it 'should add the right route' do
208
- @routes.should_receive(:add_route).once.with :some_query_app, { :request_method => "GET", :path_info => /some_url/ }, {}, "some_query"
209
-
210
- @rack_adapter.route_one %r{some_url}, :some_query, {}
211
- end
212
- it 'should add the right route' do
213
- @routes.should_receive(:add_route).once.with :some_query_app, { :request_method => "GET", :path_info => /some_url/ }, {}, "some_query"
214
-
215
- @rack_adapter.route_one 'some_url', :some_query, {}
216
- end
217
- it 'should add the right route' do
218
- @routes.should_receive(:add_route).once.with :some_query_app, { :request_method => "GET", :glarf => :blarf, :path_info => /some_url/ }, {}, "some_query"
219
-
220
- @rack_adapter.route_one 'some_url', :some_query, { :glarf => :blarf }
221
- end
222
- end
223
-
224
- describe 'default' do
225
- it 'should call answer' do
226
- @rack_adapter.should_receive(:answer).once.with nil, Picky::FrontendAdapters::Rack::STATUSES[200]
227
-
228
- @rack_adapter.default 200
229
- end
230
- end
231
-
232
- describe 'STATUSES' do
233
- it 'is a lambda' do
234
- Picky::FrontendAdapters::Rack::STATUSES[200].respond_to?(:call).should == true
235
- end
236
- it 'is a lambda' do
237
- Picky::FrontendAdapters::Rack::STATUSES[404].respond_to?(:call).should == true
238
- end
239
- end
240
-
241
- describe 'root' do
242
- it 'should call answer' do
243
- @rack_adapter.should_receive(:answer).once.with %r{^/$}, Picky::FrontendAdapters::Rack::STATUSES[200]
244
-
245
- @rack_adapter.root 200
246
- end
247
- it 'should call answer' do
248
- @rack_adapter.should_receive(:answer).once.with %r{^/$}, Picky::FrontendAdapters::Rack::STATUSES[404]
249
-
250
- @rack_adapter.root 404
251
- end
252
- end
253
-
254
- describe 'answer' do
255
- context 'with app' do
256
- before(:each) do
257
- @app = stub :app
258
- end
259
- context 'with url' do
260
- it 'should use the app with default_options from the url' do
261
- @routes.should_receive(:add_route).once.with @app, { :request_method => "GET", :path_info => /some_url/ }
262
-
263
- @rack_adapter.answer 'some_url', @app
264
- end
265
- end
266
- context 'without url' do
267
- it 'should use the app with default_options' do
268
- @routes.should_receive(:add_route).once.with @app, { :request_method => "GET" }
269
-
270
- @rack_adapter.answer nil, @app
271
- end
272
- end
273
- end
274
- context 'without app' do
275
- context 'with url' do
276
- it 'should use the 200 with default_options from the url' do
277
- @routes.should_receive(:add_route).once.with Picky::FrontendAdapters::Rack::STATUSES[200], { :request_method => "GET", :path_info => /some_url/ }
278
-
279
- @rack_adapter.answer 'some_url'
280
- end
281
- end
282
- context 'without url' do
283
- it 'should use the 200 with default_options' do
284
- @routes.should_receive(:add_route).once.with Picky::FrontendAdapters::Rack::STATUSES[200], { :request_method => "GET" }
285
-
286
- @rack_adapter.answer
287
- end
288
- end
289
- end
290
- end
291
-
292
- end
293
-
294
- end