lookup_by 0.9.0 → 0.9.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.
- checksums.yaml +4 -4
- data/Appraisals +4 -0
- data/Gemfile +2 -1
- data/README.md +25 -19
- data/Rakefile +1 -0
- data/gemfiles/rails_3.2.gemfile +1 -1
- data/gemfiles/rails_4.0.gemfile +1 -1
- data/gemfiles/rails_4.1.gemfile +1 -1
- data/gemfiles/rails_4.2.gemfile +22 -0
- data/lib/lookup_by/cache.rb +2 -1
- data/lib/lookup_by/caching/lru.rb +21 -27
- data/lib/lookup_by/caching/safe_lru.rb +24 -11
- data/lib/lookup_by/lookup.rb +1 -1
- data/lib/lookup_by/version.rb +1 -1
- data/spec/association_spec.rb +1 -1
- data/spec/caching/lru_spec.rb +36 -55
- data/spec/dummy/app/models/unsynchronizable.rb +3 -0
- data/spec/dummy/db/migrate/20121019040009_create_tables.rb +2 -0
- data/spec/dummy/db/structure.sql +51 -0
- data/spec/lookup_by_spec.rb +18 -2
- data/spec/rails_helper.rb +53 -0
- data/spec/spec_helper.rb +61 -47
- metadata +8 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f743786ef23e1404d94ab4e182d9fc4e56ebf02b
|
|
4
|
+
data.tar.gz: 544619c07c7172702cba5729e8a8c1bb80783ddf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c5e44713f89aaca0651af41331620efec4fd7e42a9dbf2d72b2617ddb95ee77d96b8f1bcb17832a31d65365aa62af4820ed29c6b23fc84e99c262446c875af59
|
|
7
|
+
data.tar.gz: 46803218755acd5241351f1ae535a6a71b41f8adfbd0fe9d53897ea677cd11358318a134c14a5ddf61487c4f823cd9eab7a6123d36c6a5ee3b2d1e211ad7577c
|
data/Appraisals
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -16,36 +16,31 @@
|
|
|
16
16
|
|
|
17
17
|
# Overview
|
|
18
18
|
|
|
19
|
-
LookupBy is a thread-safe lookup table cache for ActiveRecord that reduces normalization pains
|
|
19
|
+
LookupBy is a thread-safe lookup table cache for ActiveRecord that reduces normalization pains.
|
|
20
20
|
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
21
|
+
* Configurable lookup column
|
|
22
|
+
* Caching (read-through, write-through, least recently used (LRU))
|
|
23
|
+
* Symbolized values
|
|
24
|
+
* Normalized values, _e.g. canonicalizing UTF-8 before lookup_
|
|
24
25
|
|
|
25
26
|
### Dependencies
|
|
26
27
|
|
|
27
|
-
* Rails 3.2
|
|
28
|
+
* Rails 3.2+, _tested on Rails 3.2, 4.0, 4.1, and 4.2_
|
|
28
29
|
* PostgreSQL
|
|
29
30
|
|
|
30
31
|
### Development
|
|
31
32
|
|
|
32
|
-
[github.com/companygardener/lookup_by][development]
|
|
33
|
+
* [github.com/companygardener/lookup_by][development]
|
|
33
34
|
|
|
34
35
|
### Source
|
|
35
36
|
|
|
36
|
-
git clone git://github.com/companygardener/lookup_by.git
|
|
37
|
+
* git clone git://github.com/companygardener/lookup_by.git
|
|
37
38
|
|
|
38
39
|
### Bug reports
|
|
39
40
|
|
|
40
|
-
|
|
41
|
+
Please create [Issues][] to submit bug reports and feature requests. However, I ask that you'd kindly review [these bug reporting guidelines](https://github.com/companygardener/lookup_by/wiki/Bug-Reports) first.
|
|
41
42
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
If you find a security bug, please **_do not_** use the issue tracker. Instead, send an email to: thecompanygardener@gmail.com.
|
|
45
|
-
|
|
46
|
-
Please create [Issues][issues] to submit bug reports and feature requests.
|
|
47
|
-
|
|
48
|
-
_Provide a failing rspec test that concisely demonstrates the issue._
|
|
43
|
+
_If you find a security bug, **_do not_** use the public issue tracker. Instead, send an email to: thecompanygardener@gmail.com._
|
|
49
44
|
|
|
50
45
|
# Installation
|
|
51
46
|
|
|
@@ -211,7 +206,7 @@ lookup_by :column_name, cache: 50
|
|
|
211
206
|
|
|
212
207
|
### Cache miss
|
|
213
208
|
|
|
214
|
-
|
|
209
|
+
Enable cache read-throughs using the `:find` option.
|
|
215
210
|
|
|
216
211
|
```ruby
|
|
217
212
|
# Return nil
|
|
@@ -229,7 +224,7 @@ lookup_by :column_name, cache: true, find: true
|
|
|
229
224
|
|
|
230
225
|
### DB miss
|
|
231
226
|
|
|
232
|
-
|
|
227
|
+
Enable cache write-throughs using the `:find_or_create` option.
|
|
233
228
|
|
|
234
229
|
_Note: This will only work if the primary key is a sequence and all columns but the lookup column are optional._
|
|
235
230
|
|
|
@@ -246,7 +241,7 @@ lookup_by :column_name, cache: 20, find_or_create: true
|
|
|
246
241
|
|
|
247
242
|
### Raise on Miss
|
|
248
243
|
|
|
249
|
-
|
|
244
|
+
Configure cache misses to raise a `LookupBy::RecordNotFound` error.
|
|
250
245
|
|
|
251
246
|
```ruby
|
|
252
247
|
# Return nil
|
|
@@ -260,7 +255,6 @@ lookup_by :column_name, cache: true, raise: true
|
|
|
260
255
|
lookup_by :column_name, cache: true, find: true, raise: true
|
|
261
256
|
```
|
|
262
257
|
|
|
263
|
-
|
|
264
258
|
### Normalize values
|
|
265
259
|
|
|
266
260
|
```ruby
|
|
@@ -279,6 +273,18 @@ Can be useful to handle `params` that are not required.
|
|
|
279
273
|
lookup_by :column_name, allow_blank: true
|
|
280
274
|
```
|
|
281
275
|
|
|
276
|
+
### Threadsafety
|
|
277
|
+
|
|
278
|
+
Force the LRU to be threadsafe (used to test the SafeLRU).
|
|
279
|
+
|
|
280
|
+
With Rails 4, the Safe LRU is selected automatically in production-like environments.
|
|
281
|
+
|
|
282
|
+
```ruby
|
|
283
|
+
# Safe
|
|
284
|
+
# Use threadsafe cache
|
|
285
|
+
lookup_by :column_name, cache: 10, safe: true
|
|
286
|
+
```
|
|
287
|
+
|
|
282
288
|
# Integration
|
|
283
289
|
|
|
284
290
|
### Cucumber
|
data/Rakefile
CHANGED
data/gemfiles/rails_3.2.gemfile
CHANGED
|
@@ -8,7 +8,7 @@ group :development, :test do
|
|
|
8
8
|
gem "appraisal", "~> 1.0", :require => false
|
|
9
9
|
gem "rspec"
|
|
10
10
|
gem "rspec-its"
|
|
11
|
-
gem "
|
|
11
|
+
gem "rspec-rails"
|
|
12
12
|
gem "pg", :platform => :ruby
|
|
13
13
|
gem "activerecord-jdbcpostgresql-adapter", :platform => :jruby
|
|
14
14
|
gem "simplecov", :require => false
|
data/gemfiles/rails_4.0.gemfile
CHANGED
|
@@ -8,7 +8,7 @@ group :development, :test do
|
|
|
8
8
|
gem "appraisal", "~> 1.0", :require => false
|
|
9
9
|
gem "rspec"
|
|
10
10
|
gem "rspec-its"
|
|
11
|
-
gem "
|
|
11
|
+
gem "rspec-rails"
|
|
12
12
|
gem "pg", :platform => :ruby
|
|
13
13
|
gem "activerecord-jdbcpostgresql-adapter", :platform => :jruby
|
|
14
14
|
gem "simplecov", :require => false
|
data/gemfiles/rails_4.1.gemfile
CHANGED
|
@@ -8,7 +8,7 @@ group :development, :test do
|
|
|
8
8
|
gem "appraisal", "~> 1.0", :require => false
|
|
9
9
|
gem "rspec"
|
|
10
10
|
gem "rspec-its"
|
|
11
|
-
gem "
|
|
11
|
+
gem "rspec-rails"
|
|
12
12
|
gem "pg", :platform => :ruby
|
|
13
13
|
gem "activerecord-jdbcpostgresql-adapter", :platform => :jruby
|
|
14
14
|
gem "simplecov", :require => false
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# This file was generated by Appraisal
|
|
2
|
+
|
|
3
|
+
source "https://rubygems.org"
|
|
4
|
+
|
|
5
|
+
gem "rails", "~> 4.2.0.beta1"
|
|
6
|
+
|
|
7
|
+
group :development, :test do
|
|
8
|
+
gem "appraisal", "~> 1.0", :require => false
|
|
9
|
+
gem "rspec"
|
|
10
|
+
gem "rspec-its"
|
|
11
|
+
gem "rspec-rails"
|
|
12
|
+
gem "pg", :platform => :ruby
|
|
13
|
+
gem "activerecord-jdbcpostgresql-adapter", :platform => :jruby
|
|
14
|
+
gem "simplecov", :require => false
|
|
15
|
+
gem "coveralls", :require => false
|
|
16
|
+
gem "pry", :require => false
|
|
17
|
+
gem "colored", :require => false
|
|
18
|
+
gem "racc"
|
|
19
|
+
gem "json"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
gemspec :path => "../"
|
data/lib/lookup_by/cache.rb
CHANGED
|
@@ -17,6 +17,7 @@ module LookupBy
|
|
|
17
17
|
@raise_on_miss = options[:raise] || false
|
|
18
18
|
@testing = false
|
|
19
19
|
@enabled = true
|
|
20
|
+
@safe = options[:safe] || concurrent?
|
|
20
21
|
|
|
21
22
|
@stats = { db: Hash.new(0), cache: Hash.new(0) }
|
|
22
23
|
|
|
@@ -33,7 +34,7 @@ module LookupBy
|
|
|
33
34
|
|
|
34
35
|
@type = :lru
|
|
35
36
|
@limit = options[:cache]
|
|
36
|
-
@cache =
|
|
37
|
+
@cache = @safe ? Caching::SafeLRU.new(@limit) : Caching::LRU.new(@limit)
|
|
37
38
|
@read = true
|
|
38
39
|
@write ||= false
|
|
39
40
|
@testing = true if Rails.env.test? && @write
|
|
@@ -1,62 +1,56 @@
|
|
|
1
1
|
module LookupBy
|
|
2
2
|
module Caching
|
|
3
|
-
class LRU
|
|
3
|
+
class LRU
|
|
4
4
|
attr_reader :lru
|
|
5
5
|
|
|
6
6
|
def initialize(maxsize)
|
|
7
|
-
super()
|
|
8
|
-
|
|
9
7
|
@maxsize = maxsize
|
|
10
8
|
@lru = []
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def clear
|
|
14
|
-
@lru.clear
|
|
15
|
-
|
|
16
|
-
super
|
|
9
|
+
@hash = {}
|
|
17
10
|
end
|
|
18
11
|
|
|
19
12
|
def [](key)
|
|
20
|
-
return nil unless
|
|
13
|
+
return nil unless @hash.key?(key)
|
|
21
14
|
touch(key)
|
|
22
|
-
|
|
15
|
+
@hash[key]
|
|
23
16
|
end
|
|
24
17
|
|
|
25
18
|
def []=(key, value)
|
|
26
19
|
touch(key)
|
|
27
|
-
|
|
28
|
-
|
|
20
|
+
@hash[key] = value
|
|
21
|
+
@hash.delete(@lru.shift) while @hash.size > @maxsize
|
|
29
22
|
end
|
|
30
23
|
|
|
31
|
-
def
|
|
32
|
-
|
|
24
|
+
def delete(key)
|
|
25
|
+
@lru.delete(key)
|
|
26
|
+
|
|
27
|
+
@hash.delete(key)
|
|
33
28
|
end
|
|
34
29
|
|
|
35
|
-
def
|
|
36
|
-
|
|
30
|
+
def clear
|
|
31
|
+
@lru.clear
|
|
32
|
+
@hash.clear
|
|
37
33
|
self
|
|
38
34
|
end
|
|
39
35
|
|
|
40
|
-
def
|
|
41
|
-
@
|
|
36
|
+
def values
|
|
37
|
+
@hash.values
|
|
38
|
+
end
|
|
42
39
|
|
|
43
|
-
|
|
40
|
+
def size
|
|
41
|
+
@hash.size
|
|
44
42
|
end
|
|
45
43
|
|
|
46
44
|
def to_h
|
|
47
|
-
|
|
45
|
+
@hash.dup
|
|
48
46
|
end
|
|
49
47
|
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
private
|
|
52
49
|
def touch(key)
|
|
50
|
+
# TODO: LRU deletes are O(N)
|
|
53
51
|
@lru.delete(key)
|
|
54
52
|
@lru << key
|
|
55
53
|
end
|
|
56
|
-
|
|
57
|
-
def prune
|
|
58
|
-
delete(@lru.shift) while size > @maxsize
|
|
59
|
-
end
|
|
60
54
|
end
|
|
61
55
|
end
|
|
62
56
|
end
|
|
@@ -1,29 +1,42 @@
|
|
|
1
|
+
# TODO: Evaluate using ThreadSafe::Hash and ThreadSafe::Array.
|
|
2
|
+
|
|
3
|
+
require "mutex_m"
|
|
4
|
+
|
|
1
5
|
module LookupBy
|
|
2
6
|
module Caching
|
|
3
7
|
class SafeLRU < LRU
|
|
8
|
+
include Mutex_m
|
|
9
|
+
|
|
4
10
|
def initialize(maxsize = nil)
|
|
5
|
-
@mutex = Mutex.new
|
|
6
11
|
super
|
|
7
12
|
end
|
|
8
13
|
|
|
9
|
-
def clear
|
|
10
|
-
@mutex.synchronize { super }
|
|
11
|
-
end
|
|
12
|
-
|
|
13
14
|
def [](key)
|
|
14
|
-
|
|
15
|
+
synchronize { super }
|
|
15
16
|
end
|
|
16
17
|
|
|
17
18
|
def []=(key, value)
|
|
18
|
-
|
|
19
|
+
synchronize { super }
|
|
19
20
|
end
|
|
20
21
|
|
|
21
|
-
def
|
|
22
|
-
|
|
22
|
+
def delete(key)
|
|
23
|
+
synchronize { super }
|
|
23
24
|
end
|
|
24
25
|
|
|
25
|
-
def
|
|
26
|
-
|
|
26
|
+
def clear
|
|
27
|
+
synchronize { super }
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def values
|
|
31
|
+
synchronize { super }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def size
|
|
35
|
+
synchronize { super }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def to_h
|
|
39
|
+
synchronize { super }
|
|
27
40
|
end
|
|
28
41
|
end
|
|
29
42
|
end
|
data/lib/lookup_by/lookup.rb
CHANGED
|
@@ -29,7 +29,7 @@ module LookupBy
|
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
options.symbolize_keys!
|
|
32
|
-
options.assert_valid_keys :allow_blank, :order, :cache, :normalize, :find, :find_or_create, :raise
|
|
32
|
+
options.assert_valid_keys :allow_blank, :order, :cache, :normalize, :find, :find_or_create, :raise, :safe
|
|
33
33
|
|
|
34
34
|
raise "#{self} already called lookup_by" if is_a? Lookup::ClassMethods
|
|
35
35
|
raise "#{self} responds_to :[], needed for lookup_by" if respond_to? :[]
|
data/lib/lookup_by/version.rb
CHANGED
data/spec/association_spec.rb
CHANGED
data/spec/caching/lru_spec.rb
CHANGED
|
@@ -1,77 +1,58 @@
|
|
|
1
|
-
require "
|
|
1
|
+
require "rails_helper"
|
|
2
2
|
require "lookup_by/caching/lru"
|
|
3
3
|
|
|
4
4
|
include LookupBy::Caching
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
@cache = LRU.new(2)
|
|
6
|
+
describe LookupBy::Caching::LRU do
|
|
7
|
+
let(:cache) do
|
|
8
|
+
cache = LRU.new(2)
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
subject { @cache }
|
|
16
|
-
|
|
17
|
-
it "stores entries" do
|
|
18
|
-
expect(@cache[1]).to eq "one"
|
|
19
|
-
expect(@cache[2]).to eq "two"
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
it "drops oldest" do
|
|
23
|
-
@cache[3] = "three"
|
|
10
|
+
cache[1] = "one"
|
|
11
|
+
cache[2] = "two"
|
|
12
|
+
cache
|
|
13
|
+
end
|
|
24
14
|
|
|
25
|
-
|
|
15
|
+
describe "#[]" do
|
|
16
|
+
it "caches" do
|
|
17
|
+
expect(cache[1]).to eq "one"
|
|
18
|
+
expect(cache[2]).to eq "two"
|
|
26
19
|
end
|
|
27
20
|
|
|
28
|
-
it "
|
|
29
|
-
|
|
30
|
-
|
|
21
|
+
it "promotes gets" do
|
|
22
|
+
cache[1]
|
|
23
|
+
cache[3] = "three"
|
|
31
24
|
|
|
32
|
-
expect(
|
|
33
|
-
expect(@cache[2]).to be_nil
|
|
34
|
-
expect(@cache[3]).to eq "three"
|
|
25
|
+
expect(cache[2]).to be_nil
|
|
35
26
|
end
|
|
27
|
+
end
|
|
36
28
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
29
|
+
describe "#[]=" do
|
|
30
|
+
it "promotes sets" do
|
|
31
|
+
cache[3] = "three"
|
|
40
32
|
|
|
41
|
-
expect(
|
|
42
|
-
expect(@cache[2]).to be_nil
|
|
43
|
-
expect(@cache[3]).to eq "three"
|
|
33
|
+
expect(cache[1]).to be_nil
|
|
44
34
|
end
|
|
45
35
|
|
|
46
|
-
it "
|
|
47
|
-
cache =
|
|
36
|
+
it "deletes least-recently accessed value" do
|
|
37
|
+
cache[3] = "three"
|
|
48
38
|
|
|
49
|
-
cache[1]
|
|
50
|
-
expect(cache.size).to eq 1
|
|
51
|
-
cache.clear
|
|
52
|
-
expect(cache.size).to eq 0
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
specify "#merge" do
|
|
56
|
-
merged = @cache.merge(1 => "change", 3 => "three")
|
|
57
|
-
expect(merged).to be_instance_of(LRU)
|
|
58
|
-
expect(merged).to eq(1 => "change", 3 => "three")
|
|
39
|
+
expect(cache[1]).to be_nil
|
|
59
40
|
end
|
|
41
|
+
end
|
|
60
42
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
43
|
+
describe "#clear" do
|
|
44
|
+
specify { expect(cache.clear.size).to eq 0 }
|
|
45
|
+
end
|
|
64
46
|
|
|
65
|
-
|
|
66
|
-
|
|
47
|
+
describe "#size" do
|
|
48
|
+
specify { expect(cache.size).to eq 2 }
|
|
49
|
+
end
|
|
67
50
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
end
|
|
51
|
+
describe "#values" do
|
|
52
|
+
specify { expect(cache.values).to eq ["one", "two"] }
|
|
53
|
+
end
|
|
72
54
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
end
|
|
55
|
+
describe "#to_h" do
|
|
56
|
+
specify { expect(cache.to_h).to eq(1 => "one", 2 => "two") }
|
|
76
57
|
end
|
|
77
58
|
end
|
data/spec/dummy/db/structure.sql
CHANGED
|
@@ -469,6 +469,35 @@ CREATE SEQUENCE unfindables_unfindable_id_seq
|
|
|
469
469
|
ALTER SEQUENCE unfindables_unfindable_id_seq OWNED BY unfindables.unfindable_id;
|
|
470
470
|
|
|
471
471
|
|
|
472
|
+
--
|
|
473
|
+
-- Name: unsynchronizables; Type: TABLE; Schema: public; Owner: -; Tablespace:
|
|
474
|
+
--
|
|
475
|
+
|
|
476
|
+
CREATE TABLE unsynchronizables (
|
|
477
|
+
unsynchronizable_id integer NOT NULL,
|
|
478
|
+
unsynchronizable text NOT NULL
|
|
479
|
+
);
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
--
|
|
483
|
+
-- Name: unsynchronizables_unsynchronizable_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
|
484
|
+
--
|
|
485
|
+
|
|
486
|
+
CREATE SEQUENCE unsynchronizables_unsynchronizable_id_seq
|
|
487
|
+
START WITH 1
|
|
488
|
+
INCREMENT BY 1
|
|
489
|
+
NO MINVALUE
|
|
490
|
+
NO MAXVALUE
|
|
491
|
+
CACHE 1;
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
--
|
|
495
|
+
-- Name: unsynchronizables_unsynchronizable_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
|
496
|
+
--
|
|
497
|
+
|
|
498
|
+
ALTER SEQUENCE unsynchronizables_unsynchronizable_id_seq OWNED BY unsynchronizables.unsynchronizable_id;
|
|
499
|
+
|
|
500
|
+
|
|
472
501
|
--
|
|
473
502
|
-- Name: user_agents; Type: TABLE; Schema: public; Owner: -; Tablespace:
|
|
474
503
|
--
|
|
@@ -610,6 +639,13 @@ ALTER TABLE ONLY uncacheables ALTER COLUMN uncacheable_id SET DEFAULT nextval('u
|
|
|
610
639
|
ALTER TABLE ONLY unfindables ALTER COLUMN unfindable_id SET DEFAULT nextval('unfindables_unfindable_id_seq'::regclass);
|
|
611
640
|
|
|
612
641
|
|
|
642
|
+
--
|
|
643
|
+
-- Name: unsynchronizable_id; Type: DEFAULT; Schema: public; Owner: -
|
|
644
|
+
--
|
|
645
|
+
|
|
646
|
+
ALTER TABLE ONLY unsynchronizables ALTER COLUMN unsynchronizable_id SET DEFAULT nextval('unsynchronizables_unsynchronizable_id_seq'::regclass);
|
|
647
|
+
|
|
648
|
+
|
|
613
649
|
--
|
|
614
650
|
-- Name: user_agent_id; Type: DEFAULT; Schema: public; Owner: -
|
|
615
651
|
--
|
|
@@ -729,6 +765,14 @@ ALTER TABLE ONLY unfindables
|
|
|
729
765
|
ADD CONSTRAINT unfindables_pkey PRIMARY KEY (unfindable_id);
|
|
730
766
|
|
|
731
767
|
|
|
768
|
+
--
|
|
769
|
+
-- Name: unsynchronizables_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
|
|
770
|
+
--
|
|
771
|
+
|
|
772
|
+
ALTER TABLE ONLY unsynchronizables
|
|
773
|
+
ADD CONSTRAINT unsynchronizables_pkey PRIMARY KEY (unsynchronizable_id);
|
|
774
|
+
|
|
775
|
+
|
|
732
776
|
--
|
|
733
777
|
-- Name: user_agents_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
|
|
734
778
|
--
|
|
@@ -847,6 +891,13 @@ CREATE UNIQUE INDEX unfindables__u_unfindable ON unfindables USING btree (unfind
|
|
|
847
891
|
CREATE UNIQUE INDEX unique_schema_migrations ON schema_migrations USING btree (version);
|
|
848
892
|
|
|
849
893
|
|
|
894
|
+
--
|
|
895
|
+
-- Name: unsynchronizables__u_unsynchronizable; Type: INDEX; Schema: public; Owner: -; Tablespace:
|
|
896
|
+
--
|
|
897
|
+
|
|
898
|
+
CREATE UNIQUE INDEX unsynchronizables__u_unsynchronizable ON unsynchronizables USING btree (unsynchronizable);
|
|
899
|
+
|
|
900
|
+
|
|
850
901
|
--
|
|
851
902
|
-- Name: user_agents__u_user_agent; Type: INDEX; Schema: public; Owner: -; Tablespace:
|
|
852
903
|
--
|
data/spec/lookup_by_spec.rb
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
require "
|
|
1
|
+
require "rails_helper"
|
|
2
2
|
require "lookup_by"
|
|
3
|
-
require "pry"
|
|
4
3
|
|
|
5
4
|
describe ::ActiveRecord::Base do
|
|
6
5
|
describe "macro methods" do
|
|
@@ -210,4 +209,21 @@ describe LookupBy::Lookup do
|
|
|
210
209
|
}.to raise_error(ArgumentError)
|
|
211
210
|
end
|
|
212
211
|
end
|
|
212
|
+
|
|
213
|
+
context "Unsynchronizable.lookup_by :column, cache: 1, find_or_create: true, safe: true" do
|
|
214
|
+
subject { Unsynchronizable }
|
|
215
|
+
|
|
216
|
+
it_behaves_like "a lookup"
|
|
217
|
+
it_behaves_like "a cache"
|
|
218
|
+
it_behaves_like "a read-through cache"
|
|
219
|
+
it_behaves_like "a write-through cache"
|
|
220
|
+
|
|
221
|
+
it "does not deadlock when synchronizing access" do
|
|
222
|
+
expect {
|
|
223
|
+
Unsynchronizable['foo']
|
|
224
|
+
Unsynchronizable['foo']
|
|
225
|
+
Unsynchronizable['bar']
|
|
226
|
+
}.to_not raise_error
|
|
227
|
+
end
|
|
228
|
+
end
|
|
213
229
|
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# This file is copied to spec/ when you run 'rails generate rspec:install'
|
|
2
|
+
ENV["RAILS_ENV"] ||= 'test'
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
if ENV["COVERAGE"]
|
|
6
|
+
require 'simplecov'
|
|
7
|
+
require 'coveralls'
|
|
8
|
+
|
|
9
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
|
10
|
+
Coveralls::SimpleCov::Formatter,
|
|
11
|
+
SimpleCov::Formatter::HTMLFormatter
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
SimpleCov.start
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
begin
|
|
18
|
+
require File.expand_path("../../config/environment", __FILE__)
|
|
19
|
+
rescue LoadError
|
|
20
|
+
require File.expand_path("../dummy/config/environment", __FILE__)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
require 'pry'
|
|
24
|
+
require 'rspec/its'
|
|
25
|
+
require 'rspec/rails'
|
|
26
|
+
|
|
27
|
+
# Requires supporting ruby files with custom matchers and macros, etc, in
|
|
28
|
+
# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
|
|
29
|
+
# run as spec files by default. This means that files in spec/support that end
|
|
30
|
+
# in _spec.rb will both be required and run as specs, causing the specs to be
|
|
31
|
+
# run twice. It is recommended that you do not name files matching this glob to
|
|
32
|
+
# end with _spec.rb. You can configure this pattern with the --pattern
|
|
33
|
+
# option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
|
|
34
|
+
# require File.expand_path("../support/shared_examples_for_a_lookup.rb", __FILE__)
|
|
35
|
+
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
|
|
36
|
+
Dir[Rails.root.join( "../support/**/*.rb")].each { |f| require f }
|
|
37
|
+
|
|
38
|
+
# Checks for pending migrations before tests are run.
|
|
39
|
+
# If you are not using ActiveRecord, you can remove this line.
|
|
40
|
+
ActiveRecord::Migration.maintain_test_schema! if ActiveRecord::Migration.respond_to?(:maintain_test_schema!)
|
|
41
|
+
|
|
42
|
+
# ActiveRecord::Migration.maintain_test_schema! if defined?(ActiveRecord::Migration) && ActiveRecord::Migration.respond_to?(:maintain_test_schema!)
|
|
43
|
+
|
|
44
|
+
RSpec.configure do |config|
|
|
45
|
+
config.use_transactional_fixtures = true
|
|
46
|
+
|
|
47
|
+
config.backtrace_exclusion_patterns << %r{vendor/}
|
|
48
|
+
config.backtrace_exclusion_patterns << %r{lib/rspec/rails}
|
|
49
|
+
|
|
50
|
+
config.infer_spec_type_from_file_location!
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
require 'rubinius_helper' if ENV["DEBUG"] && RUBY_ENGINE == 'rbx'
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,60 +1,74 @@
|
|
|
1
|
-
# This file
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
require File.expand_path("../../config/environment", __FILE__)
|
|
18
|
-
rescue LoadError
|
|
19
|
-
require File.expand_path("../dummy/config/environment", __FILE__)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
require 'rspec'
|
|
23
|
-
require 'rspec/its'
|
|
24
|
-
require 'database_cleaner'
|
|
25
|
-
require 'pry'
|
|
26
|
-
|
|
27
|
-
ActiveRecord::Migration.maintain_test_schema! if defined?(ActiveRecord::Migration) && ActiveRecord::Migration.respond_to?(:maintain_test_schema!)
|
|
28
|
-
|
|
29
|
-
# Requires supporting ruby files with custom matchers and macros, etc,
|
|
30
|
-
# in spec/support/ and its subdirectories.
|
|
31
|
-
Dir[Rails.root.join("../support/**/*.rb")].each {|f| require f}
|
|
32
|
-
|
|
1
|
+
# This file was generated by the `rails generate rspec:install` command. Conventionally, all
|
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
|
3
|
+
# The generated `.rspec` file contains `--require spec_helper` which will cause this
|
|
4
|
+
# file to always be loaded, without a need to explicitly require it in any files.
|
|
5
|
+
#
|
|
6
|
+
# Given that it is always loaded, you are encouraged to keep this file as
|
|
7
|
+
# light-weight as possible. Requiring heavyweight dependencies from this file
|
|
8
|
+
# will add to the boot time of your test suite on EVERY test run, even for an
|
|
9
|
+
# individual file that may not need all of that loaded. Instead, make a
|
|
10
|
+
# separate helper file that requires this one and then use it only in the specs
|
|
11
|
+
# that actually need it.
|
|
12
|
+
#
|
|
13
|
+
# The `.rspec` file also contains a few flags that are not defaults but that
|
|
14
|
+
# users commonly want.
|
|
15
|
+
#
|
|
16
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
|
33
17
|
RSpec.configure do |config|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
#
|
|
38
|
-
config.filter_run focus
|
|
18
|
+
# These two settings work together to allow you to limit a spec run
|
|
19
|
+
# to individual examples or groups you care about by tagging them with
|
|
20
|
+
# `:focus` metadata. When nothing is tagged with `:focus`, all examples
|
|
21
|
+
# get run.
|
|
22
|
+
config.filter_run :focus
|
|
39
23
|
config.run_all_when_everything_filtered = true
|
|
40
24
|
|
|
25
|
+
# Many RSpec users commonly either run the entire suite or an individual
|
|
26
|
+
# file, and it's useful to allow more verbose output when running an
|
|
27
|
+
# individual spec file.
|
|
28
|
+
if config.files_to_run.one?
|
|
29
|
+
# Use the documentation formatter for detailed output,
|
|
30
|
+
# unless a formatter has already been configured
|
|
31
|
+
# (e.g. via a command-line flag).
|
|
32
|
+
config.default_formatter = 'doc'
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Print the 10 slowest examples and example groups at the
|
|
36
|
+
# end of the spec run, to help surface which specs are running
|
|
37
|
+
# particularly slow.
|
|
38
|
+
config.profile_examples = 10
|
|
39
|
+
|
|
41
40
|
# Run specs in random order to surface order dependencies. If you find an
|
|
42
41
|
# order dependency and want to debug it, you can fix the order by providing
|
|
43
42
|
# the seed, which is printed after each run.
|
|
44
43
|
# --seed 1234
|
|
45
|
-
config.order =
|
|
44
|
+
config.order = :random
|
|
46
45
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
# Seed global randomization in this process using the `--seed` CLI option.
|
|
47
|
+
# Setting this allows you to use `--seed` to deterministically reproduce
|
|
48
|
+
# test failures related to randomization by passing the same `--seed` value
|
|
49
|
+
# as the one that triggered the failure.
|
|
50
|
+
Kernel.srand config.seed
|
|
50
51
|
|
|
51
|
-
config.
|
|
52
|
-
|
|
52
|
+
# rspec-expectations config goes here. You can use an alternate
|
|
53
|
+
# assertion/expectation library such as wrong or the stdlib/minitest
|
|
54
|
+
# assertions if you prefer.
|
|
55
|
+
config.expect_with :rspec do |expectations|
|
|
56
|
+
# Enable only the newer, non-monkey-patching expect syntax.
|
|
57
|
+
# For more details, see:
|
|
58
|
+
# - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
|
|
59
|
+
expectations.syntax = :expect
|
|
53
60
|
end
|
|
54
61
|
|
|
55
|
-
config.
|
|
56
|
-
|
|
62
|
+
# rspec-mocks config goes here. You can use an alternate test double
|
|
63
|
+
# library (such as bogus or mocha) by changing the `mock_with` option here.
|
|
64
|
+
config.mock_with :rspec do |mocks|
|
|
65
|
+
# Enable only the newer, non-monkey-patching expect syntax.
|
|
66
|
+
# For more details, see:
|
|
67
|
+
# - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
|
|
68
|
+
mocks.syntax = :expect
|
|
69
|
+
|
|
70
|
+
# Prevents you from mocking or stubbing a method that does not exist on
|
|
71
|
+
# a real object. This is generally recommended.
|
|
72
|
+
mocks.verify_partial_doubles = true
|
|
57
73
|
end
|
|
58
74
|
end
|
|
59
|
-
|
|
60
|
-
require 'rubinius_helper' if ENV["DEBUG"] && RUBY_ENGINE == 'rbx'
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: lookup_by
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.9.
|
|
4
|
+
version: 0.9.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Erik Peterson
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2014-08-
|
|
11
|
+
date: 2014-08-21 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|
|
@@ -71,6 +71,7 @@ files:
|
|
|
71
71
|
- gemfiles/rails_3.2.gemfile
|
|
72
72
|
- gemfiles/rails_4.0.gemfile
|
|
73
73
|
- gemfiles/rails_4.1.gemfile
|
|
74
|
+
- gemfiles/rails_4.2.gemfile
|
|
74
75
|
- lib/lookup_by.rb
|
|
75
76
|
- lib/lookup_by/association.rb
|
|
76
77
|
- lib/lookup_by/cache.rb
|
|
@@ -103,6 +104,7 @@ files:
|
|
|
103
104
|
- spec/dummy/app/models/street.rb
|
|
104
105
|
- spec/dummy/app/models/uncacheable.rb
|
|
105
106
|
- spec/dummy/app/models/unfindable.rb
|
|
107
|
+
- spec/dummy/app/models/unsynchronizable.rb
|
|
106
108
|
- spec/dummy/app/models/user_agent.rb
|
|
107
109
|
- spec/dummy/bin/bundle
|
|
108
110
|
- spec/dummy/bin/rails
|
|
@@ -125,6 +127,7 @@ files:
|
|
|
125
127
|
- spec/dummy/log/.gitkeep
|
|
126
128
|
- spec/dummy/script/rails
|
|
127
129
|
- spec/lookup_by_spec.rb
|
|
130
|
+
- spec/rails_helper.rb
|
|
128
131
|
- spec/rubinius_helper.rb
|
|
129
132
|
- spec/spec_helper.rb
|
|
130
133
|
- spec/support/shared_examples_for_a_lookup.rb
|
|
@@ -148,7 +151,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
148
151
|
version: '0'
|
|
149
152
|
requirements: []
|
|
150
153
|
rubyforge_project:
|
|
151
|
-
rubygems_version: 2.
|
|
154
|
+
rubygems_version: 2.4.1
|
|
152
155
|
signing_key:
|
|
153
156
|
specification_version: 4
|
|
154
157
|
summary: A thread-safe lookup table cache for ActiveRecord
|
|
@@ -172,6 +175,7 @@ test_files:
|
|
|
172
175
|
- spec/dummy/app/models/street.rb
|
|
173
176
|
- spec/dummy/app/models/uncacheable.rb
|
|
174
177
|
- spec/dummy/app/models/unfindable.rb
|
|
178
|
+
- spec/dummy/app/models/unsynchronizable.rb
|
|
175
179
|
- spec/dummy/app/models/user_agent.rb
|
|
176
180
|
- spec/dummy/bin/bundle
|
|
177
181
|
- spec/dummy/bin/rails
|
|
@@ -194,6 +198,7 @@ test_files:
|
|
|
194
198
|
- spec/dummy/log/.gitkeep
|
|
195
199
|
- spec/dummy/script/rails
|
|
196
200
|
- spec/lookup_by_spec.rb
|
|
201
|
+
- spec/rails_helper.rb
|
|
197
202
|
- spec/rubinius_helper.rb
|
|
198
203
|
- spec/spec_helper.rb
|
|
199
204
|
- spec/support/shared_examples_for_a_lookup.rb
|