memoist 0.11.0 → 0.16.2
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.
- checksums.yaml +5 -5
- data/.travis.yml +15 -11
- data/CHANGELOG.md +130 -0
- data/README.md +79 -35
- data/Rakefile +6 -5
- data/lib/memoist/version.rb +3 -1
- data/lib/memoist.rb +78 -41
- data/memoist.gemspec +31 -23
- data/script/benchmark.rb +48 -0
- data/test/memoist_test.rb +225 -45
- data/test/test_helper.rb +1 -1
- metadata +26 -12
- data/lib/memoist/core_ext/singleton_class.rb +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: '058dae917e46d13306497f0bcd18df607cb1d5dca2d85ee6f9cbc18739172e27'
|
4
|
+
data.tar.gz: c0874b135f70db573a863e4b54bb141905c003d9e451d7c3637d8f67c96a0696
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 409f37c0861015cc81704bf4fbbb1002d7a011a5f3dccb0e1430baf8b5eac601f5caae99cf4e1634fe044ea01123c1a0319692fad6d64c848026329f9a4dfa7a
|
7
|
+
data.tar.gz: 7f3134101c02c37ce88fd6a814c6bce19f5ffc4085fcfbb08e22ce720f125b7f8c2c2644c6a694cf4bb5dc4feb40974785f1209d598c18ba098bc055bca33146
|
data/.travis.yml
CHANGED
@@ -1,17 +1,21 @@
|
|
1
|
+
sudo: false
|
2
|
+
cache: bundler
|
1
3
|
language: ruby
|
2
4
|
rvm:
|
3
|
-
- 1.8.7
|
4
|
-
- 1.9.2
|
5
5
|
- 1.9.3
|
6
6
|
- 2.0.0
|
7
|
-
- 2.1.
|
8
|
-
-
|
9
|
-
-
|
10
|
-
-
|
7
|
+
- 2.1.10
|
8
|
+
- 2.2.7
|
9
|
+
- 2.3.4
|
10
|
+
- 2.4.1
|
11
|
+
- 2.5.1
|
12
|
+
- 2.6.0
|
11
13
|
- ruby-head
|
14
|
+
- jruby-19mode
|
15
|
+
- jruby-9.1.9.0
|
12
16
|
- jruby-head
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
17
|
+
|
18
|
+
before_install:
|
19
|
+
- gem install bundler --no-document -v '~> 1.13'
|
20
|
+
before_script:
|
21
|
+
- unset JRUBY_OPTS
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
## [Unreleased](https://github.com/matthewrudy/memoist/tree/HEAD)
|
4
|
+
|
5
|
+
[Full Changelog](https://github.com/matthewrudy/memoist/compare/v0.16.1...HEAD)
|
6
|
+
|
7
|
+
**Merged pull requests:**
|
8
|
+
|
9
|
+
- Fix regression introduced by frozen symbol fix [\#86](https://github.com/matthewrudy/memoist/pull/86) ([sebjacobs](https://github.com/sebjacobs))
|
10
|
+
|
11
|
+
## [v0.16.1](https://github.com/matthewrudy/memoist/tree/v0.16.1) (2019-11-08)
|
12
|
+
|
13
|
+
[Full Changelog](https://github.com/matthewrudy/memoist/compare/v0.16.0...v0.16.1)
|
14
|
+
|
15
|
+
**Merged pull requests:**
|
16
|
+
|
17
|
+
- Remove ruby 1.9.2 from travis build matrix [\#84](https://github.com/matthewrudy/memoist/pull/84) ([unasuke](https://github.com/unasuke))
|
18
|
+
- Make Memoist.escape\_punctuation compatible with MRI 2.7 [\#82](https://github.com/matthewrudy/memoist/pull/82) ([casperisfine](https://github.com/casperisfine))
|
19
|
+
- add 2.5.1 to travis [\#77](https://github.com/matthewrudy/memoist/pull/77) ([matthewrudy](https://github.com/matthewrudy))
|
20
|
+
- Remove ghit.me [\#74](https://github.com/matthewrudy/memoist/pull/74) ([matthewrudy](https://github.com/matthewrudy))
|
21
|
+
- Place sample code for execution in README.md [\#73](https://github.com/matthewrudy/memoist/pull/73) ([3nan3](https://github.com/3nan3))
|
22
|
+
- Require Ruby \>=1.9.2 [\#69](https://github.com/matthewrudy/memoist/pull/69) ([matthewrudy](https://github.com/matthewrudy))
|
23
|
+
|
24
|
+
## [v0.16.0](https://github.com/matthewrudy/memoist/tree/v0.16.0) (2017-06-20)
|
25
|
+
|
26
|
+
[Full Changelog](https://github.com/matthewrudy/memoist/compare/v0.15.0...v0.16.0)
|
27
|
+
|
28
|
+
**Merged pull requests:**
|
29
|
+
|
30
|
+
- Fix undefined `memoized\_methods` error raised when a parent class has not call `memoize` [\#68](https://github.com/matthewrudy/memoist/pull/68) ([PikachuEXE](https://github.com/PikachuEXE))
|
31
|
+
- Add support for class-level cache flushing. [\#67](https://github.com/matthewrudy/memoist/pull/67) ([JoeMcB](https://github.com/JoeMcB))
|
32
|
+
- Add ruby 2.4 to travis \(bump 2.2 and 2.3 versions\) [\#64](https://github.com/matthewrudy/memoist/pull/64) ([jrafanie](https://github.com/jrafanie))
|
33
|
+
- Fix tests for Ruby \< 1.9.3 [\#56](https://github.com/matthewrudy/memoist/pull/56) ([matthewrudy](https://github.com/matthewrudy))
|
34
|
+
- Add return in comments for `flush\_cache`. [\#55](https://github.com/matthewrudy/memoist/pull/55) ([joshuapinter](https://github.com/joshuapinter))
|
35
|
+
- Update readme [\#53](https://github.com/matthewrudy/memoist/pull/53) ([biow0lf](https://github.com/biow0lf))
|
36
|
+
|
37
|
+
## [v0.15.0](https://github.com/matthewrudy/memoist/tree/v0.15.0) (2016-08-23)
|
38
|
+
|
39
|
+
[Full Changelog](https://github.com/matthewrudy/memoist/compare/v0.14.0...v0.15.0)
|
40
|
+
|
41
|
+
**Merged pull requests:**
|
42
|
+
|
43
|
+
- Remove test warnings [\#52](https://github.com/matthewrudy/memoist/pull/52) ([matthewrudy](https://github.com/matthewrudy))
|
44
|
+
- Use SVG badge over PNG [\#44](https://github.com/matthewrudy/memoist/pull/44) ([olivierlacan](https://github.com/olivierlacan))
|
45
|
+
|
46
|
+
## [v0.14.0](https://github.com/matthewrudy/memoist/tree/v0.14.0) (2015-12-15)
|
47
|
+
|
48
|
+
[Full Changelog](https://github.com/matthewrudy/memoist/compare/v0.13.0...v0.14.0)
|
49
|
+
|
50
|
+
**Merged pull requests:**
|
51
|
+
|
52
|
+
- Faster2: Cache the method, ivar, and arity and the ancestry memoized methods [\#38](https://github.com/matthewrudy/memoist/pull/38) ([jrafanie](https://github.com/jrafanie))
|
53
|
+
|
54
|
+
## [v0.13.0](https://github.com/matthewrudy/memoist/tree/v0.13.0) (2015-11-26)
|
55
|
+
|
56
|
+
[Full Changelog](https://github.com/matthewrudy/memoist/compare/v0.12.0...v0.13.0)
|
57
|
+
|
58
|
+
**Merged pull requests:**
|
59
|
+
|
60
|
+
- Faster memoist with less object allocations [\#36](https://github.com/matthewrudy/memoist/pull/36) ([jrafanie](https://github.com/jrafanie))
|
61
|
+
- Be optimistic about bundler version [\#35](https://github.com/matthewrudy/memoist/pull/35) ([lotyrin](https://github.com/lotyrin))
|
62
|
+
- Add syntax highlighting for code blocks. [\#34](https://github.com/matthewrudy/memoist/pull/34) ([joshuapinter](https://github.com/joshuapinter))
|
63
|
+
|
64
|
+
## [v0.12.0](https://github.com/matthewrudy/memoist/tree/v0.12.0) (2015-04-13)
|
65
|
+
|
66
|
+
[Full Changelog](https://github.com/matthewrudy/memoist/compare/v0.11.0...v0.12.0)
|
67
|
+
|
68
|
+
**Merged pull requests:**
|
69
|
+
|
70
|
+
- Fix forking link [\#30](https://github.com/matthewrudy/memoist/pull/30) ([brandondrew](https://github.com/brandondrew))
|
71
|
+
- Update README with :identifier info [\#29](https://github.com/matthewrudy/memoist/pull/29) ([fervic](https://github.com/fervic))
|
72
|
+
|
73
|
+
## [v0.11.0](https://github.com/matthewrudy/memoist/tree/v0.11.0) (2014-10-10)
|
74
|
+
|
75
|
+
[Full Changelog](https://github.com/matthewrudy/memoist/compare/v0.10.0...v0.11.0)
|
76
|
+
|
77
|
+
**Merged pull requests:**
|
78
|
+
|
79
|
+
- Call abs on arity when extracting reload [\#27](https://github.com/matthewrudy/memoist/pull/27) ([bradylove](https://github.com/bradylove))
|
80
|
+
|
81
|
+
## [v0.10.0](https://github.com/matthewrudy/memoist/tree/v0.10.0) (2014-08-13)
|
82
|
+
|
83
|
+
[Full Changelog](https://github.com/matthewrudy/memoist/compare/v0.9.3...v0.10.0)
|
84
|
+
|
85
|
+
**Merged pull requests:**
|
86
|
+
|
87
|
+
- Make memoize return a :symbol [\#24](https://github.com/matthewrudy/memoist/pull/24) ([matthewrudy](https://github.com/matthewrudy))
|
88
|
+
- Use Minitest [\#19](https://github.com/matthewrudy/memoist/pull/19) ([matthewrudy](https://github.com/matthewrudy))
|
89
|
+
|
90
|
+
## [v0.9.3](https://github.com/matthewrudy/memoist/tree/v0.9.3) (2014-06-01)
|
91
|
+
|
92
|
+
[Full Changelog](https://github.com/matthewrudy/memoist/compare/v0.9.2...v0.9.3)
|
93
|
+
|
94
|
+
**Merged pull requests:**
|
95
|
+
|
96
|
+
- Remove Array caching hack [\#17](https://github.com/matthewrudy/memoist/pull/17) ([matthewrudy](https://github.com/matthewrudy))
|
97
|
+
|
98
|
+
## [v0.9.2](https://github.com/matthewrudy/memoist/tree/v0.9.2) (2014-04-16)
|
99
|
+
|
100
|
+
[Full Changelog](https://github.com/matthewrudy/memoist/compare/0.9.0...v0.9.2)
|
101
|
+
|
102
|
+
**Merged pull requests:**
|
103
|
+
|
104
|
+
- Give double-memoize errors their own error class [\#15](https://github.com/matthewrudy/memoist/pull/15) ([zachhale](https://github.com/zachhale))
|
105
|
+
- Add tax-themed example for class method memoization fixes \#9 [\#10](https://github.com/matthewrudy/memoist/pull/10) ([fny](https://github.com/fny))
|
106
|
+
|
107
|
+
## [0.9.0](https://github.com/matthewrudy/memoist/tree/0.9.0) (2013-03-20)
|
108
|
+
|
109
|
+
[Full Changelog](https://github.com/matthewrudy/memoist/compare/0.2.0...0.9.0)
|
110
|
+
|
111
|
+
**Merged pull requests:**
|
112
|
+
|
113
|
+
- Update README.md to include memoization bypass description [\#6](https://github.com/matthewrudy/memoist/pull/6) ([andreychernih](https://github.com/andreychernih))
|
114
|
+
- Adds a note about the MIT License [\#4](https://github.com/matthewrudy/memoist/pull/4) ([matiaskorhonen](https://github.com/matiaskorhonen))
|
115
|
+
|
116
|
+
## [0.2.0](https://github.com/matthewrudy/memoist/tree/0.2.0) (2012-08-15)
|
117
|
+
|
118
|
+
[Full Changelog](https://github.com/matthewrudy/memoist/compare/0.1.0...0.2.0)
|
119
|
+
|
120
|
+
**Merged pull requests:**
|
121
|
+
|
122
|
+
- Improved performance of flush\_cache and prime\_cache when parameters are passed to them. [\#2](https://github.com/matthewrudy/memoist/pull/2) ([jrafanie](https://github.com/jrafanie))
|
123
|
+
|
124
|
+
## [0.1.0](https://github.com/matthewrudy/memoist/tree/0.1.0) (2012-01-24)
|
125
|
+
|
126
|
+
[Full Changelog](https://github.com/matthewrudy/memoist/compare/7a5352d6b6c4219f37f329d2422985961c749748...0.1.0)
|
127
|
+
|
128
|
+
|
129
|
+
|
130
|
+
\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*
|
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Memoist
|
2
2
|
=============
|
3
3
|
|
4
|
-
[](https://travis-ci.org/matthewrudy/memoist)
|
5
5
|
|
6
6
|
Memoist is an extraction of ActiveSupport::Memoizable.
|
7
7
|
|
@@ -14,53 +14,91 @@ Usage
|
|
14
14
|
|
15
15
|
Just extend with the Memoist module
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
```ruby
|
18
|
+
require 'memoist'
|
19
|
+
class Person
|
20
|
+
extend Memoist
|
20
21
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
def social_security
|
23
|
+
puts "execute!"
|
24
|
+
decrypt_social_security
|
25
|
+
end
|
26
|
+
memoize :social_security
|
27
|
+
end
|
28
|
+
|
29
|
+
person = Person.new
|
30
|
+
|
31
|
+
person.social_security
|
32
|
+
# execute!
|
33
|
+
# => (returns decrypt_social_security)
|
34
|
+
|
35
|
+
person.social_security
|
36
|
+
# => (returns the memoized value)
|
37
|
+
```
|
26
38
|
|
27
39
|
And person.social_security will only be calculated once.
|
28
40
|
|
29
41
|
Every memoized function (which initially was not accepting any arguments) has a ```(reload)```
|
30
42
|
argument you can pass in to bypass and reset the memoization:
|
31
43
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
44
|
+
```ruby
|
45
|
+
def some_method
|
46
|
+
Time.now
|
47
|
+
end
|
48
|
+
memoize :some_method
|
49
|
+
```
|
36
50
|
|
37
51
|
Calling ```some_method``` will be memoized, but calling ```some_method(true)``` will rememoize each time.
|
38
52
|
|
39
53
|
You can even memoize method that takes arguments.
|
40
54
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
55
|
+
```ruby
|
56
|
+
class Person
|
57
|
+
def taxes_due(income)
|
58
|
+
income * 0.40
|
59
|
+
end
|
60
|
+
memoize :taxes_due
|
61
|
+
end
|
62
|
+
```
|
48
63
|
|
49
64
|
This will only be calculated once per value of income.
|
50
65
|
|
51
66
|
You can also memoize class methods.
|
52
67
|
|
53
|
-
|
54
|
-
|
55
|
-
class << self
|
56
|
-
extend Memoist
|
57
|
-
def with_overdue_taxes
|
58
|
-
# ...
|
59
|
-
end
|
60
|
-
memoize :with_overdue_taxes
|
61
|
-
end
|
68
|
+
```ruby
|
69
|
+
class Person
|
62
70
|
|
71
|
+
class << self
|
72
|
+
extend Memoist
|
73
|
+
def with_overdue_taxes
|
74
|
+
# ...
|
63
75
|
end
|
76
|
+
memoize :with_overdue_taxes
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
```
|
81
|
+
|
82
|
+
When a sub-class overrides one of its parent's methods and you need to memoize both.
|
83
|
+
Then you can use the `:identifier` parameter in order to help _Memoist_ distinguish between the two.
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
class Clock
|
87
|
+
extend Memoist
|
88
|
+
def now
|
89
|
+
"The time now is #{Time.now.hour} o'clock and #{Time.now.min} minutes"
|
90
|
+
end
|
91
|
+
memoize :now
|
92
|
+
end
|
93
|
+
|
94
|
+
class AccurateClock < Clock
|
95
|
+
extend Memoist
|
96
|
+
def now
|
97
|
+
"#{super} and #{Time.now.sec} seconds"
|
98
|
+
end
|
99
|
+
memoize :now, :identifier => :accurate_clock
|
100
|
+
end
|
101
|
+
```
|
64
102
|
|
65
103
|
|
66
104
|
Reload
|
@@ -68,17 +106,23 @@ Reload
|
|
68
106
|
|
69
107
|
Each memoized function comes with a way to flush the existing value.
|
70
108
|
|
71
|
-
|
72
|
-
|
109
|
+
```ruby
|
110
|
+
person.social_security # returns the memoized value
|
111
|
+
person.social_security(true) # bypasses the memoized value and rememoizes it
|
112
|
+
```
|
73
113
|
|
74
114
|
This also works with a memoized method with arguments
|
75
115
|
|
76
|
-
|
77
|
-
|
116
|
+
```ruby
|
117
|
+
person.taxes_due(100_000) # returns the memoized value
|
118
|
+
person.taxes_due(100_000, true) # bypasses the memoized value and rememoizes it
|
119
|
+
```
|
78
120
|
|
79
121
|
If you want to flush the entire memoization cache for an object
|
80
122
|
|
81
|
-
|
123
|
+
```ruby
|
124
|
+
person.flush_cache # returns an array of flushed memoized methods, e.g. ["social_security", "some_method"]
|
125
|
+
```
|
82
126
|
|
83
127
|
Authors
|
84
128
|
===========
|
@@ -101,7 +145,7 @@ Everyone who contributed to it in the rails repository.
|
|
101
145
|
Contributing
|
102
146
|
============
|
103
147
|
|
104
|
-
1. Fork it (
|
148
|
+
1. Fork it ( https://github.com/matthewrudy/memoist/fork )
|
105
149
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
106
150
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
107
151
|
4. Push to the branch (`git push origin my-new-feature`)
|
data/Rakefile
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
require "bundler/gem_tasks"
|
3
2
|
|
4
|
-
require
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
|
5
|
+
require 'rake/testtask'
|
5
6
|
Rake::TestTask.new do |t|
|
6
|
-
t.libs <<
|
7
|
-
t.test_files = FileList[
|
7
|
+
t.libs << 'test'
|
8
|
+
t.test_files = FileList['test/**/*_test.rb']
|
8
9
|
t.verbose = true
|
9
10
|
end
|
10
11
|
|
11
|
-
task :
|
12
|
+
task default: ['test']
|
data/lib/memoist/version.rb
CHANGED
data/lib/memoist.rb
CHANGED
@@ -1,25 +1,53 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'memoist/version'
|
2
4
|
|
3
5
|
module Memoist
|
6
|
+
def self.extended(extender)
|
7
|
+
Memoist.memoist_eval(extender) do
|
8
|
+
unless singleton_class.method_defined?(:memoized_methods)
|
9
|
+
def self.memoized_methods
|
10
|
+
@_memoized_methods ||= []
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
4
15
|
|
5
|
-
def self.memoized_ivar_for(method_name, identifier=nil)
|
6
|
-
|
16
|
+
def self.memoized_ivar_for(method_name, identifier = nil)
|
17
|
+
"@#{memoized_prefix(identifier)}_#{escape_punctuation(method_name)}"
|
7
18
|
end
|
8
19
|
|
9
|
-
def self.unmemoized_method_for(method_name, identifier=nil)
|
10
|
-
|
20
|
+
def self.unmemoized_method_for(method_name, identifier = nil)
|
21
|
+
"#{unmemoized_prefix(identifier)}_#{method_name}".to_sym
|
11
22
|
end
|
12
23
|
|
13
|
-
def self.memoized_prefix(identifier=nil)
|
14
|
-
|
24
|
+
def self.memoized_prefix(identifier = nil)
|
25
|
+
if identifier
|
26
|
+
"_memoized_#{identifier}"
|
27
|
+
else
|
28
|
+
'_memoized'.freeze
|
29
|
+
end
|
15
30
|
end
|
16
31
|
|
17
|
-
def self.unmemoized_prefix(identifier=nil)
|
18
|
-
|
32
|
+
def self.unmemoized_prefix(identifier = nil)
|
33
|
+
if identifier
|
34
|
+
"_unmemoized_#{identifier}"
|
35
|
+
else
|
36
|
+
'_unmemoized'.freeze
|
37
|
+
end
|
19
38
|
end
|
20
39
|
|
21
40
|
def self.escape_punctuation(string)
|
22
|
-
string.
|
41
|
+
string = string.is_a?(String) ? string.dup : string.to_s.dup
|
42
|
+
|
43
|
+
return string unless string.end_with?('?'.freeze, '!'.freeze)
|
44
|
+
|
45
|
+
# A String can't end in both ? and !
|
46
|
+
if string.sub!(/\?\Z/, '_query'.freeze)
|
47
|
+
else
|
48
|
+
string.sub!(/!\Z/, '_bang'.freeze)
|
49
|
+
end
|
50
|
+
string
|
23
51
|
end
|
24
52
|
|
25
53
|
def self.memoist_eval(klass, *args, &block)
|
@@ -46,47 +74,55 @@ module Memoist
|
|
46
74
|
flush_cache
|
47
75
|
end
|
48
76
|
|
49
|
-
def
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
end.compact
|
57
|
-
end
|
77
|
+
def memoized_structs(names)
|
78
|
+
ref_obj = self.class.respond_to?(:class_eval) ? singleton_class : self
|
79
|
+
structs = ref_obj.all_memoized_structs
|
80
|
+
return structs if names.empty?
|
81
|
+
|
82
|
+
structs.select { |s| names.include?(s.memoized_method) }
|
83
|
+
end
|
58
84
|
|
59
|
-
|
60
|
-
|
61
|
-
|
85
|
+
def prime_cache(*method_names)
|
86
|
+
memoized_structs(method_names).each do |struct|
|
87
|
+
if struct.arity == 0
|
88
|
+
__send__(struct.memoized_method)
|
62
89
|
else
|
63
|
-
ivar
|
64
|
-
instance_variable_set(ivar, {})
|
90
|
+
instance_variable_set(struct.ivar, {})
|
65
91
|
end
|
66
92
|
end
|
67
93
|
end
|
68
94
|
|
69
95
|
def flush_cache(*method_names)
|
70
|
-
|
71
|
-
|
72
|
-
method_names = (methods + private_methods + protected_methods).collect do |method_name|
|
73
|
-
if method_name.to_s.start_with?(prefix)
|
74
|
-
method_name[prefix.length..-1]
|
75
|
-
end
|
76
|
-
end.compact
|
96
|
+
memoized_structs(method_names).each do |struct|
|
97
|
+
remove_instance_variable(struct.ivar) if instance_variable_defined?(struct.ivar)
|
77
98
|
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
MemoizedMethod = Struct.new(:memoized_method, :ivar, :arity)
|
78
103
|
|
79
|
-
|
80
|
-
|
81
|
-
|
104
|
+
def all_memoized_structs
|
105
|
+
@all_memoized_structs ||= begin
|
106
|
+
structs = memoized_methods.dup
|
107
|
+
|
108
|
+
# Collect the memoized_methods of ancestors in ancestor order
|
109
|
+
# unless we already have it since self or parents could be overriding
|
110
|
+
# an ancestor method.
|
111
|
+
ancestors.grep(Memoist).each do |ancestor|
|
112
|
+
ancestor.memoized_methods.each do |m|
|
113
|
+
structs << m unless structs.any? { |am| am.memoized_method == m.memoized_method }
|
114
|
+
end
|
82
115
|
end
|
116
|
+
structs
|
83
117
|
end
|
84
118
|
end
|
85
119
|
|
120
|
+
def clear_structs
|
121
|
+
@all_memoized_structs = nil
|
122
|
+
end
|
123
|
+
|
86
124
|
def memoize(*method_names)
|
87
|
-
if method_names.last.is_a?(Hash)
|
88
|
-
identifier = method_names.pop[:identifier]
|
89
|
-
end
|
125
|
+
identifier = method_names.pop[:identifier] if method_names.last.is_a?(Hash)
|
90
126
|
|
91
127
|
method_names.each do |method_name|
|
92
128
|
unmemoized_method = Memoist.unmemoized_method_for(method_name, identifier)
|
@@ -96,11 +132,14 @@ module Memoist
|
|
96
132
|
include InstanceMethods
|
97
133
|
|
98
134
|
if method_defined?(unmemoized_method)
|
99
|
-
|
135
|
+
warn "Already memoized #{method_name}"
|
136
|
+
return
|
100
137
|
end
|
101
138
|
alias_method unmemoized_method, method_name
|
102
139
|
|
103
|
-
|
140
|
+
mm = MemoizedMethod.new(method_name, memoized_ivar, instance_method(method_name).arity)
|
141
|
+
memoized_methods << mm
|
142
|
+
if mm.arity == 0
|
104
143
|
|
105
144
|
# define a method like this;
|
106
145
|
|
@@ -196,6 +235,4 @@ module Memoist
|
|
196
235
|
# return a chainable method_name symbol if we can
|
197
236
|
method_names.length == 1 ? method_names.first : method_names
|
198
237
|
end
|
199
|
-
|
200
|
-
class AlreadyMemoizedError < RuntimeError; end
|
201
238
|
end
|
data/memoist.gemspec
CHANGED
@@ -1,38 +1,46 @@
|
|
1
1
|
# coding: utf-8
|
2
|
+
|
2
3
|
lib = File.expand_path('../lib', __FILE__)
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
5
|
require 'memoist/version'
|
5
6
|
|
6
7
|
AUTHORS = [
|
7
|
-
[
|
8
|
-
[
|
9
|
-
[
|
10
|
-
[
|
11
|
-
[
|
12
|
-
[
|
13
|
-
[
|
14
|
-
[
|
15
|
-
[
|
16
|
-
[
|
17
|
-
[
|
18
|
-
[
|
19
|
-
]
|
8
|
+
['Joshua Peek', 'josh@joshpeek.com'],
|
9
|
+
['Tarmo Tänav', 'tarmo@itech.ee'],
|
10
|
+
['Jeremy Kemper', 'jeremy@bitsweat.net'],
|
11
|
+
['Eugene Pimenov', 'libc@mac.com'],
|
12
|
+
['Xavier Noria', 'fxn@hashref.com'],
|
13
|
+
['Niels Ganser', 'niels@herimedia.co'],
|
14
|
+
['Carl Lerche & Yehuda Katz', 'wycats@gmail.com'],
|
15
|
+
['jeem', 'jeem@hughesorama.com'],
|
16
|
+
['Jay Pignata', 'john.pignata@gmail.com'],
|
17
|
+
['Damien Mathieu', '42@dmathieu.com'],
|
18
|
+
['José Valim', 'jose.valim@gmail.com'],
|
19
|
+
['Matthew Rudy Jacobs', 'matthewrudyjacobs@gmail.com']
|
20
|
+
].freeze
|
20
21
|
|
21
22
|
Gem::Specification.new do |spec|
|
22
|
-
spec.name =
|
23
|
+
spec.name = 'memoist'
|
23
24
|
spec.version = Memoist::VERSION
|
24
|
-
spec.authors = AUTHORS.map{ |name,
|
25
|
-
spec.email = AUTHORS.map{ |
|
26
|
-
spec.summary =
|
27
|
-
spec.homepage =
|
28
|
-
spec.license =
|
25
|
+
spec.authors = AUTHORS.map { |name, _email| name }
|
26
|
+
spec.email = AUTHORS.map { |_name, email| email }
|
27
|
+
spec.summary = 'memoize methods invocation'
|
28
|
+
spec.homepage = 'https://github.com/matthewrudy/memoist'
|
29
|
+
spec.license = 'MIT'
|
29
30
|
|
30
31
|
spec.files = `git ls-files -z`.split("\x0")
|
31
32
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
32
33
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
33
|
-
spec.require_paths = [
|
34
|
+
spec.require_paths = ['lib']
|
35
|
+
|
36
|
+
spec.required_ruby_version = '>= 1.9.2'
|
34
37
|
|
35
|
-
spec.add_development_dependency
|
36
|
-
spec.add_development_dependency
|
37
|
-
|
38
|
+
spec.add_development_dependency 'benchmark-ips'
|
39
|
+
spec.add_development_dependency 'bundler'
|
40
|
+
if RUBY_VERSION < '1.9.3'
|
41
|
+
spec.add_development_dependency 'rake', '~> 10.4'
|
42
|
+
else
|
43
|
+
spec.add_development_dependency 'rake'
|
44
|
+
end
|
45
|
+
spec.add_development_dependency 'minitest', '~> 5.10'
|
38
46
|
end
|
data/script/benchmark.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
2
|
+
require 'benchmark/ips'
|
3
|
+
|
4
|
+
require 'memoist'
|
5
|
+
|
6
|
+
class Benchy
|
7
|
+
extend Memoist
|
8
|
+
|
9
|
+
def arity_0
|
10
|
+
'Hello World'
|
11
|
+
end
|
12
|
+
memoize :arity_0
|
13
|
+
|
14
|
+
def arity_1(name)
|
15
|
+
"Hello #{name}"
|
16
|
+
end
|
17
|
+
memoize :arity_1
|
18
|
+
end
|
19
|
+
|
20
|
+
OBJECT = Benchy.new
|
21
|
+
|
22
|
+
puts "Benchmarking: #{Memoist::VERSION}"
|
23
|
+
|
24
|
+
Benchmark.ips do |x|
|
25
|
+
x.report('arity 0 - memoized') do |times|
|
26
|
+
times.times do
|
27
|
+
OBJECT.arity_0
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# x.report("arity 0 - unmemoized") do |times|
|
32
|
+
# times.times do
|
33
|
+
# OBJECT._unmemoized_arity_0
|
34
|
+
# end
|
35
|
+
# end
|
36
|
+
|
37
|
+
x.report('arity 1 - memoized') do |times|
|
38
|
+
times.times do
|
39
|
+
OBJECT.arity_1(:World)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# x.report("arity 1 - unmemoized") do |times|
|
44
|
+
# times.times do
|
45
|
+
# OBJECT._unmemoized_arity_1(:World)
|
46
|
+
# end
|
47
|
+
# end
|
48
|
+
end
|
data/test/memoist_test.rb
CHANGED
@@ -1,10 +1,8 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
require 'memoist'
|
3
3
|
|
4
|
-
class MemoistTest < Minitest::
|
5
|
-
|
4
|
+
class MemoistTest < Minitest::Test
|
6
5
|
class CallCounter
|
7
|
-
|
8
6
|
def initialize
|
9
7
|
@calls = {}
|
10
8
|
end
|
@@ -17,7 +15,6 @@ class MemoistTest < Minitest::Unit::TestCase
|
|
17
15
|
def count(method_name)
|
18
16
|
@calls[method_name] ||= 0
|
19
17
|
end
|
20
|
-
|
21
18
|
end
|
22
19
|
|
23
20
|
class Person
|
@@ -49,7 +46,7 @@ class MemoistTest < Minitest::Unit::TestCase
|
|
49
46
|
|
50
47
|
def name
|
51
48
|
@counter.call(:name)
|
52
|
-
|
49
|
+
'Josh'
|
53
50
|
end
|
54
51
|
|
55
52
|
def name?
|
@@ -58,8 +55,8 @@ class MemoistTest < Minitest::Unit::TestCase
|
|
58
55
|
end
|
59
56
|
memoize :name?
|
60
57
|
|
61
|
-
def update(
|
62
|
-
|
58
|
+
def update(_name)
|
59
|
+
'Joshua'
|
63
60
|
end
|
64
61
|
memoize :update
|
65
62
|
|
@@ -70,6 +67,12 @@ class MemoistTest < Minitest::Unit::TestCase
|
|
70
67
|
|
71
68
|
memoize :name, :age
|
72
69
|
|
70
|
+
def age?
|
71
|
+
@counter.call(:age?)
|
72
|
+
true
|
73
|
+
end
|
74
|
+
memoize 'age?'
|
75
|
+
|
73
76
|
def sleep(hours = 8)
|
74
77
|
@counter.call(:sleep)
|
75
78
|
hours
|
@@ -80,7 +83,7 @@ class MemoistTest < Minitest::Unit::TestCase
|
|
80
83
|
@counter.count(:sleep)
|
81
84
|
end
|
82
85
|
|
83
|
-
def update_attributes(
|
86
|
+
def update_attributes(_options = {})
|
84
87
|
@counter.call(:update_attributes)
|
85
88
|
true
|
86
89
|
end
|
@@ -101,7 +104,7 @@ class MemoistTest < Minitest::Unit::TestCase
|
|
101
104
|
|
102
105
|
def is_developer?
|
103
106
|
@counter.call(:is_developer?)
|
104
|
-
|
107
|
+
'Yes'
|
105
108
|
end
|
106
109
|
memoize :is_developer?
|
107
110
|
end
|
@@ -111,7 +114,14 @@ class MemoistTest < Minitest::Unit::TestCase
|
|
111
114
|
@counter.call(:student_name)
|
112
115
|
"Student #{super}"
|
113
116
|
end
|
114
|
-
memoize :name, :
|
117
|
+
memoize :name, identifier: :student
|
118
|
+
end
|
119
|
+
|
120
|
+
class Teacher < Person
|
121
|
+
def seniority
|
122
|
+
'very_senior'
|
123
|
+
end
|
124
|
+
memoize :seniority
|
115
125
|
end
|
116
126
|
|
117
127
|
class Company
|
@@ -122,7 +132,7 @@ class MemoistTest < Minitest::Unit::TestCase
|
|
122
132
|
|
123
133
|
def name
|
124
134
|
@name_calls += 1
|
125
|
-
|
135
|
+
'37signals'
|
126
136
|
end
|
127
137
|
end
|
128
138
|
|
@@ -174,16 +184,68 @@ class MemoistTest < Minitest::Unit::TestCase
|
|
174
184
|
memoize :counter
|
175
185
|
end
|
176
186
|
|
187
|
+
class Book
|
188
|
+
extend Memoist
|
189
|
+
STATUSES = %w[new used].freeze
|
190
|
+
CLASSIFICATION = %w[fiction nonfiction].freeze
|
191
|
+
GENRES = %w[humor romance reference sci-fi classic philosophy].freeze
|
192
|
+
|
193
|
+
attr_reader :title, :author
|
194
|
+
def initialize(title, author)
|
195
|
+
@title = title
|
196
|
+
@author = author
|
197
|
+
end
|
198
|
+
|
199
|
+
def full_title
|
200
|
+
"#{@title} by #{@author}"
|
201
|
+
end
|
202
|
+
memoize :full_title
|
203
|
+
|
204
|
+
class << self
|
205
|
+
extend Memoist
|
206
|
+
|
207
|
+
def all_types
|
208
|
+
STATUSES.product(CLASSIFICATION).product(GENRES).collect(&:flatten)
|
209
|
+
end
|
210
|
+
memoize :all_types
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
class Abb
|
215
|
+
extend Memoist
|
216
|
+
|
217
|
+
def run(*_args)
|
218
|
+
flush_cache if respond_to?(:flush_cache)
|
219
|
+
execute
|
220
|
+
end
|
221
|
+
|
222
|
+
def execute
|
223
|
+
some_method
|
224
|
+
end
|
225
|
+
|
226
|
+
def some_method
|
227
|
+
# Override this
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
class Bbb < Abb
|
232
|
+
def some_method
|
233
|
+
:foo
|
234
|
+
end
|
235
|
+
memoize :some_method
|
236
|
+
end
|
237
|
+
|
177
238
|
def setup
|
178
239
|
@person = Person.new
|
179
240
|
@calculator = Calculator.new
|
241
|
+
@book = Book.new('My Life', "Brian 'Fudge' Turmuck")
|
180
242
|
end
|
181
243
|
|
182
244
|
def test_memoization
|
183
|
-
assert_equal
|
245
|
+
assert_equal 'Josh', @person.name
|
184
246
|
assert_equal 1, @person.name_calls
|
185
247
|
|
186
|
-
3.times { assert_equal
|
248
|
+
3.times { assert_equal 'Josh', @person.name }
|
187
249
|
assert_equal 1, @person.name_calls
|
188
250
|
end
|
189
251
|
|
@@ -199,13 +261,13 @@ class MemoistTest < Minitest::Unit::TestCase
|
|
199
261
|
end
|
200
262
|
|
201
263
|
def test_memoize_with_options_hash
|
202
|
-
assert_equal true, @person.update_attributes(:
|
264
|
+
assert_equal true, @person.update_attributes(age: 21, name: 'James')
|
203
265
|
assert_equal 1, @person.update_attributes_calls
|
204
266
|
|
205
|
-
3.times { assert_equal true, @person.update_attributes(:
|
267
|
+
3.times { assert_equal true, @person.update_attributes(age: 21, name: 'James') }
|
206
268
|
assert_equal 1, @person.update_attributes_calls
|
207
269
|
|
208
|
-
3.times { assert_equal true, @person.update_attributes({:
|
270
|
+
3.times { assert_equal true, @person.update_attributes({ age: 21, name: 'James' }, :reload) }
|
209
271
|
assert_equal 4, @person.update_attributes_calls
|
210
272
|
end
|
211
273
|
|
@@ -216,6 +278,13 @@ class MemoistTest < Minitest::Unit::TestCase
|
|
216
278
|
@person.unmemoize_all
|
217
279
|
end
|
218
280
|
|
281
|
+
def test_memoization_when_memoize_is_called_with_punctuated_string
|
282
|
+
assert_equal true, @person.age?
|
283
|
+
|
284
|
+
@person.memoize_all
|
285
|
+
@person.unmemoize_all
|
286
|
+
end
|
287
|
+
|
219
288
|
def test_memoization_flush_with_punctuation
|
220
289
|
assert_equal true, @person.name?
|
221
290
|
@person.flush_cache(:name?)
|
@@ -224,10 +293,10 @@ class MemoistTest < Minitest::Unit::TestCase
|
|
224
293
|
end
|
225
294
|
|
226
295
|
def test_memoization_with_nil_value
|
227
|
-
|
296
|
+
assert_nil @person.age
|
228
297
|
assert_equal 1, @person.age_calls
|
229
298
|
|
230
|
-
3.times {
|
299
|
+
3.times { assert_nil @person.age }
|
231
300
|
assert_equal 1, @person.age_calls
|
232
301
|
end
|
233
302
|
|
@@ -244,26 +313,116 @@ class MemoistTest < Minitest::Unit::TestCase
|
|
244
313
|
|
245
314
|
assert @calculator.instance_variable_get(:@_memoized_counter)
|
246
315
|
@calculator.flush_cache(:counter)
|
247
|
-
|
248
|
-
assert !@calculator.instance_variable_defined?(:@_memoized_counter)
|
316
|
+
assert_equal false, @calculator.instance_variable_defined?(:@_memoized_counter)
|
249
317
|
|
250
318
|
assert_equal 2, @calculator.counter
|
251
319
|
end
|
252
320
|
|
321
|
+
def test_class_flush_cache
|
322
|
+
@book.memoize_all
|
323
|
+
assert_equal "My Life by Brian 'Fudge' Turmuck", @book.full_title
|
324
|
+
|
325
|
+
Book.memoize_all
|
326
|
+
assert_instance_of Array, Book.instance_variable_get(:@_memoized_all_types)
|
327
|
+
Book.flush_cache
|
328
|
+
assert_equal false, Book.instance_variable_defined?(:@_memoized_all_types)
|
329
|
+
end
|
330
|
+
|
331
|
+
def test_class_flush_cache_preserves_instances
|
332
|
+
@book.memoize_all
|
333
|
+
Book.memoize_all
|
334
|
+
assert_equal "My Life by Brian 'Fudge' Turmuck", @book.full_title
|
335
|
+
|
336
|
+
Book.flush_cache
|
337
|
+
assert_equal false, Book.instance_variable_defined?(:@_memoized_all_types)
|
338
|
+
assert_equal "My Life by Brian 'Fudge' Turmuck", @book.full_title
|
339
|
+
end
|
340
|
+
|
341
|
+
def test_flush_cache_in_child_class
|
342
|
+
x = Bbb.new
|
343
|
+
|
344
|
+
# This should not throw error
|
345
|
+
x.run
|
346
|
+
end
|
347
|
+
|
253
348
|
def test_unmemoize_all
|
254
349
|
assert_equal 1, @calculator.counter
|
255
350
|
|
351
|
+
assert_equal true, @calculator.instance_variable_defined?(:@_memoized_counter)
|
256
352
|
assert @calculator.instance_variable_get(:@_memoized_counter)
|
257
353
|
@calculator.unmemoize_all
|
258
|
-
|
259
|
-
assert !@calculator.instance_variable_defined?(:@_memoized_counter)
|
354
|
+
assert_equal false, @calculator.instance_variable_defined?(:@_memoized_counter)
|
260
355
|
|
261
356
|
assert_equal 2, @calculator.counter
|
262
357
|
end
|
263
358
|
|
359
|
+
def test_all_memoized_structs
|
360
|
+
# Person memoize :age, :age?, :is_developer?, :memoize_protected_test, :name, :name?, :sleep, :update, :update_attributes
|
361
|
+
# Student < Person memoize :name, :identifier => :student
|
362
|
+
# Teacher < Person memoize :seniority
|
363
|
+
|
364
|
+
expected = %w[age age? is_developer? memoize_protected_test name name? sleep update update_attributes]
|
365
|
+
structs = Person.all_memoized_structs
|
366
|
+
assert_equal expected, structs.collect(&:memoized_method).collect(&:to_s).sort
|
367
|
+
assert_equal '@_memoized_name', structs.detect { |s| s.memoized_method == :name }.ivar
|
368
|
+
|
369
|
+
# Same expected methods
|
370
|
+
structs = Student.all_memoized_structs
|
371
|
+
assert_equal expected, structs.collect(&:memoized_method).collect(&:to_s).sort
|
372
|
+
assert_equal '@_memoized_student_name', structs.detect { |s| s.memoized_method == :name }.ivar
|
373
|
+
|
374
|
+
expected = (expected << 'seniority').sort
|
375
|
+
structs = Teacher.all_memoized_structs
|
376
|
+
assert_equal expected, structs.collect(&:memoized_method).collect(&:to_s).sort
|
377
|
+
assert_equal '@_memoized_name', structs.detect { |s| s.memoized_method == :name }.ivar
|
378
|
+
end
|
379
|
+
|
380
|
+
def test_unmemoize_all_subclasses
|
381
|
+
# Person memoize :age, :is_developer?, :memoize_protected_test, :name, :name?, :sleep, :update, :update_attributes
|
382
|
+
# Student < Person memoize :name, :identifier => :student
|
383
|
+
# Teacher < Person memoize :seniority
|
384
|
+
|
385
|
+
teacher = Teacher.new
|
386
|
+
assert_equal 'Josh', teacher.name
|
387
|
+
assert_equal 'Josh', teacher.instance_variable_get(:@_memoized_name)
|
388
|
+
assert_equal 'very_senior', teacher.seniority
|
389
|
+
assert_equal 'very_senior', teacher.instance_variable_get(:@_memoized_seniority)
|
390
|
+
|
391
|
+
teacher.unmemoize_all
|
392
|
+
assert_equal false, teacher.instance_variable_defined?(:@_memoized_name)
|
393
|
+
assert_equal false, teacher.instance_variable_defined?(:@_memoized_seniority)
|
394
|
+
|
395
|
+
student = Student.new
|
396
|
+
assert_equal 'Student Josh', student.name
|
397
|
+
assert_equal 'Student Josh', student.instance_variable_get(:@_memoized_student_name)
|
398
|
+
assert_equal false, student.instance_variable_defined?(:@_memoized_seniority)
|
399
|
+
|
400
|
+
student.unmemoize_all
|
401
|
+
assert_equal false, @calculator.instance_variable_defined?(:@_memoized_student_name)
|
402
|
+
end
|
403
|
+
|
264
404
|
def test_memoize_all
|
265
405
|
@calculator.memoize_all
|
266
|
-
|
406
|
+
assert_equal true, @calculator.instance_variable_defined?(:@_memoized_counter)
|
407
|
+
end
|
408
|
+
|
409
|
+
def test_memoize_all_subclasses
|
410
|
+
# Person memoize :age, :is_developer?, :memoize_protected_test, :name, :name?, :sleep, :update, :update_attributes
|
411
|
+
# Student < Person memoize :name, :identifier => :student
|
412
|
+
# Teacher < Person memoize :seniority
|
413
|
+
|
414
|
+
teacher = Teacher.new
|
415
|
+
teacher.memoize_all
|
416
|
+
|
417
|
+
assert_equal 'very_senior', teacher.instance_variable_get(:@_memoized_seniority)
|
418
|
+
assert_equal 'Josh', teacher.instance_variable_get(:@_memoized_name)
|
419
|
+
|
420
|
+
student = Student.new
|
421
|
+
student.memoize_all
|
422
|
+
|
423
|
+
assert_equal 'Student Josh', student.instance_variable_get(:@_memoized_student_name)
|
424
|
+
assert_equal 'Student Josh', student.name
|
425
|
+
assert_equal false, student.instance_variable_defined?(:@_memoized_seniority)
|
267
426
|
end
|
268
427
|
|
269
428
|
def test_memoization_cache_is_different_for_each_instance
|
@@ -272,10 +431,20 @@ class MemoistTest < Minitest::Unit::TestCase
|
|
272
431
|
assert_equal 1, Calculator.new.counter
|
273
432
|
end
|
274
433
|
|
434
|
+
def test_memoization_class_variables
|
435
|
+
@book.memoize_all
|
436
|
+
assert_equal "My Life by Brian 'Fudge' Turmuck", @book.instance_variable_get(:@_memoized_full_title)
|
437
|
+
assert_equal "My Life by Brian 'Fudge' Turmuck", @book.full_title
|
438
|
+
|
439
|
+
Book.memoize_all
|
440
|
+
assert_instance_of Array, Book.instance_variable_get(:@_memoized_all_types)
|
441
|
+
assert_equal 24, Book.all_types.count
|
442
|
+
end
|
443
|
+
|
275
444
|
def test_memoized_is_not_affected_by_freeze
|
276
445
|
@person.freeze
|
277
|
-
assert_equal
|
278
|
-
assert_equal
|
446
|
+
assert_equal 'Josh', @person.name
|
447
|
+
assert_equal 'Joshua', @person.update('Joshua')
|
279
448
|
end
|
280
449
|
|
281
450
|
def test_memoization_with_args
|
@@ -302,9 +471,9 @@ class MemoistTest < Minitest::Unit::TestCase
|
|
302
471
|
company.extend Memoist
|
303
472
|
company.memoize :name
|
304
473
|
|
305
|
-
assert_equal
|
474
|
+
assert_equal '37signals', company.name
|
306
475
|
assert_equal 1, company.name_calls
|
307
|
-
assert_equal
|
476
|
+
assert_equal '37signals', company.name
|
308
477
|
assert_equal 1, company.name_calls
|
309
478
|
end
|
310
479
|
end
|
@@ -330,20 +499,30 @@ class MemoistTest < Minitest::Unit::TestCase
|
|
330
499
|
assert_equal 2, company.sales_tax_calls
|
331
500
|
end
|
332
501
|
|
333
|
-
def test_double_memoization
|
334
|
-
assert_raises(Memoist::AlreadyMemoizedError) { Person.memoize :name }
|
335
|
-
person = Person.new
|
336
|
-
person.extend Memoist
|
337
|
-
assert_raises(Memoist::AlreadyMemoizedError) { person.memoize :name }
|
338
|
-
|
339
|
-
company = Company.new
|
340
|
-
company.extend Memoist
|
341
|
-
company.memoize :name
|
342
|
-
assert_raises(Memoist::AlreadyMemoizedError) { company.memoize :name }
|
343
|
-
end
|
344
|
-
|
345
502
|
def test_double_memoization_with_identifier
|
346
|
-
Person
|
503
|
+
# Person memoize :age, :is_developer?, :memoize_protected_test, :name, :name?, :sleep, :update, :update_attributes
|
504
|
+
# Student < Person memoize :name, :identifier => :student
|
505
|
+
# Teacher < Person memoize :seniority
|
506
|
+
|
507
|
+
Person.memoize :name, identifier: :again
|
508
|
+
p = Person.new
|
509
|
+
assert_equal 'Josh', p.name
|
510
|
+
assert p.instance_variable_get(:@_memoized_again_name)
|
511
|
+
|
512
|
+
# HACK: tl;dr: Don't memoize classes in test that are used elsewhere.
|
513
|
+
# Calling Person.memoize :name, :identifier => :again pollutes Person
|
514
|
+
# and descendents since we cache the memoized method structures.
|
515
|
+
# This populates those structs, verifies Person is polluted, resets the
|
516
|
+
# structs, cleans up cached memoized_methods
|
517
|
+
Student.all_memoized_structs
|
518
|
+
Person.all_memoized_structs
|
519
|
+
Teacher.all_memoized_structs
|
520
|
+
assert Person.memoized_methods.any? { |m| m.ivar == '@_memoized_again_name' }
|
521
|
+
|
522
|
+
[Student, Teacher, Person].each(&:clear_structs)
|
523
|
+
assert Person.memoized_methods.reject! { |m| m.ivar == '@_memoized_again_name' }
|
524
|
+
assert_nil Student.memoized_methods.reject! { |m| m.ivar == '@_memoized_again_name' }
|
525
|
+
assert_nil Teacher.memoized_methods.reject! { |m| m.ivar == '@_memoized_again_name' }
|
347
526
|
end
|
348
527
|
|
349
528
|
def test_memoization_with_a_subclass
|
@@ -356,7 +535,9 @@ class MemoistTest < Minitest::Unit::TestCase
|
|
356
535
|
|
357
536
|
def test_memoization_is_chainable
|
358
537
|
klass = Class.new do
|
359
|
-
def foo
|
538
|
+
def foo
|
539
|
+
'bar'
|
540
|
+
end
|
360
541
|
end
|
361
542
|
klass.extend Memoist
|
362
543
|
chainable = klass.memoize :foo
|
@@ -367,17 +548,16 @@ class MemoistTest < Minitest::Unit::TestCase
|
|
367
548
|
person = Person.new
|
368
549
|
|
369
550
|
assert_raises(NoMethodError) { person.memoize_protected_test }
|
370
|
-
assert_equal
|
551
|
+
assert_equal 'protected', person.send(:memoize_protected_test)
|
371
552
|
end
|
372
553
|
|
373
554
|
def test_private_method_memoization
|
374
555
|
person = Person.new
|
375
556
|
|
376
557
|
assert_raises(NoMethodError) { person.is_developer? }
|
377
|
-
assert_equal
|
558
|
+
assert_equal 'Yes', person.send(:is_developer?)
|
378
559
|
assert_equal 1, person.is_developer_calls
|
379
|
-
assert_equal
|
560
|
+
assert_equal 'Yes', person.send(:is_developer?)
|
380
561
|
assert_equal 1, person.is_developer_calls
|
381
562
|
end
|
382
|
-
|
383
563
|
end
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: memoist
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.16.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joshua Peek
|
@@ -19,22 +19,36 @@ authors:
|
|
19
19
|
autorequire:
|
20
20
|
bindir: bin
|
21
21
|
cert_chain: []
|
22
|
-
date:
|
22
|
+
date: 2019-12-04 00:00:00.000000000 Z
|
23
23
|
dependencies:
|
24
|
+
- !ruby/object:Gem::Dependency
|
25
|
+
name: benchmark-ips
|
26
|
+
requirement: !ruby/object:Gem::Requirement
|
27
|
+
requirements:
|
28
|
+
- - ">="
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '0'
|
31
|
+
type: :development
|
32
|
+
prerelease: false
|
33
|
+
version_requirements: !ruby/object:Gem::Requirement
|
34
|
+
requirements:
|
35
|
+
- - ">="
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
24
38
|
- !ruby/object:Gem::Dependency
|
25
39
|
name: bundler
|
26
40
|
requirement: !ruby/object:Gem::Requirement
|
27
41
|
requirements:
|
28
|
-
- - "
|
42
|
+
- - ">="
|
29
43
|
- !ruby/object:Gem::Version
|
30
|
-
version: '
|
44
|
+
version: '0'
|
31
45
|
type: :development
|
32
46
|
prerelease: false
|
33
47
|
version_requirements: !ruby/object:Gem::Requirement
|
34
48
|
requirements:
|
35
|
-
- - "
|
49
|
+
- - ">="
|
36
50
|
- !ruby/object:Gem::Version
|
37
|
-
version: '
|
51
|
+
version: '0'
|
38
52
|
- !ruby/object:Gem::Dependency
|
39
53
|
name: rake
|
40
54
|
requirement: !ruby/object:Gem::Requirement
|
@@ -55,14 +69,14 @@ dependencies:
|
|
55
69
|
requirements:
|
56
70
|
- - "~>"
|
57
71
|
- !ruby/object:Gem::Version
|
58
|
-
version: '
|
72
|
+
version: '5.10'
|
59
73
|
type: :development
|
60
74
|
prerelease: false
|
61
75
|
version_requirements: !ruby/object:Gem::Requirement
|
62
76
|
requirements:
|
63
77
|
- - "~>"
|
64
78
|
- !ruby/object:Gem::Version
|
65
|
-
version: '
|
79
|
+
version: '5.10'
|
66
80
|
description:
|
67
81
|
email:
|
68
82
|
- josh@joshpeek.com
|
@@ -83,14 +97,15 @@ extra_rdoc_files: []
|
|
83
97
|
files:
|
84
98
|
- ".gitignore"
|
85
99
|
- ".travis.yml"
|
100
|
+
- CHANGELOG.md
|
86
101
|
- Gemfile
|
87
102
|
- LICENSE.md
|
88
103
|
- README.md
|
89
104
|
- Rakefile
|
90
105
|
- lib/memoist.rb
|
91
|
-
- lib/memoist/core_ext/singleton_class.rb
|
92
106
|
- lib/memoist/version.rb
|
93
107
|
- memoist.gemspec
|
108
|
+
- script/benchmark.rb
|
94
109
|
- test/memoist_test.rb
|
95
110
|
- test/test_helper.rb
|
96
111
|
homepage: https://github.com/matthewrudy/memoist
|
@@ -105,15 +120,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
105
120
|
requirements:
|
106
121
|
- - ">="
|
107
122
|
- !ruby/object:Gem::Version
|
108
|
-
version:
|
123
|
+
version: 1.9.2
|
109
124
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
125
|
requirements:
|
111
126
|
- - ">="
|
112
127
|
- !ruby/object:Gem::Version
|
113
128
|
version: '0'
|
114
129
|
requirements: []
|
115
|
-
|
116
|
-
rubygems_version: 2.2.2
|
130
|
+
rubygems_version: 3.0.4
|
117
131
|
signing_key:
|
118
132
|
specification_version: 4
|
119
133
|
summary: memoize methods invocation
|