durable_decorator 0.0.4 → 0.0.6

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.
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