simple_memoize 1.0.0
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/History.txt +6 -0
- data/Manifest.txt +6 -0
- data/README.txt +110 -0
- data/Rakefile +12 -0
- data/lib/simple_memoize.rb +36 -0
- data/test/test_simple_memoize.rb +114 -0
- metadata +70 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
data/README.txt
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
= SimpleMemoize
|
2
|
+
|
3
|
+
* http://github.com/JackDanger/simple_memoize/
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Provides in-memory caching of any Ruby method. It's dead simple and won't get in the way of any of your code.
|
8
|
+
For something more robust that offers persistence try http://github.com/JackDanger/cached_values/
|
9
|
+
|
10
|
+
== USAGE:
|
11
|
+
|
12
|
+
There's only one method and it's usage is completely manual.
|
13
|
+
|
14
|
+
class Location
|
15
|
+
def geocoding(lat, long)
|
16
|
+
... complicated stuff goes here ..
|
17
|
+
end
|
18
|
+
|
19
|
+
memoize :geocoding
|
20
|
+
end
|
21
|
+
|
22
|
+
Now, when you try calling the geocoding method it might take a while the first time but the results of
|
23
|
+
that initial method call will be memoized (cached) into memory. The second time you call it the
|
24
|
+
results will return instantly.
|
25
|
+
|
26
|
+
Note: there is a separate memo of the method for each combination of arguments. So calling the
|
27
|
+
method a second time with different arguments will cause the method to execute fully.
|
28
|
+
|
29
|
+
location = Location.new
|
30
|
+
location.geocoding(45.123, 123.45) # will take a while
|
31
|
+
location.geocoding(45.123, 123.45) # will return immediately
|
32
|
+
location.geocoding(12.876, 76.914) # will take a while because these arguments haven't been memoized
|
33
|
+
location.geocoding(12.876, 76.914) # will return immediately
|
34
|
+
location.geocoding(45.123, 123.45) # will return immediately because it's still memoized from before
|
35
|
+
|
36
|
+
You can use this on all classes and modules.
|
37
|
+
|
38
|
+
Module Colorizable
|
39
|
+
|
40
|
+
def preferred_color
|
41
|
+
:blue
|
42
|
+
end
|
43
|
+
memoize :preferred_color
|
44
|
+
|
45
|
+
class << self
|
46
|
+
def colors
|
47
|
+
[:blue, :green]
|
48
|
+
end
|
49
|
+
memoize :colors
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class House
|
54
|
+
include Colorizable
|
55
|
+
|
56
|
+
def paint
|
57
|
+
'do painting'
|
58
|
+
end
|
59
|
+
memoize :paint
|
60
|
+
|
61
|
+
class << self
|
62
|
+
def find_blues
|
63
|
+
.. find blue houses..
|
64
|
+
end
|
65
|
+
memoize :find_blues
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# the following are all memoized:
|
70
|
+
Colorizable.colors
|
71
|
+
House.new.preferred_color
|
72
|
+
House.find_blues
|
73
|
+
House.new.paint
|
74
|
+
|
75
|
+
That's it. If you need anything different I recommend forking this library and bending it to your will.
|
76
|
+
|
77
|
+
== INSTALL:
|
78
|
+
|
79
|
+
In Rails:
|
80
|
+
|
81
|
+
ruby script/plugin install git://github.com/JackDanger/simple_memoize.git
|
82
|
+
|
83
|
+
As a gem:
|
84
|
+
|
85
|
+
sudo gem install simple_memoize
|
86
|
+
|
87
|
+
== LICENSE:
|
88
|
+
|
89
|
+
(The MIT License)
|
90
|
+
|
91
|
+
Copyright (c) 2008 FIX
|
92
|
+
|
93
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
94
|
+
a copy of this software and associated documentation files (the
|
95
|
+
'Software'), to deal in the Software without restriction, including
|
96
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
97
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
98
|
+
permit persons to whom the Software is furnished to do so, subject to
|
99
|
+
the following conditions:
|
100
|
+
|
101
|
+
The above copyright notice and this permission notice shall be
|
102
|
+
included in all copies or substantial portions of the Software.
|
103
|
+
|
104
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
105
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
106
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
107
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
108
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
109
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
110
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hoe'
|
5
|
+
require './lib/simple_memoize.rb'
|
6
|
+
|
7
|
+
Hoe.new('simple_memoize', SimpleMemoize::VERSION) do |p|
|
8
|
+
p.rubyforge_name = 'objectproxy' # if different than lowercase project name
|
9
|
+
p.developer('Jack Danger Canty', 'rubyforge@6brand.com')
|
10
|
+
end
|
11
|
+
|
12
|
+
# vim: syntax=Ruby
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module SimpleMemoize
|
2
|
+
VERSION = '1.0.0'
|
3
|
+
|
4
|
+
module Module
|
5
|
+
def memoize(*method_names)
|
6
|
+
method_names.each do |method_name|
|
7
|
+
method_name = method_name.to_s
|
8
|
+
memoized_method_name = "#{method_name}_with_memo"
|
9
|
+
regular_method_name = "#{method_name}_without_memo"
|
10
|
+
|
11
|
+
unless (instance_methods + private_instance_methods).include?(method_name)
|
12
|
+
raise NoMethodError, "The Method '#{method_name}' cannot be memoized because it doesn't exist in #{self}"
|
13
|
+
end
|
14
|
+
return if self.method_defined?(memoized_method_name)
|
15
|
+
|
16
|
+
self.class_eval do
|
17
|
+
|
18
|
+
define_method memoized_method_name do |*args|
|
19
|
+
@simple_memoize ||= {}
|
20
|
+
@simple_memoize[method_name] ||= {}
|
21
|
+
@simple_memoize[method_name][args] ||= send(regular_method_name, *args)
|
22
|
+
end
|
23
|
+
|
24
|
+
alias_method regular_method_name, method_name
|
25
|
+
alias_method method_name, memoized_method_name
|
26
|
+
|
27
|
+
protected method_name if protected_instance_methods.include?(regular_method_name)
|
28
|
+
private method_name if private_instance_methods.include?(regular_method_name)
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
Module.send :include, SimpleMemoize::Module
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require File.dirname(__FILE__) + '/../lib/simple_memoize'
|
3
|
+
require 'rubygems'
|
4
|
+
require 'mocha'
|
5
|
+
|
6
|
+
module Barks
|
7
|
+
def growl
|
8
|
+
'Grrrrr'
|
9
|
+
end
|
10
|
+
memoize :growl
|
11
|
+
|
12
|
+
def protected_growl
|
13
|
+
'Grrrrr'
|
14
|
+
end
|
15
|
+
protected :protected_growl
|
16
|
+
memoize :protected_growl
|
17
|
+
|
18
|
+
def private_growl
|
19
|
+
'Grrrrr'
|
20
|
+
end
|
21
|
+
private :private_growl
|
22
|
+
memoize :private_growl
|
23
|
+
|
24
|
+
class << self
|
25
|
+
def sounds
|
26
|
+
['woof', 'ruff']
|
27
|
+
end
|
28
|
+
memoize :sounds
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class Dog
|
33
|
+
include Barks
|
34
|
+
|
35
|
+
def drink
|
36
|
+
'slurp'
|
37
|
+
end
|
38
|
+
memoize :drink
|
39
|
+
|
40
|
+
class << self
|
41
|
+
def breeds
|
42
|
+
['doberman', 'dalmatian']
|
43
|
+
end
|
44
|
+
memoize :breeds
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class SimpleMemoizeTest < Test::Unit::TestCase
|
49
|
+
def test_module_method_only_calls_memoized_once
|
50
|
+
dog = Dog.new
|
51
|
+
dog.expects(:growl_without_memo).returns('Grrrrr').once
|
52
|
+
4.times { dog.growl }
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_module_method_calls_method_several_times
|
56
|
+
dog = Dog.new
|
57
|
+
dog.expects(:growl).returns('Grrrrr').times(4)
|
58
|
+
4.times { dog.growl }
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_module_class_method_only_calls_memoized_once
|
62
|
+
sounds = Barks.sounds_without_memo
|
63
|
+
Barks.expects(:sounds_without_memo).returns(sounds).once
|
64
|
+
4.times { Barks.sounds }
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_module_class_method_calls_method_several_times
|
68
|
+
sounds = Barks.sounds_without_memo
|
69
|
+
Barks.expects(:sounds).returns(sounds).times(4)
|
70
|
+
4.times { Barks.sounds }
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_object_method_calls_memoized_once
|
74
|
+
dog = Dog.new
|
75
|
+
drink = dog.drink_without_memo
|
76
|
+
dog.expects(:drink_without_memo).returns(drink).once
|
77
|
+
4.times { dog.drink }
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_object_method_calls_method_several_times
|
81
|
+
dog = Dog.new
|
82
|
+
drink = dog.drink_without_memo
|
83
|
+
dog.expects(:drink).returns(drink).times(4)
|
84
|
+
4.times { dog.drink }
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_class_method_calls_memoized_once
|
88
|
+
breeds = Dog.breeds_without_memo
|
89
|
+
Dog.expects(:breeds_without_memo).returns(breeds).once
|
90
|
+
4.times { Dog.breeds }
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_class_method_calls_method_several_times
|
94
|
+
breeds = Dog.breeds_without_memo
|
95
|
+
Dog.expects(:breeds).returns(breeds).times(4)
|
96
|
+
4.times { Dog.breeds }
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_protected_methods_remain_protected
|
100
|
+
dog = Dog.new
|
101
|
+
assert dog.protected_methods.include?('protected_growl_without_memo')
|
102
|
+
assert dog.protected_methods.include?('protected_growl')
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_private_methods_remain_private
|
106
|
+
dog = Dog.new
|
107
|
+
assert dog.private_methods.include?('private_growl_without_memo')
|
108
|
+
assert dog.private_methods.include?('private_growl')
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_cant_memoize_a_missing_method
|
112
|
+
assert_raises(NoMethodError) { Barks.memoize :totally_bad_method_name }
|
113
|
+
end
|
114
|
+
end
|
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: simple_memoize
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jack Danger Canty
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-03-26 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: hoe
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.5.1
|
23
|
+
version:
|
24
|
+
description: Provides in-memory caching of any Ruby method. It's dead simple and won't get in the way of any of your code. For something more robust that offers persistence try http://github.com/JackDanger/cached_values/
|
25
|
+
email:
|
26
|
+
- rubyforge@6brand.com
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files:
|
32
|
+
- History.txt
|
33
|
+
- Manifest.txt
|
34
|
+
- README.txt
|
35
|
+
files:
|
36
|
+
- History.txt
|
37
|
+
- Manifest.txt
|
38
|
+
- README.txt
|
39
|
+
- Rakefile
|
40
|
+
- lib/simple_memoize.rb
|
41
|
+
- test/test_simple_memoize.rb
|
42
|
+
has_rdoc: true
|
43
|
+
homepage: http://github.com/JackDanger/simple_memoize/
|
44
|
+
post_install_message:
|
45
|
+
rdoc_options:
|
46
|
+
- --main
|
47
|
+
- README.txt
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: "0"
|
55
|
+
version:
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: "0"
|
61
|
+
version:
|
62
|
+
requirements: []
|
63
|
+
|
64
|
+
rubyforge_project: objectproxy
|
65
|
+
rubygems_version: 1.0.1
|
66
|
+
signing_key:
|
67
|
+
specification_version: 2
|
68
|
+
summary: Provides in-memory caching of any Ruby method
|
69
|
+
test_files:
|
70
|
+
- test/test_simple_memoize.rb
|