durable_decorator 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -64,7 +64,7 @@ DurableDecorator::Base.determine_sha('ExampleClass#no_param_method')
64
64
  # => 'ba3114b2d46caa684b3f7ba38d6f74b2'
65
65
 
66
66
  ExampleClass.class_eval do
67
- durably_decorate :string_method, mode: 'strict', sha: 'ba3114b2d46caa684b3f7ba38d6f74b2' do
67
+ durably_decorate :string_method, mode: 'strict', sha: 'WRONG-SHA-123456' do
68
68
  string_method_original + " and new"
69
69
  end
70
70
  end
@@ -117,6 +117,22 @@ instance.string_method_ba3114b2d46caa684b3f7ba38d6f74b2
117
117
  # => "original"
118
118
  ```
119
119
 
120
+ ### Asking for history
121
+
122
+ You can inquire about the history of method [re]definitions like this:
123
+ ```ruby
124
+ DurableDecorator::Base.definitions('ExampleClass#one_param_method')
125
+ # => [{:name=>:one_param_method, :sha=>"935888f04d9e132be458591d5755cb8131fec457", :body=>"def one_param_method param\n \"original: \#{param}\"\nend\n", :source=>["/home/denis/rails/durable_decorator/spec/example_class.rb", 6]}, {:name=>:one_param_method, :sha=>"3c39948e5e83c04fd4bf7a6ffab12c6828e0d959", :body=>"durably_decorate :one_param_method do |another_string|\n \"\#{one_param_method_935888f04d9e132be458591d5755cb8131fec457('check')} and \#{another_string}\"\nend\n", :source=>["/home/denis/rails/durable_decorator/spec/durable_decorator_spec.rb", 45]}]
126
+ ```
127
+
128
+ With any luck you can even get the specific [re]definition printed!
129
+ ```ruby
130
+ puts DurableDecorator::Base.definitions('ExampleClass#one_param_method')[0][:body]
131
+ def one_param_method param
132
+ "original: #{param}"
133
+ end
134
+ ```
135
+
120
136
  ### No more suprise monkey patching
121
137
  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.
122
138
 
@@ -20,7 +20,6 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_dependency "method_source"
22
22
  spec.add_dependency "logging"
23
- #spec.add_dependency "activesupport"
24
23
 
25
24
  spec.add_development_dependency "bundler", "~> 1.3"
26
25
  spec.add_development_dependency "rake"
@@ -3,10 +3,10 @@ require 'digest/sha1'
3
3
  module DurableDecorator
4
4
  class Base
5
5
  class << self
6
- REDEFINITIONS = {}
6
+ DEFINITIONS = {}
7
7
 
8
8
  def reset!
9
- REDEFINITIONS.clear
9
+ DEFINITIONS.clear
10
10
  end
11
11
 
12
12
  def redefine clazz, method_name, meta, &block
@@ -45,8 +45,8 @@ module DurableDecorator
45
45
  end
46
46
  end
47
47
 
48
- def redefinitions
49
- REDEFINITIONS
48
+ def definitions
49
+ DEFINITIONS
50
50
  end
51
51
 
52
52
  def alias_definitions clazz, method_name, old_sha
@@ -67,11 +67,12 @@ module DurableDecorator
67
67
 
68
68
 
69
69
  def original_redefinition? clazz, method_name
70
- !REDEFINITIONS[Util.full_method_name(clazz, method_name)]
70
+ defs = DEFINITIONS[Util.full_method_name(clazz, method_name)]
71
+ !defs || defs.empty?
71
72
  end
72
73
 
73
74
  def store_redefinition clazz, name, old_method, new_method
74
- methods = REDEFINITIONS[Util.full_method_name(clazz, name)] ||= []
75
+ methods = (DEFINITIONS[Util.full_method_name(clazz, name)] ||= [])
75
76
 
76
77
  to_store = [new_method]
77
78
  to_store.unshift(old_method) if original_redefinition?(clazz, name)
@@ -86,7 +87,7 @@ module DurableDecorator
86
87
  def redefined? clazz, method_name, &block
87
88
  begin
88
89
  result =
89
- overrides = REDEFINITIONS[clazz][method_name] and
90
+ overrides = DEFINITIONS[clazz][method_name] and
90
91
  overrides.select{|o| o == Util.method_hash(method_name)}.first and
91
92
  true
92
93
  rescue
@@ -95,7 +96,7 @@ module DurableDecorator
95
96
  end
96
97
 
97
98
  def determine_sha target
98
- raise "Please provide a fully qualified method name: Module::Clazz#instance_method or ::clazz_method" unless target && target.match(/\.|#/)
99
+ raise "Please provide a fully qualified method name: Module::Clazz#instance_method or .clazz_method" unless target && target.match(/\.|#/)
99
100
 
100
101
  class_name, separator, method_name = target.match(/(.*)(\.|#)(.*)/)[1..3]
101
102
  clazz = Constantizer.constantize(class_name)
@@ -24,10 +24,18 @@ module DurableDecorator
24
24
  def method_hash name, method
25
25
  {
26
26
  :name => name,
27
- :sha => method_sha(method)
27
+ :sha => method_sha(method),
28
+ :body => outdented_method_body(method),
29
+ :source => method.source_location
28
30
  }
29
31
  end
30
32
 
33
+ def outdented_method_body method
34
+ body = method.source
35
+ indent = body.match(/^\W+/).to_s
36
+ body.lines.map{|l| l.sub(indent, '')}.join
37
+ end
38
+
31
39
  def method_sha method
32
40
  Digest::SHA1.hexdigest(method.source.gsub(/\s+/, ' '))
33
41
  end
@@ -4,23 +4,31 @@ module DurableDecorator
4
4
  DECORATION_MODES = ['strict', 'soft']
5
5
 
6
6
  def validate_decoration_meta clazz, method_name, old_method, meta
7
- return unless meta
7
+ expected_sha = Util.method_sha(old_method)
8
+
9
+ unless meta
10
+ log_sha_suggestion clazz, method_name, expected_sha
11
+ return
12
+ end
8
13
 
9
14
  chill_meta = Util.symbolized_hash(meta)
10
15
  provided_mode = chill_meta[:mode]
11
16
  provided_sha = chill_meta[:sha]
12
- expected_sha = Util.method_sha(old_method)
13
17
 
14
18
  raise InvalidDecorationError, "The :mode provided is invalid. Possible modes are: #{DECORATION_MODES.join(", ")}" unless DECORATION_MODES.include? provided_mode
15
19
  raise InvalidDecorationError, "The SHA provided appears to be empty" unless provided_sha and !provided_sha.empty?
16
20
  send("handle_#{chill_meta[:mode]}_fault", clazz, method_name, expected_sha, provided_sha) unless expected_sha == provided_sha
17
21
  end
18
22
 
19
- def handle_strict_fault(clazz, method_name, expected_sha, provided_sha)
23
+ def log_sha_suggestion clazz, method_name, expected_sha
24
+ Util.logger.warn "#{clazz}##{method_name} definition's SHA is currently: #{expected_sha}. Consider sealing it against tampering."
25
+ end
26
+
27
+ def handle_strict_fault clazz, method_name, expected_sha, provided_sha
20
28
  raise TamperedDefinitionError, "Method SHA mismatch, the definition has been tampered with. #{expected_sha} is expected but #{provided_sha} was provided."
21
29
  end
22
30
 
23
- def handle_soft_fault(clazz, method_name, expected_sha, provided_sha)
31
+ def handle_soft_fault clazz, method_name, expected_sha, provided_sha
24
32
  Util.logger.fatal "#{clazz}##{method_name} decoration uses an invalid SHA. The original method definition could have been tampered with!"
25
33
  Util.logger.fatal "Expected SHA was #{expected_sha} but the provided SHA is #{provided_sha}"
26
34
  end
@@ -1,3 +1,3 @@
1
1
  module DurableDecorator
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
@@ -74,6 +74,10 @@ describe DurableDecorator::Base do
74
74
  instance.one_param_method_9358('').should == "original: "
75
75
  instance.one_param_method_935888('').should == "original: "
76
76
  end
77
+
78
+ it 'maintains history of decorations' do
79
+ DurableDecorator::Base.definitions['ExampleClass#one_param_method'].size.should == 2
80
+ end
77
81
  end
78
82
 
79
83
  context 'for strict definitions' do
@@ -146,19 +150,27 @@ describe DurableDecorator::Base do
146
150
 
147
151
  context 'with the wrong SHA' do
148
152
  it 'logs a warning but does not raise an error' do
149
- DurableDecorator::Util.stub(:logger).and_return(Logging.logger['SuperLogger'])
150
- lambda{
151
- ExampleClass.class_eval do
152
- meta = {
153
- :mode => 'soft',
154
- :sha => '1234wrong'
155
- }
156
- durably_decorate :no_param_method, meta do
157
- no_param_method_original + " and a new string"
158
- end
153
+ ExampleClass.class_eval do
154
+ meta = {
155
+ :mode => 'soft',
156
+ :sha => '1234wrong'
157
+ }
158
+ durably_decorate :no_param_method, meta do
159
+ no_param_method_original + " and a new string"
160
+ end
161
+ end
162
+ @log_output.readline.should match(/invalid SHA/)
163
+ end
164
+ end
165
+
166
+ context 'when lacking SHA' do
167
+ it 'prints the SHA suggestion' do
168
+ ExampleClass.class_eval do
169
+ durably_decorate :no_param_method do
170
+ no_param_method_original + " and a new string"
159
171
  end
160
- @log_output.readline.should match(/invalid SHA/)
161
- }.should_not raise_error
172
+ end
173
+ @log_output.readline.should match(/d54f9c7ea2038fac0ae2ff9af49c56f35761725d/)
162
174
  end
163
175
  end
164
176
 
@@ -11,5 +11,6 @@ RSpec.configure do |config|
11
11
  load 'sample_module.rb'
12
12
 
13
13
  DurableDecorator::Base.reset!
14
+ DurableDecorator::Util.stub(:logger).and_return(Logging.logger['SuperLogger'])
14
15
  end
15
16
  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.1.0
4
+ version: 0.1.1
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-08-02 00:00:00.000000000 Z
12
+ date: 2013-08-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: method_source