memoist3 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.
- checksums.yaml +7 -0
- data/.github/workflows/ci.yml +46 -0
- data/.gitignore +18 -0
- data/CHANGELOG.md +136 -0
- data/Gemfile +4 -0
- data/LICENSE.md +20 -0
- data/README.md +172 -0
- data/Rakefile +12 -0
- data/lib/memoist/version.rb +5 -0
- data/lib/memoist.rb +238 -0
- data/memoist.gemspec +41 -0
- data/script/benchmark.rb +48 -0
- data/test/memoist_test.rb +590 -0
- data/test/test_helper.rb +3 -0
- metadata +138 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: a5a3431c7281f1d17a7c65861c9fb58e224b834c388774ad9a2f8e60e007b692
|
4
|
+
data.tar.gz: 96d5b1ba4fae250ad6b01f502041c9815e03868da2bc49cce47eb18c7ba821ea
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 65c4bf3637903fb83ea41f8b0a0a2a961d4ef5e733789f6cf5bdb2df65487fb515ae2deab75de6cdf70ab8ed5c743d6d4805d6f8cb2a79c0ce9ba88885689d98
|
7
|
+
data.tar.gz: 7df1a03a1951477837bbe5990c10e71045766f67ade3930b498ea4c6ae7fe9fc0599fff04badeb64f3008a0aa74f9fc61c6c743f614774328ab6dee2743376e3
|
@@ -0,0 +1,46 @@
|
|
1
|
+
name: ci
|
2
|
+
|
3
|
+
on: [push, pull_request]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
build:
|
7
|
+
runs-on: ubuntu-latest
|
8
|
+
strategy:
|
9
|
+
fail-fast: false
|
10
|
+
matrix:
|
11
|
+
include:
|
12
|
+
- ruby: 2.7.2
|
13
|
+
- ruby: 2.7.5
|
14
|
+
- ruby: 3.0.1
|
15
|
+
- ruby: 3.0.3
|
16
|
+
- ruby: ruby-head
|
17
|
+
steps:
|
18
|
+
- uses: actions/checkout@v2
|
19
|
+
- name: Install rvm
|
20
|
+
run: |
|
21
|
+
curl -sSL https://get.rvm.io | bash
|
22
|
+
- name: Install ruby
|
23
|
+
run: |
|
24
|
+
source $HOME/.rvm/scripts/rvm
|
25
|
+
rvm use ${{ matrix.ruby }} --default --install --binary --fuzzy --create
|
26
|
+
- name: Check ruby version
|
27
|
+
run: |
|
28
|
+
source $HOME/.rvm/scripts/rvm
|
29
|
+
ruby --version
|
30
|
+
- name: Update rubygems
|
31
|
+
run: |
|
32
|
+
source $HOME/.rvm/scripts/rvm
|
33
|
+
gem update --system ${{ matrix.rubygems }}
|
34
|
+
- name: Install bundler
|
35
|
+
run: |
|
36
|
+
source $HOME/.rvm/scripts/rvm
|
37
|
+
gem install bundler --no-document -v '~> 1.13'
|
38
|
+
- name: Install gems
|
39
|
+
run: |
|
40
|
+
source $HOME/.rvm/scripts/rvm
|
41
|
+
bundle install --jobs 4
|
42
|
+
- run: unset JRUBY_OPTS
|
43
|
+
- name: Run rake
|
44
|
+
run: |
|
45
|
+
source $HOME/.rvm/scripts/rvm
|
46
|
+
bundle exec rake
|
data/.gitignore
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
## [v1.0.0](https://github.com/honzasterba/memoist/tree/v0.16.2) (2022-01-09)
|
4
|
+
|
5
|
+
[Full Changelog](https://github.com/matthewrudy/honzasterba/compare/v0.16.1...v1.0.0)
|
6
|
+
|
7
|
+
- support for Ruby 3 kwargs
|
8
|
+
|
9
|
+
## [v0.16.2](https://github.com/matthewrudy/memoist/tree/v0.16.2) (2019-12-04)
|
10
|
+
|
11
|
+
[Full Changelog](https://github.com/matthewrudy/memoist/compare/v0.16.1...v0.16.2)
|
12
|
+
|
13
|
+
**Merged pull requests:**
|
14
|
+
|
15
|
+
- Fix regression introduced by frozen symbol fix [\#86](https://github.com/matthewrudy/memoist/pull/86) ([sebjacobs](https://github.com/sebjacobs))
|
16
|
+
|
17
|
+
## [v0.16.1](https://github.com/matthewrudy/memoist/tree/v0.16.1) (2019-11-08)
|
18
|
+
|
19
|
+
[Full Changelog](https://github.com/matthewrudy/memoist/compare/v0.16.0...v0.16.1)
|
20
|
+
|
21
|
+
**Merged pull requests:**
|
22
|
+
|
23
|
+
- Remove ruby 1.9.2 from travis build matrix [\#84](https://github.com/matthewrudy/memoist/pull/84) ([unasuke](https://github.com/unasuke))
|
24
|
+
- Make Memoist.escape\_punctuation compatible with MRI 2.7 [\#82](https://github.com/matthewrudy/memoist/pull/82) ([casperisfine](https://github.com/casperisfine))
|
25
|
+
- add 2.5.1 to travis [\#77](https://github.com/matthewrudy/memoist/pull/77) ([matthewrudy](https://github.com/matthewrudy))
|
26
|
+
- Remove ghit.me [\#74](https://github.com/matthewrudy/memoist/pull/74) ([matthewrudy](https://github.com/matthewrudy))
|
27
|
+
- Place sample code for execution in README.md [\#73](https://github.com/matthewrudy/memoist/pull/73) ([3nan3](https://github.com/3nan3))
|
28
|
+
- Require Ruby \>=1.9.2 [\#69](https://github.com/matthewrudy/memoist/pull/69) ([matthewrudy](https://github.com/matthewrudy))
|
29
|
+
|
30
|
+
## [v0.16.0](https://github.com/matthewrudy/memoist/tree/v0.16.0) (2017-06-20)
|
31
|
+
|
32
|
+
[Full Changelog](https://github.com/matthewrudy/memoist/compare/v0.15.0...v0.16.0)
|
33
|
+
|
34
|
+
**Merged pull requests:**
|
35
|
+
|
36
|
+
- 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))
|
37
|
+
- Add support for class-level cache flushing. [\#67](https://github.com/matthewrudy/memoist/pull/67) ([JoeMcB](https://github.com/JoeMcB))
|
38
|
+
- 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))
|
39
|
+
- Fix tests for Ruby \< 1.9.3 [\#56](https://github.com/matthewrudy/memoist/pull/56) ([matthewrudy](https://github.com/matthewrudy))
|
40
|
+
- Add return in comments for `flush\_cache`. [\#55](https://github.com/matthewrudy/memoist/pull/55) ([joshuapinter](https://github.com/joshuapinter))
|
41
|
+
- Update readme [\#53](https://github.com/matthewrudy/memoist/pull/53) ([biow0lf](https://github.com/biow0lf))
|
42
|
+
|
43
|
+
## [v0.15.0](https://github.com/matthewrudy/memoist/tree/v0.15.0) (2016-08-23)
|
44
|
+
|
45
|
+
[Full Changelog](https://github.com/matthewrudy/memoist/compare/v0.14.0...v0.15.0)
|
46
|
+
|
47
|
+
**Merged pull requests:**
|
48
|
+
|
49
|
+
- Remove test warnings [\#52](https://github.com/matthewrudy/memoist/pull/52) ([matthewrudy](https://github.com/matthewrudy))
|
50
|
+
- Use SVG badge over PNG [\#44](https://github.com/matthewrudy/memoist/pull/44) ([olivierlacan](https://github.com/olivierlacan))
|
51
|
+
|
52
|
+
## [v0.14.0](https://github.com/matthewrudy/memoist/tree/v0.14.0) (2015-12-15)
|
53
|
+
|
54
|
+
[Full Changelog](https://github.com/matthewrudy/memoist/compare/v0.13.0...v0.14.0)
|
55
|
+
|
56
|
+
**Merged pull requests:**
|
57
|
+
|
58
|
+
- 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))
|
59
|
+
|
60
|
+
## [v0.13.0](https://github.com/matthewrudy/memoist/tree/v0.13.0) (2015-11-26)
|
61
|
+
|
62
|
+
[Full Changelog](https://github.com/matthewrudy/memoist/compare/v0.12.0...v0.13.0)
|
63
|
+
|
64
|
+
**Merged pull requests:**
|
65
|
+
|
66
|
+
- Faster memoist with less object allocations [\#36](https://github.com/matthewrudy/memoist/pull/36) ([jrafanie](https://github.com/jrafanie))
|
67
|
+
- Be optimistic about bundler version [\#35](https://github.com/matthewrudy/memoist/pull/35) ([lotyrin](https://github.com/lotyrin))
|
68
|
+
- Add syntax highlighting for code blocks. [\#34](https://github.com/matthewrudy/memoist/pull/34) ([joshuapinter](https://github.com/joshuapinter))
|
69
|
+
|
70
|
+
## [v0.12.0](https://github.com/matthewrudy/memoist/tree/v0.12.0) (2015-04-13)
|
71
|
+
|
72
|
+
[Full Changelog](https://github.com/matthewrudy/memoist/compare/v0.11.0...v0.12.0)
|
73
|
+
|
74
|
+
**Merged pull requests:**
|
75
|
+
|
76
|
+
- Fix forking link [\#30](https://github.com/matthewrudy/memoist/pull/30) ([brandondrew](https://github.com/brandondrew))
|
77
|
+
- Update README with :identifier info [\#29](https://github.com/matthewrudy/memoist/pull/29) ([fervic](https://github.com/fervic))
|
78
|
+
|
79
|
+
## [v0.11.0](https://github.com/matthewrudy/memoist/tree/v0.11.0) (2014-10-10)
|
80
|
+
|
81
|
+
[Full Changelog](https://github.com/matthewrudy/memoist/compare/v0.10.0...v0.11.0)
|
82
|
+
|
83
|
+
**Merged pull requests:**
|
84
|
+
|
85
|
+
- Call abs on arity when extracting reload [\#27](https://github.com/matthewrudy/memoist/pull/27) ([bradylove](https://github.com/bradylove))
|
86
|
+
|
87
|
+
## [v0.10.0](https://github.com/matthewrudy/memoist/tree/v0.10.0) (2014-08-13)
|
88
|
+
|
89
|
+
[Full Changelog](https://github.com/matthewrudy/memoist/compare/v0.9.3...v0.10.0)
|
90
|
+
|
91
|
+
**Merged pull requests:**
|
92
|
+
|
93
|
+
- Make memoize return a :symbol [\#24](https://github.com/matthewrudy/memoist/pull/24) ([matthewrudy](https://github.com/matthewrudy))
|
94
|
+
- Use Minitest [\#19](https://github.com/matthewrudy/memoist/pull/19) ([matthewrudy](https://github.com/matthewrudy))
|
95
|
+
|
96
|
+
## [v0.9.3](https://github.com/matthewrudy/memoist/tree/v0.9.3) (2014-06-01)
|
97
|
+
|
98
|
+
[Full Changelog](https://github.com/matthewrudy/memoist/compare/v0.9.2...v0.9.3)
|
99
|
+
|
100
|
+
**Merged pull requests:**
|
101
|
+
|
102
|
+
- Remove Array caching hack [\#17](https://github.com/matthewrudy/memoist/pull/17) ([matthewrudy](https://github.com/matthewrudy))
|
103
|
+
|
104
|
+
## [v0.9.2](https://github.com/matthewrudy/memoist/tree/v0.9.2) (2014-04-16)
|
105
|
+
|
106
|
+
[Full Changelog](https://github.com/matthewrudy/memoist/compare/0.9.0...v0.9.2)
|
107
|
+
|
108
|
+
**Merged pull requests:**
|
109
|
+
|
110
|
+
- Give double-memoize errors their own error class [\#15](https://github.com/matthewrudy/memoist/pull/15) ([zachhale](https://github.com/zachhale))
|
111
|
+
- Add tax-themed example for class method memoization fixes \#9 [\#10](https://github.com/matthewrudy/memoist/pull/10) ([fny](https://github.com/fny))
|
112
|
+
|
113
|
+
## [0.9.0](https://github.com/matthewrudy/memoist/tree/0.9.0) (2013-03-20)
|
114
|
+
|
115
|
+
[Full Changelog](https://github.com/matthewrudy/memoist/compare/0.2.0...0.9.0)
|
116
|
+
|
117
|
+
**Merged pull requests:**
|
118
|
+
|
119
|
+
- Update README.md to include memoization bypass description [\#6](https://github.com/matthewrudy/memoist/pull/6) ([andreychernih](https://github.com/andreychernih))
|
120
|
+
- Adds a note about the MIT License [\#4](https://github.com/matthewrudy/memoist/pull/4) ([matiaskorhonen](https://github.com/matiaskorhonen))
|
121
|
+
|
122
|
+
## [0.2.0](https://github.com/matthewrudy/memoist/tree/0.2.0) (2012-08-15)
|
123
|
+
|
124
|
+
[Full Changelog](https://github.com/matthewrudy/memoist/compare/0.1.0...0.2.0)
|
125
|
+
|
126
|
+
**Merged pull requests:**
|
127
|
+
|
128
|
+
- 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))
|
129
|
+
|
130
|
+
## [0.1.0](https://github.com/matthewrudy/memoist/tree/0.1.0) (2012-01-24)
|
131
|
+
|
132
|
+
[Full Changelog](https://github.com/matthewrudy/memoist/compare/7a5352d6b6c4219f37f329d2422985961c749748...0.1.0)
|
133
|
+
|
134
|
+
|
135
|
+
|
136
|
+
\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*
|
data/Gemfile
ADDED
data/LICENSE.md
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012-2013 Matthew Rudy Jacobs
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,172 @@
|
|
1
|
+
This is a fork of the original repo by [matthewrudy](https://github.com/matthewrudy/memoist)
|
2
|
+
adapted for usage with Ruby 3.
|
3
|
+
|
4
|
+
# Memoist
|
5
|
+
|
6
|
+
[](https://badge.fury.io/rb/memoist3)
|
7
|
+
[](https://github.com/honzasterba/memoist/actions)
|
8
|
+
|
9
|
+
Memoist is an extraction of ActiveSupport::Memoizable.
|
10
|
+
|
11
|
+
Since June 2011 ActiveSupport::Memoizable has been deprecated.
|
12
|
+
But I love it, and so I plan to keep it alive.
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
```bash
|
17
|
+
bundle add memoist3
|
18
|
+
```
|
19
|
+
|
20
|
+
or
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
gem 'memoist3'
|
24
|
+
```
|
25
|
+
|
26
|
+
## Supported Rubies
|
27
|
+
|
28
|
+
This library supports
|
29
|
+
|
30
|
+
- MRI Ruby 2 (>= 2.7.2)
|
31
|
+
- MRI Ruby 3 (>= 3.0.0)
|
32
|
+
|
33
|
+
## Usage
|
34
|
+
|
35
|
+
Just extend with the Memoist module
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
require 'memoist'
|
39
|
+
class Person
|
40
|
+
extend Memoist
|
41
|
+
|
42
|
+
def social_security
|
43
|
+
puts "execute!"
|
44
|
+
decrypt_social_security
|
45
|
+
end
|
46
|
+
memoize :social_security
|
47
|
+
end
|
48
|
+
|
49
|
+
person = Person.new
|
50
|
+
|
51
|
+
person.social_security
|
52
|
+
# execute!
|
53
|
+
# => (returns decrypt_social_security)
|
54
|
+
|
55
|
+
person.social_security
|
56
|
+
# => (returns the memoized value)
|
57
|
+
```
|
58
|
+
|
59
|
+
And person.social_security will only be calculated once.
|
60
|
+
|
61
|
+
Every memoized function (which initially was not accepting any arguments) has a `(reload)`
|
62
|
+
argument you can pass in to bypass and reset the memoization:
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
def some_method
|
66
|
+
Time.now
|
67
|
+
end
|
68
|
+
memoize :some_method
|
69
|
+
```
|
70
|
+
|
71
|
+
Calling `some_method` will be memoized, but calling `some_method(true)` will rememoize each time.
|
72
|
+
|
73
|
+
You can even memoize method that takes arguments.
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
class Person
|
77
|
+
def taxes_due(income)
|
78
|
+
income * 0.40
|
79
|
+
end
|
80
|
+
memoize :taxes_due
|
81
|
+
end
|
82
|
+
```
|
83
|
+
|
84
|
+
This will only be calculated once per value of income.
|
85
|
+
|
86
|
+
You can also memoize class methods.
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
class Person
|
90
|
+
|
91
|
+
class << self
|
92
|
+
extend Memoist
|
93
|
+
def with_overdue_taxes
|
94
|
+
# ...
|
95
|
+
end
|
96
|
+
memoize :with_overdue_taxes
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
```
|
101
|
+
|
102
|
+
When a sub-class overrides one of its parent's methods and you need to memoize both.
|
103
|
+
Then you can use the `:identifier` parameter in order to help _Memoist_ distinguish between the two.
|
104
|
+
|
105
|
+
```ruby
|
106
|
+
class Clock
|
107
|
+
extend Memoist
|
108
|
+
def now
|
109
|
+
"The time now is #{Time.now.hour} o'clock and #{Time.now.min} minutes"
|
110
|
+
end
|
111
|
+
memoize :now
|
112
|
+
end
|
113
|
+
|
114
|
+
class AccurateClock < Clock
|
115
|
+
extend Memoist
|
116
|
+
def now
|
117
|
+
"#{super} and #{Time.now.sec} seconds"
|
118
|
+
end
|
119
|
+
memoize :now, :identifier => :accurate_clock
|
120
|
+
end
|
121
|
+
```
|
122
|
+
|
123
|
+
## Reload
|
124
|
+
|
125
|
+
Each memoized function comes with a way to flush the existing value.
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
person.social_security # returns the memoized value
|
129
|
+
person.social_security(true) # bypasses the memoized value and rememoizes it
|
130
|
+
```
|
131
|
+
|
132
|
+
This also works with a memoized method with arguments
|
133
|
+
|
134
|
+
```ruby
|
135
|
+
person.taxes_due(100_000) # returns the memoized value
|
136
|
+
person.taxes_due(100_000, true) # bypasses the memoized value and rememoizes it
|
137
|
+
```
|
138
|
+
|
139
|
+
If you want to flush the entire memoization cache for an object
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
person.flush_cache # returns an array of flushed memoized methods, e.g. ["social_security", "some_method"]
|
143
|
+
```
|
144
|
+
|
145
|
+
# Authors
|
146
|
+
|
147
|
+
Everyone who contributed to it in the rails repository.
|
148
|
+
|
149
|
+
- Joshua Peek
|
150
|
+
- Tarmo Tänav
|
151
|
+
- Jeremy Kemper
|
152
|
+
- Eugene Pimenov
|
153
|
+
- Xavier Noria
|
154
|
+
- Niels Ganser
|
155
|
+
- Carl Lerche & Yehuda Katz
|
156
|
+
- jeem
|
157
|
+
- Jay Pignata
|
158
|
+
- Damien Mathieu
|
159
|
+
- José Valim
|
160
|
+
- Matthew Rudy Jacobs
|
161
|
+
|
162
|
+
# Contributing
|
163
|
+
|
164
|
+
1. Fork it ( https://github.com/honzasterba/memoist/fork )
|
165
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
166
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
167
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
168
|
+
5. Create new Pull Request
|
169
|
+
|
170
|
+
# License
|
171
|
+
|
172
|
+
Released under the [MIT License](http://www.opensource.org/licenses/MIT), just as Ruby on Rails is.
|
data/Rakefile
ADDED
data/lib/memoist.rb
ADDED
@@ -0,0 +1,238 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'memoist/version'
|
4
|
+
|
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
|
15
|
+
|
16
|
+
def self.memoized_ivar_for(method_name, identifier = nil)
|
17
|
+
"@#{memoized_prefix(identifier)}_#{escape_punctuation(method_name)}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.unmemoized_method_for(method_name, identifier = nil)
|
21
|
+
"#{unmemoized_prefix(identifier)}_#{method_name}".to_sym
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.memoized_prefix(identifier = nil)
|
25
|
+
if identifier
|
26
|
+
"_memoized_#{identifier}"
|
27
|
+
else
|
28
|
+
'_memoized'.freeze
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.unmemoized_prefix(identifier = nil)
|
33
|
+
if identifier
|
34
|
+
"_unmemoized_#{identifier}"
|
35
|
+
else
|
36
|
+
'_unmemoized'.freeze
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.escape_punctuation(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
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.memoist_eval(klass, *args, **kwargs, &block)
|
54
|
+
if klass.respond_to?(:class_eval)
|
55
|
+
klass.class_eval(*args, **kwargs, &block)
|
56
|
+
else
|
57
|
+
klass.singleton_class.class_eval(*args, **kwargs, &block)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.extract_reload!(method, args)
|
62
|
+
if args.length == method.arity.abs + 1 && (args.last == true || args.last == :reload)
|
63
|
+
reload = args.pop
|
64
|
+
end
|
65
|
+
reload
|
66
|
+
end
|
67
|
+
|
68
|
+
module InstanceMethods
|
69
|
+
def memoize_all
|
70
|
+
prime_cache
|
71
|
+
end
|
72
|
+
|
73
|
+
def unmemoize_all
|
74
|
+
flush_cache
|
75
|
+
end
|
76
|
+
|
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
|
84
|
+
|
85
|
+
def prime_cache(*method_names)
|
86
|
+
memoized_structs(method_names).each do |struct|
|
87
|
+
if struct.arity == 0
|
88
|
+
__send__(struct.memoized_method)
|
89
|
+
else
|
90
|
+
instance_variable_set(struct.ivar, {})
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def flush_cache(*method_names)
|
96
|
+
memoized_structs(method_names).each do |struct|
|
97
|
+
remove_instance_variable(struct.ivar) if instance_variable_defined?(struct.ivar)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
MemoizedMethod = Struct.new(:memoized_method, :ivar, :arity)
|
103
|
+
|
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
|
115
|
+
end
|
116
|
+
structs
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def clear_structs
|
121
|
+
@all_memoized_structs = nil
|
122
|
+
end
|
123
|
+
|
124
|
+
def memoize(*method_names)
|
125
|
+
identifier = method_names.pop[:identifier] if method_names.last.is_a?(Hash)
|
126
|
+
|
127
|
+
method_names.each do |method_name|
|
128
|
+
unmemoized_method = Memoist.unmemoized_method_for(method_name, identifier)
|
129
|
+
memoized_ivar = Memoist.memoized_ivar_for(method_name, identifier)
|
130
|
+
|
131
|
+
Memoist.memoist_eval(self) do
|
132
|
+
include InstanceMethods
|
133
|
+
|
134
|
+
if method_defined?(unmemoized_method)
|
135
|
+
warn "Already memoized #{method_name}"
|
136
|
+
return
|
137
|
+
end
|
138
|
+
alias_method unmemoized_method, method_name
|
139
|
+
|
140
|
+
mm = MemoizedMethod.new(method_name, memoized_ivar, instance_method(method_name).arity)
|
141
|
+
memoized_methods << mm
|
142
|
+
if mm.arity == 0
|
143
|
+
|
144
|
+
# define a method like this;
|
145
|
+
|
146
|
+
# def mime_type(reload=true)
|
147
|
+
# skip_cache = reload || !instance_variable_defined?("@_memoized_mime_type")
|
148
|
+
# set_cache = skip_cache && !frozen?
|
149
|
+
#
|
150
|
+
# if skip_cache
|
151
|
+
# value = _unmemoized_mime_type
|
152
|
+
# else
|
153
|
+
# value = @_memoized_mime_type
|
154
|
+
# end
|
155
|
+
#
|
156
|
+
# if set_cache
|
157
|
+
# @_memoized_mime_type = value
|
158
|
+
# end
|
159
|
+
#
|
160
|
+
# value
|
161
|
+
# end
|
162
|
+
|
163
|
+
module_eval <<-EOS, __FILE__, __LINE__ + 1
|
164
|
+
def #{method_name}(reload = false)
|
165
|
+
skip_cache = reload || !instance_variable_defined?("#{memoized_ivar}")
|
166
|
+
set_cache = skip_cache && !frozen?
|
167
|
+
|
168
|
+
if skip_cache
|
169
|
+
value = #{unmemoized_method}
|
170
|
+
else
|
171
|
+
value = #{memoized_ivar}
|
172
|
+
end
|
173
|
+
|
174
|
+
if set_cache
|
175
|
+
#{memoized_ivar} = value
|
176
|
+
end
|
177
|
+
|
178
|
+
value
|
179
|
+
end
|
180
|
+
EOS
|
181
|
+
else
|
182
|
+
|
183
|
+
# define a method like this;
|
184
|
+
|
185
|
+
# def mime_type(*args)
|
186
|
+
# reload = Memoist.extract_reload!(method(:_unmemoized_mime_type), args)
|
187
|
+
#
|
188
|
+
# skip_cache = reload || !memoized_with_args?(:mime_type, args)
|
189
|
+
# set_cache = skip_cache && !frozen
|
190
|
+
#
|
191
|
+
# if skip_cache
|
192
|
+
# value = _unmemoized_mime_type(*args)
|
193
|
+
# else
|
194
|
+
# value = @_memoized_mime_type[args]
|
195
|
+
# end
|
196
|
+
#
|
197
|
+
# if set_cache
|
198
|
+
# @_memoized_mime_type ||= {}
|
199
|
+
# @_memoized_mime_type[args] = value
|
200
|
+
# end
|
201
|
+
#
|
202
|
+
# value
|
203
|
+
# end
|
204
|
+
|
205
|
+
module_eval <<-EOS, __FILE__, __LINE__ + 1
|
206
|
+
def #{method_name}(*args, **kwargs)
|
207
|
+
reload = Memoist.extract_reload!(method(#{unmemoized_method.inspect}), args)
|
208
|
+
|
209
|
+
skip_cache = reload || !(instance_variable_defined?(#{memoized_ivar.inspect}) && #{memoized_ivar} && #{memoized_ivar}.has_key?(args+kwargs.to_a))
|
210
|
+
set_cache = skip_cache && !frozen?
|
211
|
+
|
212
|
+
if skip_cache
|
213
|
+
value = #{unmemoized_method}(*args, **kwargs)
|
214
|
+
else
|
215
|
+
value = #{memoized_ivar}[args+kwargs.to_a]
|
216
|
+
end
|
217
|
+
|
218
|
+
if set_cache
|
219
|
+
#{memoized_ivar} ||= {}
|
220
|
+
#{memoized_ivar}[args+kwargs.to_a] = value
|
221
|
+
end
|
222
|
+
|
223
|
+
value
|
224
|
+
end
|
225
|
+
EOS
|
226
|
+
end
|
227
|
+
|
228
|
+
if private_method_defined?(unmemoized_method)
|
229
|
+
private method_name
|
230
|
+
elsif protected_method_defined?(unmemoized_method)
|
231
|
+
protected method_name
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
# return a chainable method_name symbol if we can
|
236
|
+
method_names.length == 1 ? method_names.first : method_names
|
237
|
+
end
|
238
|
+
end
|