cordon 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -11,7 +11,7 @@ From Wikipedia:
11
11
 
12
12
  I've never been a big fan of the way RSpec adds <code>#should</code> and <code>#should_not</code> to Kernel, but until recently I'd never been able to articulate why. Then I worked on a project that became <a href="https://github.com/geeksam/kookaburra/">Kookaburra</a>, and I found a specific reason to be annoyed.
13
13
 
14
- Basically, putting <code>#should</code> on all objects gives you the freedom to <s>shoot yourself in the foot</s> put RSpec expectations *anywhere*, not just inside an <code>#it</code> block. So, I went looking for a way to make <code>#should</code> explode if it was called outside a specific context.
14
+ Basically, putting <code>#should</code> on all objects gives you the freedom to <strike>shoot yourself in the foot</strike>^H^H^H put RSpec expectations *anywhere*, not just inside an <code>#it</code> block. So, I went looking for a way to make <code>#should</code> explode if it was called outside a specific context.
15
15
 
16
16
  After several false starts and horrible ideas, I've got something that actually isn't too bad.
17
17
 
@@ -44,13 +44,23 @@ In both examples, note that Cordon's <code>.embargo</code> method must be called
44
44
 
45
45
  ## TODO
46
46
 
47
- - Write integration macros (and tests, obviously) for various spec frameworks:
48
- - <s>RSpec</s>
49
- - <s>MiniTest::Spec</s>
50
- - <s>Yoda</s> <em>(Actually, Yoda appears to abuse Ruby syntax badly enough that it may not work with Cordon.)</em>
51
- - ?
52
- - <s>Add a declarative API to customize the name of the function that wraps assertions</s>
53
- - probably some other stuff I can't think of at the moment
47
+ <!-- Apparently Markdown and HTML don't mix, because "* <strike>foo</strike>" doesn't work the way I thought it should -->
48
+ <ul>
49
+ <li>
50
+ Write integration macros (and tests, obviously) for various spec frameworks:
51
+ <ul>
52
+ <li><strike>RSpec</strike></li>
53
+ <li><strike>MiniTest::Spec</strike></li>
54
+ <li><strike>Yoda</strike> <em>(Actually, Yoda appears to abuse Ruby syntax badly enough that it may not work with Cordon.)</em></li>
55
+ <li>?</li>
56
+ </ul>
57
+ </li>
58
+ <li><strike>Add a declarative API to customize the name of the function that wraps assertions</strike></li>
59
+ <li>RDoc</li>
60
+ <li>Add a "detection mode" which rescues Cordon::Violation, records the backtrace, and reports all violations in a Kernel#at_exit callback. (UPDATE: added Cordon.monitor for frameworks, and Cordon.watchlist for methods, but didn't get #at_exit working yet.)</li>
61
+ <li>MAYBE: Figure out how to raise Cordon::Violation only when in (or not in?) a certain calling context (this could be hairy), which might make #assert_that optional</li>
62
+ <li>probably some other stuff I can't think of at the moment</li>
63
+ </ul>
54
64
 
55
65
 
56
66
 
@@ -68,5 +78,4 @@ In both examples, note that Cordon's <code>.embargo</code> method must be called
68
78
 
69
79
  ## Copyright
70
80
 
71
- Copyright (c) 2012 Sam Livingston-Gray. See LICENSE.txt for
72
- further details.
81
+ Copyright (c) 2012 Sam Livingston-Gray. See LICENSE.txt for further details.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.2
1
+ 0.3.0
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{cordon}
8
- s.version = "0.2.2"
8
+ s.version = "0.3.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = [%q{Sam Livingston-Gray}]
12
- s.date = %q{2012-03-09}
12
+ s.date = %q{2012-03-15}
13
13
  s.description = %q{A bit of an experiment, really}
14
14
  s.email = %q{geeksam@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -24,18 +24,21 @@ Gem::Specification.new do |s|
24
24
  "cordon.gemspec",
25
25
  "lib/cordon.rb",
26
26
  "lib/cordon/blacklist.rb",
27
+ "lib/cordon/method_list.rb",
27
28
  "lib/cordon/sanitaire.rb",
28
29
  "lib/cordon/violation.rb",
30
+ "lib/cordon/watchlist.rb",
29
31
  "lib/cordon/whitelist.rb",
30
32
  "test/framework_integration/minitest_spec_spec.rb",
31
33
  "test/framework_integration/rspec_spec.rb",
32
34
  "test/helper.rb",
33
35
  "test/integration/backtrace_cleaning_test.rb",
34
- "test/integration/cordon_basic_examples_test.rb",
35
- "test/integration/cordon_customization_test.rb",
36
- "test/integration/cordon_default_behavior_test.rb",
37
- "test/integration/cordon_edge_cases_test.rb",
38
- "test/integration/integration_test_helper.rb"
36
+ "test/integration/basic_examples_test.rb",
37
+ "test/integration/customization_test.rb",
38
+ "test/integration/default_behavior_test.rb",
39
+ "test/integration/edge_cases_test.rb",
40
+ "test/integration/integration_test_helper.rb",
41
+ "test/integration/watchlist_test.rb"
39
42
  ]
40
43
  s.homepage = %q{http://github.com/geeksam/cordon}
41
44
  s.licenses = [%q{WTFPL}]
@@ -26,27 +26,78 @@ end
26
26
 
27
27
 
28
28
  module Cordon
29
- # Declare specific methods as off-limits
29
+ # Shorthand for blacklisting the undesirable methods in specific frameworks
30
+ def self.embargo(framework)
31
+ wrap_framework(framework, :blacklist)
32
+ end
33
+
34
+ # Shorthand for watchlisting the undesirable methods in specific frameworks
35
+ # NOTE: while this will record incursions, you'll have to call Cordon.incursion_report
36
+ # yourself until I figure out how to make it print out at exit.
37
+ def self.monitor(framework)
38
+ wrap_framework(framework, :watchlist)
39
+ end
40
+
41
+ # Declare specific methods as off-limits so that invocations raise an exception
30
42
  def self.blacklist(subject, methods)
31
- methods.each do |method|
32
- Blacklist.blacklist_method(subject, method.to_sym)
33
- end
43
+ Blacklist.wrap_methods(subject, methods)
34
44
  end
35
45
 
36
- # Shorthand for blacklisting the undesirable methods in specific frameworks
37
- def self.embargo(framework)
46
+ # Declare specific methods as off-limits so that invocations are logged
47
+ def self.watchlist(subject, methods)
48
+ Watchlist.wrap_methods(subject, methods)
49
+ end
50
+
51
+ # Allow user-defined aliases of #assert_that
52
+ def self.wrap_assertions_with(custom_method_name)
53
+ Sanitaire.wrap_assertions_with(custom_method_name)
54
+ end
55
+
56
+ # Convenience accessor for reporting on watchlist incursions
57
+ def self.incursions
58
+ Watchlist.incursions
59
+ end
60
+
61
+ # Plain-text report of watchlist incursions
62
+ def self.incursion_report
63
+ Watchlist.incursion_report
64
+ end
65
+
66
+ # Allow custom filtering of backtraces on Cordon::Violation errors.
67
+ # Pass this a block that takes a backtrace and returns a backtrace.
68
+ # Multiple filters can be defined; all will be applied.
69
+ def self.filter_violation_backtrace(&proc)
70
+ Violation.add_custom_backtrace_filter(&proc)
71
+ end
72
+
73
+ # Reset custom filtering of backtraces.
74
+ # (This is mostly here for ease of testing.)
75
+ def self.dont_filter_violation_backtrace!
76
+ Violation.clear_custom_backtrace_filters
77
+ end
78
+
79
+ protected
80
+
81
+ def self.wrap_framework(framework, technique)
82
+ raise "Don't know how to wrap framework with #{technique.inspect}!" unless [:blacklist, :watchlist].include?(technique)
83
+
84
+ # Figure out which methods to wrap
85
+ list = []
38
86
  case framework
39
87
  when :rspec
40
- blacklist Kernel, [:should, :should_not]
88
+ list << [Kernel, [:should, :should_not]]
41
89
  when :minitest_spec
42
90
  must_and_wont = MiniTest::Expectations.instance_methods.map(&:to_s).select {|e| e =~ /^(must|wont)_/}
43
- blacklist MiniTest::Expectations, must_and_wont
91
+ list << [MiniTest::Expectations, must_and_wont]
44
92
  else
45
93
  raise "I don't know how to embargo #{framework}!"
46
94
  end
47
- end
48
95
 
49
- def self.wrap_assertions_with(custom_method_name)
50
- Sanitaire.wrap_assertions_with(custom_method_name)
96
+ # Wrap them using the appropriate technique
97
+ # (which should be either :blacklist or :watchlist)
98
+ list.each do |subject, methods|
99
+ send technique, subject, methods
100
+ end
51
101
  end
102
+
52
103
  end
@@ -1,30 +1,7 @@
1
+ require File.join(File.dirname(__FILE__), 'method_list')
2
+
1
3
  module Cordon
2
4
  module Blacklist
3
- TheList = {}
4
-
5
- def self.blacklist_method(subject, method)
6
- return if unbound_method(subject, method) # be idempotent
7
-
8
- # Unbind the original method, and replace it with a wrapper that
9
- # checks for permission before binding and calling the original
10
- Blacklist.unbind_method(subject, method)
11
- subject.__cordon__wrap_method__(method)
12
- end
13
-
14
- def self.invoke_method(instance, subject, method, *args, &b)
15
- um = unbound_method(subject, method)
16
- um.bind(instance).call(*args, &b)
17
- end
18
-
19
- protected
20
-
21
- def self.unbind_method(subject, method)
22
- um = subject.instance_method(method) # will raise NameError if the method doesn't exist
23
- TheList[[subject, method]] = um
24
- end
25
-
26
- def self.unbound_method(subject, method)
27
- TheList[[subject, method]]
28
- end
5
+ extend MethodList
29
6
  end
30
7
  end
@@ -0,0 +1,38 @@
1
+ module Cordon
2
+ module MethodList
3
+ def includes?(subject, method)
4
+ method_list.has_key?([subject, method])
5
+ end
6
+
7
+ def wrap_methods(subject, methods)
8
+ methods.each do |method|
9
+ wrap_method(subject, method.to_sym)
10
+ end
11
+ end
12
+
13
+ def wrap_method(subject, method)
14
+ return if includes?(subject, method) # be idempotent
15
+
16
+ # Unbind the original method, and replace it with a wrapper that
17
+ # decides whether to bind and call the original
18
+ unbind_method(subject, method)
19
+ subject.__cordon__wrap_method__(method)
20
+ end
21
+
22
+ def invoke_method(instance, subject, method, *args, &b)
23
+ unbound_method = method_list[[subject, method]]
24
+ unbound_method.bind(instance).call(*args, &b)
25
+ end
26
+
27
+ protected
28
+
29
+ def unbind_method(subject, method)
30
+ unbound_method = subject.instance_method(method) # will raise NameError if the method doesn't exist
31
+ method_list[[subject, method]] = unbound_method
32
+ end
33
+
34
+ def method_list
35
+ @method_list ||= {}
36
+ end
37
+ end
38
+ end
@@ -14,8 +14,14 @@ module Cordon
14
14
  protected
15
15
 
16
16
  def __cordon__call_method__(subject, method, *args, &b)
17
- ::Cordon::Whitelist.check_permissions(self, subject, method, *args)
18
- ::Cordon::Blacklist.invoke_method(self, subject, method, *args, &b)
17
+ case
18
+ when Watchlist.includes?(subject, method)
19
+ ::Cordon::Watchlist.invoke_method(self, subject, method, *args, &b)
20
+ when Whitelist.admits?(self)
21
+ ::Cordon::Blacklist.invoke_method(self, subject, method, *args, &b)
22
+ else
23
+ raise ::Cordon::Violation.from_invocation(subject, method, args)
24
+ end
19
25
  end
20
26
  end
21
27
  end
@@ -1,9 +1,37 @@
1
1
  module Cordon
2
2
  class Violation < Exception
3
+ SelfRegex = /\/lib\/cordon.*\.rb\:\d+\:in/
4
+ CustomFilterProcs = []
5
+
6
+ def self.add_custom_backtrace_filter(&proc)
7
+ CustomFilterProcs << proc
8
+ end
9
+
10
+ def self.clear_custom_backtrace_filters
11
+ CustomFilterProcs.clear
12
+ end
13
+
14
+ def self.from_invocation(subject, method, args)
15
+ method_descriptor = '%s#%s' % [subject, method]
16
+ message = '%s(%s)' % [method_descriptor, args.map(&:inspect).join(', ')]
17
+ new(message).tap { |e| e.method_descriptor = method_descriptor }
18
+ end
19
+
20
+ attr_accessor :method_descriptor
21
+
3
22
  def backtrace
4
23
  bt = super
5
- bt.shift while bt && bt.first =~ /cordon\.rb\:\d+\:in/
6
- bt
24
+ return if bt.nil?
25
+
26
+ # Take anything in 'lib/cordon*.rb' off of the *top* of the backtrace so users don't get distracted by it
27
+ bt.shift while bt.first =~ SelfRegex
28
+
29
+ # Apply any other custom filters to the backtrace before returning it
30
+ CustomFilterProcs.each do |filter|
31
+ bt = filter.call(bt)
32
+ end
33
+
34
+ return bt
7
35
  end
8
36
  end
9
37
  end
@@ -0,0 +1,50 @@
1
+ require File.join(File.dirname(__FILE__), 'method_list')
2
+
3
+ module Cordon
4
+ module Watchlist
5
+ extend MethodList
6
+
7
+ class << self
8
+ def invoke_method(instance, subject, method, *args, &b)
9
+ record_incursion(subject, method, args)
10
+ super
11
+ end
12
+
13
+ def incursions
14
+ @incursions ||= []
15
+ end
16
+
17
+ def incursion_report
18
+ report = <<-EOF.strip
19
+ =======================
20
+ Cordon Incursion Report
21
+ =======================
22
+ EOF
23
+ n = incursions.length
24
+ max_width = n.to_s.length
25
+
26
+ incursions_by_method = Hash.new { |hash, key| hash[key] = [] }
27
+ incursions.each do |incursion|
28
+ incursions_by_method[incursion.method_descriptor] << incursion
29
+ end
30
+
31
+ incursions_by_method.to_a.sort.each do |method_descriptor, incursions|
32
+ report << "\n\n#{method_descriptor}\n#{'-' * method_descriptor.length}"
33
+ incursions.each do |incursion|
34
+ report << "\n" + incursion.backtrace.first.to_s
35
+ end
36
+ end
37
+ report << "\n"
38
+ report
39
+ end
40
+
41
+ protected
42
+
43
+ def record_incursion(subject, method, args)
44
+ raise Cordon::Violation.from_invocation(subject, method, args)
45
+ rescue Cordon::Violation => e
46
+ incursions << e
47
+ end
48
+ end
49
+ end
50
+ end
@@ -6,11 +6,8 @@ module Cordon
6
6
  TheList << object
7
7
  end
8
8
 
9
- def self.check_permissions(instance, subject, method, *args)
10
- allowed = !! TheList.delete(instance)
11
- return if allowed
12
- message = '%s#%s(%s)' % [subject, method, args.map(&:inspect).join(', ')]
13
- raise ::Cordon::Violation, message
9
+ def self.admits?(instance)
10
+ !! TheList.delete(instance)
14
11
  end
15
12
  end
16
13
  end
@@ -17,4 +17,20 @@ class BacktraceCleaningUnitTest < CordonUnitTest
17
17
  failure_message << (e.backtrace[0..3] + ['(rest of backtrace omitted)']).map { |e| ' ' + e }.join("\n")
18
18
  refute e.backtrace.first.include?('cordon.rb:'), failure_message
19
19
  end
20
+
21
+ def test_custom_cleaning
22
+ Cordon.filter_violation_backtrace { |backtrace|
23
+ project_root = File.expand_path(File.join(File.dirname(__FILE__), *%w[.. ..]))
24
+ in_project = Regexp.new(project_root)
25
+ backtrace.select { |line| line =~ in_project }
26
+ }
27
+
28
+ foo.verboten_method_for_backtrace
29
+
30
+ rescue Cordon::Violation => e
31
+ refute e.backtrace.any? { |line| line =~ /\/unit\.rb:/ }, "Custom backtrace filter did not work"
32
+
33
+ ensure
34
+ Cordon.dont_filter_violation_backtrace!
35
+ end
20
36
  end
@@ -0,0 +1,103 @@
1
+ require File.join(File.dirname(__FILE__), 'integration_test_helper')
2
+
3
+ $shady_method_call_count = 0
4
+ module Kernel
5
+ def shady_method
6
+ # we are a hedge. move along.
7
+ $shady_method_call_count += 1
8
+ end
9
+
10
+ def dubious_method
11
+ # nothing to see here either
12
+ end
13
+ end
14
+
15
+ # In addition to blacklisting methods, Cordon can also place them on a watchlist.
16
+ # This will track invocations for later reporting.
17
+ # (It's not nearly as glamorous as the Bond movies would have you believe.)
18
+ Cordon.watchlist Kernel, [:shady_method, :dubious_method]
19
+
20
+ class WatchlistTest < CordonUnitTest
21
+ def method_one
22
+ shady_method; @method_one_line = __LINE__
23
+ end
24
+ def method_two
25
+ shady_method; @method_two_line = __LINE__
26
+ end
27
+ def method_three
28
+ dubious_method; @method_three_line = __LINE__
29
+ end
30
+
31
+ def setup
32
+ $shady_method_call_count = 0
33
+ Cordon.filter_violation_backtrace do |backtrace|
34
+ current_file = File.expand_path(__FILE__)
35
+ in_file = Regexp.new(current_file)
36
+ backtrace.select { |line| line =~ in_file }
37
+ end
38
+ end
39
+
40
+ def teardown
41
+ Cordon.dont_filter_violation_backtrace!
42
+ Cordon.incursions.clear
43
+ end
44
+
45
+ def test_shady_calls_are_allowed
46
+ method_one; assert_equal 1, $shady_method_call_count
47
+ method_one; assert_equal 2, $shady_method_call_count
48
+ method_two; assert_equal 3, $shady_method_call_count
49
+ end
50
+
51
+ def test_shady_calls_are_counted
52
+ assert Cordon.incursions.empty?
53
+
54
+ method_one; assert_equal 1, Cordon.incursions.length
55
+ method_one; assert_equal 2, Cordon.incursions.length
56
+ method_two; assert_equal 3, Cordon.incursions.length
57
+ end
58
+
59
+ def test_shady_calls_are_logged
60
+ assert Cordon.incursions.empty?
61
+
62
+ method_one; invocation_1_line = __LINE__
63
+ method_one; invocation_2_line = __LINE__
64
+ method_two; invocation_3_line = __LINE__
65
+
66
+ i1, i2, i3 = *Cordon.incursions
67
+
68
+ # Quick sanity check: make sure we're only looking at backtraces in the current file (see #setup)
69
+ assert i1.backtrace.length == 2
70
+ assert i2.backtrace.length == 2
71
+ assert i3.backtrace.length == 2
72
+
73
+ # NOTE: using assert_match prints a weird MiniTest error
74
+
75
+ # First line should be the actual invocation of #shady_method
76
+ assert i1.backtrace[0] =~ /watchlist_test.rb:#{@method_one_line}:in `method_one'$/, i1.backtrace[0]
77
+ assert i2.backtrace[0] =~ /watchlist_test.rb:#{@method_one_line}:in `method_one'$/, i2.backtrace[0]
78
+ assert i3.backtrace[0] =~ /watchlist_test.rb:#{@method_two_line}:in `method_two'$/, i3.backtrace[0]
79
+
80
+ # Second line should be the place where method_(one|two) was called
81
+ assert i1.backtrace[1] =~ /watchlist_test.rb:#{invocation_1_line}:in `test_shady_calls_are_logged'$/, i1.backtrace[1]
82
+ assert i2.backtrace[1] =~ /watchlist_test.rb:#{invocation_2_line}:in `test_shady_calls_are_logged'$/, i2.backtrace[1]
83
+ assert i3.backtrace[1] =~ /watchlist_test.rb:#{invocation_3_line}:in `test_shady_calls_are_logged'$/, i3.backtrace[1]
84
+ end
85
+
86
+ def test_incursion_report
87
+ method_one
88
+ method_two
89
+ method_one
90
+ method_two
91
+ method_three
92
+
93
+ report = Cordon.incursion_report
94
+
95
+ assert report =~ /Kernel#shady_method/
96
+ assert report =~ /Kernel#dubious_method/
97
+
98
+ assert report =~ /watchlist_test.rb:#{@method_one_line}:in `method_one'$/
99
+ assert report =~ /watchlist_test.rb:#{@method_one_line}:in `method_one'$/
100
+ assert report =~ /watchlist_test.rb:#{@method_two_line}:in `method_two'$/
101
+ assert report =~ /watchlist_test.rb:#{@method_three_line}:in `method_three'$/
102
+ end
103
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cordon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-03-09 00:00:00.000000000Z
12
+ date: 2012-03-15 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rdoc
16
- requirement: &2156968780 !ruby/object:Gem::Requirement
16
+ requirement: &2155010720 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '3.12'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *2156968780
24
+ version_requirements: *2155010720
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: bundler
27
- requirement: &2156967060 !ruby/object:Gem::Requirement
27
+ requirement: &2155010220 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 1.0.0
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *2156967060
35
+ version_requirements: *2155010220
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: jeweler
38
- requirement: &2156964940 !ruby/object:Gem::Requirement
38
+ requirement: &2155009740 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 1.8.3
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *2156964940
46
+ version_requirements: *2155009740
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: mocha
49
- requirement: &2156962400 !ruby/object:Gem::Requirement
49
+ requirement: &2155009240 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: 0.10.3
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *2156962400
57
+ version_requirements: *2155009240
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: ruby-debug19
60
- requirement: &2156960720 !ruby/object:Gem::Requirement
60
+ requirement: &2155008740 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: '0'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *2156960720
68
+ version_requirements: *2155008740
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rspec
71
- requirement: &2156958500 !ruby/object:Gem::Requirement
71
+ requirement: &2155008260 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: '0'
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *2156958500
79
+ version_requirements: *2155008260
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: minitest
82
- requirement: &2156956460 !ruby/object:Gem::Requirement
82
+ requirement: &2155007680 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ! '>='
@@ -87,7 +87,7 @@ dependencies:
87
87
  version: '0'
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *2156956460
90
+ version_requirements: *2155007680
91
91
  description: A bit of an experiment, really
92
92
  email: geeksam@gmail.com
93
93
  executables: []
@@ -103,18 +103,21 @@ files:
103
103
  - cordon.gemspec
104
104
  - lib/cordon.rb
105
105
  - lib/cordon/blacklist.rb
106
+ - lib/cordon/method_list.rb
106
107
  - lib/cordon/sanitaire.rb
107
108
  - lib/cordon/violation.rb
109
+ - lib/cordon/watchlist.rb
108
110
  - lib/cordon/whitelist.rb
109
111
  - test/framework_integration/minitest_spec_spec.rb
110
112
  - test/framework_integration/rspec_spec.rb
111
113
  - test/helper.rb
112
114
  - test/integration/backtrace_cleaning_test.rb
113
- - test/integration/cordon_basic_examples_test.rb
114
- - test/integration/cordon_customization_test.rb
115
- - test/integration/cordon_default_behavior_test.rb
116
- - test/integration/cordon_edge_cases_test.rb
115
+ - test/integration/basic_examples_test.rb
116
+ - test/integration/customization_test.rb
117
+ - test/integration/default_behavior_test.rb
118
+ - test/integration/edge_cases_test.rb
117
119
  - test/integration/integration_test_helper.rb
120
+ - test/integration/watchlist_test.rb
118
121
  homepage: http://github.com/geeksam/cordon
119
122
  licenses:
120
123
  - WTFPL
@@ -130,7 +133,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
130
133
  version: '0'
131
134
  segments:
132
135
  - 0
133
- hash: 2252535489042103113
136
+ hash: 3052646131815485488
134
137
  required_rubygems_version: !ruby/object:Gem::Requirement
135
138
  none: false
136
139
  requirements: