method_cache 0.6.3 → 0.6.4

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/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
+