memoization 0.0.1
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/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +29 -0
- data/Rakefile +2 -0
- data/lib/memoization.rb +108 -0
- data/lib/memoization/version.rb +3 -0
- data/memoization.gemspec +17 -0
- data/test/abstract_unit.rb +64 -0
- data/test/memoization_test.rb +279 -0
- metadata +58 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Burke Libbey
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Memoization
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'memoization'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install memoization
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/lib/memoization.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'active_support/core_ext/kernel/singleton_class'
|
2
|
+
require 'active_support/core_ext/module/aliasing'
|
3
|
+
require 'active_support/deprecation'
|
4
|
+
|
5
|
+
module Memoization
|
6
|
+
def self.memoized_ivar_for(symbol)
|
7
|
+
"@_memoized_#{symbol.to_s.sub(/\?\Z/, '_query').sub(/!\Z/, '_bang')}".to_sym
|
8
|
+
end
|
9
|
+
|
10
|
+
module InstanceMethods
|
11
|
+
def self.included(base)
|
12
|
+
base.class_eval do
|
13
|
+
unless base.method_defined?(:freeze_without_memoizable)
|
14
|
+
alias_method_chain :freeze, :memoizable
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def freeze_with_memoizable
|
20
|
+
memoize_all unless frozen?
|
21
|
+
freeze_without_memoizable
|
22
|
+
end
|
23
|
+
|
24
|
+
def memoize_all
|
25
|
+
prime_cache ".*"
|
26
|
+
end
|
27
|
+
|
28
|
+
def unmemoize_all
|
29
|
+
flush_cache ".*"
|
30
|
+
end
|
31
|
+
|
32
|
+
def prime_cache(*syms)
|
33
|
+
syms.each do |sym|
|
34
|
+
methods.each do |m|
|
35
|
+
if m.to_s =~ /^_unmemoized_(#{sym})/
|
36
|
+
if method(m).arity == 0
|
37
|
+
__send__($1)
|
38
|
+
else
|
39
|
+
ivar = Memoization.memoized_ivar_for($1)
|
40
|
+
instance_variable_set(ivar, {})
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def flush_cache(*syms)
|
48
|
+
syms.each do |sym|
|
49
|
+
(methods + private_methods + protected_methods).each do |m|
|
50
|
+
if m.to_s =~ /^_unmemoized_(#{sym.to_s.gsub(/\?\Z/, '\?')})/
|
51
|
+
ivar = Memoization.memoized_ivar_for($1)
|
52
|
+
instance_variable_get(ivar).clear if instance_variable_defined?(ivar)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def memoize(*symbols)
|
60
|
+
symbols.each do |symbol|
|
61
|
+
original_method = :"_unmemoized_#{symbol}"
|
62
|
+
memoized_ivar = Memoization.memoized_ivar_for(symbol)
|
63
|
+
|
64
|
+
class_eval <<-EOS, __FILE__, __LINE__ + 1
|
65
|
+
include InstanceMethods # include InstanceMethods
|
66
|
+
#
|
67
|
+
if method_defined?(:#{original_method}) # if method_defined?(:_unmemoized_mime_type)
|
68
|
+
raise "Already memoized #{symbol}" # raise "Already memoized mime_type"
|
69
|
+
end # end
|
70
|
+
alias #{original_method} #{symbol} # alias _unmemoized_mime_type mime_type
|
71
|
+
#
|
72
|
+
if instance_method(:#{symbol}).arity == 0 # if instance_method(:mime_type).arity == 0
|
73
|
+
def #{symbol}(reload = false) # def mime_type(reload = false)
|
74
|
+
if reload || !defined?(#{memoized_ivar}) || #{memoized_ivar}.empty? # if reload || !defined?(@_memoized_mime_type) || @_memoized_mime_type.empty?
|
75
|
+
#{memoized_ivar} = [#{original_method}] # @_memoized_mime_type = [_unmemoized_mime_type]
|
76
|
+
end # end
|
77
|
+
#{memoized_ivar}[0] # @_memoized_mime_type[0]
|
78
|
+
end # end
|
79
|
+
else # else
|
80
|
+
def #{symbol}(*args) # def mime_type(*args)
|
81
|
+
#{memoized_ivar} ||= {} unless frozen? # @_memoized_mime_type ||= {} unless frozen?
|
82
|
+
args_length = method(:#{original_method}).arity # args_length = method(:_unmemoized_mime_type).arity
|
83
|
+
if args.length == args_length + 1 && # if args.length == args_length + 1 &&
|
84
|
+
(args.last == true || args.last == :reload) # (args.last == true || args.last == :reload)
|
85
|
+
reload = args.pop # reload = args.pop
|
86
|
+
end # end
|
87
|
+
#
|
88
|
+
if defined?(#{memoized_ivar}) && #{memoized_ivar} # if defined?(@_memoized_mime_type) && @_memoized_mime_type
|
89
|
+
if !reload && #{memoized_ivar}.has_key?(args) # if !reload && @_memoized_mime_type.has_key?(args)
|
90
|
+
#{memoized_ivar}[args] # @_memoized_mime_type[args]
|
91
|
+
elsif #{memoized_ivar} # elsif @_memoized_mime_type
|
92
|
+
#{memoized_ivar}[args] = #{original_method}(*args) # @_memoized_mime_type[args] = _unmemoized_mime_type(*args)
|
93
|
+
end # end
|
94
|
+
else # else
|
95
|
+
#{original_method}(*args) # _unmemoized_mime_type(*args)
|
96
|
+
end # end
|
97
|
+
end # end
|
98
|
+
end # end
|
99
|
+
#
|
100
|
+
if private_method_defined?(#{original_method.inspect}) # if private_method_defined?(:_unmemoized_mime_type)
|
101
|
+
private #{symbol.inspect} # private :mime_type
|
102
|
+
elsif protected_method_defined?(#{original_method.inspect}) # elsif protected_method_defined?(:_unmemoized_mime_type)
|
103
|
+
protected #{symbol.inspect} # protected :mime_type
|
104
|
+
end # end
|
105
|
+
EOS
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
data/memoization.gemspec
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/memoization/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Burke Libbey"]
|
6
|
+
gem.email = ["burke@burkelibbey.org"]
|
7
|
+
gem.description = %q{Forward-port of ActiveSupport::Memoizable for 3.2 and beyond.}
|
8
|
+
gem.summary = %q{Forward-port of ActiveSupport::Memoizable for 3.2 and beyond. Because it's actually useful.}
|
9
|
+
gem.homepage = ""
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "memoization"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Memoization::VERSION
|
17
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
ORIG_ARGV = ARGV.dup
|
2
|
+
|
3
|
+
begin
|
4
|
+
old, $VERBOSE = $VERBOSE, nil
|
5
|
+
# require File.expand_path('../../../load_paths', __FILE__)
|
6
|
+
ensure
|
7
|
+
$VERBOSE = old
|
8
|
+
end
|
9
|
+
|
10
|
+
lib = File.expand_path("#{File.dirname(__FILE__)}/../lib")
|
11
|
+
$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib)
|
12
|
+
|
13
|
+
require 'active_support/core_ext/kernel/reporting'
|
14
|
+
|
15
|
+
require 'active_support/core_ext/string/encoding'
|
16
|
+
if "ruby".encoding_aware?
|
17
|
+
# These are the normal settings that will be set up by Railties
|
18
|
+
# TODO: Have these tests support other combinations of these values
|
19
|
+
silence_warnings do
|
20
|
+
Encoding.default_internal = "UTF-8"
|
21
|
+
Encoding.default_external = "UTF-8"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
require 'test/unit'
|
26
|
+
# require 'empty_bool'
|
27
|
+
|
28
|
+
silence_warnings { require 'mocha' }
|
29
|
+
|
30
|
+
ENV['NO_RELOAD'] = '1'
|
31
|
+
require 'active_support'
|
32
|
+
|
33
|
+
# Include shims until we get off 1.8.6
|
34
|
+
require 'active_support/ruby/shim' if RUBY_VERSION < '1.8.7'
|
35
|
+
|
36
|
+
def uses_memcached(test_name)
|
37
|
+
require 'memcache'
|
38
|
+
begin
|
39
|
+
MemCache.new('localhost:11211').stats
|
40
|
+
yield
|
41
|
+
rescue MemCache::MemCacheError
|
42
|
+
$stderr.puts "Skipping #{test_name} tests. Start memcached and try again."
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def with_kcode(code)
|
47
|
+
if RUBY_VERSION < '1.9'
|
48
|
+
begin
|
49
|
+
old_kcode, $KCODE = $KCODE, code
|
50
|
+
yield
|
51
|
+
ensure
|
52
|
+
$KCODE = old_kcode
|
53
|
+
end
|
54
|
+
else
|
55
|
+
yield
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Show backtraces for deprecated behavior for quicker cleanup.
|
60
|
+
ActiveSupport::Deprecation.debug = true
|
61
|
+
|
62
|
+
if RUBY_VERSION < '1.9'
|
63
|
+
$KCODE = 'UTF8'
|
64
|
+
end
|
@@ -0,0 +1,279 @@
|
|
1
|
+
require './lib/memoization'
|
2
|
+
require './test/abstract_unit'
|
3
|
+
|
4
|
+
class MemoizationTest < ActiveSupport::TestCase
|
5
|
+
class Person
|
6
|
+
extend Memoization
|
7
|
+
|
8
|
+
attr_reader :name_calls, :age_calls, :is_developer_calls, :name_query_calls
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@name_calls = 0
|
12
|
+
@age_calls = 0
|
13
|
+
@is_developer_calls = 0
|
14
|
+
@name_query_calls = 0
|
15
|
+
end
|
16
|
+
|
17
|
+
def name
|
18
|
+
@name_calls += 1
|
19
|
+
"Josh"
|
20
|
+
end
|
21
|
+
|
22
|
+
def name?
|
23
|
+
@name_query_calls += 1
|
24
|
+
true
|
25
|
+
end
|
26
|
+
memoize :name?
|
27
|
+
|
28
|
+
def update(name)
|
29
|
+
"Joshua"
|
30
|
+
end
|
31
|
+
memoize :update
|
32
|
+
|
33
|
+
def age
|
34
|
+
@age_calls += 1
|
35
|
+
nil
|
36
|
+
end
|
37
|
+
|
38
|
+
memoize :name, :age
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
def memoize_protected_test
|
43
|
+
'protected'
|
44
|
+
end
|
45
|
+
memoize :memoize_protected_test
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def is_developer?
|
50
|
+
@is_developer_calls += 1
|
51
|
+
"Yes"
|
52
|
+
end
|
53
|
+
memoize :is_developer?
|
54
|
+
end
|
55
|
+
|
56
|
+
class Company
|
57
|
+
attr_reader :name_calls
|
58
|
+
def initialize
|
59
|
+
@name_calls = 0
|
60
|
+
end
|
61
|
+
|
62
|
+
def name
|
63
|
+
@name_calls += 1
|
64
|
+
"37signals"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
module Rates
|
69
|
+
extend Memoization
|
70
|
+
|
71
|
+
attr_reader :sales_tax_calls
|
72
|
+
def sales_tax(price)
|
73
|
+
@sales_tax_calls ||= 0
|
74
|
+
@sales_tax_calls += 1
|
75
|
+
price * 0.1025
|
76
|
+
end
|
77
|
+
memoize :sales_tax
|
78
|
+
end
|
79
|
+
|
80
|
+
class Calculator
|
81
|
+
extend Memoization
|
82
|
+
include Rates
|
83
|
+
|
84
|
+
attr_reader :fib_calls
|
85
|
+
def initialize
|
86
|
+
@fib_calls = 0
|
87
|
+
end
|
88
|
+
|
89
|
+
def fib(n)
|
90
|
+
@fib_calls += 1
|
91
|
+
|
92
|
+
if n == 0 || n == 1
|
93
|
+
n
|
94
|
+
else
|
95
|
+
fib(n - 1) + fib(n - 2)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
memoize :fib
|
99
|
+
|
100
|
+
def add_or_subtract(i, j, add)
|
101
|
+
if add
|
102
|
+
i + j
|
103
|
+
else
|
104
|
+
i - j
|
105
|
+
end
|
106
|
+
end
|
107
|
+
memoize :add_or_subtract
|
108
|
+
|
109
|
+
def counter
|
110
|
+
@count ||= 0
|
111
|
+
@count += 1
|
112
|
+
end
|
113
|
+
memoize :counter
|
114
|
+
end
|
115
|
+
|
116
|
+
def setup
|
117
|
+
@person = Person.new
|
118
|
+
@calculator = Calculator.new
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_memoization
|
122
|
+
assert_equal "Josh", @person.name
|
123
|
+
assert_equal 1, @person.name_calls
|
124
|
+
|
125
|
+
3.times { assert_equal "Josh", @person.name }
|
126
|
+
assert_equal 1, @person.name_calls
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_memoization_with_punctuation
|
130
|
+
assert_equal true, @person.name?
|
131
|
+
|
132
|
+
assert_nothing_raised(NameError) do
|
133
|
+
@person.memoize_all
|
134
|
+
@person.unmemoize_all
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_memoization_flush_with_punctuation
|
139
|
+
assert_equal true, @person.name?
|
140
|
+
@person.flush_cache(:name?)
|
141
|
+
3.times { assert_equal true, @person.name? }
|
142
|
+
assert_equal 2, @person.name_query_calls
|
143
|
+
end
|
144
|
+
|
145
|
+
def test_memoization_with_nil_value
|
146
|
+
assert_equal nil, @person.age
|
147
|
+
assert_equal 1, @person.age_calls
|
148
|
+
|
149
|
+
3.times { assert_equal nil, @person.age }
|
150
|
+
assert_equal 1, @person.age_calls
|
151
|
+
end
|
152
|
+
|
153
|
+
def test_reloadable
|
154
|
+
assert_equal 1, @calculator.counter
|
155
|
+
assert_equal 2, @calculator.counter(:reload)
|
156
|
+
assert_equal 2, @calculator.counter
|
157
|
+
assert_equal 3, @calculator.counter(true)
|
158
|
+
assert_equal 3, @calculator.counter
|
159
|
+
end
|
160
|
+
|
161
|
+
def test_flush_cache
|
162
|
+
assert_equal 1, @calculator.counter
|
163
|
+
|
164
|
+
assert @calculator.instance_variable_get(:@_memoized_counter).any?
|
165
|
+
@calculator.flush_cache(:counter)
|
166
|
+
assert @calculator.instance_variable_get(:@_memoized_counter).empty?
|
167
|
+
|
168
|
+
assert_equal 2, @calculator.counter
|
169
|
+
end
|
170
|
+
|
171
|
+
def test_unmemoize_all
|
172
|
+
assert_equal 1, @calculator.counter
|
173
|
+
|
174
|
+
assert @calculator.instance_variable_get(:@_memoized_counter).any?
|
175
|
+
@calculator.unmemoize_all
|
176
|
+
assert @calculator.instance_variable_get(:@_memoized_counter).empty?
|
177
|
+
|
178
|
+
assert_equal 2, @calculator.counter
|
179
|
+
end
|
180
|
+
|
181
|
+
def test_memoize_all
|
182
|
+
@calculator.memoize_all
|
183
|
+
assert @calculator.instance_variable_defined?(:@_memoized_counter)
|
184
|
+
end
|
185
|
+
|
186
|
+
def test_memoization_cache_is_different_for_each_instance
|
187
|
+
assert_equal 1, @calculator.counter
|
188
|
+
assert_equal 2, @calculator.counter(:reload)
|
189
|
+
assert_equal 1, Calculator.new.counter
|
190
|
+
end
|
191
|
+
|
192
|
+
def test_memoized_is_not_affected_by_freeze
|
193
|
+
@person.freeze
|
194
|
+
assert_equal "Josh", @person.name
|
195
|
+
assert_equal "Joshua", @person.update("Joshua")
|
196
|
+
end
|
197
|
+
|
198
|
+
def test_memoization_with_args
|
199
|
+
assert_equal 55, @calculator.fib(10)
|
200
|
+
assert_equal 11, @calculator.fib_calls
|
201
|
+
end
|
202
|
+
|
203
|
+
def test_reloadable_with_args
|
204
|
+
assert_equal 55, @calculator.fib(10)
|
205
|
+
assert_equal 11, @calculator.fib_calls
|
206
|
+
assert_equal 55, @calculator.fib(10, :reload)
|
207
|
+
assert_equal 12, @calculator.fib_calls
|
208
|
+
assert_equal 55, @calculator.fib(10, true)
|
209
|
+
assert_equal 13, @calculator.fib_calls
|
210
|
+
end
|
211
|
+
|
212
|
+
def test_memoization_with_boolean_arg
|
213
|
+
assert_equal 4, @calculator.add_or_subtract(2, 2, true)
|
214
|
+
assert_equal 2, @calculator.add_or_subtract(4, 2, false)
|
215
|
+
end
|
216
|
+
|
217
|
+
def test_object_memoization
|
218
|
+
[Company.new, Company.new, Company.new].each do |company|
|
219
|
+
company.extend Memoization
|
220
|
+
company.memoize :name
|
221
|
+
|
222
|
+
assert_equal "37signals", company.name
|
223
|
+
assert_equal 1, company.name_calls
|
224
|
+
assert_equal "37signals", company.name
|
225
|
+
assert_equal 1, company.name_calls
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def test_memoized_module_methods
|
230
|
+
assert_equal 1.025, @calculator.sales_tax(10)
|
231
|
+
assert_equal 1, @calculator.sales_tax_calls
|
232
|
+
assert_equal 1.025, @calculator.sales_tax(10)
|
233
|
+
assert_equal 1, @calculator.sales_tax_calls
|
234
|
+
assert_equal 2.5625, @calculator.sales_tax(25)
|
235
|
+
assert_equal 2, @calculator.sales_tax_calls
|
236
|
+
end
|
237
|
+
|
238
|
+
def test_object_memoized_module_methods
|
239
|
+
company = Company.new
|
240
|
+
company.extend(Rates)
|
241
|
+
|
242
|
+
assert_equal 1.025, company.sales_tax(10)
|
243
|
+
assert_equal 1, company.sales_tax_calls
|
244
|
+
assert_equal 1.025, company.sales_tax(10)
|
245
|
+
assert_equal 1, company.sales_tax_calls
|
246
|
+
assert_equal 2.5625, company.sales_tax(25)
|
247
|
+
assert_equal 2, company.sales_tax_calls
|
248
|
+
end
|
249
|
+
|
250
|
+
def test_double_memoization
|
251
|
+
assert_raise(RuntimeError) { Person.memoize :name }
|
252
|
+
person = Person.new
|
253
|
+
person.extend Memoization
|
254
|
+
assert_raise(RuntimeError) { person.memoize :name }
|
255
|
+
|
256
|
+
company = Company.new
|
257
|
+
company.extend Memoization
|
258
|
+
company.memoize :name
|
259
|
+
assert_raise(RuntimeError) { company.memoize :name }
|
260
|
+
end
|
261
|
+
|
262
|
+
def test_protected_method_memoization
|
263
|
+
person = Person.new
|
264
|
+
|
265
|
+
assert_raise(NoMethodError) { person.memoize_protected_test }
|
266
|
+
assert_equal "protected", person.send(:memoize_protected_test)
|
267
|
+
end
|
268
|
+
|
269
|
+
def test_private_method_memoization
|
270
|
+
person = Person.new
|
271
|
+
|
272
|
+
assert_raise(NoMethodError) { person.is_developer? }
|
273
|
+
assert_equal "Yes", person.send(:is_developer?)
|
274
|
+
assert_equal 1, person.is_developer_calls
|
275
|
+
assert_equal "Yes", person.send(:is_developer?)
|
276
|
+
assert_equal 1, person.is_developer_calls
|
277
|
+
end
|
278
|
+
|
279
|
+
end
|
metadata
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: memoization
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Burke Libbey
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-03-30 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Forward-port of ActiveSupport::Memoizable for 3.2 and beyond.
|
15
|
+
email:
|
16
|
+
- burke@burkelibbey.org
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- .gitignore
|
22
|
+
- Gemfile
|
23
|
+
- LICENSE
|
24
|
+
- README.md
|
25
|
+
- Rakefile
|
26
|
+
- lib/memoization.rb
|
27
|
+
- lib/memoization/version.rb
|
28
|
+
- memoization.gemspec
|
29
|
+
- test/abstract_unit.rb
|
30
|
+
- test/memoization_test.rb
|
31
|
+
homepage: ''
|
32
|
+
licenses: []
|
33
|
+
post_install_message:
|
34
|
+
rdoc_options: []
|
35
|
+
require_paths:
|
36
|
+
- lib
|
37
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ! '>='
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
43
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
44
|
+
none: false
|
45
|
+
requirements:
|
46
|
+
- - ! '>='
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
requirements: []
|
50
|
+
rubyforge_project:
|
51
|
+
rubygems_version: 1.8.11
|
52
|
+
signing_key:
|
53
|
+
specification_version: 3
|
54
|
+
summary: Forward-port of ActiveSupport::Memoizable for 3.2 and beyond. Because it's
|
55
|
+
actually useful.
|
56
|
+
test_files:
|
57
|
+
- test/abstract_unit.rb
|
58
|
+
- test/memoization_test.rb
|