stable 1.20.0 → 1.20.1
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/lib/stable/version.rb +1 -1
- data/lib/stable.rb +30 -2
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6e15bc20c1e3075bbcf961acf641350f5a86f28d344c4cdf10714d1f81e5cedb
|
4
|
+
data.tar.gz: 6c7e38b8cdb11d438057c612b7be9c7c0509ec627ff1702d5bb0a829cd4108f5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6f713c013b885c9297b227d46b8ee5195b4d38844f042a7c6df9706e605eaec397eceeac54cb40962df2f9cccef49ec617234f7abd42956026ecbd99e6d574bd
|
7
|
+
data.tar.gz: 59902723fb85cdde62aab42c994570d4f630f4373a046e90b6f955b2b6bbd296f091c63c06a0b0ce93671bfee8e1326addf6316858b48ac3a5ed850ba5fa1817
|
data/lib/stable/version.rb
CHANGED
data/lib/stable.rb
CHANGED
@@ -58,6 +58,34 @@ module Stable
|
|
58
58
|
@storage = nil
|
59
59
|
end
|
60
60
|
|
61
|
+
# This is the core method for observing a method on a class or module. It
|
62
|
+
# uses a dynamic module and `prepend` to intercept method calls without
|
63
|
+
# altering the original method.
|
64
|
+
#
|
65
|
+
# The design handles several complexities:
|
66
|
+
#
|
67
|
+
# 1. **Instance vs. Class Methods:** It accepts a `type` parameter to
|
68
|
+
# differentiate between instance and class methods. For class methods,
|
69
|
+
# it targets the singleton class (`klass.singleton_class`) to inject
|
70
|
+
# the wrapper.
|
71
|
+
#
|
72
|
+
# 2. **State Capture:** For instance methods, it captures the object's state
|
73
|
+
# (instance variables) *before* the method is called. This `prior` state
|
74
|
+
# is crucial for rehydrating the object during verification. State is not
|
75
|
+
# captured for class methods to prevent infinite loops, as the recording
|
76
|
+
# process itself may call class methods (e.g., `.name`).
|
77
|
+
#
|
78
|
+
# 3. **Method Binding:** It correctly handles both bound (`Method`) and
|
79
|
+
# unbound (`UnboundMethod`) method objects, ensuring `self` is correctly
|
80
|
+
# bound when the original method is eventually called.
|
81
|
+
#
|
82
|
+
# 4. **Fact Creation:** It gathers all relevant data—class name, method name,
|
83
|
+
# arguments, prior state, and the result or error—into a `Fact` object.
|
84
|
+
#
|
85
|
+
# 5. **Duplicate Prevention:** It generates a signature for each potential
|
86
|
+
# fact and checks if a fact with the same signature has already been
|
87
|
+
# recorded to prevent creating duplicate entries.
|
88
|
+
#
|
61
89
|
def watch(klass, method_name, type: :instance)
|
62
90
|
original_method = type == :instance ? klass.instance_method(method_name) : klass.method(method_name)
|
63
91
|
target = type == :instance ? klass : klass.singleton_class
|
@@ -66,7 +94,7 @@ module Stable
|
|
66
94
|
define_method(method_name) do |*args, **kwargs, &block|
|
67
95
|
if Stable.enabled?
|
68
96
|
begin
|
69
|
-
prior = Stable.send(:_capture_state, self)
|
97
|
+
prior = type == :instance ? Stable.send(:_capture_state, self) : nil
|
70
98
|
result = original_method.is_a?(UnboundMethod) ? original_method.bind(self).call(*args, **kwargs, &block) : original_method.call(*args, **kwargs, &block)
|
71
99
|
fact = Fact.new(
|
72
100
|
class_name: klass.name,
|
@@ -84,7 +112,7 @@ module Stable
|
|
84
112
|
end
|
85
113
|
result
|
86
114
|
rescue => e
|
87
|
-
prior = Stable.send(:_capture_state, self)
|
115
|
+
prior = type == :instance ? Stable.send(:_capture_state, self) : nil
|
88
116
|
fact = Fact.new(
|
89
117
|
class_name: klass.name,
|
90
118
|
method_name: method_name,
|