memoist 0.13.0 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/memoist.rb +41 -17
- data/lib/memoist/version.rb +1 -1
- data/test/memoist_test.rb +93 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aca25d96c69122d50102f2d9615409389004002e
|
4
|
+
data.tar.gz: db741378eab95d22ee2b6e6b9cde18fb4ec2abdb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1307707c8feba8c316cb1628503b76fde33e5c04b62de897c6350edc67333f325d652b45b614ecb4365229e909c7869e71c2713272b971826f8e33c7ddcbb566
|
7
|
+
data.tar.gz: 8b8141373347a9b87b7923fca58c3d3fb1daaa660af63ca765d1f9654343a77dbd915b3a8e0b89188870222a3d85cf8c9e9dba4d2af638cda4a63c50530c2acd
|
data/lib/memoist.rb
CHANGED
@@ -3,7 +3,7 @@ require 'memoist/core_ext/singleton_class'
|
|
3
3
|
module Memoist
|
4
4
|
|
5
5
|
def self.memoized_ivar_for(method_name, identifier=nil)
|
6
|
-
"@#{memoized_prefix(identifier)}_#{escape_punctuation(method_name
|
6
|
+
"@#{memoized_prefix(identifier)}_#{escape_punctuation(method_name)}"
|
7
7
|
end
|
8
8
|
|
9
9
|
def self.unmemoized_method_for(method_name, identifier=nil)
|
@@ -27,9 +27,9 @@ module Memoist
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def self.escape_punctuation(string)
|
30
|
-
|
30
|
+
string = string.is_a?(String) ? string.dup : string.to_s
|
31
31
|
|
32
|
-
string
|
32
|
+
return string unless string.end_with?('?'.freeze, '!'.freeze)
|
33
33
|
|
34
34
|
# A String can't end in both ? and !
|
35
35
|
if string.sub!(/\?\Z/, '_query'.freeze)
|
@@ -63,28 +63,52 @@ module Memoist
|
|
63
63
|
flush_cache
|
64
64
|
end
|
65
65
|
|
66
|
+
def memoized_structs(names)
|
67
|
+
structs = self.class.all_memoized_structs
|
68
|
+
return structs if names.empty?
|
69
|
+
|
70
|
+
structs.select { |s| names.include?(s.memoized_method) }
|
71
|
+
end
|
72
|
+
|
66
73
|
def prime_cache(*method_names)
|
67
|
-
method_names
|
68
|
-
|
69
|
-
|
70
|
-
__send__(method_name)
|
74
|
+
memoized_structs(method_names).each do |struct|
|
75
|
+
if struct.arity == 0
|
76
|
+
__send__(struct.memoized_method)
|
71
77
|
else
|
72
|
-
ivar
|
73
|
-
instance_variable_set(ivar, {})
|
78
|
+
instance_variable_set(struct.ivar, {})
|
74
79
|
end
|
75
80
|
end
|
76
81
|
end
|
77
82
|
|
78
83
|
def flush_cache(*method_names)
|
79
|
-
method_names
|
84
|
+
memoized_structs(method_names).each do |struct|
|
85
|
+
remove_instance_variable(struct.ivar) if instance_variable_defined?(struct.ivar)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
MemoizedMethod = Struct.new(:memoized_method, :ivar, :arity)
|
91
|
+
|
92
|
+
def all_memoized_structs
|
93
|
+
@all_memoized_structs ||= begin
|
94
|
+
structs = memoized_methods.dup
|
80
95
|
|
81
|
-
|
82
|
-
|
83
|
-
|
96
|
+
# Collect the memoized_methods of ancestors in ancestor order
|
97
|
+
# unless we already have it since self or parents could be overriding
|
98
|
+
# an ancestor method.
|
99
|
+
ancestors.grep(Memoist).each do |ancestor|
|
100
|
+
ancestor.memoized_methods.each do |m|
|
101
|
+
structs << m unless structs.any? {|am| am.memoized_method == m.memoized_method }
|
102
|
+
end
|
84
103
|
end
|
104
|
+
structs
|
85
105
|
end
|
86
106
|
end
|
87
107
|
|
108
|
+
def clear_structs
|
109
|
+
@all_memoized_structs = nil
|
110
|
+
end
|
111
|
+
|
88
112
|
def memoize(*method_names)
|
89
113
|
if method_names.last.is_a?(Hash)
|
90
114
|
identifier = method_names.pop[:identifier]
|
@@ -92,8 +116,7 @@ module Memoist
|
|
92
116
|
|
93
117
|
Memoist.memoist_eval(self) do
|
94
118
|
def self.memoized_methods
|
95
|
-
|
96
|
-
@_memoized_methods ||= Set.new
|
119
|
+
@_memoized_methods ||= []
|
97
120
|
end
|
98
121
|
end
|
99
122
|
|
@@ -110,8 +133,9 @@ module Memoist
|
|
110
133
|
end
|
111
134
|
alias_method unmemoized_method, method_name
|
112
135
|
|
113
|
-
|
114
|
-
|
136
|
+
mm = MemoizedMethod.new(method_name, memoized_ivar, instance_method(method_name).arity)
|
137
|
+
self.memoized_methods << mm
|
138
|
+
if mm.arity == 0
|
115
139
|
|
116
140
|
# define a method like this;
|
117
141
|
|
data/lib/memoist/version.rb
CHANGED
data/test/memoist_test.rb
CHANGED
@@ -114,6 +114,13 @@ class MemoistTest < Minitest::Test
|
|
114
114
|
memoize :name, :identifier => :student
|
115
115
|
end
|
116
116
|
|
117
|
+
class Teacher < Person
|
118
|
+
def seniority
|
119
|
+
"very_senior"
|
120
|
+
end
|
121
|
+
memoize :seniority
|
122
|
+
end
|
123
|
+
|
117
124
|
class Company
|
118
125
|
attr_reader :name_calls
|
119
126
|
def initialize
|
@@ -261,11 +268,75 @@ class MemoistTest < Minitest::Test
|
|
261
268
|
assert_equal 2, @calculator.counter
|
262
269
|
end
|
263
270
|
|
271
|
+
def test_all_memoized_structs
|
272
|
+
# Person memoize :age, :is_developer?, :memoize_protected_test, :name, :name?, :sleep, :update, :update_attributes
|
273
|
+
# Student < Person memoize :name, :identifier => :student
|
274
|
+
# Teacher < Person memoize :seniority
|
275
|
+
|
276
|
+
expected = %w(age is_developer? memoize_protected_test name name? sleep update update_attributes)
|
277
|
+
structs = Person.all_memoized_structs
|
278
|
+
assert_equal expected, structs.collect(&:memoized_method).collect(&:to_s).sort
|
279
|
+
assert_equal "@_memoized_name", structs.detect {|s| s.memoized_method == :name }.ivar
|
280
|
+
|
281
|
+
# Same expected methods
|
282
|
+
structs = Student.all_memoized_structs
|
283
|
+
assert_equal expected, structs.collect(&:memoized_method).collect(&:to_s).sort
|
284
|
+
assert_equal "@_memoized_student_name", structs.detect {|s| s.memoized_method == :name }.ivar
|
285
|
+
|
286
|
+
expected = (expected << "seniority").sort
|
287
|
+
structs = Teacher.all_memoized_structs
|
288
|
+
assert_equal expected, structs.collect(&:memoized_method).collect(&:to_s).sort
|
289
|
+
assert_equal "@_memoized_name", structs.detect {|s| s.memoized_method == :name }.ivar
|
290
|
+
end
|
291
|
+
|
292
|
+
def test_unmemoize_all_subclasses
|
293
|
+
# Person memoize :age, :is_developer?, :memoize_protected_test, :name, :name?, :sleep, :update, :update_attributes
|
294
|
+
# Student < Person memoize :name, :identifier => :student
|
295
|
+
# Teacher < Person memoize :seniority
|
296
|
+
|
297
|
+
teacher = Teacher.new
|
298
|
+
assert_equal "Josh", teacher.name
|
299
|
+
assert_equal "Josh", teacher.instance_variable_get(:@_memoized_name)
|
300
|
+
assert_equal "very_senior", teacher.seniority
|
301
|
+
assert_equal "very_senior", teacher.instance_variable_get(:@_memoized_seniority)
|
302
|
+
|
303
|
+
teacher.unmemoize_all
|
304
|
+
assert_nil teacher.instance_variable_get(:@_memoized_name)
|
305
|
+
assert_nil teacher.instance_variable_get(:@_memoized_seniority)
|
306
|
+
|
307
|
+
student = Student.new
|
308
|
+
assert_equal "Student Josh", student.name
|
309
|
+
assert_equal "Student Josh", student.instance_variable_get(:@_memoized_student_name)
|
310
|
+
assert_nil student.instance_variable_get(:@_memoized_seniority)
|
311
|
+
|
312
|
+
student.unmemoize_all
|
313
|
+
assert_nil student.instance_variable_get(:@_memoized_student_name)
|
314
|
+
end
|
315
|
+
|
264
316
|
def test_memoize_all
|
265
317
|
@calculator.memoize_all
|
266
318
|
assert @calculator.instance_variable_defined?(:@_memoized_counter)
|
267
319
|
end
|
268
320
|
|
321
|
+
def test_memoize_all_subclasses
|
322
|
+
# Person memoize :age, :is_developer?, :memoize_protected_test, :name, :name?, :sleep, :update, :update_attributes
|
323
|
+
# Student < Person memoize :name, :identifier => :student
|
324
|
+
# Teacher < Person memoize :seniority
|
325
|
+
|
326
|
+
teacher = Teacher.new
|
327
|
+
teacher.memoize_all
|
328
|
+
|
329
|
+
assert_equal "very_senior", teacher.instance_variable_get(:@_memoized_seniority)
|
330
|
+
assert_equal "Josh", teacher.instance_variable_get(:@_memoized_name)
|
331
|
+
|
332
|
+
student = Student.new
|
333
|
+
student.memoize_all
|
334
|
+
|
335
|
+
assert_equal "Student Josh", student.instance_variable_get(:@_memoized_student_name)
|
336
|
+
assert_equal "Student Josh", student.name
|
337
|
+
assert_nil student.instance_variable_get(:@_memoized_seniority)
|
338
|
+
end
|
339
|
+
|
269
340
|
def test_memoization_cache_is_different_for_each_instance
|
270
341
|
assert_equal 1, @calculator.counter
|
271
342
|
assert_equal 2, @calculator.counter(:reload)
|
@@ -331,7 +402,29 @@ class MemoistTest < Minitest::Test
|
|
331
402
|
end
|
332
403
|
|
333
404
|
def test_double_memoization_with_identifier
|
405
|
+
# Person memoize :age, :is_developer?, :memoize_protected_test, :name, :name?, :sleep, :update, :update_attributes
|
406
|
+
# Student < Person memoize :name, :identifier => :student
|
407
|
+
# Teacher < Person memoize :seniority
|
408
|
+
|
334
409
|
Person.memoize :name, :identifier => :again
|
410
|
+
p = Person.new
|
411
|
+
assert_equal "Josh", p.name
|
412
|
+
assert p.instance_variable_get(:@_memoized_again_name)
|
413
|
+
|
414
|
+
# HACK: tl;dr: Don't memoize classes in test that are used elsewhere.
|
415
|
+
# Calling Person.memoize :name, :identifier => :again pollutes Person
|
416
|
+
# and descendents since we cache the memoized method structures.
|
417
|
+
# This populates those structs, verifies Person is polluted, resets the
|
418
|
+
# structs, cleans up cached memoized_methods
|
419
|
+
Student.all_memoized_structs
|
420
|
+
Person.all_memoized_structs
|
421
|
+
Teacher.all_memoized_structs
|
422
|
+
assert Person.memoized_methods.any? { |m| m.ivar == "@_memoized_again_name" }
|
423
|
+
|
424
|
+
[Student, Teacher, Person].each { |obj| obj.clear_structs }
|
425
|
+
assert Person.memoized_methods.reject! { |m| m.ivar == "@_memoized_again_name" }
|
426
|
+
assert_nil Student.memoized_methods.reject! { |m| m.ivar == "@_memoized_again_name" }
|
427
|
+
assert_nil Teacher.memoized_methods.reject! { |m| m.ivar == "@_memoized_again_name" }
|
335
428
|
end
|
336
429
|
|
337
430
|
def test_memoization_with_a_subclass
|
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.14.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joshua Peek
|
@@ -19,7 +19,7 @@ authors:
|
|
19
19
|
autorequire:
|
20
20
|
bindir: bin
|
21
21
|
cert_chain: []
|
22
|
-
date: 2015-
|
22
|
+
date: 2015-12-15 00:00:00.000000000 Z
|
23
23
|
dependencies:
|
24
24
|
- !ruby/object:Gem::Dependency
|
25
25
|
name: bundler
|
@@ -120,3 +120,4 @@ summary: memoize methods invocation
|
|
120
120
|
test_files:
|
121
121
|
- test/memoist_test.rb
|
122
122
|
- test/test_helper.rb
|
123
|
+
has_rdoc:
|