durable_decorator 0.1.0 → 0.1.1

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