typed_cache 0.1.1 → 0.2.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
- checksums.yaml.gz.sig +0 -0
- data/README.md +116 -19
- data/examples.md +106 -50
- data/lib/typed_cache/backends/memory.rb +9 -6
- data/lib/typed_cache/backends.rb +6 -8
- data/lib/typed_cache/cache_builder.rb +72 -19
- data/lib/typed_cache/cache_key.rb +2 -0
- data/lib/typed_cache/cache_ref.rb +4 -0
- data/lib/typed_cache/clock.rb +31 -14
- data/lib/typed_cache/decorator.rb +17 -0
- data/lib/typed_cache/{store → decorators}/instrumented.rb +19 -23
- data/lib/typed_cache/decorators.rb +7 -3
- data/lib/typed_cache/errors.rb +9 -1
- data/lib/typed_cache/instrumenter.rb +43 -0
- data/lib/typed_cache/instrumenters/active_support.rb +28 -0
- data/lib/typed_cache/instrumenters/mixins/namespaced_singleton.rb +52 -0
- data/lib/typed_cache/instrumenters/mixins.rb +8 -0
- data/lib/typed_cache/instrumenters/monitor.rb +27 -0
- data/lib/typed_cache/instrumenters/null.rb +26 -0
- data/lib/typed_cache/instrumenters.rb +38 -0
- data/lib/typed_cache/registry.rb +15 -0
- data/lib/typed_cache/store.rb +3 -0
- data/lib/typed_cache/version.rb +1 -1
- data/lib/typed_cache.rb +30 -14
- data/sig/generated/typed_cache/backends.rbs +2 -0
- data/sig/generated/typed_cache/cache_builder.rbs +13 -2
- data/sig/generated/typed_cache/clock.rbs +19 -9
- data/sig/generated/typed_cache/decorator.rbs +8 -0
- data/sig/generated/typed_cache/decorators/instrumented.rbs +35 -0
- data/sig/generated/typed_cache/decorators.rbs +2 -0
- data/sig/generated/typed_cache/errors.rbs +2 -0
- data/sig/generated/typed_cache/instrumenter.rbs +31 -0
- data/sig/generated/typed_cache/instrumenters/active_support.rbs +20 -0
- data/sig/generated/typed_cache/instrumenters/mixins/namespaced_singleton.rbs +33 -0
- data/sig/generated/typed_cache/instrumenters/mixins.rbs +8 -0
- data/sig/generated/typed_cache/instrumenters/monitor.rbs +19 -0
- data/sig/generated/typed_cache/instrumenters/null.rbs +21 -0
- data/sig/generated/typed_cache/instrumenters.rbs +24 -0
- data/sig/generated/typed_cache/registry.rbs +8 -0
- data/sig/generated/typed_cache/store/instrumented.rbs +2 -6
- data/sig/generated/typed_cache/store.rbs +3 -0
- data/sig/generated/typed_cache.rbs +6 -6
- data/typed_cache.gemspec +4 -3
- data.tar.gz.sig +0 -0
- metadata +25 -27
- metadata.gz.sig +0 -0
- data/lib/typed_cache/instrumentation.rb +0 -112
- data/sig/generated/typed_cache/instrumentation.rbs +0 -30
- data/sig/handwritten/gems/zeitwerk/2.7/zeitwerk.rbs +0 -9
data/lib/typed_cache/clock.rb
CHANGED
@@ -1,22 +1,39 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'dry/struct'
|
4
|
+
require 'dry/types'
|
5
|
+
|
3
6
|
module TypedCache
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
+
module Clock
|
8
|
+
# @rbs generic R
|
9
|
+
class Measured < Dry::Struct
|
10
|
+
# @rbs! def start: () -> Float
|
11
|
+
# @rbs! def end: () -> Float
|
12
|
+
# @rbs! def result: () -> [R]
|
13
|
+
|
14
|
+
attribute :start, Dry.Types::Float
|
15
|
+
attribute :end, Dry.Types::Float
|
16
|
+
attribute :result, Dry.Types.Instance(Object) #: [R]
|
17
|
+
|
18
|
+
# @rbs! def initialize: (start: Float, end: Float, result: [R]) -> void
|
19
|
+
|
20
|
+
#: -> Float
|
21
|
+
def duration
|
22
|
+
self.end - start
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
7
26
|
class << self
|
8
|
-
#
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
27
|
+
# @rbs [R]() { () -> R } -> Measured[R]
|
28
|
+
def measure(&)
|
29
|
+
start = now
|
30
|
+
result = yield
|
31
|
+
Measured.new(start:, end: now, result:)
|
32
|
+
end
|
33
|
+
|
13
34
|
# @rbs () -> Time
|
14
|
-
def
|
15
|
-
|
16
|
-
Time.current
|
17
|
-
else
|
18
|
-
Time.now
|
19
|
-
end
|
35
|
+
def now
|
36
|
+
Time.now
|
20
37
|
end
|
21
38
|
end
|
22
39
|
end
|
@@ -1,12 +1,29 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'forwardable'
|
4
|
+
|
3
5
|
module TypedCache
|
4
6
|
# Marker mixin for cache store decorators. A decorator behaves exactly like a
|
5
7
|
# Store but must accept another Store instance in its constructor.
|
6
8
|
# @rbs generic V
|
7
9
|
module Decorator
|
10
|
+
extend Forwardable
|
11
|
+
|
8
12
|
include Store #[V]
|
9
13
|
# @rbs! include Store::_Store[V]
|
10
14
|
# @rbs! include Store::_Decorator[V]
|
15
|
+
|
16
|
+
# @rbs!
|
17
|
+
# def store: -> Store[V]
|
18
|
+
|
19
|
+
Store.instance_methods(false).each do |method_name|
|
20
|
+
def_delegator :store, method_name
|
21
|
+
end
|
22
|
+
|
23
|
+
# @rbs override
|
24
|
+
#: (cache_key) -> either[Error, CacheRef[V]]
|
25
|
+
def ref(key)
|
26
|
+
CacheRef.new(self, key)
|
27
|
+
end
|
11
28
|
end
|
12
29
|
end
|
@@ -4,40 +4,42 @@ module TypedCache
|
|
4
4
|
# Decorator that adds instrumentation to any Store implementation
|
5
5
|
# This decorator can wrap any store to add ActiveSupport::Notifications
|
6
6
|
# @rbs generic V
|
7
|
-
class
|
7
|
+
class Decorators::Instrumented # rubocop:disable Style/ClassAndModuleChildren
|
8
8
|
include Decorator #[V]
|
9
9
|
|
10
10
|
extend Forwardable
|
11
11
|
|
12
12
|
attr_reader :store #: TypedCache::Store[V]
|
13
|
+
attr_reader :instrumenter #: Instrumenter
|
13
14
|
|
14
15
|
class << self
|
15
16
|
private
|
16
17
|
|
17
18
|
# @rbs (Symbol, ?operation: String) ?{ (*untyped, **untyped) -> String } -> void
|
18
19
|
def instrument(method_name, operation: method_name.to_s, &key_selector)
|
19
|
-
|
20
|
-
|
20
|
+
key_selector ||= ->(*_args, **_kwargs, &_block) { 'n/a' }
|
21
|
+
alias_prefix = method_name.to_s.delete('?!')
|
21
22
|
|
22
|
-
|
23
|
-
|
23
|
+
define_method(:"#{alias_prefix}_instrumentation_key", &key_selector)
|
24
|
+
|
25
|
+
class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
|
26
|
+
def #{alias_prefix}_with_instrumentation(...)
|
27
|
+
key = #{alias_prefix}_instrumentation_key(...)
|
28
|
+
instrumenter.instrument(:"#{operation}", key, store_type: store_type) do
|
29
|
+
#{alias_prefix}_without_instrumentation(...)
|
30
|
+
end
|
24
31
|
end
|
25
|
-
|
32
|
+
RUBY
|
26
33
|
|
27
|
-
alias_method(:"#{
|
28
|
-
alias_method(method_name, :"#{
|
34
|
+
alias_method(:"#{alias_prefix}_without_instrumentation", method_name)
|
35
|
+
alias_method(method_name, :"#{alias_prefix}_with_instrumentation")
|
29
36
|
end
|
30
37
|
end
|
31
38
|
|
32
|
-
#: (TypedCache::Store[V]) -> void
|
33
|
-
def initialize(store)
|
39
|
+
#: (TypedCache::Store[V], instrumenter: Instrumenter) -> void
|
40
|
+
def initialize(store, instrumenter:)
|
34
41
|
@store = store
|
35
|
-
|
36
|
-
|
37
|
-
# @rbs override
|
38
|
-
#: -> String
|
39
|
-
def namespace
|
40
|
-
store.namespace
|
42
|
+
@instrumenter = instrumenter
|
41
43
|
end
|
42
44
|
|
43
45
|
# @rbs override
|
@@ -48,7 +50,7 @@ module TypedCache
|
|
48
50
|
end
|
49
51
|
|
50
52
|
# @rbs override
|
51
|
-
|
53
|
+
# @rbs (key) -> CacheRef[V]
|
52
54
|
def ref(key)
|
53
55
|
CacheRef.new(self, key)
|
54
56
|
end
|
@@ -66,12 +68,6 @@ module TypedCache
|
|
66
68
|
end
|
67
69
|
end
|
68
70
|
|
69
|
-
Store.instance_methods(false).each do |method_name|
|
70
|
-
next if instance_methods(false).include?(method_name)
|
71
|
-
|
72
|
-
def_delegator :store, method_name
|
73
|
-
end
|
74
|
-
|
75
71
|
# Instrument core operations with proper key extraction
|
76
72
|
instrument(:get) { |key, *_| key }
|
77
73
|
instrument(:set) { |key, *_| key }
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'typed_cache/registry'
|
4
|
+
|
3
5
|
module TypedCache
|
4
6
|
# Holds store decorators (e.g., instrumentation wrappers) that can be composed
|
5
7
|
# by the CacheBuilder. Decorators must conform to the same API as the wrapped
|
@@ -14,20 +16,22 @@ module TypedCache
|
|
14
16
|
# .build.value
|
15
17
|
#
|
16
18
|
module Decorators
|
19
|
+
autoload :Instrumented, 'typed_cache/decorators/instrumented'
|
20
|
+
|
21
|
+
# @api private
|
17
22
|
# Default decorator set – starts with instrumentation only, but this registry
|
18
23
|
# lets end-users register their own via `Decorators.register`.
|
19
24
|
REGISTRY = Registry.new('decorator', {
|
20
|
-
instrumented:
|
25
|
+
instrumented: Instrumented,
|
21
26
|
}).freeze
|
22
27
|
|
23
|
-
private_constant :REGISTRY
|
24
|
-
|
25
28
|
class << self
|
26
29
|
extend Forwardable
|
27
30
|
|
28
31
|
# Delegate common registry helpers
|
29
32
|
delegate [:resolve, :register, :available, :registered?] => :registry
|
30
33
|
|
34
|
+
# @api private
|
31
35
|
# @rbs () -> Registry[Store[untyped]]
|
32
36
|
def registry = REGISTRY
|
33
37
|
end
|
data/lib/typed_cache/errors.rb
CHANGED
@@ -2,7 +2,13 @@
|
|
2
2
|
|
3
3
|
module TypedCache
|
4
4
|
# Base error class for TypedCache operations
|
5
|
-
class Error < StandardError
|
5
|
+
class Error < StandardError
|
6
|
+
# @rbs (*untyped) -> void
|
7
|
+
def initialize(*args)
|
8
|
+
super(*args)
|
9
|
+
set_backtrace(caller(2))
|
10
|
+
end
|
11
|
+
end
|
6
12
|
|
7
13
|
# Store operation errors (network, I/O, etc.)
|
8
14
|
class StoreError < Error
|
@@ -14,6 +20,8 @@ module TypedCache
|
|
14
20
|
@operation = operation
|
15
21
|
@key = key
|
16
22
|
@original_error = original_error
|
23
|
+
|
24
|
+
set_backtrace(original_error.backtrace) if original_error
|
17
25
|
end
|
18
26
|
|
19
27
|
# @rbs () -> String
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TypedCache
|
4
|
+
# Instrumenter for cache operations
|
5
|
+
module Instrumenter
|
6
|
+
# @rbs! type event = Dry::Events::Event | ActiveSupport::Notifications::Event
|
7
|
+
|
8
|
+
# @rbs [R](String, String, **untyped) { -> R } -> R
|
9
|
+
def instrument(event_name, key, **payload)
|
10
|
+
raise NotImplementedError, "#{self.class} must implement #instrument"
|
11
|
+
end
|
12
|
+
|
13
|
+
# @rbs (String, **untyped) { (event) -> void } -> void
|
14
|
+
def subscribe(event_name, **filters, &block)
|
15
|
+
raise NotImplementedError, "#{self.class} must implement #subscribe"
|
16
|
+
end
|
17
|
+
|
18
|
+
#: -> String
|
19
|
+
def namespace
|
20
|
+
config.namespace
|
21
|
+
end
|
22
|
+
|
23
|
+
# @rbs (String, String, **untyped) -> Hash[Symbol, untyped]
|
24
|
+
def build_payload(operation, key, **payload)
|
25
|
+
{ namespace:, key:, operation: }.merge(payload)
|
26
|
+
end
|
27
|
+
|
28
|
+
# @rbs () -> bool
|
29
|
+
def enabled? = config.enabled
|
30
|
+
|
31
|
+
# @rbs (String) -> String
|
32
|
+
def event_name(operation)
|
33
|
+
"#{namespace}.#{operation}"
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
# @rbs () -> TypedCache::_TypedCacheInstrumentationConfig
|
39
|
+
def config
|
40
|
+
TypedCache.config.instrumentation
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/notifications'
|
4
|
+
|
5
|
+
module TypedCache
|
6
|
+
module Instrumenters
|
7
|
+
# Instrumenter for ActiveSupport::Notifications
|
8
|
+
class ActiveSupport
|
9
|
+
include Instrumenter
|
10
|
+
include Mixins::NamespacedSingleton
|
11
|
+
|
12
|
+
# @rbs override
|
13
|
+
#: [R] (String, String, Hash[Symbol, untyped]) { -> R } -> R
|
14
|
+
def instrument(operation, key, **payload, &block)
|
15
|
+
return yield unless enabled?
|
16
|
+
|
17
|
+
payload = build_payload(operation, key, **payload)
|
18
|
+
::ActiveSupport::Notifications.instrument(event_name(operation), **payload, &block)
|
19
|
+
end
|
20
|
+
|
21
|
+
# @rbs override
|
22
|
+
# @rbs (String, **top) { (event) -> void } -> void
|
23
|
+
def subscribe(operation, **filters, &block)
|
24
|
+
::ActiveSupport::Notifications.monotonic_subscribe(event_name(operation), &block)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TypedCache
|
4
|
+
module Instrumenters
|
5
|
+
module Mixins
|
6
|
+
module NamespacedSingleton
|
7
|
+
class << self
|
8
|
+
# @rbs () -> Array[Class[Instrumenter & NamespacedSingleton]]
|
9
|
+
def all = @all ||= [] # rubocop:disable ThreadSafety
|
10
|
+
|
11
|
+
# @rbs (Class[Instrumenter & NamespacedSingleton]) -> void
|
12
|
+
def included(base)
|
13
|
+
base.singleton_class.class_eval do
|
14
|
+
alias private_new new
|
15
|
+
private(:private_new)
|
16
|
+
end
|
17
|
+
|
18
|
+
base.extend(ClassMethods)
|
19
|
+
|
20
|
+
all << base
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# @rbs override
|
25
|
+
# @rbs () -> String
|
26
|
+
def namespace
|
27
|
+
@namespace
|
28
|
+
end
|
29
|
+
|
30
|
+
# @rbs (String | Namespace) -> void
|
31
|
+
def initialize(namespace)
|
32
|
+
@namespace = namespace.to_s
|
33
|
+
end
|
34
|
+
|
35
|
+
module ClassMethods
|
36
|
+
# @rbs (String | Namespace) -> class
|
37
|
+
def new(namespace: TypedCache.config.instrumentation.namespace)
|
38
|
+
namespace_cache.compute_if_absent(namespace.to_s) { private_new(namespace) }
|
39
|
+
end
|
40
|
+
|
41
|
+
# @rbs (String) -> maybe[class]
|
42
|
+
def get(namespace)
|
43
|
+
namespace_cache.get(namespace.to_s)
|
44
|
+
end
|
45
|
+
|
46
|
+
# @rbs () -> Concurrent::Map[String, Class[Instrumenter & NamespacedSingleton]]
|
47
|
+
def namespace_cache = @namespace_cache ||= Concurrent::Map.new # rubocop:disable ThreadSafety
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'dry/monitor'
|
4
|
+
|
5
|
+
module TypedCache
|
6
|
+
module Instrumenters
|
7
|
+
class Monitor
|
8
|
+
include Instrumenter
|
9
|
+
include Mixins::NamespacedSingleton
|
10
|
+
|
11
|
+
# @rbs override
|
12
|
+
#: [R] (String, String, **untyped) { -> R } -> R
|
13
|
+
def instrument(operation, key, **payload, &block)
|
14
|
+
return yield unless enabled?
|
15
|
+
|
16
|
+
payload = build_payload(operation, key, **payload)
|
17
|
+
Dry::Monitor::Notifications.instrument(event_name(operation), payload, &block)
|
18
|
+
end
|
19
|
+
|
20
|
+
# @rbs override
|
21
|
+
# @rbs (String, **top) { (event) -> void } -> void
|
22
|
+
def subscribe(operation, **filters, &block)
|
23
|
+
Dry::Monitor::Notifications.subscribe(event_name(operation), **filters, &block)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'singleton'
|
4
|
+
|
5
|
+
module TypedCache
|
6
|
+
module Instrumenters
|
7
|
+
# A no-op implementation used when instrumentation is disabled.
|
8
|
+
# It fulfils the Instrumenter contract but simply yields.
|
9
|
+
class Null
|
10
|
+
include Instrumenter
|
11
|
+
include Mixins::NamespacedSingleton
|
12
|
+
|
13
|
+
# @rbs override
|
14
|
+
# [R] (String, String, **untyped) { -> R } -> R
|
15
|
+
def instrument(_operation, _key, **_payload)
|
16
|
+
yield
|
17
|
+
end
|
18
|
+
|
19
|
+
# @rbs override
|
20
|
+
# @rbs (String, **top) { (event) -> void } -> void
|
21
|
+
def subscribe(_event_name, **_filters, &_block)
|
22
|
+
# no-op
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'typed_cache/instrumenters/mixins'
|
4
|
+
require 'typed_cache/instrumenters/mixins/namespaced_singleton'
|
5
|
+
|
6
|
+
module TypedCache
|
7
|
+
module Instrumenters
|
8
|
+
autoload :ActiveSupport, 'typed_cache/instrumenters/active_support'
|
9
|
+
autoload :Monitor, 'typed_cache/instrumenters/monitor'
|
10
|
+
autoload :Null, 'typed_cache/instrumenters/null'
|
11
|
+
|
12
|
+
# @api private
|
13
|
+
# Registry mapping symbols to instrumenter classes. We can't reuse the generic
|
14
|
+
# Registry class directly because many instrumenters mix in `Singleton`,
|
15
|
+
# making `.new` inaccessible. Instead we implement a thin facade that
|
16
|
+
# returns either the singleton instance (preferred) or a fresh instance.
|
17
|
+
REGISTRY = Registry.new('instrumenter', {
|
18
|
+
dry: Monitor,
|
19
|
+
rails: ActiveSupport,
|
20
|
+
default: Null,
|
21
|
+
null: Null,
|
22
|
+
}) #: Registry[Symbol, Class[Instrumenter]]
|
23
|
+
|
24
|
+
class << self
|
25
|
+
extend Forwardable
|
26
|
+
|
27
|
+
# @api private
|
28
|
+
# @rbs () -> Registry[Symbol, Class[Instrumenter]]
|
29
|
+
def registry = REGISTRY
|
30
|
+
|
31
|
+
# @rbs! def resolve: (Symbol, **untyped) -> either[Error, Instrumenter]
|
32
|
+
# @rbs! def available: () -> Array[Symbol]
|
33
|
+
# @rbs! def registered?: (Symbol) -> Boolean
|
34
|
+
|
35
|
+
def_delegators :registry, :resolve, :available, :registered?
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/typed_cache/registry.rb
CHANGED
@@ -10,6 +10,17 @@ module TypedCache
|
|
10
10
|
@registry = defaults.dup
|
11
11
|
end
|
12
12
|
|
13
|
+
# @rbs (Registry[T]) -> Registry[T]
|
14
|
+
def initialize_copy(other)
|
15
|
+
super
|
16
|
+
@registry = other.registry.dup
|
17
|
+
end
|
18
|
+
|
19
|
+
# @rbs () -> void
|
20
|
+
def clear
|
21
|
+
@registry.clear
|
22
|
+
end
|
23
|
+
|
13
24
|
# @rbs (Symbol, *untyped, **untyped) -> either[Error, T]
|
14
25
|
def resolve(key, *, **, &)
|
15
26
|
klass = @registry[key]
|
@@ -51,5 +62,9 @@ module TypedCache
|
|
51
62
|
def registered?(key)
|
52
63
|
@registry.key?(key)
|
53
64
|
end
|
65
|
+
|
66
|
+
protected
|
67
|
+
|
68
|
+
attr_reader :registry #: Hash[Symbol, Class[T]]
|
54
69
|
end
|
55
70
|
end
|
data/lib/typed_cache/store.rb
CHANGED
data/lib/typed_cache/version.rb
CHANGED
data/lib/typed_cache.rb
CHANGED
@@ -1,18 +1,35 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
4
|
-
require 'dry
|
5
|
-
require '
|
3
|
+
require 'dry/configurable'
|
4
|
+
require 'dry/struct'
|
5
|
+
require 'dry/types'
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
require_relative 'typed_cache/errors'
|
7
|
+
require 'typed_cache/either'
|
8
|
+
require 'typed_cache/maybe'
|
10
9
|
|
11
|
-
|
10
|
+
require 'typed_cache/cache_key'
|
11
|
+
require 'typed_cache/errors'
|
12
|
+
require 'typed_cache/namespace'
|
13
|
+
require 'typed_cache/registry'
|
14
|
+
require 'typed_cache/clock'
|
15
|
+
|
16
|
+
require 'typed_cache/store'
|
17
|
+
require 'typed_cache/instrumenter'
|
18
|
+
require 'typed_cache/backend'
|
19
|
+
require 'typed_cache/decorator'
|
20
|
+
|
21
|
+
require 'typed_cache/snapshot'
|
22
|
+
require 'typed_cache/cache_ref'
|
23
|
+
|
24
|
+
require 'typed_cache/cache_builder'
|
12
25
|
|
13
26
|
module TypedCache
|
14
27
|
extend Dry::Configurable
|
15
28
|
|
29
|
+
autoload :Backends, 'typed_cache/backends'
|
30
|
+
autoload :Decorators, 'typed_cache/decorators'
|
31
|
+
autoload :Instrumenters, 'typed_cache/instrumenters'
|
32
|
+
|
16
33
|
# @rbs!
|
17
34
|
# interface _TypedCacheInstrumentationConfig
|
18
35
|
# def enabled: -> bool
|
@@ -33,6 +50,7 @@ module TypedCache
|
|
33
50
|
setting :instrumentation do
|
34
51
|
setting :enabled, default: false
|
35
52
|
setting :namespace, default: 'typed_cache'
|
53
|
+
setting :instrumenter, default: :default
|
36
54
|
end
|
37
55
|
|
38
56
|
class << self
|
@@ -44,15 +62,13 @@ module TypedCache
|
|
44
62
|
|
45
63
|
# @rbs! def config: -> _TypedCacheConfig
|
46
64
|
|
47
|
-
# @rbs () -> singleton(
|
48
|
-
def instrumentation
|
49
|
-
Instrumentation
|
50
|
-
end
|
51
|
-
|
52
|
-
# @rbs () -> Registry[backend[untyped]]
|
65
|
+
# @rbs () -> singleton(Backends)
|
53
66
|
def backends = Backends
|
54
67
|
|
55
|
-
# @rbs () ->
|
68
|
+
# @rbs () -> singleton(Decorators)
|
56
69
|
def decorators = Decorators
|
70
|
+
|
71
|
+
# @rbs () -> singleton(Instrumenters)
|
72
|
+
def instrumenters = Instrumenters
|
57
73
|
end
|
58
74
|
end
|
@@ -4,6 +4,14 @@ module TypedCache
|
|
4
4
|
class CacheBuilder
|
5
5
|
type config = TypedCache::typed_cache_config
|
6
6
|
|
7
|
+
type instrumenter_source = :default | :dry | :rails | Instrumenter
|
8
|
+
|
9
|
+
class BackendConfig < Dry::Struct
|
10
|
+
end
|
11
|
+
|
12
|
+
class DecoratorConfig < Dry::Struct
|
13
|
+
end
|
14
|
+
|
7
15
|
# @rbs (config, Registry[backend[untyped]], Registry[decorator[untyped]]) -> void
|
8
16
|
def initialize: (config, Registry[backend[untyped]], Registry[decorator[untyped]]) -> void
|
9
17
|
|
@@ -20,8 +28,9 @@ module TypedCache
|
|
20
28
|
# @rbs (Symbol) -> self
|
21
29
|
def with_decorator: (Symbol) -> self
|
22
30
|
|
23
|
-
#
|
24
|
-
|
31
|
+
# Adds instrumentation using the specified strategy.
|
32
|
+
# @rbs (instrumenter_source) -> either[Error, self]
|
33
|
+
def with_instrumentation: (instrumenter_source) -> either[Error, self]
|
25
34
|
|
26
35
|
private
|
27
36
|
|
@@ -33,5 +42,7 @@ module TypedCache
|
|
33
42
|
|
34
43
|
# @rbs (Store[V]) -> either[Error, Store[V]]
|
35
44
|
def apply_decorators: (Store[V]) -> either[Error, Store[V]]
|
45
|
+
|
46
|
+
def apply_instrumentation: (untyped store) -> untyped
|
36
47
|
end
|
37
48
|
end
|
@@ -1,15 +1,25 @@
|
|
1
1
|
# Generated from lib/typed_cache/clock.rb with RBS::Inline
|
2
2
|
|
3
3
|
module TypedCache
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
4
|
+
module Clock
|
5
|
+
# @rbs generic R
|
6
|
+
class Measured[R] < Dry::Struct
|
7
|
+
def start: () -> Float
|
8
|
+
|
9
|
+
def end: () -> Float
|
10
|
+
|
11
|
+
def result: () -> [ R ]
|
12
|
+
|
13
|
+
def initialize: (start: Float, end: Float, result: [ R ]) -> void
|
14
|
+
|
15
|
+
# : -> Float
|
16
|
+
def duration: () -> Float
|
17
|
+
end
|
18
|
+
|
19
|
+
# @rbs [R]() { () -> R } -> Measured[R]
|
20
|
+
def self.measure: [R] () { () -> R } -> Measured[R]
|
21
|
+
|
12
22
|
# @rbs () -> Time
|
13
|
-
def self.
|
23
|
+
def self.now: () -> Time
|
14
24
|
end
|
15
25
|
end
|
@@ -5,10 +5,18 @@ module TypedCache
|
|
5
5
|
# Store but must accept another Store instance in its constructor.
|
6
6
|
# @rbs generic V
|
7
7
|
module Decorator[V]
|
8
|
+
extend Forwardable
|
9
|
+
|
8
10
|
include Store[V]
|
9
11
|
|
10
12
|
include Store::_Store[V]
|
11
13
|
|
12
14
|
include Store::_Decorator[V]
|
15
|
+
|
16
|
+
def store: () -> Store[V]
|
17
|
+
|
18
|
+
# @rbs override
|
19
|
+
# : (cache_key) -> either[Error, CacheRef[V]]
|
20
|
+
def ref: ...
|
13
21
|
end
|
14
22
|
end
|