memoist 0.13.0 → 0.14.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5f737a677ee84ae6e38db47c459ce5151d87d57b
4
- data.tar.gz: 454244a7dc119201a0339227a5e6c54a8ec64e06
3
+ metadata.gz: aca25d96c69122d50102f2d9615409389004002e
4
+ data.tar.gz: db741378eab95d22ee2b6e6b9cde18fb4ec2abdb
5
5
  SHA512:
6
- metadata.gz: 67f7764129d2f645a6d9e4d586bf8fed469460b10af0eb56bf7906191ce271a1d1ca7413e2f67cab12519862342b516c305994f2e1f73d263443f48e79dfffc9
7
- data.tar.gz: 2b7d05ccffe29ce0cd42b93aa430ed682fbe90dae8badfe632f6e2573f9daa1705aabb2fb16bf360ba7b649128caecddd9a7ce8cfebcedf055beefd5d690db07
6
+ metadata.gz: 1307707c8feba8c316cb1628503b76fde33e5c04b62de897c6350edc67333f325d652b45b614ecb4365229e909c7869e71c2713272b971826f8e33c7ddcbb566
7
+ data.tar.gz: 8b8141373347a9b87b7923fca58c3d3fb1daaa660af63ca765d1f9654343a77dbd915b3a8e0b89188870222a3d85cf8c9e9dba4d2af638cda4a63c50530c2acd
@@ -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.to_s)}"
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
- return string unless string.end_with?('?'.freeze, '!'.freeze)
30
+ string = string.is_a?(String) ? string.dup : string.to_s
31
31
 
32
- string = string.dup
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 = self.class.memoized_methods if method_names.empty?
68
- method_names.each do |method_name|
69
- if method(Memoist.unmemoized_method_for(method_name)).arity == 0
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 = Memoist.memoized_ivar_for(method_name)
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 = self.class.memoized_methods if method_names.empty?
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
- method_names.each do |method_name|
82
- ivar = Memoist.memoized_ivar_for(method_name)
83
- remove_instance_variable(ivar) if instance_variable_defined?(ivar)
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
- require 'set'
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
- self.memoized_methods << method_name
114
- if instance_method(method_name).arity == 0
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
 
@@ -1,3 +1,3 @@
1
1
  module Memoist
2
- VERSION = "0.13.0"
2
+ VERSION = "0.14.0"
3
3
  end
@@ -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.13.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-11-26 00:00:00.000000000 Z
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: