durable_decorator 0.0.4 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  [![Build Status](https://travis-ci.org/jumph4x/durable_decorator.png)](https://travis-ci.org/jumph4x/durable_decorator)
6
6
  [![Code Climate](https://codeclimate.com/github/jumph4x/durable_decorator.png)](https://codeclimate.com/github/jumph4x/durable_decorator)
7
7
 
8
- This is a project for modifying the behavior of gems outside of your reach. You may be using a large Rails Engine and be wanting to simple decorate some existing behavior, but at the same time you want to inherit original behavior.
8
+ This is a project for modifying the behavior of gems outside of your reach. You may be using a large Rails Engine and be wanting to simply decorate some existing behavior, but at the same time you want to inherit original behavior.
9
9
 
10
10
  ## On tracking new decorators and managing fragility
11
11
 
@@ -33,8 +33,8 @@ class ExampleClass
33
33
  end
34
34
 
35
35
  class ExampleClass
36
- decorate :string_method do
37
- string_method_old + " and new"
36
+ durably_decorate :string_method do
37
+ string_method_original + " and new"
38
38
  end
39
39
  end
40
40
 
@@ -67,15 +67,15 @@ ExampleClass.class_eval do
67
67
  sha: 'WE-IGNORE-THE-ABOVE'
68
68
  }
69
69
 
70
- decorate :string_method, meta do
71
- string_method_old + " and new"
70
+ durably_decorate :string_method, meta do
71
+ string_method_original + " and new"
72
72
  end
73
73
  end
74
74
 
75
75
  DurableDecorator::TamperedDefinitionError: Method SHA mismatch, the definition has been tampered with
76
76
  ```
77
77
 
78
- DurableDecorator also maintains explicit versions of each method overriden by creating aliases with appended SHAs of the form ```some_method_1234abcd``` so you can always target explicit method versions without relying on ```some_method_old```.
78
+ DurableDecorator also maintains explicit versions of each method overriden by creating aliases with appended SHAs of the form ```some_method_1234abcd``` so you can always target explicit method versions without relying on ```some_method_original```.
79
79
 
80
80
  ### No more suprise monkey patching
81
81
  Once you decorate the method and seal it with its SHA, if some gem tries to come in and overwrite your work **BEFORE** decorate-time, DurableDecorator will warn you. Similarly, expect to see an exception bubble up if the definition of the original method has changed and requires a review and a re-hash.
@@ -1,4 +1,4 @@
1
- require 'digest/md5'
1
+ require 'digest/sha1'
2
2
 
3
3
  module DurableDecorator
4
4
  class Base
@@ -6,6 +6,10 @@ module DurableDecorator
6
6
  DECORATION_MODES = ['strict']
7
7
  REDEFINITIONS = {}
8
8
 
9
+ def reset!
10
+ REDEFINITIONS.clear
11
+ end
12
+
9
13
  def redefine clazz, method_name, meta, &block
10
14
  if method_name.to_s.match /^self\./
11
15
  redefine_instance (class << clazz; self; end), method_name.to_s.gsub("self.",''), meta, &block
@@ -17,6 +21,7 @@ module DurableDecorator
17
21
  def redefine_instance clazz, method_name, meta, &block
18
22
  return unless old_method = existing_method(clazz, method_name, meta, &block)
19
23
 
24
+ alias_original clazz, method_name
20
25
  alias_definitions clazz, method_name, method_sha(old_method)
21
26
  redefine_method clazz, method_name, &block
22
27
 
@@ -65,24 +70,48 @@ module DurableDecorator
65
70
  end
66
71
  end
67
72
 
73
+ def redefinitions
74
+ REDEFINITIONS
75
+ end
76
+
68
77
  def alias_definitions clazz, method_name, old_sha
69
78
  clazz.class_eval do
70
79
  alias_method("#{method_name}_#{old_sha}", method_name)
71
- alias_method("#{method_name}_old", method_name)
80
+ alias_method("#{method_name}_#{old_sha[0..3]}", method_name)
81
+ alias_method("#{method_name}_#{old_sha[0..5]}", method_name)
72
82
  end
73
83
  end
74
84
 
85
+ def alias_original clazz, method_name
86
+ return unless original_redefinition? clazz, method_name
87
+
88
+ clazz.class_eval do
89
+ alias_method("#{method_name}_original", method_name)
90
+ end
91
+ end
92
+
93
+ def class_name clazz
94
+ name = clazz.name || ''
95
+ name = clazz.to_s if name.empty?
96
+ name.to_sym
97
+ end
98
+
99
+ def full_method_name clazz, method_name
100
+ "#{class_name(clazz)}##{method_name}"
101
+ end
102
+
103
+ def original_redefinition? clazz, method_name
104
+ !REDEFINITIONS[full_method_name(clazz, method_name)]
105
+ end
106
+
75
107
  def store_redefinition clazz, name, old_method, new_method
76
- class_name = clazz.name || ''
77
- class_name = "Meta#{clazz.superclass.to_s}" if class_name.empty?
78
- class_index = REDEFINITIONS[class_name.to_sym] ||= {}
79
- method_index = class_index[name.to_sym] ||= []
108
+ methods = REDEFINITIONS[full_method_name(clazz, name)] ||= []
80
109
 
81
110
  to_store = [new_method]
82
- to_store.unshift(old_method) if method_index.empty?
111
+ to_store.unshift(old_method) if original_redefinition?(clazz, name)
83
112
 
84
113
  to_store.each do |method|
85
- method_index << method_hash(name, method)
114
+ methods << method_hash(name, method)
86
115
  end
87
116
 
88
117
  true
@@ -96,7 +125,7 @@ module DurableDecorator
96
125
  end
97
126
 
98
127
  def method_sha method
99
- Digest::MD5.hexdigest(method.source.gsub(/\s+/, ' '))
128
+ Digest::SHA1.hexdigest(method.source.gsub(/\s+/, ' '))
100
129
  end
101
130
 
102
131
  def redefined? clazz, method_name, &block
@@ -1,3 +1,3 @@
1
1
  module DurableDecorator
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.6"
3
3
  end
@@ -21,18 +21,18 @@ end
21
21
  # monkey-patching Ruby core to create an API
22
22
  Object.class_eval do
23
23
  class << self
24
- def decorate method_name, meta = nil, &block
24
+ def durably_decorate method_name, meta = nil, &block
25
25
  DurableDecorator::Base.redefine self, method_name, meta, &block
26
26
  end
27
27
 
28
- def decorate_singleton method_name, meta = nil, &block
29
- decorate "self.#{method_name}", meta, &block
28
+ def durably_decorate_singleton method_name, meta = nil, &block
29
+ durably_decorate "self.#{method_name}", meta, &block
30
30
  end
31
31
  end
32
32
  end
33
33
 
34
34
  Module.class_eval do
35
- def decorate method_name, meta = nil, &block
35
+ def durably_decorate method_name, meta = nil, &block
36
36
  DurableDecorator::Base.redefine self, method_name, meta, &block
37
37
  end
38
38
  end
@@ -3,34 +3,34 @@ require 'spec_helper'
3
3
  describe DurableDecorator::Base do
4
4
 
5
5
  context 'with classes' do
6
- # Spec uses ./example_class.rb
6
+ # Spec uses ./example_class.rb
7
7
  context 'for existing instance methods' do
8
- it 'guarantees access to #method_old' do
8
+ it 'guarantees access to #method_original' do
9
9
  ExampleClass.class_eval do
10
- decorate :no_param_method do
11
- no_param_method_old + " and a new string"
10
+ durably_decorate :no_param_method do
11
+ no_param_method_original + " and a new string"
12
12
  end
13
13
  end
14
14
 
15
15
  instance = ExampleClass.new
16
16
  instance.no_param_method.should == 'original and a new string'
17
- end
17
+ end
18
18
 
19
19
  context 'with incorrect arity' do
20
20
  it 'throws an error' do
21
21
  lambda{
22
22
  ExampleClass.class_eval do
23
- decorate(:no_param_method){|a,b| }
23
+ durably_decorate(:no_param_method){|a,b| }
24
24
  end
25
25
  }.should raise_error(DurableDecorator::BadArityError)
26
26
  end
27
27
  end
28
28
 
29
29
  context 'for methods with parameters' do
30
- it 'guarantees access to #method_old' do
30
+ it 'guarantees access to #method_original' do
31
31
  ExampleClass.class_eval do
32
- decorate :one_param_method do |another_string|
33
- "#{one_param_method_old('check')} and #{another_string}"
32
+ durably_decorate :one_param_method do |another_string|
33
+ "#{one_param_method_original('check')} and #{another_string}"
34
34
  end
35
35
  end
36
36
 
@@ -44,8 +44,8 @@ describe DurableDecorator::Base do
44
44
  @original_sha = DurableDecorator::Base.determine_sha("ExampleClass#one_param_method")
45
45
 
46
46
  ExampleClass.class_eval do
47
- decorate :one_param_method do |another_string|
48
- "#{one_param_method_1884eb7af7abbccec3fd4048f99363a3('check')} and #{another_string}"
47
+ durably_decorate :one_param_method do |another_string|
48
+ "#{one_param_method_935888f04d9e132be458591d5755cb8131fec457('check')} and #{another_string}"
49
49
  end
50
50
  end
51
51
 
@@ -54,9 +54,9 @@ describe DurableDecorator::Base do
54
54
 
55
55
  it 'works with explicit method version invocation' do
56
56
  ExampleClass.class_eval do
57
- decorate :one_param_method do |boolean|
57
+ durably_decorate :one_param_method do |boolean|
58
58
  if boolean
59
- one_param_method_old("")
59
+ one_param_method_original("check and ")
60
60
  else
61
61
  "latest"
62
62
  end
@@ -68,18 +68,24 @@ describe DurableDecorator::Base do
68
68
  instance.one_param_method(false).should == 'latest'
69
69
  @original_sha.should_not == @redef_sha
70
70
  end
71
+
72
+ it 'work with short explicit method version invocation' do
73
+ instance = ExampleClass.new
74
+ instance.one_param_method_9358('').should == "original: "
75
+ instance.one_param_method_935888('').should == "original: "
76
+ end
71
77
  end
72
78
 
73
79
  context 'for strict definitions' do
74
80
  context 'with the correct SHA' do
75
- it 'guarantees access to #method_old' do
81
+ it 'guarantees access to #method_original' do
76
82
  ExampleClass.class_eval do
77
83
  meta = {
78
84
  :mode => 'strict',
79
- :sha => 'ba3114b2d46caa684b3f7ba38d6f74b2'
85
+ :sha => 'd54f9c7ea2038fac0ae2ff9af49c56f35761725d'
80
86
  }
81
- decorate :no_param_method, meta do
82
- no_param_method_old + " and a new string"
87
+ durably_decorate :no_param_method, meta do
88
+ no_param_method_original + " and a new string"
83
89
  end
84
90
  end
85
91
 
@@ -96,8 +102,8 @@ describe DurableDecorator::Base do
96
102
  :mode => 'strict',
97
103
  :sha => '1234wrong'
98
104
  }
99
- decorate :no_param_method, meta do
100
- no_param_method_old + " and a new string"
105
+ durably_decorate :no_param_method, meta do
106
+ no_param_method_original + " and a new string"
101
107
  end
102
108
  end
103
109
  }.should raise_error(DurableDecorator::TamperedDefinitionError)
@@ -111,8 +117,8 @@ describe DurableDecorator::Base do
111
117
  meta = {
112
118
  :mode => 'strict'
113
119
  }
114
- decorate :no_param_method, meta do
115
- no_param_method_old + " and a new string"
120
+ durably_decorate :no_param_method, meta do
121
+ no_param_method_original + " and a new string"
116
122
  end
117
123
  end
118
124
  }.should raise_error(DurableDecorator::InvalidDecorationError)
@@ -125,38 +131,38 @@ describe DurableDecorator::Base do
125
131
  it 'throws an error' do
126
132
  lambda{
127
133
  ExampleClass.class_eval do
128
- decorate(:integer_method){ }
134
+ durably_decorate(:integer_method){ }
129
135
  end
130
136
  }.should raise_error(DurableDecorator::UndefinedMethodError)
131
137
  end
132
138
  end
133
139
 
134
140
  context 'for existing class methods' do
135
- it 'guarantees access to ::method_old' do
141
+ it 'guarantees access to ::method_original' do
136
142
  ExampleClass.class_eval do
137
- decorate_singleton :clazz_level do
138
- clazz_level_old + " and a new string"
143
+ durably_decorate_singleton :clazz_level do
144
+ clazz_level_original + " and a new string"
139
145
  end
140
146
  end
141
147
 
142
148
  ExampleClass.clazz_level.should == 'original and a new string'
143
- end
149
+ end
144
150
 
145
151
  context 'with incorrect arity' do
146
152
  it 'throws an error' do
147
153
  lambda{
148
154
  ExampleClass.class_eval do
149
- decorate_singleton(:clazz_level){|a,b| }
155
+ durably_decorate_singleton(:clazz_level){|a,b| }
150
156
  end
151
157
  }.should raise_error(DurableDecorator::BadArityError)
152
158
  end
153
159
  end
154
160
 
155
161
  context 'for methods with parameters' do
156
- it 'guarantees access to ::method_old' do
162
+ it 'guarantees access to ::method_original' do
157
163
  ExampleClass.class_eval do
158
- decorate_singleton :clazz_level_paramed do |another_string|
159
- "#{clazz_level_paramed_old('check')} and #{another_string}"
164
+ durably_decorate_singleton :clazz_level_paramed do |another_string|
165
+ "#{clazz_level_paramed_original('check')} and #{another_string}"
160
166
  end
161
167
  end
162
168
 
@@ -169,7 +175,7 @@ describe DurableDecorator::Base do
169
175
  it 'throws an error' do
170
176
  lambda{
171
177
  ExampleClass.class_eval do
172
- decorate_singleton(:integer_method){ }
178
+ durably_decorate_singleton(:integer_method){ }
173
179
  end
174
180
  }.should raise_error(DurableDecorator::UndefinedMethodError)
175
181
  end
@@ -177,25 +183,25 @@ describe DurableDecorator::Base do
177
183
  end
178
184
 
179
185
  context 'with modules' do
180
- # Spec uses ./sample_module.rb
186
+ # Spec uses ./sample_module.rb
181
187
  context 'for existing methods' do
182
- it 'guarantees access to #method_old' do
188
+ it 'guarantees access to #method_original' do
183
189
  Sample.class_eval do
184
- decorate :module_method do
185
- module_method_old + " and a new string"
190
+ durably_decorate :module_method do
191
+ module_method_original + " and a new string"
186
192
  end
187
193
  end
188
194
 
189
195
  o = Object.new
190
196
  o.extend(Sample)
191
197
  o.module_method.should == 'original and a new string'
192
- end
198
+ end
193
199
 
194
200
  context 'with incorrect arity' do
195
201
  it 'throws an error' do
196
202
  lambda{
197
203
  Sample.class_eval do
198
- decorate(:module_method){|a,b| }
204
+ durably_decorate(:module_method){|a,b| }
199
205
  end
200
206
  }.should raise_error(DurableDecorator::BadArityError)
201
207
  end
@@ -206,7 +212,7 @@ describe DurableDecorator::Base do
206
212
  it 'throws an error' do
207
213
  lambda{
208
214
  Sample.class_eval do
209
- decorate(:integer_method){ }
215
+ durably_decorate(:integer_method){ }
210
216
  end
211
217
  }.should raise_error(DurableDecorator::UndefinedMethodError)
212
218
  end
@@ -226,14 +232,14 @@ describe DurableDecorator::Base do
226
232
  context 'when the target is an instance method' do
227
233
  it 'should return the sha' do
228
234
  DurableDecorator::Base.determine_sha('ExampleClass#no_param_method').should ==
229
- 'ba3114b2d46caa684b3f7ba38d6f74b2'
235
+ 'd54f9c7ea2038fac0ae2ff9af49c56f35761725d'
230
236
  end
231
237
  end
232
238
 
233
239
  context 'when the target is a class method' do
234
240
  it 'should return the sha' do
235
241
  DurableDecorator::Base.determine_sha('ExampleClass.clazz_level').should ==
236
- 'c5a3870a3934ce8d2145b841e42a8ad4'
242
+ 'f6490bec1af021697ed8e5990f0d1db3976f065f'
237
243
  end
238
244
  end
239
245
  end
data/spec/spec_helper.rb CHANGED
@@ -5,5 +5,7 @@ RSpec.configure do |config|
5
5
  config.before(:each) do
6
6
  load 'example_class.rb'
7
7
  load 'sample_module.rb'
8
+
9
+ DurableDecorator::Base.reset!
8
10
  end
9
11
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: durable_decorator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.6
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-06-14 00:00:00.000000000 Z
12
+ date: 2013-06-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: method_source