lookup_by 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/lookup_by/cache.rb +47 -48
- data/lib/lookup_by/lookup.rb +19 -27
- data/lib/lookup_by/version.rb +1 -1
- data/spec/lookup_by_spec.rb +4 -4
- data/spec/support/shared_examples_for_a_lookup.rb +6 -6
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 170c2ef2408cf8495f0cfe3f30cd4811ee17cd6f
|
4
|
+
data.tar.gz: 14e0c54b5ec327fa87cd0044b67cd921df3a002b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 258e5adbe68b2c181613e08e5cb59e6d8044e1b28cea20dffb282d3489826aa9061e884cd200844953e95a23cc4e9286595f0a3e849205faa4ba6a102bd27d71
|
7
|
+
data.tar.gz: 76c03e4a60019234ba204c47d65520076b5dad3705a765523be4706b9caa78ae5199d9f9f992dca7e7c3ef65a48f8dc0d1563bdaf666bcc970e5343e29f7b0fd
|
data/lib/lookup_by/cache.rb
CHANGED
@@ -1,30 +1,28 @@
|
|
1
1
|
module LookupBy
|
2
2
|
class Cache
|
3
|
-
attr_reader :
|
4
|
-
|
5
|
-
attr_reader :field, :order, :type, :limit, :find, :write, :normalize
|
6
|
-
|
7
|
-
attr_accessor :enabled
|
3
|
+
attr_reader :cache, :field, :stats
|
4
|
+
attr_accessor :testing
|
8
5
|
|
9
6
|
def initialize(klass, options = {})
|
10
7
|
@klass = klass
|
11
8
|
@primary_key = klass.primary_key
|
12
9
|
@field = options[:field].to_sym
|
13
10
|
@cache = {}
|
14
|
-
@order = options[:order] || field
|
11
|
+
@order = options[:order] || @field
|
15
12
|
@read = options[:find]
|
16
13
|
@write = options[:find_or_create]
|
17
14
|
@normalize = options[:normalize]
|
15
|
+
@testing = false
|
18
16
|
@enabled = true
|
19
17
|
|
20
18
|
@stats = { db: Hash.new(0), cache: Hash.new(0) }
|
21
19
|
|
22
|
-
raise ArgumentError, %Q(unknown attribute "#{field}" for <#{klass}>) unless klass.column_names.include?(field.to_s)
|
20
|
+
raise ArgumentError, %Q(unknown attribute "#{@field}" for <#{klass}>) unless klass.column_names.include?(@field.to_s)
|
23
21
|
|
24
22
|
case options[:cache]
|
25
23
|
when true
|
26
|
-
@type
|
27
|
-
@read
|
24
|
+
@type = :all
|
25
|
+
@read ||= false
|
28
26
|
when ::Fixnum
|
29
27
|
raise ArgumentError, "`#{@klass}.lookup_by :#{@field}` options[:find] must be true when caching N" if @read == false
|
30
28
|
|
@@ -33,70 +31,87 @@ module LookupBy
|
|
33
31
|
@cache = Rails.configuration.allow_concurrency ? Caching::SafeLRU.new(@limit) : Caching::LRU.new(@limit)
|
34
32
|
@read = true
|
35
33
|
@write ||= false
|
36
|
-
@
|
34
|
+
@testing = true if Rails.env.test? && @write
|
37
35
|
else
|
38
36
|
@read = true
|
39
37
|
end
|
40
38
|
end
|
41
39
|
|
42
40
|
def reload
|
43
|
-
return unless
|
41
|
+
return unless @type == :all
|
44
42
|
|
45
43
|
clear
|
46
44
|
|
47
|
-
::ActiveRecord::Base.connection.send :log, "", "#{klass.name} Load Cache All" do
|
48
|
-
klass.order(order).each do |i|
|
49
|
-
cache[i.id] = i
|
45
|
+
::ActiveRecord::Base.connection.send :log, "", "#{@klass.name} Load Cache All" do
|
46
|
+
@klass.order(@order).each do |i|
|
47
|
+
@cache[i.id] = i
|
50
48
|
end
|
51
49
|
end
|
52
50
|
end
|
53
51
|
|
54
52
|
def clear
|
55
|
-
cache.clear
|
53
|
+
@cache.clear
|
56
54
|
end
|
57
55
|
|
58
56
|
def create!(*args, &block)
|
59
|
-
created = klass.create!(*args, &block)
|
60
|
-
cache[created.id] = created if cache?
|
57
|
+
created = @klass.create!(*args, &block)
|
58
|
+
@cache[created.id] = created if cache?
|
61
59
|
created
|
62
60
|
end
|
63
61
|
|
64
62
|
def fetch(value)
|
65
63
|
increment :cache, :get
|
66
64
|
|
67
|
-
value =
|
65
|
+
value = normalize(value) if @normalize && !value.is_a?(Fixnum)
|
68
66
|
|
69
67
|
found = cache_read(value) if cache?
|
70
|
-
found ||= db_read(value) if
|
68
|
+
found ||= db_read(value) if @read
|
69
|
+
found ||= db_read(value) if not @enabled
|
71
70
|
|
72
|
-
cache[found.id] = found
|
71
|
+
@cache[found.id] = found if found && cache?
|
73
72
|
|
74
|
-
found ||= db_write(value) if write
|
73
|
+
found ||= db_write(value) if @write
|
75
74
|
|
76
75
|
found
|
77
76
|
end
|
78
77
|
|
79
78
|
def has_cache?
|
80
|
-
|
79
|
+
@type && @enabled
|
81
80
|
end
|
82
81
|
|
83
82
|
def read_through?
|
84
83
|
@read
|
85
84
|
end
|
86
85
|
|
87
|
-
|
86
|
+
def enabled?
|
87
|
+
@enabled
|
88
|
+
end
|
88
89
|
|
89
|
-
def
|
90
|
-
|
90
|
+
def disabled?
|
91
|
+
!@enabled
|
92
|
+
end
|
91
93
|
|
92
|
-
|
94
|
+
def enable!
|
95
|
+
@enabled = true
|
96
|
+
reload
|
97
|
+
end
|
98
|
+
|
99
|
+
def disable!
|
100
|
+
@enabled = false
|
101
|
+
clear
|
102
|
+
end
|
103
|
+
|
104
|
+
private
|
105
|
+
|
106
|
+
def normalize(value)
|
107
|
+
@klass.new(@field => value).send(@field)
|
93
108
|
end
|
94
109
|
|
95
110
|
def cache_read(value)
|
96
111
|
if value.is_a? Fixnum
|
97
|
-
found = cache[value]
|
112
|
+
found = @cache[value]
|
98
113
|
else
|
99
|
-
found = cache.values.detect { |o| o.send(field) == value }
|
114
|
+
found = @cache.values.detect { |o| o.send(@field) == value }
|
100
115
|
end
|
101
116
|
|
102
117
|
increment :cache, found ? :hit : :miss
|
@@ -107,7 +122,7 @@ module LookupBy
|
|
107
122
|
def db_read(value)
|
108
123
|
increment :db, :get
|
109
124
|
|
110
|
-
found = klass.where(column_for(value) => value).first
|
125
|
+
found = @klass.where(column_for(value) => value).first
|
111
126
|
|
112
127
|
increment :db, found ? :hit : :miss
|
113
128
|
|
@@ -118,32 +133,16 @@ module LookupBy
|
|
118
133
|
def db_write(value)
|
119
134
|
column = column_for(value)
|
120
135
|
|
121
|
-
found = klass.create!(column => value) if column != primary_key
|
136
|
+
found = @klass.create!(column => value) if column != @primary_key
|
122
137
|
found
|
123
138
|
end
|
124
139
|
|
125
140
|
def column_for(value)
|
126
|
-
value.is_a?(Fixnum) ? primary_key : field
|
127
|
-
end
|
128
|
-
|
129
|
-
def enabled?
|
130
|
-
enabled
|
131
|
-
end
|
132
|
-
|
133
|
-
def cache_all?
|
134
|
-
type == :all
|
141
|
+
value.is_a?(Fixnum) ? @primary_key : @field
|
135
142
|
end
|
136
143
|
|
137
144
|
def cache?
|
138
|
-
|
139
|
-
end
|
140
|
-
|
141
|
-
def write?
|
142
|
-
!!write
|
143
|
-
end
|
144
|
-
|
145
|
-
def normalize?
|
146
|
-
!!normalize
|
145
|
+
@type && @enabled && !@testing
|
147
146
|
end
|
148
147
|
|
149
148
|
def increment(type, stat)
|
data/lib/lookup_by/lookup.rb
CHANGED
@@ -2,14 +2,26 @@ module LookupBy
|
|
2
2
|
module Lookup
|
3
3
|
module MacroMethods
|
4
4
|
def is_a_lookup?
|
5
|
-
is_a?
|
5
|
+
is_a? Lookup::ClassMethods
|
6
|
+
end
|
7
|
+
|
8
|
+
def lookup_by_disable(*methods)
|
9
|
+
methods.each do |method|
|
10
|
+
instance_eval <<-"END", __FILE__, __LINE__ + 1
|
11
|
+
def self.#{method}(*args)
|
12
|
+
raise NotImplementedError, "#{name}.#{method} is not supported on cached lookup tables." if @lookup.has_cache?
|
13
|
+
|
14
|
+
super
|
15
|
+
end
|
16
|
+
END
|
17
|
+
end
|
6
18
|
end
|
7
19
|
|
8
20
|
def lookup_by(field, options = {})
|
9
21
|
options.symbolize_keys!
|
10
22
|
options.assert_valid_keys :order, :cache, :normalize, :find, :find_or_create, :raise
|
11
23
|
|
12
|
-
raise "#{self} already called lookup_by" if is_a?
|
24
|
+
raise "#{self} already called lookup_by" if is_a? Lookup::ClassMethods
|
13
25
|
raise "#{self} responds_to :[], needed for lookup_by" if respond_to? :[]
|
14
26
|
raise "#{self} responds_to :lookup, needed for lookup_by" if respond_to? :lookup
|
15
27
|
|
@@ -18,7 +30,11 @@ module LookupBy
|
|
18
30
|
class_eval do
|
19
31
|
include InstanceMethods
|
20
32
|
|
21
|
-
|
33
|
+
singleton_class.class_eval do
|
34
|
+
attr_reader :lookup
|
35
|
+
end
|
36
|
+
|
37
|
+
lookup_by_disable :destroy, :destroy_all, :delete, :delete_all
|
22
38
|
|
23
39
|
# TODO: check for a db unique constraint or Rails validation
|
24
40
|
|
@@ -65,30 +81,6 @@ module LookupBy
|
|
65
81
|
else raise TypeError, "#{name}[arg]: arg must be a String, Symbol, Fixnum, nil, or #{name}"
|
66
82
|
end
|
67
83
|
end
|
68
|
-
|
69
|
-
def destroy_all(conditions = nil)
|
70
|
-
raise NotImplementedError, "#{name}.destroy_all is not supported on cached lookup tables." if @lookup.has_cache?
|
71
|
-
|
72
|
-
super
|
73
|
-
end
|
74
|
-
|
75
|
-
def destroy(id)
|
76
|
-
raise NotImplementedError, "#{name}.destroy(arg) is not supported on cached lookup tables" if @lookup.has_cache?
|
77
|
-
|
78
|
-
super
|
79
|
-
end
|
80
|
-
|
81
|
-
def delete_all(conditions = nil)
|
82
|
-
raise NotImplementedError, "#{name}.delete_all is not supported on cached lookup tables." if @lookup.has_cache?
|
83
|
-
|
84
|
-
super
|
85
|
-
end
|
86
|
-
|
87
|
-
def delete(id_or_array)
|
88
|
-
raise NotImplementedError, "#{name}.delete(arg) is not supported on cached lookup tables." if @lookup.has_cache?
|
89
|
-
|
90
|
-
super
|
91
|
-
end
|
92
84
|
end
|
93
85
|
|
94
86
|
module InstanceMethods
|
data/lib/lookup_by/version.rb
CHANGED
data/spec/lookup_by_spec.rb
CHANGED
@@ -80,8 +80,8 @@ describe LookupBy::Lookup do
|
|
80
80
|
it_behaves_like "a cache"
|
81
81
|
it_behaves_like "a read-through cache"
|
82
82
|
|
83
|
-
it "
|
84
|
-
subject.lookup.
|
83
|
+
it "is not testing when not writing through the LRU" do
|
84
|
+
subject.lookup.testing.should be_false
|
85
85
|
end
|
86
86
|
end
|
87
87
|
|
@@ -93,8 +93,8 @@ describe LookupBy::Lookup do
|
|
93
93
|
it_behaves_like "a read-through cache"
|
94
94
|
it_behaves_like "a write-through cache"
|
95
95
|
|
96
|
-
it "
|
97
|
-
subject.lookup.
|
96
|
+
it "sets testing when RAILS_ENV=test" do
|
97
|
+
subject.lookup.testing.should be_true
|
98
98
|
end
|
99
99
|
end
|
100
100
|
end
|
@@ -60,8 +60,8 @@ end
|
|
60
60
|
|
61
61
|
shared_examples "a cache" do
|
62
62
|
it "caches records" do
|
63
|
-
|
64
|
-
subject.lookup.
|
63
|
+
was_testing = subject.lookup.testing
|
64
|
+
subject.lookup.testing = false
|
65
65
|
|
66
66
|
original = subject.create(name: "original")
|
67
67
|
|
@@ -71,7 +71,7 @@ shared_examples "a cache" do
|
|
71
71
|
subject.update(original.id, subject.lookup.field => "updated")
|
72
72
|
subject[original.id].name.should eq "original"
|
73
73
|
|
74
|
-
subject.lookup.
|
74
|
+
subject.lookup.testing = was_testing
|
75
75
|
end
|
76
76
|
|
77
77
|
it "raises on .destroy_all" do
|
@@ -146,8 +146,8 @@ shared_examples "a read-through cache" do
|
|
146
146
|
it_behaves_like "a read-through proxy"
|
147
147
|
|
148
148
|
it "caches new records" do
|
149
|
-
|
150
|
-
subject.lookup.
|
149
|
+
was_testing = subject.lookup.testing
|
150
|
+
subject.lookup.testing = false
|
151
151
|
|
152
152
|
created = subject.create(name: "cached")
|
153
153
|
|
@@ -157,7 +157,7 @@ shared_examples "a read-through cache" do
|
|
157
157
|
subject.update(created.id, name: "changed")
|
158
158
|
subject[created.id].name.should eq "cached"
|
159
159
|
|
160
|
-
subject.lookup.
|
160
|
+
subject.lookup.testing = was_testing
|
161
161
|
end
|
162
162
|
end
|
163
163
|
|