memoist3 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Gem Version](https://badge.fury.io/rb/memoist3.svg)](https://badge.fury.io/rb/memoist3)
|
7
|
+
[![Build Status](https://github.com/honzasterba/memoist/workflows/ci/badge.svg)](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
|