safe_monkeypatch 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +57 -8
- data/lib/safe_monkeypatch.rb +22 -2
- data/safe_monkeypatch.gemspec +1 -1
- data/spec/safe_monkeypatch_spec.rb +110 -3
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 38da338572140b59706ba5ba0021bae5605b9af7
|
4
|
+
data.tar.gz: b36380cd9a7a6818a2eaa2ae84ee7e4eaffc3b79
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0b1360b349f2d26ab655c2a7d8cfd954df14f67764dce80bab4c55b5d44c954eca5cedf5aa76bf287223edb147d39e8df98411454638bb6a64a1285da074cadb
|
7
|
+
data.tar.gz: 72cf5eef62fef71733b04a824a3bbf0b2fcf7d13595151afa8f4596f7f920a2dd195626d6293eb1a9150047c3b847e9afd226d00a7ad56ac64daa0f5b0abeda7
|
data/README.md
CHANGED
@@ -10,9 +10,10 @@ it's gonna break in the next version of Rails. This gem
|
|
10
10
|
would raise an error if monkey patched method has changed
|
11
11
|
since last time you've adapted your patch to the upstream.
|
12
12
|
|
13
|
-
##
|
13
|
+
## Simple usage
|
14
|
+
|
15
|
+
Assume some upstream in foo.gem:
|
14
16
|
|
15
|
-
# assume some upstream in foo.gem:
|
16
17
|
class Foo
|
17
18
|
def bar
|
18
19
|
puts "do first thing"
|
@@ -21,12 +22,10 @@ since last time you've adapted your patch to the upstream.
|
|
21
22
|
end
|
22
23
|
end
|
23
24
|
|
24
|
-
|
25
|
-
class Foo
|
25
|
+
And your code:
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
safe_monkeypatch :bar, md5: "", error: "my additional info for exception"
|
27
|
+
class Foo
|
28
|
+
safe_monkeypatch :bar, md5: "", error: "patch for foo.gem v0.0.1"
|
30
29
|
|
31
30
|
def bar
|
32
31
|
puts "do first thing"
|
@@ -35,13 +34,63 @@ since last time you've adapted your patch to the upstream.
|
|
35
34
|
end
|
36
35
|
end
|
37
36
|
|
37
|
+
**NOTE:** do this BEFORE monkeypatch happens
|
38
|
+
|
39
|
+
You can also use any of Digest::*** checksum's methods: sha1 or even combine md5+sha1
|
40
|
+
|
38
41
|
Until upstream code isn't changed, it's working like usual.
|
39
42
|
But if the new version changes the implementation of `Foo#bar` method, an
|
40
43
|
error is raised **while startup time**
|
41
44
|
(unless you monkeypatch in runtime, but now you're on your own):
|
42
45
|
|
43
46
|
SafeMonkeypatch::UpstreamChanged: Foo#bar expected to have md5 checksum: "", but has: ""
|
44
|
-
|
47
|
+
patch for foo.gem v0.0.1
|
48
|
+
|
49
|
+
## Matching usage
|
50
|
+
|
51
|
+
Unfortunately, if you have to support different versions of `foo.gem`, you have to monkeypatch all the
|
52
|
+
variant implementation. Use blocks for this:
|
53
|
+
|
54
|
+
class Foo
|
55
|
+
safe_monkeypatch :bar, md5: 'some_checksum' do
|
56
|
+
def bar
|
57
|
+
"this works if upstream Foo#bar method has md5 of source equals 'some_checksum'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
safe_monkeypatch :bar, md5: 'another_checksum' do
|
62
|
+
def bar
|
63
|
+
"this works if upstream Foo#bar method has md5 of source equals 'another_checksum'
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
**Note:** if source of upstream change dramatically and you haven't such matching checksum,
|
69
|
+
**you won't notice this**, as such use this method:
|
70
|
+
|
71
|
+
class Foo
|
72
|
+
|
73
|
+
# NOTE: insert this BEFORE ANY monkeypatch: list all checksum variants
|
74
|
+
safe_monkeypatch :bar, md5: ['some_checksum', 'another_checksum']
|
75
|
+
|
76
|
+
safe_monkeypatch :bar, md5: 'some_checksum' do
|
77
|
+
def bar
|
78
|
+
"this works if upstream Foo#bar method has md5 of source equals 'some_checksum'
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
safe_monkeypatch :bar, md5: 'another_checksum' do
|
83
|
+
def bar
|
84
|
+
"another patch"
|
85
|
+
"this works if upstream Foo#bar method has md5 of source equals 'another_checksum'
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
Use block matching **always this way**. This will guarantee, that any of patches will be applied,
|
91
|
+
or you'll get standard exception.
|
92
|
+
|
93
|
+
## Advanced usage
|
45
94
|
|
46
95
|
You can also use it without patched module scope (for proper error use patched class/module name):
|
47
96
|
|
data/lib/safe_monkeypatch.rb
CHANGED
@@ -36,12 +36,32 @@ class Module
|
|
36
36
|
raise SafeMonkeypatch::ConfigurationError, "Provide at least one cypher name like: md5: '...'"
|
37
37
|
end
|
38
38
|
|
39
|
+
found_match = false
|
40
|
+
error_parts = ["#{inspect}##{meth} expected to have"]
|
41
|
+
|
39
42
|
options.each do |cypher_name, expected|
|
40
43
|
cypher = Digest.const_get(cypher_name.upcase)
|
41
|
-
|
42
|
-
|
44
|
+
actual = cypher.hexdigest(source)
|
45
|
+
found_match = if expected.is_a? Array
|
46
|
+
expected.any? { |e| e == actual }
|
47
|
+
else
|
48
|
+
actual == expected
|
49
|
+
end
|
50
|
+
|
51
|
+
unless found_match
|
52
|
+
error_parts << "#{cypher_name} expected: #{expected.inspect}, but has: #{actual.inspect}"
|
43
53
|
end
|
44
54
|
end
|
55
|
+
|
56
|
+
error_parts << info.to_s if info
|
57
|
+
|
58
|
+
if block_given? && found_match
|
59
|
+
yield
|
60
|
+
elsif block_given?
|
61
|
+
nil # pass
|
62
|
+
elsif not found_match
|
63
|
+
raise SafeMonkeypatch::UpstreamChanged, error_parts.join(" ")
|
64
|
+
end
|
45
65
|
end
|
46
66
|
end
|
47
67
|
|
data/safe_monkeypatch.gemspec
CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "safe_monkeypatch"
|
7
|
-
spec.version = "0.0
|
7
|
+
spec.version = "0.1.0"
|
8
8
|
spec.authors = ["Vlad Bokov"]
|
9
9
|
spec.email = ["razum2um@mail.ru"]
|
10
10
|
spec.summary = %q{Patch methods without fear!}
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
MD5_CHECKSUM = 'b1c5ef3149e6e0062e1c21c3ce8af7d8'
|
4
|
+
SHA1_CHECKSUM = '31c701df5f245ac40a1f8cc958c77e4c4fa815df'
|
4
5
|
|
5
6
|
RSpec.describe SafeMonkeypatch do
|
6
7
|
subject { Foo.new }
|
@@ -13,7 +14,7 @@ RSpec.describe SafeMonkeypatch do
|
|
13
14
|
end
|
14
15
|
end
|
15
16
|
|
16
|
-
it "works
|
17
|
+
it "works" do
|
17
18
|
class Foo
|
18
19
|
safe_monkeypatch :bar, md5: MD5_CHECKSUM
|
19
20
|
|
@@ -61,7 +62,7 @@ RSpec.describe SafeMonkeypatch do
|
|
61
62
|
end
|
62
63
|
}.to raise_error(
|
63
64
|
SafeMonkeypatch::UpstreamChanged,
|
64
|
-
/Foo#bar expected to have md5 expected:
|
65
|
+
/Foo#bar expected to have md5 expected: "invalid_checksum", but has: "#{MD5_CHECKSUM}"/
|
65
66
|
)
|
66
67
|
end
|
67
68
|
|
@@ -70,7 +71,113 @@ RSpec.describe SafeMonkeypatch do
|
|
70
71
|
Foo.safe_monkeypatch Foo.instance_method(:bar), md5: 'another_checksum'
|
71
72
|
}.to raise_error(
|
72
73
|
SafeMonkeypatch::UpstreamChanged,
|
73
|
-
/Foo#bar expected to have md5 expected:
|
74
|
+
/Foo#bar expected to have md5 expected: "another_checksum", but has: "#{MD5_CHECKSUM}"/
|
74
75
|
)
|
75
76
|
end
|
77
|
+
|
78
|
+
describe "multiple cyphers" do
|
79
|
+
it "works" do
|
80
|
+
class Foo
|
81
|
+
safe_monkeypatch :bar, md5: MD5_CHECKSUM, sha1: SHA1_CHECKSUM
|
82
|
+
|
83
|
+
def bar
|
84
|
+
"patched bar"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
expect(subject.bar).to eq "patched bar"
|
89
|
+
end
|
90
|
+
|
91
|
+
it "fails if some cypher is invalid" do
|
92
|
+
expect {
|
93
|
+
class Foo
|
94
|
+
safe_monkeypatch :bar, md5: MD5_CHECKSUM, sha1: 'invalid'
|
95
|
+
|
96
|
+
def bar
|
97
|
+
"patched bar"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
}.to raise_error(
|
101
|
+
SafeMonkeypatch::UpstreamChanged,
|
102
|
+
/Foo#bar expected to have sha1 expected: "invalid", but has: "#{SHA1_CHECKSUM}"/
|
103
|
+
)
|
104
|
+
end
|
105
|
+
|
106
|
+
it "works with mutlipatch" do
|
107
|
+
expect(Kernel).to receive(:puts).once
|
108
|
+
|
109
|
+
class Foo
|
110
|
+
safe_monkeypatch :bar, md5: MD5_CHECKSUM, sha1: SHA1_CHECKSUM do
|
111
|
+
Kernel.puts
|
112
|
+
|
113
|
+
def bar
|
114
|
+
"patched bar"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
expect(subject.bar).to eq "patched bar"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe "multipatching" do
|
124
|
+
it "works" do
|
125
|
+
class Foo
|
126
|
+
safe_monkeypatch :bar, md5: 'invalid_checksum' do
|
127
|
+
def bar
|
128
|
+
"invalid patch"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
safe_monkeypatch :bar, md5: MD5_CHECKSUM do
|
133
|
+
def bar
|
134
|
+
"patched bar"
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
safe_monkeypatch :bar, md5: 'another_checksum' do
|
139
|
+
def bar
|
140
|
+
"another patch"
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
expect(subject.bar).to eq "patched bar"
|
146
|
+
end
|
147
|
+
|
148
|
+
it "doesn't complain if no matching block found" do
|
149
|
+
class Foo
|
150
|
+
safe_monkeypatch :bar, md5: 'invalid_checksum' do
|
151
|
+
def bar
|
152
|
+
"invalid patch"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
expect(subject.bar).to eq "bar"
|
158
|
+
end
|
159
|
+
|
160
|
+
it "complains if no matching block found if array given" do
|
161
|
+
expect {
|
162
|
+
class Foo
|
163
|
+
safe_monkeypatch :bar, md5: ['invalid_checksum', 'another_checksum']
|
164
|
+
|
165
|
+
safe_monkeypatch :bar, md5: 'invalid_checksum' do
|
166
|
+
def bar
|
167
|
+
"invalid patch"
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
safe_monkeypatch :bar, md5: 'another_checksum' do
|
172
|
+
def bar
|
173
|
+
"invalid patch"
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
}.to raise_error(
|
178
|
+
SafeMonkeypatch::UpstreamChanged,
|
179
|
+
/Foo#bar expected to have md5 expected: \["invalid_checksum", "another_checksum"\], but has: "#{MD5_CHECKSUM}"/
|
180
|
+
)
|
181
|
+
end
|
182
|
+
end
|
76
183
|
end
|