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 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: