safe_monkeypatch 0.0.1 → 0.1.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/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
|