monkey_bars 0.1.2 → 0.2.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/README.md +30 -0
- data/docs/llm-usage.md +64 -0
- data/lib/monkey_bars/errors.rb +54 -0
- data/lib/monkey_bars/validation.rb +94 -2
- data/lib/monkey_bars/version.rb +1 -1
- data/lib/monkey_bars.rb +6 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 959654729be5d09d997d89340df3d00652a0a39f962cbf0f87a3223a24b22195
|
|
4
|
+
data.tar.gz: b36eaea242ef45cb939040f6436af3ed3f9cb806f261141ab5c68e9ba7c24967
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5084d4cc7c224bf0fcf5eeaae3aa02da22ea2b5cac93e8561983bb1d1d3d61a371f7a5401d319117b9efce894ff2e85c1f908a7e2a8777d585791160a4959359
|
|
7
|
+
data.tar.gz: 4633ed06204dd319134fd7c05ff437c649c1c441ab890abe4b3c51b38bcc02c0bc976c41f7e634d17b9bc461b2d0294007bc055f82fa8c71b47e4770322eacd2
|
data/README.md
CHANGED
|
@@ -73,6 +73,7 @@ declared inside a block and then applied with `patch` (immediately) or
|
|
|
73
73
|
- `patch!` applies a prepared patch
|
|
74
74
|
|
|
75
75
|
If `patch!` runs without any methods or constants defined, it emits a warning.
|
|
76
|
+
Calling `prepare_for_patching` or `patch!` more than once raises an error.
|
|
76
77
|
|
|
77
78
|
The `monkey` can be:
|
|
78
79
|
|
|
@@ -96,6 +97,30 @@ You can call any of these helpers multiple times; MonkeyBars will combine them.
|
|
|
96
97
|
This is helpful when you want to ignore some arity check errors (see below) for
|
|
97
98
|
some methods but not others.
|
|
98
99
|
|
|
100
|
+
When patching existing methods, visibility must match the target method exactly.
|
|
101
|
+
If the target is public, keep the patch method public. If the target is
|
|
102
|
+
protected/private, mark the patch method as protected/private in the block.
|
|
103
|
+
|
|
104
|
+
```ruby
|
|
105
|
+
patch_instance_methods do
|
|
106
|
+
private
|
|
107
|
+
|
|
108
|
+
def internal_token
|
|
109
|
+
"#{super}-patched"
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
```ruby
|
|
115
|
+
patch_instance_methods do
|
|
116
|
+
def internal_token(*args)
|
|
117
|
+
super(*args)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
protected :internal_token
|
|
121
|
+
end
|
|
122
|
+
```
|
|
123
|
+
|
|
99
124
|
### Method arity checks
|
|
100
125
|
|
|
101
126
|
When patching existing methods, arity must match by default. You can opt out:
|
|
@@ -209,11 +234,16 @@ MonkeyBars raises specific errors to keep patches safe and explicit:
|
|
|
209
234
|
- `MonkeyBars::NoPatchableClassMethodFoundError`
|
|
210
235
|
- `MonkeyBars::MismatchedInstanceMethodArityError`
|
|
211
236
|
- `MonkeyBars::MismatchedClassMethodArityError`
|
|
237
|
+
- `MonkeyBars::PatchableInstanceMethodIsPrivateError`
|
|
238
|
+
- `MonkeyBars::PatchableInstanceMethodIsNotPrivateError`
|
|
239
|
+
- `MonkeyBars::PatchableClassMethodIsPrivateError`
|
|
240
|
+
- `MonkeyBars::PatchableClassMethodIsNotPrivateError`
|
|
212
241
|
- `MonkeyBars::NewInstanceMethodAlreadyExistsError`
|
|
213
242
|
- `MonkeyBars::NewClassMethodAlreadyExistsError`
|
|
214
243
|
- `MonkeyBars::PatchConstantNotFoundError`
|
|
215
244
|
- `MonkeyBars::NewConstantAlreadyExistsError`
|
|
216
245
|
- `MonkeyBars::PatchAlreadyPerformedError`
|
|
246
|
+
- `MonkeyBars::PrepareForPatchingAlreadyPerformedError`
|
|
217
247
|
|
|
218
248
|
## Development
|
|
219
249
|
|
data/docs/llm-usage.md
CHANGED
|
@@ -46,6 +46,8 @@ compares it with `version` using exact equality. Mismatches raise
|
|
|
46
46
|
- `prepare_for_patching(...)` validates and stores the patch.
|
|
47
47
|
- `patch!` applies a previously prepared patch and can only be called once.
|
|
48
48
|
|
|
49
|
+
Calling `prepare_for_patching` more than once raises
|
|
50
|
+
`MonkeyBars::PrepareForPatchingAlreadyPerformedError`.
|
|
49
51
|
Calling `patch!` more than once raises `MonkeyBars::PatchAlreadyPerformedError`.
|
|
50
52
|
|
|
51
53
|
## API reference
|
|
@@ -86,6 +88,14 @@ Overrides existing instance methods via `prepend`.
|
|
|
86
88
|
- Error: `MonkeyBars::NoPatchableInstanceMethodFoundError` if method does not exist.
|
|
87
89
|
- Error: `MonkeyBars::MismatchedInstanceMethodArityError` when arity differs,
|
|
88
90
|
unless `ignore_arity_errors: true` is set.
|
|
91
|
+
- Error: `MonkeyBars::PatchableInstanceMethodIsPrivateError` when the target
|
|
92
|
+
method is private but the patch method is defined as public/protected.
|
|
93
|
+
- Error: `MonkeyBars::PatchableInstanceMethodIsNotPrivateError` when the target
|
|
94
|
+
method is public/protected but the patch method is marked `private`.
|
|
95
|
+
- Error: `MonkeyBars::PatchableInstanceMethodIsProtectedError` when the target
|
|
96
|
+
method is protected but the patch method is defined as public/private.
|
|
97
|
+
- Error: `MonkeyBars::PatchableInstanceMethodIsNotProtectedError` when the target
|
|
98
|
+
method is public/private but the patch method is marked `protected`.
|
|
89
99
|
- `include_super_super: true` makes `#super_super` available for these methods.
|
|
90
100
|
|
|
91
101
|
#### `new_class_methods(&block)`
|
|
@@ -101,6 +111,14 @@ Overrides existing class methods via `singleton_class.prepend`.
|
|
|
101
111
|
- Error: `MonkeyBars::NoPatchableClassMethodFoundError` if method does not exist.
|
|
102
112
|
- Error: `MonkeyBars::MismatchedClassMethodArityError` when arity differs,
|
|
103
113
|
unless `ignore_arity_errors: true` is set.
|
|
114
|
+
- Error: `MonkeyBars::PatchableClassMethodIsPrivateError` when the target class
|
|
115
|
+
method is private but the patch method is defined as public/protected.
|
|
116
|
+
- Error: `MonkeyBars::PatchableClassMethodIsNotPrivateError` when the target
|
|
117
|
+
class method is public/protected but the patch method is marked `private`.
|
|
118
|
+
- Error: `MonkeyBars::PatchableClassMethodIsProtectedError` when the target class
|
|
119
|
+
method is protected but the patch method is defined as public/private.
|
|
120
|
+
- Error: `MonkeyBars::PatchableClassMethodIsNotProtectedError` when the target
|
|
121
|
+
class method is public/private but the patch method is marked `protected`.
|
|
104
122
|
- `include_super_super: true` makes `#super_super` available for these methods.
|
|
105
123
|
|
|
106
124
|
#### `patch_constants(&block)`
|
|
@@ -140,6 +158,24 @@ class FixPatch
|
|
|
140
158
|
end
|
|
141
159
|
```
|
|
142
160
|
|
|
161
|
+
### Patch a protected method
|
|
162
|
+
|
|
163
|
+
```ruby
|
|
164
|
+
class ProtectedPatch
|
|
165
|
+
extend MonkeyBars
|
|
166
|
+
|
|
167
|
+
patch(SomeLibrary, version: "1.0.0", version_check: -> { SomeLibrary::VERSION }) do
|
|
168
|
+
patch_instance_methods do
|
|
169
|
+
def internal_token(value)
|
|
170
|
+
super(value) + "-patched"
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
protected :internal_token
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
```
|
|
178
|
+
|
|
143
179
|
### Add new class method and constant
|
|
144
180
|
|
|
145
181
|
```ruby
|
|
@@ -200,8 +236,31 @@ Use this section when the patch fails. The message usually suggests the fix.
|
|
|
200
236
|
Update the version string or the version check.
|
|
201
237
|
- `MonkeyBars::NoPatchableInstanceMethodFoundError`: method does not exist.
|
|
202
238
|
Move it to `new_instance_methods` or fix the method name.
|
|
239
|
+
- `MonkeyBars::PatchableInstanceMethodIsPrivateError`: target method is private
|
|
240
|
+
but patch method is public/protected. Mark the patch method as `private`.
|
|
241
|
+
- `MonkeyBars::PatchableInstanceMethodIsNotPrivateError`: target method is
|
|
242
|
+
public/protected but patch method is private. Remove `private` in the patch
|
|
243
|
+
block or patch a private target.
|
|
244
|
+
- `MonkeyBars::PatchableInstanceMethodIsProtectedError`: target method is
|
|
245
|
+
protected but patch method is public/private. Mark the patch method as
|
|
246
|
+
`protected`.
|
|
247
|
+
- `MonkeyBars::PatchableInstanceMethodIsNotProtectedError`: target method is
|
|
248
|
+
public/private but patch method is protected. Remove `protected` in the patch
|
|
249
|
+
block or patch a protected target.
|
|
203
250
|
- `MonkeyBars::NoPatchableClassMethodFoundError`: method does not exist.
|
|
204
251
|
Move it to `new_class_methods` or fix the method name.
|
|
252
|
+
- `MonkeyBars::PatchableClassMethodIsPrivateError`: target class method is
|
|
253
|
+
private but patch method is public/protected. Mark the patch method as
|
|
254
|
+
`private`.
|
|
255
|
+
- `MonkeyBars::PatchableClassMethodIsNotPrivateError`: target class method is
|
|
256
|
+
public/protected but patch method is private. Remove `private` in the patch
|
|
257
|
+
block or patch a private target.
|
|
258
|
+
- `MonkeyBars::PatchableClassMethodIsProtectedError`: target class method is
|
|
259
|
+
protected but patch method is public/private. Mark the patch method as
|
|
260
|
+
`protected`.
|
|
261
|
+
- `MonkeyBars::PatchableClassMethodIsNotProtectedError`: target class method is
|
|
262
|
+
public/private but patch method is protected. Remove `protected` in the patch
|
|
263
|
+
block or patch a protected target.
|
|
205
264
|
- `MonkeyBars::MismatchedInstanceMethodArityError`: arity differs.
|
|
206
265
|
Match the signature or set `ignore_arity_errors: true`.
|
|
207
266
|
- `MonkeyBars::MismatchedClassMethodArityError`: arity differs.
|
|
@@ -216,6 +275,9 @@ Use this section when the patch fails. The message usually suggests the fix.
|
|
|
216
275
|
Move it to `patch_constants`.
|
|
217
276
|
- `MonkeyBars::PatchAlreadyPerformedError`: `patch!` was called twice.
|
|
218
277
|
Ensure you only call `patch!` once per prepared patch.
|
|
278
|
+
- `MonkeyBars::PrepareForPatchingAlreadyPerformedError`:
|
|
279
|
+
`prepare_for_patching` was called twice. Ensure you only prepare once per
|
|
280
|
+
patcher.
|
|
219
281
|
|
|
220
282
|
## Best practices for LLMs
|
|
221
283
|
|
|
@@ -223,6 +285,8 @@ Use this section when the patch fails. The message usually suggests the fix.
|
|
|
223
285
|
- Prefer `patch(...)` for immediate application unless delayed patching is required.
|
|
224
286
|
- Use `patch_*` helpers for existing methods/constants and `new_*` for new ones.
|
|
225
287
|
- Keep patched method arity identical to the original unless explicitly allowed.
|
|
288
|
+
- Keep patched method visibility aligned exactly with the target
|
|
289
|
+
(`public`/`protected`/`private`).
|
|
226
290
|
- Add targeted tests around the patched behavior; avoid testing internal details.
|
|
227
291
|
|
|
228
292
|
## Testing checklist
|
data/lib/monkey_bars/errors.rb
CHANGED
|
@@ -61,6 +61,54 @@ module MonkeyBars
|
|
|
61
61
|
end
|
|
62
62
|
end
|
|
63
63
|
|
|
64
|
+
class PatchableClassMethodIsNotPrivateError < StandardError
|
|
65
|
+
def initialize(patcher_name, monkey: nil, method: nil)
|
|
66
|
+
super("[#{patcher_name}] The class method `.#{method}` on `#{monkey}` is not private, but is on the patch. Remove it from `private` in your patch.")
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
class PatchableClassMethodIsPrivateError < StandardError
|
|
71
|
+
def initialize(patcher_name, monkey: nil, method: nil)
|
|
72
|
+
super("[#{patcher_name}] The class method `.#{method}` on `#{monkey}` is private, but isn't on the patch. Mark it as `private` in your patch.")
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
class PatchableClassMethodIsNotProtectedError < StandardError
|
|
77
|
+
def initialize(patcher_name, monkey: nil, method: nil)
|
|
78
|
+
super("[#{patcher_name}] The class method `.#{method}` on `#{monkey}` is not protected, but is on the patch. Remove it from `protected` in your patch.")
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
class PatchableClassMethodIsProtectedError < StandardError
|
|
83
|
+
def initialize(patcher_name, monkey: nil, method: nil)
|
|
84
|
+
super("[#{patcher_name}] The class method `.#{method}` on `#{monkey}` is protected, but isn't on the patch. Mark it as `protected` in your patch.")
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
class PatchableInstanceMethodIsNotPrivateError < StandardError
|
|
89
|
+
def initialize(patcher_name, monkey: nil, method: nil)
|
|
90
|
+
super("[#{patcher_name}] The instance method `##{method}` on `#{monkey}` is not private, but is on the patch. Remove it from `private` in your patch.")
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
class PatchableInstanceMethodIsPrivateError < StandardError
|
|
95
|
+
def initialize(patcher_name, monkey: nil, method: nil)
|
|
96
|
+
super("[#{patcher_name}] The instance method `##{method}` on `#{monkey}` is private, but isn't on the patch. Mark it as `private` in your patch.")
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
class PatchableInstanceMethodIsNotProtectedError < StandardError
|
|
101
|
+
def initialize(patcher_name, monkey: nil, method: nil)
|
|
102
|
+
super("[#{patcher_name}] The instance method `##{method}` on `#{monkey}` is not protected, but is on the patch. Remove it from `protected` in your patch.")
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
class PatchableInstanceMethodIsProtectedError < StandardError
|
|
107
|
+
def initialize(patcher_name, monkey: nil, method: nil)
|
|
108
|
+
super("[#{patcher_name}] The instance method `##{method}` on `#{monkey}` is protected, but isn't on the patch. Mark it as `protected` in your patch.")
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
64
112
|
class PatchAlreadyPerformedError < StandardError
|
|
65
113
|
def initialize(patcher_name)
|
|
66
114
|
super("[#{patcher_name}] `#patch!` has already been called and cannot be called again")
|
|
@@ -72,4 +120,10 @@ module MonkeyBars
|
|
|
72
120
|
super("[#{patcher_name}] Couldn't find constant `#{constant}` on `#{monkey}` despite it being marked as patchable. Perhaps move it to the `new_constants` block?")
|
|
73
121
|
end
|
|
74
122
|
end
|
|
123
|
+
|
|
124
|
+
class PrepareForPatchingAlreadyPerformedError < StandardError
|
|
125
|
+
def initialize(patcher_name)
|
|
126
|
+
super("[#{patcher_name}] `#prepare_for_patching` has already been called and cannot be called again")
|
|
127
|
+
end
|
|
128
|
+
end
|
|
75
129
|
end
|
|
@@ -34,6 +34,16 @@ module MonkeyBars
|
|
|
34
34
|
preexisting_instance_method => {block:, ignore_arity_errors:, include_super_super:}
|
|
35
35
|
module_to_prepend.module_eval(&block)
|
|
36
36
|
module_to_prepend.instance_methods.each do |method_name|
|
|
37
|
+
next if module_to_prepend.protected_method_defined?(method_name)
|
|
38
|
+
|
|
39
|
+
if @monkey.protected_method_defined?(method_name)
|
|
40
|
+
raise(PatchableInstanceMethodIsProtectedError.new(@monkey_patcher_name, monkey: @monkey, method: method_name))
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
if @monkey.private_method_defined?(method_name)
|
|
44
|
+
raise(PatchableInstanceMethodIsPrivateError.new(@monkey_patcher_name, monkey: @monkey, method: method_name))
|
|
45
|
+
end
|
|
46
|
+
|
|
37
47
|
unless @monkey.method_defined?(method_name)
|
|
38
48
|
raise(NoPatchableInstanceMethodFoundError.new(@monkey_patcher_name, monkey: @monkey, method: method_name))
|
|
39
49
|
end
|
|
@@ -47,6 +57,42 @@ module MonkeyBars
|
|
|
47
57
|
end
|
|
48
58
|
end
|
|
49
59
|
|
|
60
|
+
module_to_prepend.protected_instance_methods.each do |method_name|
|
|
61
|
+
if @monkey.private_method_defined?(method_name) || (@monkey.method_defined?(method_name) && !@monkey.protected_method_defined?(method_name))
|
|
62
|
+
raise(PatchableInstanceMethodIsNotProtectedError.new(@monkey_patcher_name, monkey: @monkey, method: method_name))
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
unless @monkey.protected_method_defined?(method_name)
|
|
66
|
+
raise(NoPatchableInstanceMethodFoundError.new(@monkey_patcher_name, monkey: @monkey, method: method_name))
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
next if ignore_arity_errors
|
|
70
|
+
|
|
71
|
+
prepatched_method = @monkey.instance_method(method_name)
|
|
72
|
+
patched_method = module_to_prepend.instance_method(method_name)
|
|
73
|
+
if prepatched_method.arity != patched_method.arity
|
|
74
|
+
raise(MismatchedInstanceMethodArityError.new(@monkey_patcher_name, monkey: @monkey, method: method_name, prepatched_arity: prepatched_method.arity, patched_arity: patched_method.arity))
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
module_to_prepend.private_instance_methods.each do |method_name|
|
|
79
|
+
if @monkey.method_defined?(method_name)
|
|
80
|
+
raise(PatchableInstanceMethodIsNotPrivateError.new(@monkey_patcher_name, monkey: @monkey, method: method_name))
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
unless @monkey.private_method_defined?(method_name)
|
|
84
|
+
raise(NoPatchableInstanceMethodFoundError.new(@monkey_patcher_name, monkey: @monkey, method: method_name))
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
next if ignore_arity_errors
|
|
88
|
+
|
|
89
|
+
prepatched_method = @monkey.instance_method(method_name)
|
|
90
|
+
patched_method = module_to_prepend.instance_method(method_name)
|
|
91
|
+
if prepatched_method.arity != patched_method.arity
|
|
92
|
+
raise(MismatchedInstanceMethodArityError.new(@monkey_patcher_name, monkey: @monkey, method: method_name, prepatched_arity: prepatched_method.arity, patched_arity: patched_method.arity))
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
50
96
|
# If anyone asks for super_super, include it
|
|
51
97
|
@include_instance_super_super = true if include_super_super
|
|
52
98
|
@patch_instance_methods_module.module_eval(&block)
|
|
@@ -80,6 +126,16 @@ module MonkeyBars
|
|
|
80
126
|
preexisting_class_method => {block:, ignore_arity_errors:, include_super_super:}
|
|
81
127
|
module_to_prepend.module_eval(&block)
|
|
82
128
|
module_to_prepend.instance_methods.each do |method_name|
|
|
129
|
+
next if module_to_prepend.protected_method_defined?(method_name)
|
|
130
|
+
|
|
131
|
+
if @monkey.singleton_class.protected_method_defined?(method_name)
|
|
132
|
+
raise(PatchableClassMethodIsProtectedError.new(@monkey_patcher_name, monkey: @monkey, method: method_name))
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
if @monkey.singleton_class.private_method_defined?(method_name)
|
|
136
|
+
raise(PatchableClassMethodIsPrivateError.new(@monkey_patcher_name, monkey: @monkey, method: method_name))
|
|
137
|
+
end
|
|
138
|
+
|
|
83
139
|
unless @monkey.singleton_class.method_defined?(method_name)
|
|
84
140
|
raise(NoPatchableClassMethodFoundError.new(@monkey_patcher_name, monkey: @monkey, method: method_name))
|
|
85
141
|
end
|
|
@@ -93,6 +149,42 @@ module MonkeyBars
|
|
|
93
149
|
end
|
|
94
150
|
end
|
|
95
151
|
|
|
152
|
+
module_to_prepend.protected_instance_methods.each do |method_name|
|
|
153
|
+
if @monkey.singleton_class.private_method_defined?(method_name) || (@monkey.singleton_class.method_defined?(method_name) && !@monkey.singleton_class.protected_method_defined?(method_name))
|
|
154
|
+
raise(PatchableClassMethodIsNotProtectedError.new(@monkey_patcher_name, monkey: @monkey, method: method_name))
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
unless @monkey.singleton_class.protected_method_defined?(method_name)
|
|
158
|
+
raise(NoPatchableClassMethodFoundError.new(@monkey_patcher_name, monkey: @monkey, method: method_name))
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
next if ignore_arity_errors
|
|
162
|
+
|
|
163
|
+
prepatched_method = @monkey.singleton_class.instance_method(method_name)
|
|
164
|
+
patched_method = module_to_prepend.instance_method(method_name)
|
|
165
|
+
if prepatched_method.arity != patched_method.arity
|
|
166
|
+
raise(MismatchedClassMethodArityError.new(@monkey_patcher_name, monkey: @monkey, method: method_name, prepatched_arity: prepatched_method.arity, patched_arity: patched_method.arity))
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
module_to_prepend.private_instance_methods.each do |method_name|
|
|
171
|
+
if @monkey.singleton_class.method_defined?(method_name)
|
|
172
|
+
raise(PatchableClassMethodIsNotPrivateError.new(@monkey_patcher_name, monkey: @monkey, method: method_name))
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
unless @monkey.singleton_class.private_method_defined?(method_name)
|
|
176
|
+
raise(NoPatchableClassMethodFoundError.new(@monkey_patcher_name, monkey: @monkey, method: method_name))
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
next if ignore_arity_errors
|
|
180
|
+
|
|
181
|
+
prepatched_method = @monkey.singleton_class.instance_method(method_name)
|
|
182
|
+
patched_method = module_to_prepend.instance_method(method_name)
|
|
183
|
+
if prepatched_method.arity != patched_method.arity
|
|
184
|
+
raise(MismatchedClassMethodArityError.new(@monkey_patcher_name, monkey: @monkey, method: method_name, prepatched_arity: prepatched_method.arity, patched_arity: patched_method.arity))
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
96
188
|
# If anyone asks for super_super, include it
|
|
97
189
|
@include_class_super_super = true if include_super_super
|
|
98
190
|
@patch_class_methods_module.module_eval(&block)
|
|
@@ -124,7 +216,7 @@ module MonkeyBars
|
|
|
124
216
|
module_to_redefine = Module.new
|
|
125
217
|
module_to_redefine.module_eval(&redefined_constant)
|
|
126
218
|
module_to_redefine.constants(false).each do |const_name|
|
|
127
|
-
unless @monkey.
|
|
219
|
+
unless @monkey.const_defined?(const_name, false)
|
|
128
220
|
raise(PatchConstantNotFoundError.new(@monkey_patcher_name, monkey: @monkey, constant: const_name))
|
|
129
221
|
end
|
|
130
222
|
end
|
|
@@ -141,7 +233,7 @@ module MonkeyBars
|
|
|
141
233
|
module_to_include = Module.new
|
|
142
234
|
module_to_include.module_eval(&new_constant)
|
|
143
235
|
module_to_include.constants(false).each do |const_name|
|
|
144
|
-
if @monkey.
|
|
236
|
+
if @monkey.const_defined?(const_name, false)
|
|
145
237
|
raise(NewConstantAlreadyExistsError.new(@monkey_patcher_name, monkey: @monkey, constant: const_name))
|
|
146
238
|
end
|
|
147
239
|
end
|
data/lib/monkey_bars/version.rb
CHANGED
data/lib/monkey_bars.rb
CHANGED
|
@@ -31,6 +31,10 @@ module MonkeyBars
|
|
|
31
31
|
alias_method :🐵, :patch
|
|
32
32
|
|
|
33
33
|
def prepare_for_patching(monkey, version:, version_check:, patch_immediately: false, &block)
|
|
34
|
+
if @prepare_for_patching_performed
|
|
35
|
+
raise(PrepareForPatchingAlreadyPerformedError.new(@monkey_patcher_name))
|
|
36
|
+
end
|
|
37
|
+
|
|
34
38
|
@monkey = monkey
|
|
35
39
|
@version = version
|
|
36
40
|
@version_check_block = version_check
|
|
@@ -38,6 +42,8 @@ module MonkeyBars
|
|
|
38
42
|
yield if block_given?
|
|
39
43
|
|
|
40
44
|
patch! if patch_immediately
|
|
45
|
+
|
|
46
|
+
@prepare_for_patching_performed = true
|
|
41
47
|
end
|
|
42
48
|
|
|
43
49
|
def patch!
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: monkey_bars
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1
|
|
4
|
+
version: 0.2.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrés Rojas
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-02-
|
|
11
|
+
date: 2026-02-24 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rake
|