method_cache 0.6.3 → 0.6.4

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -33,10 +33,8 @@ Ruby.
33
33
 
34
34
  == Install:
35
35
 
36
- sudo gem install ninjudd-memcache -s http://gems.github.com
37
- sudo gem install ninjudd-cache_version -s http://gems.github.com
38
- sudo gem install ninjudd-method_cache -s http://gems.github.com
36
+ gem install method_cache
39
37
 
40
38
  == License:
41
39
 
42
- Copyright (c) 2009 Justin Balthrop, Geni.com; Published under The MIT License, see LICENSE
40
+ Copyright (c) 2010 Justin Balthrop, Geni.com; Published under The MIT License, see LICENSE
data/VERSION.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
2
  :build:
3
- :patch: 3
4
- :major: 0
5
3
  :minor: 6
4
+ :patch: 4
5
+ :major: 0
@@ -1,10 +1,14 @@
1
+ require 'digest/sha1'
2
+
1
3
  module MethodCache
2
4
  class Proxy
3
5
  attr_reader :method_name, :opts, :args, :target
6
+ NULL = 'NULL'
4
7
 
5
8
  def initialize(method_name, opts)
9
+ opts[:cache] ||= :counters if opts[:counter]
6
10
  @method_name = method_name
7
- @opts = opts
11
+ @opts = opts
8
12
  end
9
13
 
10
14
  def bind(target, args)
@@ -46,11 +50,12 @@ module MethodCache
46
50
  end
47
51
 
48
52
  def value
49
- value = cache[key] unless MethodCache.disabled?
53
+ value = opts[:counter] ? cache.count(key) : cache[key] unless MethodCache.disabled?
50
54
  value = nil unless valid?(:load, value)
51
55
 
52
56
  if value.nil?
53
57
  value = target.send(method_name_without_caching, *args)
58
+ raise "non-integer value returned by counter method" if opts[:counter] and not value.kind_of?(Fixnum)
54
59
  write_to_cache(key, value) if valid?(:save, value)
55
60
  end
56
61
 
@@ -62,7 +67,6 @@ module MethodCache
62
67
  end
63
68
  end
64
69
 
65
- NULL = 'NULL'
66
70
  def method_with_caching
67
71
  proxy = self # Need access to the proxy in the closure.
68
72
 
@@ -71,6 +75,18 @@ module MethodCache
71
75
  end
72
76
  end
73
77
 
78
+ def counter_method(method_name)
79
+ proxy = self # Need access to the proxy in the closure.
80
+
81
+ lambda do |*args|
82
+ if args.last.kind_of?(Hash) and args.last.keys == [:by]
83
+ amount = args.last[:by]
84
+ args.pop
85
+ end
86
+ proxy.bind(self, args).send(method_name, amount || 1)
87
+ end
88
+ end
89
+
74
90
  def method_name_without_caching
75
91
  @method_name_without_caching ||= begin
76
92
  base_name, punctuation = method_name.to_s.sub(/([?!=])$/, ''), $1
@@ -100,6 +116,7 @@ module MethodCache
100
116
  object_key(arg)
101
117
  end.join('|')
102
118
  @key = ['m', version, arg_string].compact.join('|')
119
+ @key = "m|#{Digest::SHA1.hexdigest(@key)}" if @key.length > 250
103
120
  end
104
121
  @key
105
122
  end
@@ -122,8 +139,8 @@ module MethodCache
122
139
  if opts[name].kind_of?(Proc)
123
140
  proc = opts[name].bind(target)
124
141
  case proc.arity
125
- when 0: proc.call()
126
- when 1: proc.call(value)
142
+ when 0 then proc.call()
143
+ when 1 then proc.call(value)
127
144
  else
128
145
  proc.call(value, *args)
129
146
  end
@@ -134,25 +151,38 @@ module MethodCache
134
151
 
135
152
  def write_to_cache(key, value)
136
153
  if cache.kind_of?(Hash)
137
- raise 'expiry not permitted when cache is a Hash' if opts[:expiry]
154
+ raise 'expiry not permitted when cache is a Hash' if opts[:expiry]
155
+ raise 'counter cache not permitted when cache is a Hash' if opts[:counter]
138
156
  cache[key] = value
157
+ elsif opts[:counter]
158
+ cache.write(key, value.to_s, :expiry => expiry(value))
139
159
  else
140
- value = value.nil? ? NULL : value
160
+ value = value.nil? ? NULL : value
141
161
  cache.set(key, value, :expiry => expiry(value))
142
162
  end
143
163
  end
144
164
 
165
+ def increment(amount)
166
+ raise "cannot increment non-counter method" unless opts[:counter]
167
+ cache.incr(key, amount)
168
+ end
169
+
170
+ def decrement(amount)
171
+ raise "cannot decrement non-counter method" unless opts[:counter]
172
+ cache.decr(key, amount)
173
+ end
174
+
145
175
  def object_key(arg)
146
176
  return "#{class_key(arg.class)}-#{arg.string_hash}" if arg.respond_to?(:string_hash)
147
177
 
148
178
  case arg
149
- when NilClass : 'nil'
150
- when TrueClass : 'true'
151
- when FalseClass : 'false'
152
- when Numeric : arg.to_s
153
- when Symbol : ":#{arg}"
154
- when String : "'#{arg}'"
155
- when Class, Module : class_key(arg)
179
+ when NilClass then 'nil'
180
+ when TrueClass then 'true'
181
+ when FalseClass then 'false'
182
+ when Numeric then arg.to_s
183
+ when Symbol then ":#{arg}"
184
+ when String then "'#{arg}'"
185
+ when Class, Module then class_key(arg)
156
186
  when Hash
157
187
  '{' + arg.collect {|key, value| "#{object_key(key)}=#{object_key(value)}"}.sort.join(',') + '}'
158
188
  when Array
data/lib/method_cache.rb CHANGED
@@ -17,13 +17,15 @@ module MethodCache
17
17
  end
18
18
 
19
19
  cached_instance_methods[method_name] = nil
20
- begin
20
+ if method_defined?(method_name) or private_method_defined?(method_name)
21
+ if proxy.opts[:counter]
22
+ define_method "increment_#{method_name}", proxy.counter_method(:increment)
23
+ define_method "decrement_#{method_name}", proxy.counter_method(:decrement)
24
+ end
25
+
21
26
  # Replace instance method.
22
27
  alias_method proxy.method_name_without_caching, method_name
23
28
  define_method method_name, proxy.method_with_caching
24
- rescue NameError => e
25
- # The method has not been defined yet. We will alias it in method_added.
26
- # pp e, e.backtrace
27
29
  end
28
30
  cached_instance_methods[method_name] = proxy
29
31
 
@@ -47,19 +49,28 @@ module MethodCache
47
49
 
48
50
  method_name = method_name.to_sym
49
51
  cached_class_methods[method_name] = nil
50
- begin
51
- # Replace class method.
52
+ if class_method_defined?(method_name)
52
53
  (class << self; self; end).module_eval do
54
+ if proxy.opts[:counter]
55
+ define_method "increment_#{method_name}", proxy.counter_method(:increment)
56
+ define_method "decrement_#{method_name}", proxy.counter_method(:decrement)
57
+ end
58
+
59
+ # Replace class method.
53
60
  alias_method proxy.method_name_without_caching, method_name
54
61
  define_method method_name, proxy.method_with_caching
55
62
  end
56
- rescue NameError => e
57
- # The method has not been defined yet. We will alias it in singleton_method_added.
58
- # pp e, e.backtrace
59
63
  end
60
64
  cached_class_methods[method_name] = proxy
61
65
  end
62
66
 
67
+ def class_method_defined?(method_name)
68
+ method(method_name)
69
+ true
70
+ rescue NameError
71
+ false
72
+ end
73
+
63
74
  def self.default_cache
64
75
  @default_cache ||= {}
65
76
  end
data/method_cache.gemspec CHANGED
@@ -1,47 +1,41 @@
1
1
  # Generated by jeweler
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{method_cache}
8
- s.version = "0.6.3"
8
+ s.version = "0.6.4"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Justin Balthrop"]
12
- s.date = %q{2010-04-13}
12
+ s.date = %q{2011-08-23}
13
13
  s.description = %q{Simple memcache-based memoization library for Ruby}
14
14
  s.email = %q{code@justinbalthrop.com}
15
15
  s.extra_rdoc_files = [
16
16
  "LICENSE",
17
- "README.rdoc"
17
+ "README.rdoc"
18
18
  ]
19
19
  s.files = [
20
20
  "LICENSE",
21
- "README.rdoc",
22
- "Rakefile",
23
- "VERSION.yml",
24
- "lib/method_cache.rb",
25
- "lib/method_cache/proxy.rb",
26
- "method_cache.gemspec",
27
- "test/method_cache_test.rb",
28
- "test/test_helper.rb"
21
+ "README.rdoc",
22
+ "Rakefile",
23
+ "VERSION.yml",
24
+ "lib/method_cache.rb",
25
+ "lib/method_cache/proxy.rb",
26
+ "method_cache.gemspec",
27
+ "test/method_cache_test.rb",
28
+ "test/test_helper.rb"
29
29
  ]
30
30
  s.homepage = %q{http://github.com/ninjudd/method_cache}
31
- s.rdoc_options = ["--charset=UTF-8"]
32
31
  s.require_paths = ["lib"]
33
- s.rubygems_version = %q{1.3.5}
32
+ s.rubygems_version = %q{1.5.2}
34
33
  s.summary = %q{Simple memcache-based memoization library for Ruby}
35
- s.test_files = [
36
- "test/method_cache_test.rb",
37
- "test/test_helper.rb"
38
- ]
39
34
 
40
35
  if s.respond_to? :specification_version then
41
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
42
36
  s.specification_version = 3
43
37
 
44
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
38
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
45
39
  s.add_runtime_dependency(%q<memcache>, [">= 1.0.0"])
46
40
  else
47
41
  s.add_dependency(%q<memcache>, [">= 1.0.0"])
@@ -20,6 +20,17 @@ class Foo
20
20
  @@i += i
21
21
  end
22
22
  cache_method :baz, :cache => :remote
23
+
24
+ cache_class_method :bap
25
+ def self.bap(i)
26
+ @i ||= 0
27
+ @i += i
28
+ end
29
+
30
+ cache_class_method :zap, :counter => true
31
+ def self.zap
32
+ 0
33
+ end
23
34
  end
24
35
 
25
36
  module Bar
@@ -30,10 +41,16 @@ module Bar
30
41
  @i ||= 0
31
42
  @i += i
32
43
  end
44
+
45
+ cache_method :foo_count, :counter => true, :cache => :default
46
+ def foo_count(key)
47
+ 100
48
+ end
33
49
  end
34
50
 
35
51
  class Baz
36
52
  include Bar
53
+ extend Bar
37
54
  end
38
55
 
39
56
  class TestMethodCache < Test::Unit::TestCase
@@ -84,6 +101,13 @@ class TestMethodCache < Test::Unit::TestCase
84
101
  assert b2 == a.baz(2)
85
102
  end
86
103
 
104
+ should 'cache class methods' do
105
+ assert_equal 10, Foo.bap(10)
106
+ assert_equal 23, Foo.bap(13)
107
+ assert_equal 10, Foo.bap(10)
108
+ assert_equal 23, Foo.bap(13)
109
+ end
110
+
87
111
  should 'cache methods for mixins' do
88
112
  a = Baz.new
89
113
 
@@ -93,6 +117,13 @@ class TestMethodCache < Test::Unit::TestCase
93
117
  assert_equal 3, a.foo(2)
94
118
  end
95
119
 
120
+ should 'cache class methods for mixins' do
121
+ assert_equal 1, Baz.foo(1)
122
+ assert_equal 1, Baz.foo(1)
123
+ assert_equal 3, Baz.foo(2)
124
+ assert_equal 3, Baz.foo(2)
125
+ end
126
+
96
127
  should 'invalidate cached method' do
97
128
  a = Foo.new
98
129
 
@@ -105,6 +136,29 @@ class TestMethodCache < Test::Unit::TestCase
105
136
  assert_equal 3, a.foo(2)
106
137
  end
107
138
 
139
+ should 'cache counters' do
140
+ b = Baz.new
141
+
142
+ assert_equal 100, b.foo_count(:bar)
143
+ b.increment_foo_count(:bar, :by => 42)
144
+ assert_equal 142, b.foo_count(:bar)
145
+ b.decrement_foo_count(:bar, :by => 99)
146
+ assert_equal 43, b.foo_count(:bar)
147
+ b.increment_foo_count(:bar)
148
+ assert_equal 44, b.foo_count(:bar)
149
+
150
+ assert_equal 100, b.foo_count(:baz)
151
+ b.increment_foo_count(:baz)
152
+ assert_equal 101, b.foo_count(:baz)
153
+ assert_equal 44, b.foo_count(:bar) # make sure :bar wasn't affected
154
+
155
+ assert_equal 0, Foo.zap
156
+ Foo.increment_zap(:by => 3)
157
+ assert_equal 3, Foo.zap
158
+ Foo.decrement_zap
159
+ assert_equal 2, Foo.zap
160
+ end
161
+
108
162
  should 'use consistent local keys' do
109
163
  a = Foo.new
110
164
  o = Object.new
metadata CHANGED
@@ -1,7 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: method_cache
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.3
4
+ hash: 15
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 6
9
+ - 4
10
+ version: 0.6.4
5
11
  platform: ruby
6
12
  authors:
7
13
  - Justin Balthrop
@@ -9,19 +15,25 @@ autorequire:
9
15
  bindir: bin
10
16
  cert_chain: []
11
17
 
12
- date: 2010-04-13 00:00:00 -07:00
18
+ date: 2011-08-23 00:00:00 -07:00
13
19
  default_executable:
14
20
  dependencies:
15
21
  - !ruby/object:Gem::Dependency
16
22
  name: memcache
17
- type: :runtime
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
20
26
  requirements:
21
27
  - - ">="
22
28
  - !ruby/object:Gem::Version
29
+ hash: 23
30
+ segments:
31
+ - 1
32
+ - 0
33
+ - 0
23
34
  version: 1.0.0
24
- version:
35
+ type: :runtime
36
+ version_requirements: *id001
25
37
  description: Simple memcache-based memoization library for Ruby
26
38
  email: code@justinbalthrop.com
27
39
  executables: []
@@ -46,29 +58,34 @@ homepage: http://github.com/ninjudd/method_cache
46
58
  licenses: []
47
59
 
48
60
  post_install_message:
49
- rdoc_options:
50
- - --charset=UTF-8
61
+ rdoc_options: []
62
+
51
63
  require_paths:
52
64
  - lib
53
65
  required_ruby_version: !ruby/object:Gem::Requirement
66
+ none: false
54
67
  requirements:
55
68
  - - ">="
56
69
  - !ruby/object:Gem::Version
70
+ hash: 3
71
+ segments:
72
+ - 0
57
73
  version: "0"
58
- version:
59
74
  required_rubygems_version: !ruby/object:Gem::Requirement
75
+ none: false
60
76
  requirements:
61
77
  - - ">="
62
78
  - !ruby/object:Gem::Version
79
+ hash: 3
80
+ segments:
81
+ - 0
63
82
  version: "0"
64
- version:
65
83
  requirements: []
66
84
 
67
85
  rubyforge_project:
68
- rubygems_version: 1.3.5
86
+ rubygems_version: 1.5.2
69
87
  signing_key:
70
88
  specification_version: 3
71
89
  summary: Simple memcache-based memoization library for Ruby
72
- test_files:
73
- - test/method_cache_test.rb
74
- - test/test_helper.rb
90
+ test_files: []
91
+