lookup_by 0.1.2 → 0.1.3
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/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
|
|