mize 0.6.0 → 0.7.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 +4 -4
- data/.all_images.yml +21 -17
- data/.github/workflows/static.yml +51 -0
- data/.rspec +1 -0
- data/CHANGES.md +173 -0
- data/Gemfile +0 -2
- data/LICENSE +19 -0
- data/README.md +144 -29
- data/Rakefile +11 -2
- data/VERSION +1 -1
- data/lib/mize/cache_methods.rb +42 -1
- data/lib/mize/cache_protocol.rb +19 -0
- data/lib/mize/configure.rb +31 -0
- data/lib/mize/default_cache.rb +45 -12
- data/lib/mize/global_clear.rb +15 -1
- data/lib/mize/memoize.rb +65 -9
- data/lib/mize/railtie.rb +7 -0
- data/lib/mize/reload.rb +16 -3
- data/lib/mize/version.rb +7 -2
- data/lib/mize.rb +63 -0
- data/mize.gemspec +12 -10
- data/spec/mize/global_clear_spec.rb +0 -2
- data/spec/mize/memoize_method_spec.rb +0 -2
- data/spec/mize/memoize_reload_spec.rb +0 -2
- data/spec/mize/version_spec.rb +0 -2
- data/spec/mize_spec.rb +13 -0
- data/spec/spec_helper.rb +3 -8
- metadata +31 -18
- data/.tool-versions +0 -1
- data/.utilsrc +0 -26
- data/config/broken_config.yml +0 -1
- data/config/config.yml +0 -13
data/lib/mize/configure.rb
CHANGED
|
@@ -1,10 +1,40 @@
|
|
|
1
|
+
# Configuration helpers mixed in / extended onto the top-level +Mize+ object.
|
|
2
|
+
#
|
|
3
|
+
# Provides the block-based +Mize.configure+ DSL and the +default_cache+
|
|
4
|
+
# accessor so users can swap the global cache backend.
|
|
1
5
|
module Mize::Configure
|
|
6
|
+
# The global default cache backend.
|
|
7
|
+
#
|
|
8
|
+
# Every memoized object that has not been given an explicit cache
|
|
9
|
+
# instantiates a fresh copy (via +prototype+ / "dup") of this backend.
|
|
10
|
+
# Reassign it to route all new memoized calls through a different store
|
|
11
|
+
# (Redis, Memcached, ...).
|
|
12
|
+
#
|
|
13
|
+
# @return [Mize::CacheProtocol] The current global default cache backend.
|
|
2
14
|
attr_accessor :default_cache
|
|
3
15
|
|
|
16
|
+
# Set the default cache object to +cache+.
|
|
17
|
+
#
|
|
18
|
+
# Intended for use inside a +Mize.configure {}+ block.
|
|
19
|
+
#
|
|
20
|
+
# @param cache [Mize::CacheProtocol] The backend to install as the default.
|
|
21
|
+
# @return [Mize::CacheProtocol] The backend now installed.
|
|
4
22
|
def cache(cache)
|
|
5
23
|
self.default_cache = cache
|
|
6
24
|
end
|
|
7
25
|
|
|
26
|
+
# Configure Mize by evaluating +block+ in the context of the +Mize+ object.
|
|
27
|
+
#
|
|
28
|
+
# Inside the block, +cache+ (and the +default_cache+ accessor) are called
|
|
29
|
+
# directly on +Mize+, so no receiver is required.
|
|
30
|
+
#
|
|
31
|
+
# @example
|
|
32
|
+
# Mize.configure do
|
|
33
|
+
# cache MyRedisCache.new
|
|
34
|
+
# end
|
|
35
|
+
#
|
|
36
|
+
# @yield The configuration block, evaluated via +instance_eval+.
|
|
37
|
+
# @return [Object] The return value of +block+.
|
|
8
38
|
def configure(&block)
|
|
9
39
|
instance_eval(&block)
|
|
10
40
|
end
|
|
@@ -14,4 +44,5 @@ module Mize
|
|
|
14
44
|
extend Mize::Configure
|
|
15
45
|
end
|
|
16
46
|
|
|
47
|
+
# Install the built-in in-memory backend as the global default.
|
|
17
48
|
Mize.default_cache = Mize::DefaultCache.new
|
data/lib/mize/default_cache.rb
CHANGED
|
@@ -1,14 +1,30 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
# The default in-memory cache backend.
|
|
2
|
+
#
|
|
3
|
+
# A plain +Hash+ wrapper that implements just enough of the Mize cache
|
|
4
|
+
# protocol to back memoization out of the box: +read+ / +write+ /
|
|
5
|
+
# +exist?+ / +delete+ / +clear+ / +each_name+.
|
|
6
|
+
#
|
|
7
|
+
# Individual operations are atomic under the GVL. For multi-step
|
|
8
|
+
# atomicity (e.g. check→compute→write), wrap the call in
|
|
9
|
+
# +Mize.synchronize+.
|
|
10
|
+
#
|
|
11
|
+
# Because it is backed by a plain +Hash+, entries are never evicted until you
|
|
12
|
+
# clear the cache explicitly (or the object is garbage-collected). For
|
|
13
|
+
# persistent or evicting behaviour, swap in a different
|
|
14
|
+
# +Mize::CacheProtocol+ implementation via +Mize.configure+.
|
|
3
15
|
class Mize::DefaultCache
|
|
4
16
|
include Mize::CacheProtocol
|
|
5
|
-
include MonitorMixin
|
|
6
17
|
|
|
18
|
+
# Create an empty cache.
|
|
19
|
+
#
|
|
20
|
+
# @return [Mize::DefaultCache] A new, empty cache instance.
|
|
7
21
|
def initialize
|
|
8
22
|
@data = {}
|
|
9
23
|
end
|
|
10
24
|
|
|
11
|
-
# Clear the cache by removing all entries from the cache
|
|
25
|
+
# Clear the cache by removing all entries from the cache.
|
|
26
|
+
#
|
|
27
|
+
# @return [self] The receiver, for chaining.
|
|
12
28
|
def clear(options = nil)
|
|
13
29
|
@data.clear
|
|
14
30
|
self
|
|
@@ -17,16 +33,18 @@ class Mize::DefaultCache
|
|
|
17
33
|
# Determine whether a cache entry exists in this cache.
|
|
18
34
|
#
|
|
19
35
|
# @param name [String] The name of the cache entry to check.
|
|
36
|
+
# @param options [Hash, nil] Optional backend-specific options (ignored).
|
|
20
37
|
# @return [Boolean] Whether or not the cache entry exists.
|
|
21
38
|
def exist?(name, options = nil)
|
|
22
39
|
@data.key?(name)
|
|
23
40
|
end
|
|
24
41
|
|
|
25
42
|
# Read a value from the cache by name. If the entry does not exist in the
|
|
26
|
-
# cache, it will return nil
|
|
43
|
+
# cache, it will return +nil+.
|
|
27
44
|
#
|
|
28
45
|
# @param name [String] The name of the cache entry to read.
|
|
29
|
-
# @
|
|
46
|
+
# @param options [Hash, nil] Optional backend-specific options (ignored).
|
|
47
|
+
# @return [Object, nil] The value stored in the cache for +name+, or +nil+.
|
|
30
48
|
def read(name, options = nil)
|
|
31
49
|
@data.fetch(name, nil)
|
|
32
50
|
end
|
|
@@ -35,34 +53,49 @@ class Mize::DefaultCache
|
|
|
35
53
|
# exists in the cache, it will be overwritten.
|
|
36
54
|
#
|
|
37
55
|
# @param name [String] The name of the cache entry to write.
|
|
38
|
-
# @param value [Object] The value to store in the cache for
|
|
39
|
-
# @
|
|
56
|
+
# @param value [Object] The value to store in the cache for +name+.
|
|
57
|
+
# @param options [Hash, nil] Optional backend-specific options (ignored).
|
|
58
|
+
# @return [Object] The value now stored in the cache.
|
|
40
59
|
def write(name, value, options = nil)
|
|
41
60
|
@data.store(name, value)
|
|
42
61
|
end
|
|
43
62
|
|
|
44
|
-
# Delete a cache entry by name. If
|
|
63
|
+
# Delete a cache entry by name. If an entry does not exist in the cache, it
|
|
45
64
|
# will do nothing.
|
|
46
65
|
#
|
|
47
66
|
# @param name [String] The name of the cache entry to delete.
|
|
48
|
-
# @
|
|
67
|
+
# @param options [Hash, nil] Optional backend-specific options (ignored).
|
|
68
|
+
# @return [Object, nil] The value stored in the cache before deletion, or
|
|
69
|
+
# +nil+ if the entry was absent.
|
|
49
70
|
def delete(name, options = nil)
|
|
50
71
|
@data.delete(name)
|
|
51
72
|
end
|
|
52
73
|
|
|
53
74
|
# Each name of the cache is yielded to the block.
|
|
54
|
-
#
|
|
75
|
+
#
|
|
76
|
+
# @yieldparam name [String] Each cache entry name, in turn.
|
|
77
|
+
# @return [self] The receiver, for chaining.
|
|
55
78
|
def each_name(&block)
|
|
56
79
|
@data.each_key(&block)
|
|
57
80
|
self
|
|
58
81
|
end
|
|
59
82
|
|
|
60
83
|
# Initialize a duplicate of this cache.
|
|
61
|
-
#
|
|
84
|
+
#
|
|
85
|
+
# The underlying store is shallow-copied so the original and the duplicate
|
|
86
|
+
# diverge immediately (this is what +prototype+ relies on to hand each
|
|
87
|
+
# memoized object its own independent cache).
|
|
88
|
+
#
|
|
89
|
+
# @param other [Mize::DefaultCache] The cache to initialize a duplicate of.
|
|
90
|
+
# @return [Mize::DefaultCache] +self+, now a copy of +other+.
|
|
62
91
|
def initialize_dup(other)
|
|
63
92
|
super
|
|
64
93
|
other.instance_variable_set :@data, @data.dup
|
|
65
94
|
end
|
|
66
95
|
|
|
96
|
+
# Create a shallow copy of this cache; the public name for +dup+.
|
|
97
|
+
#
|
|
98
|
+
# @return [Mize::DefaultCache] A new cache with an independent copy of the
|
|
99
|
+
# entries.
|
|
67
100
|
alias prototype dup
|
|
68
101
|
end
|
data/lib/mize/global_clear.rb
CHANGED
|
@@ -2,14 +2,28 @@ module Mize
|
|
|
2
2
|
class << self
|
|
3
3
|
|
|
4
4
|
# Clear all memoization caches at once.
|
|
5
|
+
#
|
|
6
|
+
# Walks every live +Mize::CacheProtocol+ instance in the process (see
|
|
7
|
+
# +each_cache+) and invokes +clear+ on each, inside +Mize.synchronize+ so
|
|
8
|
+
# the sweep is atomic with respect to concurrent reads/writes.
|
|
9
|
+
#
|
|
10
|
+
# @return [Mize] The +Mize+ module itself.
|
|
5
11
|
def cache_clear
|
|
6
12
|
each_cache(&:clear)
|
|
7
13
|
end
|
|
8
14
|
|
|
9
15
|
private
|
|
10
16
|
|
|
17
|
+
# Yield every live +Mize::CacheProtocol+ object to the block.
|
|
18
|
+
#
|
|
19
|
+
# The sweep runs under +Mize.synchronize+ so it cannot observe a
|
|
20
|
+
# half-cleared cache. Objects only appear here because they
|
|
21
|
+
# +include Mize::CacheProtocol+.
|
|
22
|
+
#
|
|
23
|
+
# @yield [cache] Yields each live cache backend in turn.
|
|
24
|
+
# @return [Mize] The +Mize+ module itself.
|
|
11
25
|
def each_cache
|
|
12
|
-
Mize
|
|
26
|
+
Mize.synchronize do
|
|
13
27
|
for cache in ObjectSpace.each_object(Mize::CacheProtocol)
|
|
14
28
|
yield cache
|
|
15
29
|
end
|
data/lib/mize/memoize.rb
CHANGED
|
@@ -2,18 +2,43 @@ require 'mize/cache_methods'
|
|
|
2
2
|
require 'mize/reload'
|
|
3
3
|
|
|
4
4
|
module Mize
|
|
5
|
+
# Memoization entry point, prepended into every +::Module+ by +mize.rb+.
|
|
6
|
+
#
|
|
7
|
+
# Including this module (or relying on the global +prepend+) exposes
|
|
8
|
+
# +memoize+, +mize_cache_clear+ and +mize_cache_clear_name+ on the
|
|
9
|
+
# receiver. The heavy lifting is delegated to +Mize::CacheMethods+ for
|
|
10
|
+
# key/state management and +Mize::Reload+ for cache invalidation.
|
|
5
11
|
module Memoize
|
|
6
12
|
include CacheMethods
|
|
7
13
|
|
|
8
|
-
# Memoize either a +method+ or a +function+.
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
14
|
+
# Memoize either a +method+ or a +function+.
|
|
15
|
+
#
|
|
16
|
+
# In the +method+ case the memoized results do NOT ONLY depend on the
|
|
17
|
+
# arguments, but ALSO on the object the method is called on (each object
|
|
18
|
+
# keeps its own cache). In the +function+ case the memoized results ONLY
|
|
19
|
+
# depend on the arguments, and a single shared cache backs every call.
|
|
20
|
+
#
|
|
21
|
+
# You must specify exactly one of +method:+ or +function:+; passing both
|
|
22
|
+
# or neither raises +ArgumentError+.
|
|
23
|
+
#
|
|
24
|
+
# @param method [String, Symbol, nil] The instance method to wrap.
|
|
25
|
+
# @param function [String, Symbol, nil] The bare/stateless function to wrap.
|
|
26
|
+
# @param freeze [true, false] When true, successfully computed results are
|
|
27
|
+
# frozen (if they respond to +freeze+) to make them immutable.
|
|
28
|
+
# @param store_nil [true, false] When false, +nil+ results are not stored
|
|
29
|
+
# and are recomputed every call; defaults to +true+ (store +nil+).
|
|
30
|
+
# @raise [ArgumentError] If both or neither of +method:+/+function:+ are
|
|
31
|
+
# given.
|
|
32
|
+
# @return [Symbol] The (stringified) symbol of the wrapped method id.
|
|
33
|
+
# @example Memoizing an instance method
|
|
34
|
+
# class Foo
|
|
35
|
+
# include Mize::Memoize
|
|
36
|
+
#
|
|
37
|
+
# def expensive(x) x * 2 end
|
|
38
|
+
# memoize method: :expensive, freeze: true
|
|
39
|
+
# end
|
|
15
40
|
def memoize(method: nil, function: nil, freeze: false, store_nil: true)
|
|
16
|
-
Mize
|
|
41
|
+
Mize.synchronize do
|
|
17
42
|
if method && function
|
|
18
43
|
raise ArgumentError, 'memoize a method xor a function'
|
|
19
44
|
elsif method
|
|
@@ -31,6 +56,19 @@ module Mize
|
|
|
31
56
|
class << self
|
|
32
57
|
private
|
|
33
58
|
|
|
59
|
+
# Compute the real result of a memoized call.
|
|
60
|
+
#
|
|
61
|
+
# Binds +orig_method+ to +context+ and invokes it with +args+; when
|
|
62
|
+
# running under +$DEBUG+ a diagnostic line is emitted to +STDERR+.
|
|
63
|
+
#
|
|
64
|
+
# @param method_id [Symbol] The wrapped method name (diagnostics only).
|
|
65
|
+
# @param orig_method [UnboundMethod] The original, unwrapped method.
|
|
66
|
+
# @param key [String] The cache key for this call (diagnostics only).
|
|
67
|
+
# @param context [Object] The object the method is bound to.
|
|
68
|
+
# @param args [Array] The positional arguments.
|
|
69
|
+
# @param kargs [Hash] The keyword arguments.
|
|
70
|
+
# @param freeze [true, false] Whether to freeze the resulting value.
|
|
71
|
+
# @return [Object] The (possibly frozen) computed result.
|
|
34
72
|
def compute_result(method_id, orig_method, key, context, args, kargs, freeze)
|
|
35
73
|
result = orig_method.bind(context).call(*args)
|
|
36
74
|
if $DEBUG
|
|
@@ -43,7 +81,25 @@ module Mize
|
|
|
43
81
|
end
|
|
44
82
|
end
|
|
45
83
|
|
|
46
|
-
|
|
84
|
+
# Wrap +method_id+ with a memoizing closure.
|
|
85
|
+
#
|
|
86
|
+
# Idempotency: a +[self, method_id, function]+ target already present in
|
|
87
|
+
# +Mize.wrapped+ with identical +freeze+ / +store_nil+ options is a
|
|
88
|
+
# no-op; conflicting options raise +ArgumentError+.
|
|
89
|
+
#
|
|
90
|
+
# For instance methods (+function: false+) the receiver gets its own
|
|
91
|
+
# per-object cache via +Mize::CacheMethods+ and +Mize::Reload+ is
|
|
92
|
+
# prepended so +reload+ invalidates entries. For bare functions a single
|
|
93
|
+
# shared cache is used instead.
|
|
94
|
+
#
|
|
95
|
+
# @param method_id [String, Symbol] The name of the method to wrap.
|
|
96
|
+
# @param freeze [true, false] Forwarded to the wrapper's result handling.
|
|
97
|
+
# @param function [true, false] Whether +method_id+ is a bare function.
|
|
98
|
+
# @param store_nil [true, false] Whether +nil+ results should be cached.
|
|
99
|
+
# @raise [ArgumentError] If the target is already wrapped with different
|
|
100
|
+
# +freeze+ / +store_nil+ options.
|
|
101
|
+
# @return [Symbol] The stringified symbol of the wrapped method id.
|
|
102
|
+
def wrap_method(method_id, freeze: false, function: false, store_nil: true)
|
|
47
103
|
verbose, $VERBOSE = $VERBOSE, nil
|
|
48
104
|
if already_wrapped = Mize.wrapped[ [ self, method_id, function ] ]
|
|
49
105
|
if already_wrapped == [ freeze, store_nil ]
|
data/lib/mize/railtie.rb
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
module Mize
|
|
2
|
+
# Rails integration.
|
|
3
|
+
#
|
|
4
|
+
# Hooks into the Rails preparation lifecycle so that every code reload
|
|
5
|
+
# clears all Mize caches via +Mize.cache_clear+, preventing stale memoized
|
|
6
|
+
# results from surviving a development-environment class reload.
|
|
7
|
+
#
|
|
8
|
+
# Loaded automatically by +mize.rb+ only when +Rails+ is defined.
|
|
2
9
|
class Railtie < Rails::Railtie
|
|
3
10
|
config.to_prepare do
|
|
4
11
|
Mize.cache_clear
|
data/lib/mize/reload.rb
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
|
+
# Reload/invalidation hook, prepended into any module that memoizes an
|
|
2
|
+
# instance method.
|
|
3
|
+
#
|
|
4
|
+
# When a class defines (or inherits) its own +reload+, Mize wraps it so the
|
|
5
|
+
# cache is guaranteed to be cleared alongside whatever the user's +reload+
|
|
6
|
+
# does, keeping memoized state consistent after a full object reload.
|
|
1
7
|
module Mize::Reload
|
|
2
|
-
#
|
|
3
|
-
#
|
|
8
|
+
# Run the parent +reload+ (if any), then clear Mize's bookkeeping and the
|
|
9
|
+
# object's memoization cache.
|
|
10
|
+
#
|
|
11
|
+
# The whole sequence is serialized on +Mize.synchronize+. +Mize.wrapped+ is
|
|
12
|
+
# reset so a re-memoization with different options is allowed, and
|
|
13
|
+
# +mize_cache_clear+ drops every cached value for this object.
|
|
14
|
+
#
|
|
15
|
+
# @return [Object] The result of the parent +reload+ if one was defined,
|
|
16
|
+
# otherwise +self+.
|
|
4
17
|
def reload(*)
|
|
5
|
-
Mize
|
|
18
|
+
Mize.synchronize do
|
|
6
19
|
result = self
|
|
7
20
|
if defined? super
|
|
8
21
|
result = super
|
data/lib/mize/version.rb
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
# Version information for the Mize gem.
|
|
2
|
+
#
|
|
3
|
+
# This module is auto-generated by GemHadar and exposes the
|
|
4
|
+
# current release version as a set of constants. Do not edit it
|
|
5
|
+
# by hand; it is rewritten on every `rake version` invocation.
|
|
1
6
|
module Mize
|
|
2
|
-
# Mize
|
|
3
|
-
VERSION = '0.
|
|
7
|
+
# The current version of the Mize gem as a String.
|
|
8
|
+
VERSION = '0.7.0'
|
|
4
9
|
VERSION_ARRAY = VERSION.split('.').map(&:to_i) # :nodoc:
|
|
5
10
|
VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
|
|
6
11
|
VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
|
data/lib/mize.rb
CHANGED
|
@@ -1,10 +1,71 @@
|
|
|
1
1
|
require 'thread'
|
|
2
2
|
|
|
3
|
+
# Mize — a minimal, dependency-free memoization toolkit for Ruby.
|
|
4
|
+
#
|
|
5
|
+
# Mize lets you wrap any method (or a bare, stateless "function") so that its
|
|
6
|
+
# result is cached and reused for identical arguments. It ships with an
|
|
7
|
+
# in-memory +Mize::DefaultCache+ but accepts any object that includes
|
|
8
|
+
# +Mize::CacheProtocol+, so you can plug in Redis, Memcached, and friends.
|
|
9
|
+
#
|
|
10
|
+
# @example Wrapping a method
|
|
11
|
+
# class Greeter
|
|
12
|
+
# include Mize::Memoize
|
|
13
|
+
#
|
|
14
|
+
# def expensive(name)
|
|
15
|
+
# # ...
|
|
16
|
+
# end
|
|
17
|
+
# memoize method: :expensive
|
|
18
|
+
# end
|
|
3
19
|
module Mize
|
|
20
|
+
# Process-wide lock guarding all cache and wrapping mutations.
|
|
21
|
+
#
|
|
22
|
+
# Every operation that mutates shared Mize state (+memoize+,
|
|
23
|
+
# +Mize.cache_clear+, +Mize::Reload#reload+) serialises on this mutex, so
|
|
24
|
+
# the toolkit is safe to use from multiple threads.
|
|
4
25
|
MUTEX = Mutex.new
|
|
5
26
|
|
|
6
27
|
class << self
|
|
28
|
+
# Bookkeeping of already-wrapped targets.
|
|
29
|
+
#
|
|
30
|
+
# Maps +[module, method_id, function]+ => +[freeze, store_nil]+ so that
|
|
31
|
+
# duplicate +memoize+ calls can be detected and conflicting options
|
|
32
|
+
# rejected. Cleared on +Mize::Reload#reload+.
|
|
7
33
|
attr_accessor :wrapped
|
|
34
|
+
|
|
35
|
+
# Acquire the global Mize mutex for the duration of +block+.
|
|
36
|
+
#
|
|
37
|
+
# Exposes the internal +MUTEX+ under a stable API so callers can make
|
|
38
|
+
# a sequence of memoized calls atomic with respect to other threads:
|
|
39
|
+
#
|
|
40
|
+
# @example
|
|
41
|
+
# Mize.synchronize do
|
|
42
|
+
# obj.foo(42)
|
|
43
|
+
# obj.bar(42)
|
|
44
|
+
# end
|
|
45
|
+
#
|
|
46
|
+
# The hot path (individual memoized calls) is lock-free by design; use
|
|
47
|
+
# this when you need the check→compute→write cycle to be indivisible.
|
|
48
|
+
#
|
|
49
|
+
# MRI forbids +Mutex#synchronize+ from a trap context (signal handlers
|
|
50
|
+
# and GC finalizers), raising +ThreadError: can't be called from trap
|
|
51
|
+
# context+. This is an intentional, still-current design decision (see
|
|
52
|
+
# DevMeeting-2025-07-10 on
|
|
53
|
+
# https://bugs.ruby-lang.org/issues/19473), not a bug being patched, so
|
|
54
|
+
# this method rescues that specific error and runs +block+ without the
|
|
55
|
+
# lock rather than raising into a finalizer. Other +ThreadError+s (e.g.
|
|
56
|
+
# recursive locking) are re-raised.
|
|
57
|
+
#
|
|
58
|
+
# @yield Executes the block while holding the mutex.
|
|
59
|
+
# @return [Object] The return value of +block+.
|
|
60
|
+
def synchronize(&block)
|
|
61
|
+
MUTEX.synchronize(&block)
|
|
62
|
+
rescue ThreadError => e
|
|
63
|
+
if e.message.include?("trap context")
|
|
64
|
+
block.()
|
|
65
|
+
else
|
|
66
|
+
raise e
|
|
67
|
+
end
|
|
68
|
+
end
|
|
8
69
|
end
|
|
9
70
|
self.wrapped = {}
|
|
10
71
|
end
|
|
@@ -15,6 +76,8 @@ require 'mize/configure'
|
|
|
15
76
|
require 'mize/global_clear'
|
|
16
77
|
require 'mize/railtie' if defined? Rails
|
|
17
78
|
|
|
79
|
+
# Inject +memoize+ into every module so any class can opt in with a single
|
|
80
|
+
# +include Mize::Memoize+.
|
|
18
81
|
class ::Module
|
|
19
82
|
prepend Mize::Memoize
|
|
20
83
|
end
|
data/mize.gemspec
CHANGED
|
@@ -1,32 +1,34 @@
|
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
|
2
|
-
# stub: mize 0.
|
|
2
|
+
# stub: mize 0.7.0 ruby lib
|
|
3
3
|
|
|
4
4
|
Gem::Specification.new do |s|
|
|
5
5
|
s.name = "mize".freeze
|
|
6
|
-
s.version = "0.
|
|
6
|
+
s.version = "0.7.0".freeze
|
|
7
7
|
|
|
8
8
|
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
|
9
|
+
s.metadata = { "source_code_uri" => "https://github.com/flori/mize" } if s.respond_to? :metadata=
|
|
9
10
|
s.require_paths = ["lib".freeze]
|
|
10
11
|
s.authors = ["Florian Frank".freeze]
|
|
11
|
-
s.date = "
|
|
12
|
-
s.description = "Library that provides
|
|
12
|
+
s.date = "1980-01-02"
|
|
13
|
+
s.description = "Library that provides memoization for methods and functions for Ruby.".freeze
|
|
13
14
|
s.email = "flori@ping.de".freeze
|
|
14
15
|
s.extra_rdoc_files = ["README.md".freeze, "lib/mize.rb".freeze, "lib/mize/cache_methods.rb".freeze, "lib/mize/cache_protocol.rb".freeze, "lib/mize/configure.rb".freeze, "lib/mize/default_cache.rb".freeze, "lib/mize/global_clear.rb".freeze, "lib/mize/memoize.rb".freeze, "lib/mize/railtie.rb".freeze, "lib/mize/reload.rb".freeze, "lib/mize/version.rb".freeze]
|
|
15
|
-
s.files = [".all_images.yml".freeze, ".
|
|
16
|
+
s.files = [".all_images.yml".freeze, ".github/workflows/static.yml".freeze, ".gitignore".freeze, ".rspec".freeze, ".travis.yml".freeze, "CHANGES.md".freeze, "Gemfile".freeze, "LICENSE".freeze, "README.md".freeze, "Rakefile".freeze, "VERSION".freeze, "lib/mize.rb".freeze, "lib/mize/cache_methods.rb".freeze, "lib/mize/cache_protocol.rb".freeze, "lib/mize/configure.rb".freeze, "lib/mize/default_cache.rb".freeze, "lib/mize/global_clear.rb".freeze, "lib/mize/memoize.rb".freeze, "lib/mize/railtie.rb".freeze, "lib/mize/reload.rb".freeze, "lib/mize/version.rb".freeze, "mize.gemspec".freeze, "spec/mize/global_clear_spec.rb".freeze, "spec/mize/memoize_method_spec.rb".freeze, "spec/mize/memoize_reload_spec.rb".freeze, "spec/mize/version_spec.rb".freeze, "spec/mize_spec.rb".freeze, "spec/spec_helper.rb".freeze]
|
|
16
17
|
s.homepage = "https://github.com/flori/mize".freeze
|
|
17
18
|
s.licenses = ["MIT".freeze]
|
|
18
|
-
s.rdoc_options = ["--title".freeze, "Mize - Library that provides
|
|
19
|
+
s.rdoc_options = ["--title".freeze, "Mize - Library that provides memoization for methods and functions".freeze, "--main".freeze, "README.md".freeze]
|
|
19
20
|
s.required_ruby_version = Gem::Requirement.new(">= 2".freeze)
|
|
20
|
-
s.rubygems_version = "
|
|
21
|
-
s.summary = "Library that provides
|
|
22
|
-
s.test_files = ["spec/mize/global_clear_spec.rb".freeze, "spec/mize/memoize_method_spec.rb".freeze, "spec/mize/memoize_reload_spec.rb".freeze, "spec/mize/version_spec.rb".freeze, "spec/spec_helper.rb".freeze]
|
|
21
|
+
s.rubygems_version = "4.0.22".freeze
|
|
22
|
+
s.summary = "Library that provides memoization for methods and functions".freeze
|
|
23
|
+
s.test_files = ["spec/mize/global_clear_spec.rb".freeze, "spec/mize/memoize_method_spec.rb".freeze, "spec/mize/memoize_reload_spec.rb".freeze, "spec/mize/version_spec.rb".freeze, "spec/mize_spec.rb".freeze, "spec/spec_helper.rb".freeze]
|
|
23
24
|
|
|
24
25
|
s.specification_version = 4
|
|
25
26
|
|
|
26
|
-
s.add_development_dependency(%q<gem_hadar>.freeze, ["
|
|
27
|
+
s.add_development_dependency(%q<gem_hadar>.freeze, [">= 2.20.1".freeze])
|
|
27
28
|
s.add_development_dependency(%q<rake>.freeze, [">= 0".freeze])
|
|
28
29
|
s.add_development_dependency(%q<simplecov>.freeze, [">= 0".freeze])
|
|
29
30
|
s.add_development_dependency(%q<rspec>.freeze, [">= 0".freeze])
|
|
30
31
|
s.add_development_dependency(%q<yard>.freeze, [">= 0".freeze])
|
|
31
32
|
s.add_development_dependency(%q<all_images>.freeze, [">= 0".freeze])
|
|
33
|
+
s.add_development_dependency(%q<debug>.freeze, [">= 0".freeze])
|
|
32
34
|
end
|
data/spec/mize/version_spec.rb
CHANGED
data/spec/mize_spec.rb
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
describe Mize do
|
|
2
|
+
describe '.synchronize' do
|
|
3
|
+
it 'executes the block and returns its value' do
|
|
4
|
+
expect(described_class.synchronize { 42 }).to eq(42)
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
it 'is the same lock object as Mize::MUTEX' do
|
|
8
|
+
expect {
|
|
9
|
+
Mize::MUTEX.synchronize { Mize.synchronize { :x } }
|
|
10
|
+
}.to raise_error(ThreadError)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
if ENV['START_SIMPLECOV'].to_i == 1
|
|
2
|
-
require 'simplecov'
|
|
3
|
-
SimpleCov.start do
|
|
4
|
-
add_filter "#{File.basename(File.dirname(__FILE__))}/"
|
|
5
|
-
end
|
|
6
|
-
end
|
|
7
|
-
require 'rspec'
|
|
8
1
|
begin
|
|
9
|
-
require '
|
|
2
|
+
require 'gem_hadar/simplecov'
|
|
3
|
+
GemHadar::SimpleCov.start
|
|
10
4
|
rescue LoadError
|
|
11
5
|
end
|
|
6
|
+
require 'rspec'
|
|
12
7
|
require 'mize'
|
metadata
CHANGED
|
@@ -1,29 +1,28 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mize
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Florian Frank
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: gem_hadar
|
|
15
14
|
requirement: !ruby/object:Gem::Requirement
|
|
16
15
|
requirements:
|
|
17
|
-
- - "
|
|
16
|
+
- - ">="
|
|
18
17
|
- !ruby/object:Gem::Version
|
|
19
|
-
version:
|
|
18
|
+
version: 2.20.1
|
|
20
19
|
type: :development
|
|
21
20
|
prerelease: false
|
|
22
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
22
|
requirements:
|
|
24
|
-
- - "
|
|
23
|
+
- - ">="
|
|
25
24
|
- !ruby/object:Gem::Version
|
|
26
|
-
version:
|
|
25
|
+
version: 2.20.1
|
|
27
26
|
- !ruby/object:Gem::Dependency
|
|
28
27
|
name: rake
|
|
29
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -94,7 +93,21 @@ dependencies:
|
|
|
94
93
|
- - ">="
|
|
95
94
|
- !ruby/object:Gem::Version
|
|
96
95
|
version: '0'
|
|
97
|
-
|
|
96
|
+
- !ruby/object:Gem::Dependency
|
|
97
|
+
name: debug
|
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
|
99
|
+
requirements:
|
|
100
|
+
- - ">="
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
version: '0'
|
|
103
|
+
type: :development
|
|
104
|
+
prerelease: false
|
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
106
|
+
requirements:
|
|
107
|
+
- - ">="
|
|
108
|
+
- !ruby/object:Gem::Version
|
|
109
|
+
version: '0'
|
|
110
|
+
description: Library that provides memoization for methods and functions for Ruby.
|
|
98
111
|
email: flori@ping.de
|
|
99
112
|
executables: []
|
|
100
113
|
extensions: []
|
|
@@ -112,17 +125,16 @@ extra_rdoc_files:
|
|
|
112
125
|
- lib/mize/version.rb
|
|
113
126
|
files:
|
|
114
127
|
- ".all_images.yml"
|
|
128
|
+
- ".github/workflows/static.yml"
|
|
115
129
|
- ".gitignore"
|
|
116
130
|
- ".rspec"
|
|
117
|
-
- ".tool-versions"
|
|
118
131
|
- ".travis.yml"
|
|
119
|
-
-
|
|
132
|
+
- CHANGES.md
|
|
120
133
|
- Gemfile
|
|
134
|
+
- LICENSE
|
|
121
135
|
- README.md
|
|
122
136
|
- Rakefile
|
|
123
137
|
- VERSION
|
|
124
|
-
- config/broken_config.yml
|
|
125
|
-
- config/config.yml
|
|
126
138
|
- lib/mize.rb
|
|
127
139
|
- lib/mize/cache_methods.rb
|
|
128
140
|
- lib/mize/cache_protocol.rb
|
|
@@ -138,15 +150,16 @@ files:
|
|
|
138
150
|
- spec/mize/memoize_method_spec.rb
|
|
139
151
|
- spec/mize/memoize_reload_spec.rb
|
|
140
152
|
- spec/mize/version_spec.rb
|
|
153
|
+
- spec/mize_spec.rb
|
|
141
154
|
- spec/spec_helper.rb
|
|
142
155
|
homepage: https://github.com/flori/mize
|
|
143
156
|
licenses:
|
|
144
157
|
- MIT
|
|
145
|
-
metadata:
|
|
146
|
-
|
|
158
|
+
metadata:
|
|
159
|
+
source_code_uri: https://github.com/flori/mize
|
|
147
160
|
rdoc_options:
|
|
148
161
|
- "--title"
|
|
149
|
-
- Mize - Library that provides
|
|
162
|
+
- Mize - Library that provides memoization for methods and functions
|
|
150
163
|
- "--main"
|
|
151
164
|
- README.md
|
|
152
165
|
require_paths:
|
|
@@ -162,13 +175,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
162
175
|
- !ruby/object:Gem::Version
|
|
163
176
|
version: '0'
|
|
164
177
|
requirements: []
|
|
165
|
-
rubygems_version:
|
|
166
|
-
signing_key:
|
|
178
|
+
rubygems_version: 4.0.22
|
|
167
179
|
specification_version: 4
|
|
168
|
-
summary: Library that provides
|
|
180
|
+
summary: Library that provides memoization for methods and functions
|
|
169
181
|
test_files:
|
|
170
182
|
- spec/mize/global_clear_spec.rb
|
|
171
183
|
- spec/mize/memoize_method_spec.rb
|
|
172
184
|
- spec/mize/memoize_reload_spec.rb
|
|
173
185
|
- spec/mize/version_spec.rb
|
|
186
|
+
- spec/mize_spec.rb
|
|
174
187
|
- spec/spec_helper.rb
|
data/.tool-versions
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
ruby 3.3.4
|