cachely 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -64,8 +64,8 @@ will still work, it will cache both the instance method foo and the class method
64
64
  keyed locations, of course. To specify instance or class method, do
65
65
 
66
66
  cachely :foo, :type => "instance"
67
- cachely :foo, :type => "class"
68
-
67
+ cachely :foo, :type => "class"
68
+
69
69
  Cachely is able to figure out whether or not to use the cache by looking at the arguments you pass in.
70
70
  Generally, if your arguments are the same, and the object you're calling the method on is the same(Cachely uses
71
71
  the to_json method on the object you call the method on to determine this), then it assumes the result
@@ -74,6 +74,11 @@ will be the same and uses the cached result.
74
74
  Cachely expects that any objects you return or pass in to methods as arguments have to_json methods. Without
75
75
  this, it won't work.
76
76
 
77
+ Because of this, you can expire method results by their "signatures", that is, the object the method is being called on,
78
+ the method name, and it's arguments. To expire a cached result by this signature, call
79
+
80
+ Cachely::Mechanics.expire(object, method, *args)
81
+
77
82
  CAVEAT: Do NOT use Cachely for functions that depend on time of day or random numbers, as these are inherently uncachable.
78
83
  If you check the tests out, you'll see random number functions are used exhaustively to test the caching ability of cachely,
79
84
  because we know the function wasn't called if the second call yields the same number.
@@ -37,7 +37,7 @@ module Cachely
37
37
  end
38
38
  return @redis
39
39
  end
40
-
40
+
41
41
  # Defines the method using my hacky eval script. So far, this is the only way I've found that
42
42
  # allows me to define variable argument length definitions. If you have a better idea, please
43
43
  # refactor it!
@@ -48,34 +48,56 @@ module Cachely
48
48
  context = (is_class_method ? klazz : klazz.new)
49
49
  args_str = context.method("#{name.to_s}_old".to_sym).parameters.map { |k| k.last}.join(',')
50
50
  args_to_use_in_def = args_str.empty? ? "" : "," + args_str
51
+ time_exp_str = time_to_expire_in_s.nil? ? ",nil" : ",time_to_expire_in_s"
51
52
  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
+ "result = Cachely::Mechanics.get(context,:#{name}#{time_exp_str}#{args_to_use_in_def});" +
53
54
  "return result.first if result.is_a?(Array);" +
54
55
  "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
+ "Cachely::Mechanics.store(context,:#{"#{name.to_s}"}, result#{time_exp_str}#{args_to_use_in_def});" +
56
57
  "return result;" +
57
58
  "end"
58
59
  )
59
60
  end
60
-
61
+
62
+ # Force-expires a result to a method with this signature given by obj, method, args.
63
+ #
64
+ # @obj [Object] the object you're calling method on
65
+ # @method [String,Symbol] the method name
66
+ # @args The arguments of the method
67
+ # @return The original response of the method back, whatever it may be.
68
+ def self.expire(obj, method, *args)
69
+ key = redis_key(obj, method, *args)
70
+ result = get(obj,method,1,*args)
71
+ redis.del(key)
72
+ return result
73
+ end
74
+
61
75
  # Gets a cached response to a method.
62
76
  #
77
+ # @obj [Object] the object you're calling method on
78
+ # @time_to_exp_in_s [Fixnum] num of seconds to set expire on key. Needs to be reset.
63
79
  # @method [String,Symbol] the method name
64
80
  # @args The arguments of the method
65
81
  # @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)]
82
+ def self.get(obj, method, time_to_exp_in_s, *args)
83
+ key = redis_key(obj, method, *args)
84
+ result = redis.get(key)
85
+ if result
86
+ redis.expire(key, time_to_exp_in_s) if time_to_exp_in_s #reset the expiry
87
+ #return an array, bc if the result stored was nil, it looks the same as if
88
+ #we got no result back(which we would return nil) so we differentiate by putting
89
+ #our return value always in an array. Easy to check.
90
+ return [map_s_to_param(result)]
91
+ end
72
92
  end
73
93
 
74
94
  # Stores the result in it's proper cached location on redis by getting the redis key and parsing
75
95
  # The result into a storable string, mostly made up of recursive json.
76
96
  #
97
+ # @obj [Object] object you call method on
77
98
  # @method [Symbol] Method name
78
99
  # @result Anything, really.
100
+ # @time_to_exp_in_s time in seconds before it expires
79
101
  # @args Arguments of the method
80
102
  # @return [String] Should be "Ok" or something similar.
81
103
  def self.store(obj, method, result, time_to_exp_in_sec, *args)
@@ -1,3 +1,3 @@
1
1
  module Cachely
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -3,6 +3,7 @@ class DummyClass
3
3
  attr_accessor :random_no
4
4
 
5
5
  cachely :cache_expiry, time_to_expiry: 1.seconds
6
+ cachely :cache_expiry_3, time_to_expiry: 3.seconds
6
7
 
7
8
  cachely :class_diff, time_to_expiry: 3.minutes
8
9
 
@@ -127,6 +128,10 @@ class DummyClass
127
128
  rand(500)
128
129
  end
129
130
 
131
+ def cache_expiry_3
132
+ rand(500)
133
+ end
134
+
130
135
  def cache_expiry
131
136
  rand(500)
132
137
  end
@@ -142,5 +142,17 @@ class CachelyTest < BaseTest
142
142
  sleep(3)
143
143
  assert_not_equal(old, obj.cache_expiry)
144
144
  end
145
+
146
+ test "cache with 3 s expiry doesnt expire in 3 s if we keep hitting it" do
147
+ obj = DummyClass.new
148
+ old = obj.cache_expiry_3
149
+ 5.times do #should still be present on fourth and fifth times
150
+ sleep(1)
151
+ assert_equal(old, obj.cache_expiry_3)
152
+ end
145
153
 
154
+ sleep(4)
155
+ assert_not_equal(old, obj.cache_expiry_3)
156
+ end
157
+
146
158
  end
@@ -5,12 +5,12 @@ require_relative 'base_test.rb'
5
5
  class MechanicsTest < BaseTest
6
6
  test "get/store array" do
7
7
  Cachely::Mechanics.store(DummyClass,:foo, [1,2,3], nil, [3,4])
8
- assert_equal(0, [1,2,3] <=> Cachely::Mechanics.get(DummyClass,:foo, [3,4]).first)
8
+ assert_equal(0, [1,2,3] <=> Cachely::Mechanics.get(DummyClass,:foo,nil, [3,4]).first)
9
9
  end
10
10
 
11
11
  test "get/store hash" do
12
12
  Cachely::Mechanics.store(DummyClass,:foo, {:bar => "baz"}, nil, [3,4])
13
- respawned = Cachely::Mechanics.get(DummyClass,:foo, [3,4]).first
13
+ respawned = Cachely::Mechanics.get(DummyClass,:foo,nil, [3,4]).first
14
14
  assert_equal(1, respawned.keys.size)
15
15
  assert_equal("baz", respawned[:bar])
16
16
  end
@@ -18,7 +18,7 @@ class MechanicsTest < BaseTest
18
18
  test "get/store orm" do
19
19
  d = DummyModel.create!(:attr_1 => 1, :attr_2 => 3)
20
20
  Cachely::Mechanics.store(DummyClass,:foo, d,nil,[3,4])
21
- respawned = Cachely::Mechanics.get(DummyClass,:foo, [3,4]).first
21
+ respawned = Cachely::Mechanics.get(DummyClass,:foo, nil, [3,4]).first
22
22
  assert_equal(d.id, respawned.id)
23
23
  assert_equal(d.attr_1, respawned.attr_1)
24
24
  assert_equal(d.attr_2, respawned.attr_2)
@@ -27,15 +27,29 @@ class MechanicsTest < BaseTest
27
27
  test "get/store to_json" do
28
28
  d = DummyClass.new
29
29
  Cachely::Mechanics.store(DummyClass,:foo, d,nil, [3,4])
30
- respawned = Cachely::Mechanics.get(DummyClass,:foo, [3,4]).first
30
+ respawned = Cachely::Mechanics.get(DummyClass,:foo, nil, [3,4]).first
31
31
  assert_equal(d.random_no, respawned.random_no)
32
32
  end
33
33
 
34
34
  test "get/store primitive" do
35
35
  [3, "3", true, false, nil, 3.5, :stuff].each do |result|
36
36
  Cachely::Mechanics.store(DummyClass,:foo, result, nil, [3,4])
37
- respawned = Cachely::Mechanics.get(DummyClass,:foo, [3,4]).first
37
+ respawned = Cachely::Mechanics.get(DummyClass,:foo, nil, [3,4]).first
38
38
  assert_equal(result, respawned)
39
39
  end
40
40
  end
41
- end
41
+
42
+ test "expire method works" do
43
+ old = DummyClass.class_fixnum
44
+ assert_equal(old, DummyClass.class_fixnum)
45
+ Cachely::Mechanics.expire(DummyClass, :class_fixnum)
46
+ assert_not_equal(old, DummyClass.class_fixnum)
47
+
48
+ obj = DummyClass.new
49
+ old = obj.instance_fixnum_one(5)
50
+ assert_equal(old, obj.instance_fixnum_one(5))
51
+ Cachely::Mechanics.expire(obj, :instance_fixnum_one,5)
52
+ assert_not_equal(old, obj.instance_fixnum_one(5))
53
+ end
54
+
55
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cachely
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2013-03-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: redis
16
- requirement: &16110720 !ruby/object:Gem::Requirement
16
+ requirement: &9945220 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 3.0.1
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *16110720
24
+ version_requirements: *9945220
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: hiredis
27
- requirement: &16121280 !ruby/object:Gem::Requirement
27
+ requirement: &9958720 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 0.4.5
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *16121280
35
+ version_requirements: *9958720
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: em-synchrony
38
- requirement: &16118820 !ruby/object:Gem::Requirement
38
+ requirement: &9954440 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *16118820
46
+ version_requirements: *9954440
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: json
49
- requirement: &16116540 !ruby/object:Gem::Requirement
49
+ requirement: &9960660 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,7 +54,7 @@ dependencies:
54
54
  version: '0'
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *16116540
57
+ version_requirements: *9960660
58
58
  description: Transparently cache the results of methods using redis.
59
59
  email:
60
60
  - jordanmprince@gmail.com