cordon 0.2.2 → 0.3.0
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.markdown +19 -10
- data/VERSION +1 -1
- data/cordon.gemspec +10 -7
- data/lib/cordon.rb +62 -11
- data/lib/cordon/blacklist.rb +3 -26
- data/lib/cordon/method_list.rb +38 -0
- data/lib/cordon/sanitaire.rb +8 -2
- data/lib/cordon/violation.rb +30 -2
- data/lib/cordon/watchlist.rb +50 -0
- data/lib/cordon/whitelist.rb +2 -5
- data/test/integration/backtrace_cleaning_test.rb +16 -0
- data/test/integration/{cordon_basic_examples_test.rb → basic_examples_test.rb} +0 -0
- data/test/integration/{cordon_customization_test.rb → customization_test.rb} +0 -0
- data/test/integration/{cordon_default_behavior_test.rb → default_behavior_test.rb} +0 -0
- data/test/integration/{cordon_edge_cases_test.rb → edge_cases_test.rb} +0 -0
- data/test/integration/watchlist_test.rb +103 -0
- metadata +24 -21
data/README.markdown
CHANGED
@@ -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 <
|
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
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
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.
|
1
|
+
0.3.0
|
data/cordon.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{cordon}
|
8
|
-
s.version = "0.
|
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-
|
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/
|
35
|
-
"test/integration/
|
36
|
-
"test/integration/
|
37
|
-
"test/integration/
|
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}]
|
data/lib/cordon.rb
CHANGED
@@ -26,27 +26,78 @@ end
|
|
26
26
|
|
27
27
|
|
28
28
|
module Cordon
|
29
|
-
#
|
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
|
-
|
32
|
-
Blacklist.blacklist_method(subject, method.to_sym)
|
33
|
-
end
|
43
|
+
Blacklist.wrap_methods(subject, methods)
|
34
44
|
end
|
35
45
|
|
36
|
-
#
|
37
|
-
def self.
|
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
|
-
|
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
|
-
|
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
|
-
|
50
|
-
|
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
|
data/lib/cordon/blacklist.rb
CHANGED
@@ -1,30 +1,7 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'method_list')
|
2
|
+
|
1
3
|
module Cordon
|
2
4
|
module Blacklist
|
3
|
-
|
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
|
data/lib/cordon/sanitaire.rb
CHANGED
@@ -14,8 +14,14 @@ module Cordon
|
|
14
14
|
protected
|
15
15
|
|
16
16
|
def __cordon__call_method__(subject, method, *args, &b)
|
17
|
-
|
18
|
-
|
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
|
data/lib/cordon/violation.rb
CHANGED
@@ -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
|
-
|
6
|
-
|
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
|
data/lib/cordon/whitelist.rb
CHANGED
@@ -6,11 +6,8 @@ module Cordon
|
|
6
6
|
TheList << object
|
7
7
|
end
|
8
8
|
|
9
|
-
def self.
|
10
|
-
|
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
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -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.
|
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-
|
12
|
+
date: 2012-03-15 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rdoc
|
16
|
-
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: *
|
24
|
+
version_requirements: *2155010720
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: bundler
|
27
|
-
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: *
|
35
|
+
version_requirements: *2155010220
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: jeweler
|
38
|
-
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: *
|
46
|
+
version_requirements: *2155009740
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: mocha
|
49
|
-
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: *
|
57
|
+
version_requirements: *2155009240
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: ruby-debug19
|
60
|
-
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: *
|
68
|
+
version_requirements: *2155008740
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rspec
|
71
|
-
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: *
|
79
|
+
version_requirements: *2155008260
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: minitest
|
82
|
-
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: *
|
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/
|
114
|
-
- test/integration/
|
115
|
-
- test/integration/
|
116
|
-
- test/integration/
|
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:
|
136
|
+
hash: 3052646131815485488
|
134
137
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
135
138
|
none: false
|
136
139
|
requirements:
|