ruby_memoized 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +132 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/memoized/memoizer.rb +19 -0
- data/lib/memoized/version.rb +3 -0
- data/lib/memoized.rb +44 -0
- data/memoized.gemspec +30 -0
- metadata +104 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f8396b17290439869c6555618f070d73da03aa80
|
4
|
+
data.tar.gz: 3de622bd348b5295cb8b4c034446b600ce10ae88
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 50183e3a8c22c13a61e3ad93d86b06a43d12505483bf2baf3c01c30775f12079bd41e3d13fc8f19ea43f06bfb069c8429005a626bc66d4d10d42d086e6a27a24
|
7
|
+
data.tar.gz: edf825b1725d51e115a713daf1c6ccff9b921627ea283f97259bb7dfbf1f62b6e4d17acc8b9cf9adcdd1b29f919931443ec66ee83456af93ea866bdb8f0e797e
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
memoized
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.4.0
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2017 Kirill Klimuk
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
# Memoized
|
2
|
+
|
3
|
+
Memoized makes it easy to memoize methods, even if they have arguments or blocks,
|
4
|
+
by making memoization as easy as declaring a method private.
|
5
|
+
To experiment with that code, run `bin/console` for an interactive prompt.
|
6
|
+
|
7
|
+
For more information about the motivation behind the gem,
|
8
|
+
please see [this blog post](https://medium.com/@kklimuk/memoization-in-ruby-made-easy-a4b0f6c11846).
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
Add this line to your application's Gemfile:
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
gem 'ruby_memoized'
|
16
|
+
```
|
17
|
+
|
18
|
+
And then execute:
|
19
|
+
|
20
|
+
$ bundle
|
21
|
+
|
22
|
+
Or install it yourself as:
|
23
|
+
|
24
|
+
$ gem install memoized
|
25
|
+
|
26
|
+
## Usage
|
27
|
+
|
28
|
+
Suppose we have the following class:
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
class FibonacciCalculator
|
32
|
+
def calculate(n)
|
33
|
+
return n if (0..1).include?(n)
|
34
|
+
calculate(n - 1) + calculate(n - 2)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
```
|
38
|
+
|
39
|
+
Right now, when we try to use this `FibonacciCalculator` for any larger number, it takes quite a while to compute since
|
40
|
+
it has to perform the method calls in line 34.
|
41
|
+
|
42
|
+
One of the ways we can make this computation much faster is to save (memoize) the pieces so they return immediately.
|
43
|
+
Let's do that in a separate method:
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
class FibonacciCalculator
|
47
|
+
def calculate(n)
|
48
|
+
return n if (0..1).include?(n)
|
49
|
+
calculate(n - 1) + calculate(n - 2)
|
50
|
+
end
|
51
|
+
|
52
|
+
memoized
|
53
|
+
|
54
|
+
def memoized_calculate(n)
|
55
|
+
return n if (0..1).include?(n)
|
56
|
+
memoized_calculate(n - 1) + memoized_calculate(n - 2)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
```
|
60
|
+
|
61
|
+
Here, we put a call to the `memoized` class method. This class method will allow us to make sure that the outputs of
|
62
|
+
any method calls below it will be saved (memoized).
|
63
|
+
|
64
|
+
Let's see the how the performance of one stacks up against the other for an `n` of 35.
|
65
|
+
|
66
|
+
```
|
67
|
+
user system total real
|
68
|
+
with memoization 0.000000 0.000000 0.000000 ( 0.000469)
|
69
|
+
without memoization 46.010000 0.160000 46.170000 (46.597599)
|
70
|
+
```
|
71
|
+
|
72
|
+
Cool, but now suppose we wrote another method that we didn't want memoized after `memoized_calculate`.
|
73
|
+
We could unmemoize it by doing the following:
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
class FibonacciCalculator
|
77
|
+
include Memoized
|
78
|
+
|
79
|
+
memoized
|
80
|
+
|
81
|
+
def memoized_calculate(n)
|
82
|
+
return n if (0..1).include?(n)
|
83
|
+
memoized_calculate(n - 1) + memoized_calculate(n - 2)
|
84
|
+
end
|
85
|
+
|
86
|
+
unmemoized
|
87
|
+
|
88
|
+
def calculate(n)
|
89
|
+
return n if (0..1).include?(n)
|
90
|
+
calculate(n - 1) + calculate(n - 2)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
```
|
94
|
+
|
95
|
+
Alright, that sounds all well and good. But what if we really didn't wanna call `include Memoized` everywhere but
|
96
|
+
still wanted to use memoization?
|
97
|
+
|
98
|
+
We could just add it to `Object`!
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
class Object
|
102
|
+
include Memoized
|
103
|
+
end
|
104
|
+
```
|
105
|
+
|
106
|
+
Now we make objects that use `memoized`/`unmemoized` willy-nilly.
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
class RandomThing
|
110
|
+
memoize
|
111
|
+
def hardcore_calculation
|
112
|
+
# TODO: Write really hardcore calculation.
|
113
|
+
end
|
114
|
+
end
|
115
|
+
```
|
116
|
+
|
117
|
+
|
118
|
+
## Development
|
119
|
+
|
120
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
121
|
+
|
122
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
123
|
+
|
124
|
+
## Contributing
|
125
|
+
|
126
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/kklimuk/memoized. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
127
|
+
|
128
|
+
|
129
|
+
## License
|
130
|
+
|
131
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
132
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'memoized'
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require 'irb'
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module Memoized
|
2
|
+
class Memoizer
|
3
|
+
attr_reader :context, :method
|
4
|
+
|
5
|
+
def initialize(context, method)
|
6
|
+
@context = context
|
7
|
+
@method = method
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(*args, &block)
|
11
|
+
return cache[[args, block]] if cache.has_key?([args, block])
|
12
|
+
cache[[args, block]] = context.send(method, *args, &block)
|
13
|
+
end
|
14
|
+
|
15
|
+
def cache
|
16
|
+
@cache ||= {}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/memoized.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'memoized/version'
|
2
|
+
require 'memoized/memoizer'
|
3
|
+
|
4
|
+
module Memoized
|
5
|
+
def self.included(klass)
|
6
|
+
klass.extend(ClassMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def memoized
|
11
|
+
@memoized = true
|
12
|
+
end
|
13
|
+
|
14
|
+
def unmemoized
|
15
|
+
@memoized = false
|
16
|
+
end
|
17
|
+
|
18
|
+
def method_added(method_name)
|
19
|
+
if @memoized
|
20
|
+
@memoized = false
|
21
|
+
|
22
|
+
unmemoized_method_name = :"unmemoized_#{method_name}"
|
23
|
+
|
24
|
+
memoizer_name = :"memoizer_for_#{method_name}"
|
25
|
+
define_method memoizer_name do
|
26
|
+
memoizer = instance_variable_get "@#{memoizer_name}"
|
27
|
+
if memoizer
|
28
|
+
memoizer
|
29
|
+
else
|
30
|
+
instance_variable_set "@#{memoizer_name}", Memoizer.new(self, unmemoized_method_name)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
alias_method unmemoized_method_name, method_name
|
35
|
+
|
36
|
+
define_method method_name do |*args, &block|
|
37
|
+
send(memoizer_name).call(*args, &block)
|
38
|
+
end
|
39
|
+
|
40
|
+
@memoized = true
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/memoized.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'memoized/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'ruby_memoized'
|
8
|
+
spec.version = Memoized::VERSION
|
9
|
+
spec.authors = ['Kirill Klimuk']
|
10
|
+
spec.email = ['kklimuk@gmail.com']
|
11
|
+
|
12
|
+
spec.summary = %q{Memoize method return values even with different arguments.}
|
13
|
+
spec.description = <<-DESC.gsub(/\s\s+/, ' ')
|
14
|
+
Memoized makes it easy to memoize methods, even if they have arguments or blocks, by making memoization as easy
|
15
|
+
as declaring a method private.
|
16
|
+
DESC
|
17
|
+
spec.homepage = 'https://github.com/kklimuk/memoized'
|
18
|
+
spec.license = 'MIT'
|
19
|
+
|
20
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
21
|
+
f.match(%r{^(test|spec|features)/})
|
22
|
+
end
|
23
|
+
spec.bindir = 'exe'
|
24
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
25
|
+
spec.require_paths = ['lib']
|
26
|
+
|
27
|
+
spec.add_development_dependency 'bundler', '~> 1.13'
|
28
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
29
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
30
|
+
end
|
metadata
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruby_memoized
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kirill Klimuk
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-04-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.13'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.13'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
description: 'Memoized makes it easy to memoize methods, even if they have arguments
|
56
|
+
or blocks, by making memoization as easy as declaring a method private.
|
57
|
+
|
58
|
+
'
|
59
|
+
email:
|
60
|
+
- kklimuk@gmail.com
|
61
|
+
executables: []
|
62
|
+
extensions: []
|
63
|
+
extra_rdoc_files: []
|
64
|
+
files:
|
65
|
+
- ".gitignore"
|
66
|
+
- ".rspec"
|
67
|
+
- ".ruby-gemset"
|
68
|
+
- ".ruby-version"
|
69
|
+
- ".travis.yml"
|
70
|
+
- Gemfile
|
71
|
+
- LICENSE.txt
|
72
|
+
- README.md
|
73
|
+
- Rakefile
|
74
|
+
- bin/console
|
75
|
+
- bin/setup
|
76
|
+
- lib/memoized.rb
|
77
|
+
- lib/memoized/memoizer.rb
|
78
|
+
- lib/memoized/version.rb
|
79
|
+
- memoized.gemspec
|
80
|
+
homepage: https://github.com/kklimuk/memoized
|
81
|
+
licenses:
|
82
|
+
- MIT
|
83
|
+
metadata: {}
|
84
|
+
post_install_message:
|
85
|
+
rdoc_options: []
|
86
|
+
require_paths:
|
87
|
+
- lib
|
88
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '0'
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
requirements: []
|
99
|
+
rubyforge_project:
|
100
|
+
rubygems_version: 2.6.11
|
101
|
+
signing_key:
|
102
|
+
specification_version: 4
|
103
|
+
summary: Memoize method return values even with different arguments.
|
104
|
+
test_files: []
|