cachely 0.0.1 → 0.0.2
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.
- data/Gemfile +1 -1
- data/README.md +75 -5
- data/cachely.gemspec +6 -3
- data/config/database.yml +1 -0
- data/config/redis.yml +4 -0
- data/lib/cachely.rb +42 -12
- data/lib/cachely/mechanics.rb +218 -0
- data/lib/cachely/version.rb +1 -1
- data/test/models/dummy_class.rb +439 -76
- data/test/models/dummy_model.rb +5 -1
- data/test/unit/base_test.rb +3 -1
- data/test/unit/cachely_test.rb +142 -3
- data/test/unit/conversions_test.rb +68 -0
- data/test/unit/mechanics_test.rb +41 -0
- metadata +84 -33
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,81 @@
|
|
1
1
|
# Cachely
|
2
2
|
|
3
|
-
|
3
|
+
Transparent method level caching using redis. Event machine optional.
|
4
4
|
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
class A
|
8
|
+
include Cachely
|
9
|
+
|
10
|
+
cachely :foo
|
11
|
+
|
12
|
+
def foo
|
13
|
+
sleep(10)
|
14
|
+
return rand(500) #Holy moly, what a HUGE, LONG CALL! Returns a different value every time.
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
a = A.new
|
20
|
+
|
21
|
+
start = Time.now
|
22
|
+
result_1 = a.foo
|
23
|
+
after = Time.now
|
24
|
+
time_1 = after-start
|
25
|
+
|
26
|
+
start = Time.now
|
27
|
+
result_2 = a.foo #Now it uses the redis cache.
|
28
|
+
after = Time.now
|
29
|
+
time_2 = after-start
|
30
|
+
|
31
|
+
p "First call took #{time_1}"
|
32
|
+
|
33
|
+
p "Second call took #{time_2}"
|
34
|
+
|
35
|
+
p "Results equal? #{result_2 == result_1}. Of course! It cached the output."
|
36
|
+
|
37
|
+
=> "First call took 10.031092"
|
38
|
+
=> "Second call took 0.032047"
|
39
|
+
=> "Results equal? true. Of course! It cached the output."
|
40
|
+
|
41
|
+
|
42
|
+
In order to make this work, you must connect to a redis store using the method:
|
43
|
+
|
44
|
+
Cachely::Mechanics.connect(opts = {})
|
45
|
+
|
46
|
+
Opts accepts keys :host, :port, :password, :driver. See redis-rb documentation for which drivers you want,
|
47
|
+
including whether or not you wish it to be evented.
|
48
|
+
|
49
|
+
I'd recommend doing this in a Rails initializer, or if you're using sinatra or other rack app, in config.ru.
|
50
|
+
|
51
|
+
If you want cached results to expire, instead of
|
52
|
+
|
53
|
+
cachely :foo
|
54
|
+
|
55
|
+
use
|
56
|
+
|
57
|
+
cachely :foo, time_to_expiry: 3.minutes
|
58
|
+
|
59
|
+
If you have a class method of the same name as an instance variable,
|
60
|
+
|
61
|
+
cachely :foo
|
62
|
+
|
63
|
+
will still work, it will cache both the instance method foo and the class method foo, but in different
|
64
|
+
keyed locations, of course. To specify instance or class method, do
|
65
|
+
|
66
|
+
cachely :foo, :type => "instance"
|
67
|
+
cachely :foo, :type => "class"
|
68
|
+
|
69
|
+
Cachely is able to figure out whether or not to use the cache by looking at the arguments you pass in.
|
70
|
+
Generally, if your arguments are the same, and the object you're calling the method on is the same(Cachely uses
|
71
|
+
the to_json method on the object you call the method on to determine this), then it assumes the result
|
72
|
+
will be the same and uses the cached result.
|
73
|
+
|
74
|
+
CAVEAT: Do NOT use Cachely for functions that depend on time of day or random numbers, as these are inherently uncachable.
|
75
|
+
If you check the tests out, you'll see random number functions are used exhaustively to test the caching ability of cachely,
|
76
|
+
because we know the function wasn't called if the second call yields the same number.
|
77
|
+
|
78
|
+
If you do not understand the implications of the caveat, do not use cachely. You're not ready yet.
|
5
79
|
## Installation
|
6
80
|
|
7
81
|
Add this line to your application's Gemfile:
|
@@ -16,10 +90,6 @@ Or install it yourself as:
|
|
16
90
|
|
17
91
|
$ gem install cachely
|
18
92
|
|
19
|
-
## Usage
|
20
|
-
|
21
|
-
TODO: Write usage instructions here
|
22
|
-
|
23
93
|
## Contributing
|
24
94
|
|
25
95
|
1. Fork it
|
data/cachely.gemspec
CHANGED
@@ -4,8 +4,8 @@ require File.expand_path('../lib/cachely/version', __FILE__)
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
5
|
gem.authors = ["Jordan Prince"]
|
6
6
|
gem.email = ["jordanmprince@gmail.com"]
|
7
|
-
gem.description = %q{
|
8
|
-
gem.summary = %q{
|
7
|
+
gem.description = %q{Transparently cache the results of methods using redis.}
|
8
|
+
gem.summary = %q{Transparently cache the results of methods using redis.}
|
9
9
|
gem.homepage = ""
|
10
10
|
|
11
11
|
gem.files = `git ls-files`.split($\)
|
@@ -14,5 +14,8 @@ Gem::Specification.new do |gem|
|
|
14
14
|
gem.name = "cachely"
|
15
15
|
gem.require_paths = ["lib"]
|
16
16
|
gem.version = Cachely::VERSION
|
17
|
-
gem.add_dependency "
|
17
|
+
gem.add_dependency "redis", '~> 3.0.1'
|
18
|
+
gem.add_dependency "hiredis", '~> 0.4.5'
|
19
|
+
gem.add_dependency "em-synchrony"
|
20
|
+
gem.add_dependency "json"
|
18
21
|
end
|
data/config/database.yml
CHANGED
data/config/redis.yml
ADDED
data/lib/cachely.rb
CHANGED
@@ -1,25 +1,55 @@
|
|
1
1
|
require_relative "cachely/version"
|
2
|
-
|
2
|
+
require_relative 'cachely/mechanics'
|
3
|
+
require 'redis'
|
4
|
+
require 'hiredis'
|
5
|
+
require 'em-synchrony'
|
6
|
+
require 'json'
|
3
7
|
module Cachely
|
4
8
|
module ClassMethods
|
5
|
-
|
9
|
+
|
10
|
+
# Called after class methods loaded, this aliases out the old method, puts in place the listener version
|
11
|
+
# That only calls it if the cache can't fill in.
|
12
|
+
#
|
13
|
+
# @name [Symbol] fcn name
|
14
|
+
# @return nil
|
15
|
+
def singleton_method_added(name)
|
16
|
+
if(@cachely_fcns and @cachely_fcns.include?(name) and !self.respond_to?("#{name.to_s}_old".to_sym))
|
17
|
+
unless(@cachely_opts[name][:type] and @cachely_opts[name][:type] == "instance")
|
18
|
+
self.instance_eval("alias :#{"#{name.to_s}_old".to_sym} :#{name}")
|
19
|
+
Cachely::Mechanics.setup_method(self,name, @cachely_opts[name][:time_to_expiry], true)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
super
|
23
|
+
end
|
24
|
+
|
25
|
+
# Called after methods loaded, this aliases out the old method, puts in place the listener version
|
26
|
+
# That only calls it if the cache can't fill in.
|
27
|
+
#
|
28
|
+
# @name [Symbol] fcn name
|
29
|
+
# @return nil
|
6
30
|
def method_added(name)
|
7
|
-
if(@cachely_fcns.include?(name) and
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
self.define_method name do |*args| #define new one
|
14
|
-
send "#{name.to_s}_old".to_sym, *args
|
31
|
+
if(@cachely_fcns and @cachely_fcns.include?(name) and !self.new.respond_to?("#{name.to_s}_old".to_sym))
|
32
|
+
# only do this if we either haven't explicitly labeled fcn type, or it's not class.
|
33
|
+
unless(@cachely_opts[name][:type] and @cachely_opts[name][:type] == "class")
|
34
|
+
self.class_eval("alias :#{"#{name.to_s}_old".to_sym} :#{name}") #alias old function out
|
35
|
+
Cachely::Mechanics.setup_method(self,name, @cachely_opts[name][:time_to_expiry])
|
15
36
|
end
|
16
37
|
end
|
38
|
+
super
|
17
39
|
end
|
18
40
|
|
41
|
+
# Catches the method name, stores for after because methods aren't loaded when this is called.
|
42
|
+
#
|
43
|
+
# @fcn [Symbol] fcn name
|
44
|
+
# @opts [Hash] options
|
45
|
+
# @extension No idea
|
46
|
+
# @return [Array] Array of current fcns to be added.
|
19
47
|
def cachely(fcn, opts = {}, &extension)
|
20
|
-
@
|
21
|
-
@
|
48
|
+
@cachely_fcns ||= []
|
49
|
+
@cachely_opts ||= {}
|
50
|
+
|
22
51
|
@cachely_fcns << fcn
|
52
|
+
@cachely_opts[fcn] = opts
|
23
53
|
end
|
24
54
|
end
|
25
55
|
|
@@ -0,0 +1,218 @@
|
|
1
|
+
#place all mechanics methods here bc we do not want to introduce random method namespaces to objects
|
2
|
+
module Cachely
|
3
|
+
module Mechanics
|
4
|
+
|
5
|
+
# Connects to the Redis store you want to use for a cache.
|
6
|
+
#
|
7
|
+
# @opt [Hash<Symbol>]
|
8
|
+
# @return [Boolean] success or not
|
9
|
+
def self.connect(opts = {})
|
10
|
+
@redis ||= Redis.new(
|
11
|
+
:host => opts[:host],
|
12
|
+
:port => opts[:port],
|
13
|
+
:password => opts[:password],
|
14
|
+
:driver => opts[:driver])
|
15
|
+
end
|
16
|
+
|
17
|
+
# Flush the Redis store of all keys.
|
18
|
+
#
|
19
|
+
# @return [String] success or not, normally "OK"
|
20
|
+
def self.flush_all_keys
|
21
|
+
redis.flushdb
|
22
|
+
end
|
23
|
+
|
24
|
+
# Grab current redis instance. Has ability to reconnect for you if it fails.
|
25
|
+
#
|
26
|
+
# @return [Redis], instance of Redis client.
|
27
|
+
def self.redis
|
28
|
+
@tries = 0 unless @tries
|
29
|
+
begin
|
30
|
+
@redis.get("test") #tests to see if we're still authed.
|
31
|
+
@tries = 0 #means we can reset our trymeter.
|
32
|
+
rescue Exception => e
|
33
|
+
@tries+=1 if @tries
|
34
|
+
if @tries<5
|
35
|
+
connect
|
36
|
+
end
|
37
|
+
end
|
38
|
+
return @redis
|
39
|
+
end
|
40
|
+
|
41
|
+
# Defines the method using my hacky eval script. So far, this is the only way I've found that
|
42
|
+
# allows me to define variable argument length definitions. If you have a better idea, please
|
43
|
+
# refactor it!
|
44
|
+
#
|
45
|
+
# @name [Symbol] fcn name
|
46
|
+
# @return nil
|
47
|
+
def self.setup_method(klazz, name, time_to_expire_in_s, is_class_method = false)
|
48
|
+
context = (is_class_method ? klazz : klazz.new)
|
49
|
+
args_str = context.method("#{name.to_s}_old".to_sym).parameters.map { |k| k.last}.join(',')
|
50
|
+
args_to_use_in_def = args_str.empty? ? "" : "," + args_str
|
51
|
+
eval("klazz.define_#{is_class_method ? "singleton_" : ""}method(:#{name}) do #{args_str.empty? ? "" : "|#{args_str}|"}; " +
|
52
|
+
"result = Cachely::Mechanics.get(context,:#{name}#{args_to_use_in_def});" +
|
53
|
+
"return result.first if result.is_a?(Array);" +
|
54
|
+
"result = context.send(:#{"#{name.to_s}_old"}#{args_to_use_in_def});" +
|
55
|
+
"Cachely::Mechanics.store(context,:#{"#{name.to_s}"}, result#{time_to_expire_in_s.nil? ? ",nil": ",#{time_to_expire_in_s}"}#{args_to_use_in_def});" +
|
56
|
+
"return result;" +
|
57
|
+
"end"
|
58
|
+
)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Gets a cached response to a method.
|
62
|
+
#
|
63
|
+
# @method [String,Symbol] the method name
|
64
|
+
# @args The arguments of the method
|
65
|
+
# @return The original response of the method back, whatever it may be.
|
66
|
+
def self.get(obj, method, *args)
|
67
|
+
result = redis.get(redis_key(obj, method, *args))
|
68
|
+
#return an array, bc if the result stored was nil, it looks the same as if
|
69
|
+
#we got no result back(which we would return nil) so we differentiate by putting
|
70
|
+
#our return value always in an array. Easy to check.
|
71
|
+
result.nil? ? nil : [map_s_to_param(result)]
|
72
|
+
end
|
73
|
+
|
74
|
+
# Stores the result in it's proper cached location on redis by getting the redis key and parsing
|
75
|
+
# The result into a storable string, mostly made up of recursive json.
|
76
|
+
#
|
77
|
+
# @method [Symbol] Method name
|
78
|
+
# @result Anything, really.
|
79
|
+
# @args Arguments of the method
|
80
|
+
# @return [String] Should be "Ok" or something similar.
|
81
|
+
def self.store(obj, method, result, time_to_exp_in_sec, *args)
|
82
|
+
redis.set(redis_key(obj, method, *args), map_param_to_s(result))
|
83
|
+
redis.expire(redis_key(obj, method, *args), time_to_exp_in_sec) if time_to_exp_in_sec
|
84
|
+
end
|
85
|
+
|
86
|
+
# Converts method name and arguments into a coherent key. Creates a hash and to_jsons it
|
87
|
+
# And that becomes the redis key. Spiffy, I know.
|
88
|
+
#
|
89
|
+
# @method [String,Symbol] The method name
|
90
|
+
# @return [String] The proper redis key to be used in storage.
|
91
|
+
def self.redis_key(obj, method, *args)
|
92
|
+
map_param_to_s({
|
93
|
+
:obj => obj.to_s.match(/^#</) ? "instance:#{obj.class}" : obj.to_s,
|
94
|
+
:attributes => obj.to_json, #Best way to identify objects is to just to_json them.
|
95
|
+
:method => method,
|
96
|
+
:args => args
|
97
|
+
})
|
98
|
+
end
|
99
|
+
|
100
|
+
# Turns any string into a parameter. Current supported types are primitives, orm models
|
101
|
+
# That respond to id and have an updated_at field, and objects that have a to_json method.
|
102
|
+
#
|
103
|
+
# @s The string to convert
|
104
|
+
# @return [Object] The respawned object
|
105
|
+
def self.map_s_to_param(s)
|
106
|
+
begin
|
107
|
+
respawned_hash = JSON.parse(s)
|
108
|
+
|
109
|
+
if respawned_hash.is_a?(Array)
|
110
|
+
respawned_hash.map! do |piece|
|
111
|
+
map_s_to_param(piece)
|
112
|
+
end
|
113
|
+
elsif respawned_hash.is_a?(Hash)
|
114
|
+
respawned_hash = respawned_hash.inject(Hash.new) do |new_hash, entry|
|
115
|
+
new_hash[map_s_to_param(entry[0])] = map_s_to_param(entry[1])
|
116
|
+
new_hash
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
return respawned_hash
|
121
|
+
rescue JSON::ParserError => e
|
122
|
+
#The only times the string isn't json is if it is a primitive, or an ORM object
|
123
|
+
#This exception happens then, we catch it, and check orm signature.
|
124
|
+
|
125
|
+
return map_s_to_obj(s)
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
# Turns String into an actual object
|
131
|
+
#
|
132
|
+
# @s The string to convert
|
133
|
+
# @return The respawned object
|
134
|
+
def self.map_s_to_obj(s)
|
135
|
+
type = s.split(":").first
|
136
|
+
data = s.gsub(/^#{type}:/,'')
|
137
|
+
|
138
|
+
case type
|
139
|
+
when "TrueClass"
|
140
|
+
return true
|
141
|
+
when "FalseClass"
|
142
|
+
return false
|
143
|
+
when "Symbol"
|
144
|
+
return data.to_sym
|
145
|
+
when "Fixnum"
|
146
|
+
return data.to_i
|
147
|
+
when "Float"
|
148
|
+
return data.to_f
|
149
|
+
when "String"
|
150
|
+
return data
|
151
|
+
when "NilClass"
|
152
|
+
return nil
|
153
|
+
else
|
154
|
+
obj = Object.const_get(type).new
|
155
|
+
JSON.parse(data).each do |key, value|
|
156
|
+
obj.send(key+"=",value)
|
157
|
+
end
|
158
|
+
return obj
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
# Turns any parameter into a string. Current supported types are primitives, orm models
|
163
|
+
# That respond to id and have an updated_at field, and objects that have a to_json method.
|
164
|
+
#
|
165
|
+
# @p The object to convert
|
166
|
+
# @return [String] The redis coded string.
|
167
|
+
def self.map_param_to_s(p)
|
168
|
+
if(p.is_a?(Hash))
|
169
|
+
return map_hash_to_s(p)
|
170
|
+
elsif(p.is_a?(Array))
|
171
|
+
return map_array_to_s(p)
|
172
|
+
elsif(p.respond_to?("to_json"))
|
173
|
+
#below do extra search if string bc string puts annoying quotes in json like "\"1\""
|
174
|
+
#breaks the parser on the return translation.
|
175
|
+
translated = nil
|
176
|
+
if p.is_a?(String)
|
177
|
+
translated = p
|
178
|
+
elsif p.is_a?(Symbol)
|
179
|
+
translated = p.to_s
|
180
|
+
elsif p.nil?
|
181
|
+
translated = "nil"
|
182
|
+
elsif p.is_a?(ActiveRecord::Base)
|
183
|
+
#don't want { "dummy_model" = > {:attributes => 1}}
|
184
|
+
#want {:attributes => 1}
|
185
|
+
translated = JSON.parse(p.to_json)[p.class.to_s.underscore].to_json
|
186
|
+
else
|
187
|
+
translated = p.to_json
|
188
|
+
end
|
189
|
+
|
190
|
+
return p.class.to_s + ":" + translated
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
# Maps hash to s, basically does recursive call to map_param_to_s to get everythign inside
|
195
|
+
# and then to_jsons.
|
196
|
+
#
|
197
|
+
# @p [Hash] Incoming hash
|
198
|
+
# @return [String] Outgoing redis string
|
199
|
+
def self.map_hash_to_s(p)
|
200
|
+
p.inject(Hash.new) do |hash, entry|
|
201
|
+
hash[map_param_to_s(entry[0])] = map_param_to_s(entry[1])
|
202
|
+
hash
|
203
|
+
end.to_json
|
204
|
+
end
|
205
|
+
|
206
|
+
# Map array to s, calls recursively on elements then to json
|
207
|
+
#
|
208
|
+
# @p [Array] Incoming array
|
209
|
+
# @return [String] Outgoing redis string
|
210
|
+
def self.map_array_to_s(p)
|
211
|
+
p.map do |part|
|
212
|
+
map_param_to_s(part)
|
213
|
+
end.to_json
|
214
|
+
end
|
215
|
+
|
216
|
+
|
217
|
+
end
|
218
|
+
end
|
data/lib/cachely/version.rb
CHANGED
data/test/models/dummy_class.rb
CHANGED
@@ -1,92 +1,455 @@
|
|
1
1
|
class DummyClass
|
2
2
|
include Cachely
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
3
|
+
attr_accessor :random_no
|
4
|
+
|
5
|
+
cachely :cache_expiry, time_to_expiry: 1.seconds
|
6
|
+
|
7
|
+
cachely :class_diff, time_to_expiry: 3.minutes
|
8
|
+
|
9
|
+
cachely :instance_only_cache, time_to_expiry: 3.minutes, type: "instance"
|
10
|
+
cachely :class_only_cache, time_to_expiry: 3.minutes, type: "class"
|
11
|
+
|
12
|
+
cachely :instance_fixnum, time_to_expiry: 3.minutes
|
13
|
+
cachely :instance_fixnum_one, time_to_expiry: 3.minutes
|
14
|
+
cachely :instance_fixnum_two, time_to_expiry: 3.minutes
|
15
|
+
|
16
|
+
cachely :instance_float, time_to_expiry: 3.minutes
|
17
|
+
cachely :instance_float_one, time_to_expiry: 3.minutes
|
18
|
+
cachely :instance_float_two, time_to_expiry: 3.minutes
|
19
|
+
|
20
|
+
cachely :instance_string, time_to_expiry: 3.minutes
|
21
|
+
cachely :instance_string_one, time_to_expiry: 3.minutes
|
22
|
+
cachely :instance_string_two, time_to_expiry: 3.minutes
|
23
|
+
|
24
|
+
cachely :instance_symbol, time_to_expiry: 3.minutes
|
25
|
+
cachely :instance_symbol_one, time_to_expiry: 3.minutes
|
26
|
+
cachely :instance_symbol_two, time_to_expiry: 3.minutes
|
27
|
+
|
28
|
+
cachely :instance_nilclass, time_to_expiry: 3.minutes
|
29
|
+
cachely :instance_nilclass_one, time_to_expiry: 3.minutes
|
30
|
+
cachely :instance_nilclass_two, time_to_expiry: 3.minutes
|
31
|
+
|
32
|
+
cachely :instance_falseclass, time_to_expiry: 3.minutes
|
33
|
+
cachely :instance_falseclass_one, time_to_expiry: 3.minutes
|
34
|
+
cachely :instance_falseclass_two, time_to_expiry: 3.minutes
|
35
|
+
|
36
|
+
cachely :instance_trueclass, time_to_expiry: 3.minutes
|
37
|
+
cachely :instance_trueclass_one, time_to_expiry: 3.minutes
|
38
|
+
cachely :instance_trueclass_two, time_to_expiry: 3.minutes
|
39
|
+
|
40
|
+
cachely :instance_orm, time_to_expiry: 3.minutes
|
41
|
+
cachely :instance_orm_one, time_to_expiry: 3.minutes
|
42
|
+
cachely :instance_orm_two, time_to_expiry: 3.minutes
|
43
|
+
|
44
|
+
cachely :instance_array, time_to_expiry: 3.minutes
|
45
|
+
cachely :instance_array_one, time_to_expiry: 3.minutes
|
46
|
+
cachely :instance_array_two, time_to_expiry: 3.minutes
|
47
|
+
|
48
|
+
cachely :instance_hash, time_to_expiry: 3.minutes
|
49
|
+
cachely :instance_hash_one, time_to_expiry: 3.minutes
|
50
|
+
cachely :instance_hash_two, time_to_expiry: 3.minutes
|
51
|
+
|
52
|
+
cachely :instance_to_json, time_to_expiry: 3.minutes
|
53
|
+
cachely :instance_to_json_one, time_to_expiry: 3.minutes
|
54
|
+
cachely :instance_to_json_two, time_to_expiry: 3.minutes
|
55
|
+
|
56
|
+
cachely :class_fixnum, time_to_expiry: 3.minutes
|
57
|
+
cachely :class_fixnum_one, time_to_expiry: 3.minutes
|
58
|
+
cachely :class_fixnum_two, time_to_expiry: 3.minutes
|
59
|
+
|
60
|
+
cachely :class_float, time_to_expiry: 3.minutes
|
61
|
+
cachely :class_float_one, time_to_expiry: 3.minutes
|
62
|
+
cachely :class_float_two, time_to_expiry: 3.minutes
|
63
|
+
|
64
|
+
cachely :class_string, time_to_expiry: 3.minutes
|
65
|
+
cachely :class_string_one, time_to_expiry: 3.minutes
|
66
|
+
cachely :class_string_two, time_to_expiry: 3.minutes
|
67
|
+
|
68
|
+
cachely :class_symbol, time_to_expiry: 3.minutes
|
69
|
+
cachely :class_symbol_one, time_to_expiry: 3.minutes
|
70
|
+
cachely :class_symbol_two, time_to_expiry: 3.minutes
|
71
|
+
|
72
|
+
cachely :class_nilclass, time_to_expiry: 3.minutes
|
73
|
+
cachely :class_nilclass_one, time_to_expiry: 3.minutes
|
74
|
+
cachely :class_nilclass_two, time_to_expiry: 3.minutes
|
75
|
+
|
76
|
+
cachely :class_falseclass, time_to_expiry: 3.minutes
|
77
|
+
cachely :class_falseclass_one, time_to_expiry: 3.minutes
|
78
|
+
cachely :class_falseclass_two, time_to_expiry: 3.minutes
|
79
|
+
|
80
|
+
cachely :class_trueclass, time_to_expiry: 3.minutes
|
81
|
+
cachely :class_trueclass_one, time_to_expiry: 3.minutes
|
82
|
+
cachely :class_trueclass_two, time_to_expiry: 3.minutes
|
83
|
+
|
84
|
+
cachely :class_orm, time_to_expiry: 3.minutes
|
85
|
+
cachely :class_orm_one, time_to_expiry: 3.minutes
|
86
|
+
cachely :class_orm_two, time_to_expiry: 3.minutes
|
87
|
+
|
88
|
+
cachely :class_array, time_to_expiry: 3.minutes
|
89
|
+
cachely :class_array_one, time_to_expiry: 3.minutes
|
90
|
+
cachely :class_array_two, time_to_expiry: 3.minutes
|
91
|
+
|
92
|
+
cachely :class_hash, time_to_expiry: 3.minutes
|
93
|
+
cachely :class_hash_one, time_to_expiry: 3.minutes
|
94
|
+
cachely :class_hash_two, time_to_expiry: 3.minutes
|
95
|
+
|
96
|
+
cachely :class_to_json, time_to_expiry: 3.minutes
|
97
|
+
cachely :class_to_json_one, time_to_expiry: 3.minutes
|
98
|
+
cachely :class_to_json_two, time_to_expiry: 3.minutes
|
99
|
+
|
100
|
+
def to_json
|
101
|
+
{
|
102
|
+
"random_no" => self.random_no
|
103
|
+
}.to_json
|
104
|
+
end
|
105
|
+
|
106
|
+
def instance_only_cache
|
12
107
|
rand(500)
|
13
108
|
end
|
14
|
-
|
15
|
-
def self.
|
109
|
+
|
110
|
+
def self.instance_only_cache
|
16
111
|
rand(500)
|
17
112
|
end
|
18
|
-
|
19
|
-
def
|
113
|
+
|
114
|
+
def class_only_cache
|
20
115
|
rand(500)
|
21
116
|
end
|
22
|
-
|
23
|
-
def
|
117
|
+
|
118
|
+
def self.class_only_cache
|
24
119
|
rand(500)
|
25
120
|
end
|
26
|
-
|
27
|
-
def
|
28
|
-
|
121
|
+
|
122
|
+
def self.class_diff
|
123
|
+
rand(500)
|
29
124
|
end
|
30
|
-
|
31
|
-
def
|
32
|
-
|
125
|
+
|
126
|
+
def class_diff
|
127
|
+
rand(500)
|
33
128
|
end
|
34
|
-
|
35
|
-
def
|
36
|
-
|
37
|
-
:foo => "bar#{rand(500)}",
|
38
|
-
:baz => "boof"
|
39
|
-
}
|
129
|
+
|
130
|
+
def cache_expiry
|
131
|
+
rand(500)
|
40
132
|
end
|
41
|
-
|
42
|
-
def
|
43
|
-
|
44
|
-
:foo => "bar#{rand(500)}",
|
45
|
-
:baz => "boof"
|
46
|
-
}
|
47
|
-
end
|
48
|
-
|
49
|
-
def test_function_string
|
50
|
-
rand(500).to_s
|
51
|
-
end
|
52
|
-
|
53
|
-
def self.class_test_function_string
|
54
|
-
rand(500).to_s
|
55
|
-
end
|
56
|
-
|
57
|
-
def test_function_obj
|
58
|
-
DummyModel.create(
|
59
|
-
:attr1 => rand(500),
|
60
|
-
:attr2 => rand(500)
|
61
|
-
)
|
62
|
-
end
|
63
|
-
|
64
|
-
def self.class_test_function_obj
|
65
|
-
DummyModel.create(
|
66
|
-
:attr1 => rand(500),
|
67
|
-
:attr2 => rand(500)
|
68
|
-
)
|
69
|
-
end
|
70
|
-
|
71
|
-
def test_function_array_obj
|
72
|
-
[test_function_obj, test_function_obj]
|
73
|
-
end
|
74
|
-
|
75
|
-
def self.class_test_function_array_obj
|
76
|
-
[test_function_obj, test_function_obj]
|
77
|
-
end
|
78
|
-
|
79
|
-
def test_function_hash_obj
|
80
|
-
{
|
81
|
-
:foo => test_function_obj,
|
82
|
-
:bar => test_function_obj
|
83
|
-
}
|
133
|
+
|
134
|
+
def instance_fixnum
|
135
|
+
rand(500)
|
84
136
|
end
|
85
|
-
|
86
|
-
def
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
137
|
+
|
138
|
+
def instance_fixnum_one(a)
|
139
|
+
rand(500)
|
140
|
+
end
|
141
|
+
|
142
|
+
def instance_fixnum_two(a,b)
|
143
|
+
rand(500)
|
144
|
+
end
|
145
|
+
|
146
|
+
def instance_float
|
147
|
+
rand(500).to_f + 0.5
|
148
|
+
end
|
149
|
+
|
150
|
+
def instance_float_one(a)
|
151
|
+
rand(500).to_f + 0.5
|
152
|
+
end
|
153
|
+
|
154
|
+
def instance_float_two(a,b)
|
155
|
+
rand(500).to_f + 0.5
|
156
|
+
end
|
157
|
+
|
158
|
+
def instance_string
|
159
|
+
rand(500).to_s + "cheese"
|
160
|
+
end
|
161
|
+
|
162
|
+
def instance_string_one(a)
|
163
|
+
rand(500).to_s + "cheese"
|
164
|
+
end
|
165
|
+
|
166
|
+
def instance_string_two(a,b)
|
167
|
+
rand(500).to_s + "cheese"
|
168
|
+
end
|
169
|
+
|
170
|
+
def instance_symbol
|
171
|
+
"cheese#{rand(500)}".to_sym
|
172
|
+
end
|
173
|
+
|
174
|
+
def instance_symbol_one(a)
|
175
|
+
"cheese#{rand(500)}".to_sym
|
176
|
+
end
|
177
|
+
|
178
|
+
def instance_symbol_two(a,b)
|
179
|
+
"cheese#{rand(500)}".to_sym
|
180
|
+
end
|
181
|
+
|
182
|
+
def instance_nilclass #force it to be nil ONLY once to check caching ability.
|
183
|
+
@@set_nilclass_0 ||= false
|
184
|
+
p "i am false now " if @@set_nilclass_0
|
185
|
+
return "1" if @@set_nilclass_0
|
186
|
+
@@set_nilclass_0 = true
|
187
|
+
nil
|
188
|
+
end
|
189
|
+
|
190
|
+
def instance_nilclass_one(a)
|
191
|
+
@@set_nilclass_1 ||= false
|
192
|
+
p "i am false now " if @@set_nilclass_1
|
193
|
+
return "1" if @@set_nilclass_1
|
194
|
+
@@set_nilclass_1 = true
|
195
|
+
nil end
|
196
|
+
|
197
|
+
def instance_nilclass_two(a,b)
|
198
|
+
@@set_nilclass_2 ||= false
|
199
|
+
p "i am false now " if @@set_nilclass_2
|
200
|
+
return "1" if @@set_nilclass_2
|
201
|
+
@@set_nilclass_2 = true
|
202
|
+
nil
|
203
|
+
end
|
204
|
+
|
205
|
+
def instance_falseclass
|
206
|
+
@@set_falseclass_0 ||= false
|
207
|
+
return true if @@set_falseclass_0
|
208
|
+
@@set_falseclass_0 = true
|
209
|
+
false
|
210
|
+
end
|
211
|
+
|
212
|
+
def instance_falseclass_one(a)
|
213
|
+
@@set_falseclass_1 ||= false
|
214
|
+
return true if @@set_falseclass_1
|
215
|
+
@@set_falseclass_1 = true
|
216
|
+
false
|
217
|
+
end
|
218
|
+
|
219
|
+
def instance_falseclass_two(a,b)
|
220
|
+
@@set_falseclass_2 ||= false
|
221
|
+
return true if @@set_falseclass_2
|
222
|
+
@@set_falseclass_2 = true
|
223
|
+
false
|
224
|
+
end
|
225
|
+
|
226
|
+
def instance_trueclass
|
227
|
+
@@set_trueclass_0 ||= false
|
228
|
+
return false if @@set_trueclass_0
|
229
|
+
@@set_trueclass_0 = true
|
230
|
+
true
|
231
|
+
end
|
232
|
+
|
233
|
+
def instance_trueclass_one(a)
|
234
|
+
@@set_trueclass_1 ||= false
|
235
|
+
return false if @@set_trueclass_1
|
236
|
+
@@set_trueclass_1 = true
|
237
|
+
true
|
238
|
+
end
|
239
|
+
|
240
|
+
def instance_trueclass_two(a,b)
|
241
|
+
@@set_trueclass_2 ||= false
|
242
|
+
return false if @@set_trueclass_2
|
243
|
+
@@set_trueclass_2 = true
|
244
|
+
true
|
245
|
+
end
|
246
|
+
|
247
|
+
def instance_orm
|
248
|
+
DummyModel.create!(:attr_1 => rand(500), :attr_2 => rand(500))
|
249
|
+
end
|
250
|
+
|
251
|
+
def instance_orm_one(a)
|
252
|
+
DummyModel.create!(:attr_1 => rand(500), :attr_2 => rand(500))
|
253
|
+
end
|
254
|
+
|
255
|
+
def instance_orm_two(a,b)
|
256
|
+
DummyModel.create!(:attr_1 => rand(500), :attr_2 => rand(500))
|
257
|
+
end
|
258
|
+
|
259
|
+
def instance_to_json
|
260
|
+
DummyClass.new
|
261
|
+
end
|
262
|
+
|
263
|
+
def instance_to_json_one(a)
|
264
|
+
DummyClass.new
|
265
|
+
end
|
266
|
+
|
267
|
+
def instance_to_json_two(a,b)
|
268
|
+
DummyClass.new
|
269
|
+
end
|
270
|
+
|
271
|
+
def instance_hash
|
272
|
+
{:foo => rand(500)}
|
273
|
+
end
|
274
|
+
|
275
|
+
def instance_hash_one(a)
|
276
|
+
{:foo => rand(500)}
|
277
|
+
end
|
278
|
+
|
279
|
+
def instance_hash_two(a,b)
|
280
|
+
{:foo => rand(500)}
|
281
|
+
end
|
282
|
+
|
283
|
+
def instance_array
|
284
|
+
[rand(500)]
|
285
|
+
end
|
286
|
+
|
287
|
+
def instance_array_one(a)
|
288
|
+
[rand(500)]
|
289
|
+
end
|
290
|
+
|
291
|
+
def instance_array_two(a,b)
|
292
|
+
[rand(500)]
|
293
|
+
end
|
294
|
+
|
295
|
+
def self.class_fixnum
|
296
|
+
rand(500)
|
297
|
+
end
|
298
|
+
|
299
|
+
def self.class_fixnum_one(a)
|
300
|
+
rand(500)
|
301
|
+
end
|
302
|
+
|
303
|
+
def self.class_fixnum_two(a,b)
|
304
|
+
rand(500)
|
305
|
+
end
|
306
|
+
|
307
|
+
def self.class_float
|
308
|
+
rand(500).to_f + 0.5
|
309
|
+
end
|
310
|
+
|
311
|
+
def self.class_float_one(a)
|
312
|
+
rand(500).to_f + 0.5
|
313
|
+
end
|
314
|
+
|
315
|
+
def self.class_float_two(a,b)
|
316
|
+
rand(500).to_f + 0.5
|
317
|
+
end
|
318
|
+
|
319
|
+
def self.class_string
|
320
|
+
rand(500).to_s + "cheese"
|
321
|
+
end
|
322
|
+
|
323
|
+
def self.class_string_one(a)
|
324
|
+
rand(500).to_s + "cheese"
|
325
|
+
end
|
326
|
+
|
327
|
+
def self.class_string_two(a,b)
|
328
|
+
rand(500).to_s + "cheese"
|
329
|
+
end
|
330
|
+
|
331
|
+
def self.class_symbol
|
332
|
+
"cheese#{rand(500)}".to_sym
|
333
|
+
end
|
334
|
+
|
335
|
+
def self.class_symbol_one(a)
|
336
|
+
"cheese#{rand(500)}".to_sym
|
337
|
+
end
|
338
|
+
|
339
|
+
def self.class_symbol_two(a,b)
|
340
|
+
"cheese#{rand(500)}".to_sym
|
341
|
+
end
|
342
|
+
|
343
|
+
def self.class_nilclass #force it to be nil ONLY once to check caching ability.
|
344
|
+
@@set_nilclass_0 ||= false
|
345
|
+
p "i am false now " if @@set_nilclass_0
|
346
|
+
return "1" if @@set_nilclass_0
|
347
|
+
@@set_nilclass_0 = true
|
348
|
+
nil
|
349
|
+
end
|
350
|
+
|
351
|
+
def self.class_nilclass_one(a)
|
352
|
+
@@set_nilclass_1 ||= false
|
353
|
+
p "i am false now " if @@set_nilclass_1
|
354
|
+
return "1" if @@set_nilclass_1
|
355
|
+
@@set_nilclass_1 = true
|
356
|
+
nil end
|
357
|
+
|
358
|
+
def self.class_nilclass_two(a,b)
|
359
|
+
@@set_nilclass_2 ||= false
|
360
|
+
p "i am false now " if @@set_nilclass_2
|
361
|
+
return "1" if @@set_nilclass_2
|
362
|
+
@@set_nilclass_2 = true
|
363
|
+
nil
|
364
|
+
end
|
365
|
+
|
366
|
+
def self.class_falseclass
|
367
|
+
@@set_falseclass_0 ||= false
|
368
|
+
return true if @@set_falseclass_0
|
369
|
+
@@set_falseclass_0 = true
|
370
|
+
false
|
371
|
+
end
|
372
|
+
|
373
|
+
def self.class_falseclass_one(a)
|
374
|
+
@@set_falseclass_1 ||= false
|
375
|
+
return true if @@set_falseclass_1
|
376
|
+
@@set_falseclass_1 = true
|
377
|
+
false
|
378
|
+
end
|
379
|
+
|
380
|
+
def self.class_falseclass_two(a,b)
|
381
|
+
@@set_falseclass_2 ||= false
|
382
|
+
return true if @@set_falseclass_2
|
383
|
+
@@set_falseclass_2 = true
|
384
|
+
false
|
385
|
+
end
|
386
|
+
|
387
|
+
def self.class_trueclass
|
388
|
+
@@set_trueclass_0 ||= false
|
389
|
+
return false if @@set_trueclass_0
|
390
|
+
@@set_trueclass_0 = true
|
391
|
+
true
|
392
|
+
end
|
393
|
+
|
394
|
+
def self.class_trueclass_one(a)
|
395
|
+
@@set_trueclass_1 ||= false
|
396
|
+
return false if @@set_trueclass_1
|
397
|
+
@@set_trueclass_1 = true
|
398
|
+
true
|
399
|
+
end
|
400
|
+
|
401
|
+
def self.class_trueclass_two(a,b)
|
402
|
+
@@set_trueclass_2 ||= false
|
403
|
+
return false if @@set_trueclass_2
|
404
|
+
@@set_trueclass_2 = true
|
405
|
+
true
|
406
|
+
end
|
407
|
+
|
408
|
+
def self.class_orm
|
409
|
+
DummyModel.create!(:attr_1 => rand(500), :attr_2 => rand(500))
|
410
|
+
end
|
411
|
+
|
412
|
+
def self.class_orm_one(a)
|
413
|
+
DummyModel.create!(:attr_1 => rand(500), :attr_2 => rand(500))
|
414
|
+
end
|
415
|
+
|
416
|
+
def self.class_orm_two(a,b)
|
417
|
+
DummyModel.create!(:attr_1 => rand(500), :attr_2 => rand(500))
|
418
|
+
end
|
419
|
+
|
420
|
+
def self.class_to_json
|
421
|
+
DummyClass.new
|
422
|
+
end
|
423
|
+
|
424
|
+
def self.class_to_json_one(a)
|
425
|
+
DummyClass.new
|
426
|
+
end
|
427
|
+
|
428
|
+
def self.class_to_json_two(a,b)
|
429
|
+
DummyClass.new
|
430
|
+
end
|
431
|
+
|
432
|
+
def self.class_hash
|
433
|
+
{:foo => rand(500)}
|
434
|
+
end
|
435
|
+
|
436
|
+
def self.class_hash_one(a)
|
437
|
+
{:foo => rand(500)}
|
438
|
+
end
|
439
|
+
|
440
|
+
def self.class_hash_two(a,b)
|
441
|
+
{:foo => rand(500)}
|
442
|
+
end
|
443
|
+
|
444
|
+
def self.class_array
|
445
|
+
[rand(500)]
|
446
|
+
end
|
447
|
+
|
448
|
+
def self.class_array_one(a)
|
449
|
+
[rand(500)]
|
450
|
+
end
|
451
|
+
|
452
|
+
def self.class_array_two(a,b)
|
453
|
+
[rand(500)]
|
91
454
|
end
|
92
455
|
end
|