spinel 0.4.0 → 0.5.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 36f6bf12711194f3614c34dbfc4f8867c38f622c
4
- data.tar.gz: d21f2b552b8bf29de5182be3970ba97b9c76cbb3
3
+ metadata.gz: 7efbff4b362858d3bb4ec7ad0efb505b1876b094
4
+ data.tar.gz: f9084f203a49492a4d13c8fabadf886d656cb11c
5
5
  SHA512:
6
- metadata.gz: 483bffbfa8cd936502ac4eaae3d218b59bee7a6ecf3b77e43661de092027bbaac0a2a81b200d6bfccf482a10d2250d4f418813733310d74fcaa8f94f32a887f5
7
- data.tar.gz: a0023b87aba1bc5204751d9d4af65acd32efe7b906a7f5b9a2b44d091a7e6ee990da4ed157c785d94a883628f95bc3503168567d34b53eaed510d7a3575fba21
6
+ metadata.gz: 685721dab555cf5cd26d3f14b97104acddd6eb89dd8fd05561d3b4f2f780a7204f18f628dee704df67ef9b74c1681e9523c2235c74907a54741da6d9c1612ff7
7
+ data.tar.gz: 4c41ca8da330313b2f203afc114926f844f8a4213482228ad91b8ae7303b91045a8ab7b9ae01b2e353b806d3363cd55074672e78ee8f0ace6f48e88ae81751f2
@@ -1,3 +1,8 @@
1
+ # 0.5.0
2
+
3
+ * インデキシングするフィールドを複数指定できるようにする
4
+ * Redisへの接続の取り回しをConnectionPool対応にする
5
+
1
6
  # 0.4.0
2
7
 
3
8
  * デフォルト検索上限数オプションが効いていなかったバグを修正
data/README.md CHANGED
@@ -79,7 +79,7 @@ Spinel.configure do |config|
79
79
  config.minimal_word = 2
80
80
  config.cache_expire = 600
81
81
  config.search_limit = 10
82
- config.document_key = :body
82
+ config.index_fields = :body
83
83
  config.namespace = 'spinel'
84
84
  end
85
85
  ```
@@ -88,15 +88,22 @@ end
88
88
 
89
89
  デフォルトでは `redis://127.0.0.1:6379/0` に接続しようとします。
90
90
  環境変数に `REDIS_URL` が存在するとき、`redis://127.0.0.1:6379/0` よりも優先してその値を使おうとします。
91
- 明示的な設定が行われた場合には環境変数よりも設定が優先されます。
91
+ また`Redis.current`で指定することも可能です。
92
92
 
93
- 明示的な設定において文字列が与えられた場合には、文字列をパースしてredisの接続を作成します。
94
- [resque/redis-namespace](https://github.com/resque/redis-namespace)等を使いたい場合には、直接指定することも可能です。
93
+ ```
94
+ Redis.current = Redis.new(host: '127.0.0.1', port: 6379, db: 15)
95
+ ```
96
+
97
+ [resque/redis-namespace](https://github.com/resque/redis-namespace)や、[mperham/connection_pool](https://github.com/mperham/connection_pool)等を使いたい場合には直接指定することも可能です。
95
98
 
96
99
  ```ruby
97
- Spinel.configure do |config|
98
- config.redis = Redis::Namespace.new(:ns, redis: Redis.new)
99
- end
100
+ require 'redis-namespace'
101
+ Spinel.redis = Redis::Namespace.new(:ns, redis: Redis.new)
102
+ ```
103
+
104
+ ```
105
+ require 'connection_pool'
106
+ Spinel.redis = ConnectionPool.new(size: 5, timeout: 5) { Redis.new(host: '127.0.0.1', port: 6379) }
100
107
  ```
101
108
 
102
109
  #### 検索結果のキャッシュ / 候補数
@@ -5,6 +5,7 @@ require "spinel/config"
5
5
  require "spinel/helper"
6
6
  require "spinel/indexer"
7
7
  require "spinel/searcher"
8
+ require "spinel/connection_pool_proxy"
8
9
  require "spinel/client"
9
10
 
10
11
  module Spinel
@@ -3,10 +3,10 @@ module Spinel
3
3
  DEFAULT_MINIMAL_WORD = 2
4
4
  DEFAULT_CACHE_EXPIRE = 600
5
5
  DEFAULT_SEARCH_LIMIT = 10
6
- DEFAULT_DOCUMENT_KEY = :body
6
+ DEFAULT_INDEX_FIELDS = [:body]
7
7
  DEFAULT_NAMESPACE = 'spinel'
8
8
 
9
- attr_writer :minimal_word, :cache_expire, :search_limit, :document_key, :namespace
9
+ attr_writer :minimal_word, :cache_expire, :search_limit, :index_fields, :namespace
10
10
 
11
11
  def minimal_word
12
12
  @minimal_word ||= DEFAULT_MINIMAL_WORD
@@ -20,35 +20,21 @@ module Spinel
20
20
  @search_limit ||= DEFAULT_SEARCH_LIMIT
21
21
  end
22
22
 
23
- def document_key
24
- (@document_key ||= DEFAULT_DOCUMENT_KEY).to_s
23
+ def index_fields
24
+ Array(@index_fields ||= DEFAULT_INDEX_FIELDS)
25
25
  end
26
26
 
27
27
  def namespace
28
28
  @namespace ||= DEFAULT_NAMESPACE
29
29
  end
30
30
 
31
- def redis=(server)
32
- if server.is_a?(String)
33
- @redis = nil
34
- @redis_url = server
35
- else
36
- @redis = server
37
- end
38
- redis
31
+ def redis= conn
32
+ @redis = Spinel::ConnectionPoolProxy.proxy_if_needed(conn)
39
33
  end
40
34
 
41
35
  def redis
42
- @redis ||= (
43
- url = URI(@redis_url || ENV["REDIS_URL"] || "redis://127.0.0.1:6379/0")
44
-
45
- ::Redis.new({
46
- host: url.host,
47
- port: url.port,
48
- db: url.path[1..-1],
49
- password: url.password
50
- })
51
- )
36
+ @redis || $redis || Redis.current ||
37
+ raise(NotConnected, "Redis::Objects.redis not set to a Redis.new connection")
52
38
  end
53
39
 
54
40
  def configure
@@ -0,0 +1,24 @@
1
+ module Spinel
2
+ class ConnectionPoolProxy
3
+ def initialize pool
4
+ raise ArgumentError, "Should only proxy ConnectionPool!" unless self.class.should_proxy?(pool)
5
+ @pool = pool
6
+ end
7
+
8
+ def method_missing name, *args, &block
9
+ @pool.with { |x| x.send(name, *args, &block) }
10
+ end
11
+
12
+ def respond_to_missing? name, include_all = false
13
+ @pool.with { |x| x.respond_to?(name, include_all) }
14
+ end
15
+
16
+ def self.should_proxy?(conn)
17
+ defined?(::ConnectionPool) && conn.is_a?(::ConnectionPool)
18
+ end
19
+
20
+ def self.proxy_if_needed(conn)
21
+ should_proxy?(conn) ? self.new(conn) : conn
22
+ end
23
+ end
24
+ end
@@ -12,11 +12,9 @@ module Spinel
12
12
  end
13
13
 
14
14
  def get_valid_document doc
15
- id = document_id doc
16
- body = document_body doc
17
- score = document_score doc
18
- raise ArgumentError, "documents must specify both an id and a body" unless id && body
19
- [id, body, score]
15
+ id = document_id doc
16
+ raise ArgumentError, "documents must specify id" unless id
17
+ [id, document_index_fields(doc), document_score(doc)]
20
18
  end
21
19
 
22
20
  def document_id doc
@@ -27,8 +25,10 @@ module Spinel
27
25
  (doc[:score] || doc["score"]).to_f
28
26
  end
29
27
 
30
- def document_body doc
31
- doc[Spinel.document_key.to_sym] || doc[Spinel.document_key]
28
+ def document_index_fields doc
29
+ Spinel.index_fields.map {|field|
30
+ doc[field.to_s.to_sym] || doc[field.to_s] || doc[field]
31
+ }.compact.join(' ')
32
32
  end
33
33
 
34
34
  end
@@ -28,7 +28,7 @@ module Spinel
28
28
  prev_id = document_id prev_doc
29
29
  Spinel.redis.pipelined do
30
30
  Spinel.redis.hdel(database, prev_id)
31
- prefixes(document_body(prev_doc)).each do |p|
31
+ prefixes(document_index_fields(prev_doc)).each do |p|
32
32
  Spinel.redis.zrem(index(p), prev_id)
33
33
  end
34
34
  end
@@ -1,6 +1,6 @@
1
1
  module Spinel
2
2
  MAJOR = 0
3
- MINOR = 4
3
+ MINOR = 5
4
4
  PATCH = 0
5
5
  VERSION = [MAJOR, MINOR, PATCH].compact.join('.')
6
6
  end
@@ -29,4 +29,5 @@ Gem::Specification.new do |spec|
29
29
  spec.add_development_dependency "codeclimate-test-reporter"
30
30
  spec.add_development_dependency "dotenv"
31
31
  spec.add_development_dependency "mock_redis"
32
+ spec.add_development_dependency "connection_pool"
32
33
  end
@@ -0,0 +1,24 @@
1
+ require 'test_helper'
2
+
3
+ class ConfigTest < SpinelTestBase
4
+
5
+ def test_minimal_word
6
+ assert { 2 == Spinel.minimal_word }
7
+ end
8
+
9
+ def test_cache_expire
10
+ assert { 600 == Spinel.cache_expire }
11
+ end
12
+
13
+ def test_search_limit
14
+ assert { 10 == Spinel.search_limit }
15
+ end
16
+
17
+ def test_index_fields
18
+ assert { [:body] == Spinel.index_fields }
19
+ end
20
+
21
+ def test_namespace
22
+ assert { 'spinel' == Spinel.namespace }
23
+ end
24
+ end
@@ -0,0 +1,25 @@
1
+ require 'test_helper'
2
+
3
+ class ConnectionPoolProxy < Minitest::Test
4
+
5
+ def setup
6
+ @proxy = Spinel::ConnectionPoolProxy.new(ConnectionPool.new { MockRedis.new })
7
+ end
8
+
9
+ def test_initialize
10
+ assert_raises(ArgumentError){ Spinel::ConnectionPoolProxy.new 'string' }
11
+ end
12
+
13
+ def test_method_missing
14
+ assert { 'PONG' == @proxy.ping }
15
+ end
16
+
17
+ def test_respond_to?
18
+ assert { true == @proxy.respond_to?(:ping) }
19
+ end
20
+
21
+ def test_should_proxy?
22
+ assert { true == Spinel::ConnectionPoolProxy.should_proxy?(ConnectionPool.new { MockRedis.new }) }
23
+ end
24
+
25
+ end
@@ -0,0 +1,38 @@
1
+ require 'test_helper'
2
+
3
+ class HelperTest < SpinelTestBase
4
+
5
+ def test_prefixes
6
+ assert { ["ta", "tak", "take", "tal", "talk"] == @spinel.prefixes("take talk") }
7
+ end
8
+
9
+ def test_squish
10
+ assert { "quick brown fox" == @spinel.squish(" quick \t brown\n fox ") }
11
+ end
12
+
13
+ def test_get_valid_document
14
+ assert_raises(ArgumentError){ @spinel.get_valid_document({body: 'body'}) }
15
+ assert { [1, 'body', 0.0] == @spinel.get_valid_document({id: 1, body: 'body'}) }
16
+ assert { [1, '', 0.0] == @spinel.get_valid_document({id: 1}) }
17
+ end
18
+
19
+ def test_document_id
20
+ assert { "doc_id" == @spinel.document_id({id: "doc_id"}) }
21
+ assert { "doc_id" == @spinel.document_id({"id" => "doc_id"}) }
22
+ end
23
+
24
+ def test_document_score
25
+ assert { 1.0 == @spinel.document_score({score: 1}) }
26
+ assert { 1.0 == @spinel.document_score({"score" => 1}) }
27
+ assert { 0.0 == @spinel.document_score({}) }
28
+ end
29
+
30
+ def test_document_index_fields
31
+ assert { "test" == @spinel.document_index_fields({body: "test"}) }
32
+ assert { "test" == @spinel.document_index_fields({"body" => "test"}) }
33
+ Spinel.index_fields = [:index, :aliase]
34
+ assert { "test word" == @spinel.document_index_fields({index: "test", "aliase" => "word"}) }
35
+ assert { "test word" == @spinel.document_index_fields({"index" => "test", aliase: "word"}) }
36
+ Spinel.index_fields = Spinel::Config::DEFAULT_INDEX_FIELDS
37
+ end
38
+ end
@@ -0,0 +1,23 @@
1
+ require 'test_helper'
2
+
3
+ class IndexerTest < SpinelTestBase
4
+
5
+ def test_store
6
+ Spinel.redis.flushall
7
+ @spinel.store id: 1, body: 'test'
8
+ assert { 1 == Spinel.redis.hlen(@spinel.database) }
9
+ end
10
+
11
+ def test_get
12
+ Spinel.redis.flushall
13
+ @spinel.store id: 1, body: 'test'
14
+ assert { {"id" => 1, "body" => 'test'} == @spinel.get(1) }
15
+ end
16
+
17
+ def test_remove
18
+ Spinel.redis.flushall
19
+ @spinel.store id: 1, body: 'test'
20
+ @spinel.remove id: 1
21
+ assert { 0 == Spinel.redis.hlen(@spinel.database) }
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ require 'test_helper'
2
+
3
+ class SearcherTest < SpinelTestBase
4
+
5
+ def test_search
6
+ Spinel.redis.flushall
7
+ @spinel.store id: 1, body: 'ruby'
8
+ @spinel.store id: 2, body: 'rubx'
9
+ assert { 2 == @spinel.search('rub').size }
10
+ assert { 1 == @spinel.search('ruby').size }
11
+ end
12
+
13
+ def test_search_option
14
+ assert { {limit: 10, cache: true} == @spinel.search_option }
15
+ assert { {limit: 1, cache: true} == @spinel.search_option({limit: 1}) }
16
+ assert { {limit: 10, cache: false} == @spinel.search_option({cache: false}) }
17
+ end
18
+
19
+ def test_search_word_split
20
+ assert { ['test','word'] == @spinel.search_word_split('test word') }
21
+ assert { ['abc','def'] == @spinel.search_word_split(' def abc ') }
22
+ end
23
+ end
@@ -1,16 +1,10 @@
1
1
  require 'test_helper'
2
2
 
3
- class SpinelTest < Minitest::Test
4
- def setup
5
- @spinel = Spinel.new
6
- end
3
+ class SpinelTest < SpinelTestBase
7
4
 
8
5
  def test_redis
9
6
  assert { 'PONG' == Spinel.redis.ping }
10
7
 
11
- Spinel.redis = 'redis://127.0.0.1:6379/0'
12
- assert { 'PONG' == Spinel.redis.ping }
13
-
14
8
  mock_redis = MockRedis.new
15
9
  Spinel.redis = mock_redis
16
10
  assert { mock_redis.object_id == Spinel.redis.object_id }
@@ -41,91 +35,4 @@ class SpinelTest < Minitest::Test
41
35
  assert { 'spinel:cache:default:word1|word2' == @spinel.cachekey(%w(word1 word2)) }
42
36
  end
43
37
 
44
- def test_prefixes
45
- assert { ["ta", "tak", "take", "tal", "talk"] == @spinel.prefixes("take talk") }
46
- end
47
-
48
- def test_squish
49
- assert { "quick brown fox" == @spinel.squish(" quick \t brown\n fox ") }
50
- end
51
-
52
- def test_get_valid_document
53
- assert_raises(ArgumentError){ @spinel.get_valid_document({id: 1}) }
54
- assert_raises(ArgumentError){ @spinel.get_valid_document({body: 'body'}) }
55
- assert { [1, 'body', 0.0] == @spinel.get_valid_document({id: 1, body: 'body'}) }
56
- end
57
-
58
- def test_document_id
59
- assert { "doc_id" == @spinel.document_id({id: "doc_id"}) }
60
- assert { "doc_id" == @spinel.document_id({"id" => "doc_id"}) }
61
- end
62
-
63
- def test_document_score
64
- assert { 1.0 == @spinel.document_score({score: 1}) }
65
- assert { 1.0 == @spinel.document_score({"score" => 1}) }
66
- assert { 0.0 == @spinel.document_score({}) }
67
- end
68
-
69
- def test_document_body
70
- assert { "doc_body" == @spinel.document_body({body: "doc_body"}) }
71
- assert { "doc_body" == @spinel.document_body({"body" => "doc_body"}) }
72
- end
73
-
74
- def test_minimal_word
75
- assert { 2 == Spinel.minimal_word }
76
- end
77
-
78
- def test_cache_expire
79
- assert { 600 == Spinel.cache_expire }
80
- end
81
-
82
- def test_search_limit
83
- assert { 10 == Spinel.search_limit }
84
- end
85
-
86
- def test_document_key
87
- assert { 'body' == Spinel.document_key }
88
- end
89
-
90
- def test_namespace
91
- assert { 'spinel' == Spinel.namespace }
92
- end
93
-
94
- def test_store
95
- Spinel.redis.flushall
96
- @spinel.store id: 1, body: 'test'
97
- assert { 1 == Spinel.redis.hlen(@spinel.database) }
98
- end
99
-
100
- def test_get
101
- Spinel.redis.flushall
102
- @spinel.store id: 1, body: 'test'
103
- assert { {"id" => 1, "body" => 'test'} == @spinel.get(1) }
104
- end
105
-
106
- def test_remove
107
- Spinel.redis.flushall
108
- @spinel.store id: 1, body: 'test'
109
- @spinel.remove id: 1
110
- assert { 0 == Spinel.redis.hlen(@spinel.database) }
111
- end
112
-
113
- def test_search
114
- Spinel.redis.flushall
115
- @spinel.store id: 1, body: 'ruby'
116
- @spinel.store id: 2, body: 'rubx'
117
- assert { 2 == @spinel.search('rub').size }
118
- assert { 1 == @spinel.search('ruby').size }
119
- end
120
-
121
- def test_search_option
122
- assert { {limit: 10, cache: true} == @spinel.search_option }
123
- assert { {limit: 1, cache: true} == @spinel.search_option({limit: 1}) }
124
- assert { {limit: 10, cache: false} == @spinel.search_option({cache: false}) }
125
- end
126
-
127
- def test_search_word_split
128
- assert { ['test','word'] == @spinel.search_word_split('test word') }
129
- assert { ['abc','def'] == @spinel.search_word_split(' def abc ') }
130
- end
131
38
  end
@@ -7,10 +7,12 @@ CodeClimate::TestReporter.start if ENV['CCR']
7
7
 
8
8
  SimpleCov.start do
9
9
  add_filter "vendor"
10
+ add_filter "test"
10
11
  end
11
12
 
12
13
  require 'spinel'
13
14
  require 'mock_redis'
15
+ require 'connection_pool'
14
16
  require 'minitest/autorun'
15
17
  require 'minitest/unit'
16
18
  require 'minitest-power_assert'
@@ -20,10 +22,17 @@ Spinel.configure do |config|
20
22
  config.minimal_word = 2
21
23
  config.cache_expire = 600
22
24
  config.search_limit = 10
23
- config.document_key = :body
25
+ config.index_fields = :body
24
26
  config.namespace = 'spinel'
25
27
  end
26
28
 
29
+
30
+ class SpinelTestBase < Minitest::Test
31
+ def setup
32
+ @spinel = Spinel.new
33
+ end
34
+ end
35
+
27
36
  def test_data
28
37
  [
29
38
  {id: 1, body: 'and all with pearl and ruby glowing'},
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spinel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - k-shogo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-04 00:00:00.000000000 Z
11
+ date: 2015-02-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -150,6 +150,20 @@ dependencies:
150
150
  - - ">="
151
151
  - !ruby/object:Gem::Version
152
152
  version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: connection_pool
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
153
167
  description: lightweight text search system on Redis
154
168
  email:
155
169
  - platycod0n.ramosa@gmail.com
@@ -166,11 +180,17 @@ files:
166
180
  - lib/spinel.rb
167
181
  - lib/spinel/client.rb
168
182
  - lib/spinel/config.rb
183
+ - lib/spinel/connection_pool_proxy.rb
169
184
  - lib/spinel/helper.rb
170
185
  - lib/spinel/indexer.rb
171
186
  - lib/spinel/searcher.rb
172
187
  - lib/spinel/version.rb
173
188
  - spinel.gemspec
189
+ - test/config_test.rb
190
+ - test/connection_pool_proxy_test.rb
191
+ - test/helper_test.rb
192
+ - test/indexer_test.rb
193
+ - test/searcher_test.rb
174
194
  - test/spinel_test.rb
175
195
  - test/test_helper.rb
176
196
  homepage: ''
@@ -198,5 +218,10 @@ signing_key:
198
218
  specification_version: 4
199
219
  summary: lightweight text search system on Redis
200
220
  test_files:
221
+ - test/config_test.rb
222
+ - test/connection_pool_proxy_test.rb
223
+ - test/helper_test.rb
224
+ - test/indexer_test.rb
225
+ - test/searcher_test.rb
201
226
  - test/spinel_test.rb
202
227
  - test/test_helper.rb