mspec 1.0.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.
Files changed (162) hide show
  1. data/LICENSE +22 -0
  2. data/README +101 -0
  3. data/Rakefile +44 -0
  4. data/bin/mkspec +7 -0
  5. data/bin/mspec +7 -0
  6. data/bin/mspec-ci +8 -0
  7. data/bin/mspec-run +8 -0
  8. data/bin/mspec-tag +8 -0
  9. data/lib/mspec.rb +6 -0
  10. data/lib/mspec/commands/mkspec.rb +147 -0
  11. data/lib/mspec/commands/mspec-ci.rb +71 -0
  12. data/lib/mspec/commands/mspec-run.rb +80 -0
  13. data/lib/mspec/commands/mspec-tag.rb +87 -0
  14. data/lib/mspec/commands/mspec.rb +143 -0
  15. data/lib/mspec/expectations.rb +2 -0
  16. data/lib/mspec/expectations/expectations.rb +12 -0
  17. data/lib/mspec/expectations/should.rb +23 -0
  18. data/lib/mspec/guards.rb +13 -0
  19. data/lib/mspec/guards/bug.rb +27 -0
  20. data/lib/mspec/guards/compliance.rb +18 -0
  21. data/lib/mspec/guards/conflict.rb +16 -0
  22. data/lib/mspec/guards/endian.rb +40 -0
  23. data/lib/mspec/guards/extensions.rb +12 -0
  24. data/lib/mspec/guards/guard.rb +120 -0
  25. data/lib/mspec/guards/noncompliance.rb +12 -0
  26. data/lib/mspec/guards/platform.rb +38 -0
  27. data/lib/mspec/guards/quarantine.rb +15 -0
  28. data/lib/mspec/guards/runner.rb +30 -0
  29. data/lib/mspec/guards/superuser.rb +15 -0
  30. data/lib/mspec/guards/support.rb +12 -0
  31. data/lib/mspec/guards/version.rb +40 -0
  32. data/lib/mspec/helpers.rb +6 -0
  33. data/lib/mspec/helpers/bignum.rb +5 -0
  34. data/lib/mspec/helpers/const_lookup.rb +5 -0
  35. data/lib/mspec/helpers/flunk.rb +5 -0
  36. data/lib/mspec/helpers/io.rb +13 -0
  37. data/lib/mspec/helpers/scratch.rb +17 -0
  38. data/lib/mspec/helpers/tmp.rb +32 -0
  39. data/lib/mspec/matchers.rb +16 -0
  40. data/lib/mspec/matchers/base.rb +95 -0
  41. data/lib/mspec/matchers/be_ancestor_of.rb +24 -0
  42. data/lib/mspec/matchers/be_close.rb +27 -0
  43. data/lib/mspec/matchers/be_empty.rb +20 -0
  44. data/lib/mspec/matchers/be_false.rb +20 -0
  45. data/lib/mspec/matchers/be_kind_of.rb +24 -0
  46. data/lib/mspec/matchers/be_nil.rb +20 -0
  47. data/lib/mspec/matchers/be_true.rb +20 -0
  48. data/lib/mspec/matchers/complain.rb +56 -0
  49. data/lib/mspec/matchers/eql.rb +26 -0
  50. data/lib/mspec/matchers/equal.rb +26 -0
  51. data/lib/mspec/matchers/equal_utf16.rb +34 -0
  52. data/lib/mspec/matchers/include.rb +32 -0
  53. data/lib/mspec/matchers/output.rb +67 -0
  54. data/lib/mspec/matchers/output_to_fd.rb +71 -0
  55. data/lib/mspec/matchers/raise_error.rb +48 -0
  56. data/lib/mspec/mocks.rb +3 -0
  57. data/lib/mspec/mocks/mock.rb +123 -0
  58. data/lib/mspec/mocks/object.rb +28 -0
  59. data/lib/mspec/mocks/proxy.rb +112 -0
  60. data/lib/mspec/runner.rb +13 -0
  61. data/lib/mspec/runner/actions.rb +6 -0
  62. data/lib/mspec/runner/actions/debug.rb +17 -0
  63. data/lib/mspec/runner/actions/filter.rb +40 -0
  64. data/lib/mspec/runner/actions/gdb.rb +17 -0
  65. data/lib/mspec/runner/actions/tag.rb +97 -0
  66. data/lib/mspec/runner/actions/tally.rb +80 -0
  67. data/lib/mspec/runner/actions/timer.rb +22 -0
  68. data/lib/mspec/runner/filters.rb +4 -0
  69. data/lib/mspec/runner/filters/match.rb +22 -0
  70. data/lib/mspec/runner/filters/profile.rb +54 -0
  71. data/lib/mspec/runner/filters/regexp.rb +7 -0
  72. data/lib/mspec/runner/filters/tag.rb +29 -0
  73. data/lib/mspec/runner/formatters.rb +7 -0
  74. data/lib/mspec/runner/formatters/dotted.rb +81 -0
  75. data/lib/mspec/runner/formatters/html.rb +87 -0
  76. data/lib/mspec/runner/formatters/specdoc.rb +27 -0
  77. data/lib/mspec/runner/formatters/spinner.rb +89 -0
  78. data/lib/mspec/runner/formatters/summary.rb +8 -0
  79. data/lib/mspec/runner/formatters/unit.rb +25 -0
  80. data/lib/mspec/runner/formatters/yaml.rb +43 -0
  81. data/lib/mspec/runner/mspec.rb +232 -0
  82. data/lib/mspec/runner/object.rb +20 -0
  83. data/lib/mspec/runner/shared.rb +12 -0
  84. data/lib/mspec/runner/state.rb +116 -0
  85. data/lib/mspec/runner/tag.rb +20 -0
  86. data/lib/mspec/utils/name_map.rb +130 -0
  87. data/lib/mspec/utils/options.rb +344 -0
  88. data/lib/mspec/utils/script.rb +77 -0
  89. data/lib/mspec/version.rb +3 -0
  90. data/spec/commands/mkspec_spec.rb +321 -0
  91. data/spec/commands/mspec_ci_spec.rb +139 -0
  92. data/spec/commands/mspec_run_spec.rb +146 -0
  93. data/spec/commands/mspec_spec.rb +359 -0
  94. data/spec/commands/mspec_tag_spec.rb +131 -0
  95. data/spec/expectations/expectations_spec.rb +16 -0
  96. data/spec/expectations/should_spec.rb +99 -0
  97. data/spec/guards/bug_spec.rb +137 -0
  98. data/spec/guards/compliance_spec.rb +70 -0
  99. data/spec/guards/conflict_spec.rb +20 -0
  100. data/spec/guards/endian_spec.rb +42 -0
  101. data/spec/guards/extensions_spec.rb +36 -0
  102. data/spec/guards/guard_spec.rb +355 -0
  103. data/spec/guards/noncompliance_spec.rb +36 -0
  104. data/spec/guards/platform_spec.rb +84 -0
  105. data/spec/guards/quarantine_spec.rb +19 -0
  106. data/spec/guards/runner_spec.rb +75 -0
  107. data/spec/guards/superuser_spec.rb +22 -0
  108. data/spec/guards/support_spec.rb +22 -0
  109. data/spec/guards/version_spec.rb +133 -0
  110. data/spec/helpers/bignum_spec.rb +11 -0
  111. data/spec/helpers/const_lookup_spec.rb +19 -0
  112. data/spec/helpers/flunk_spec.rb +15 -0
  113. data/spec/helpers/io_spec.rb +34 -0
  114. data/spec/helpers/scratch_spec.rb +22 -0
  115. data/spec/helpers/tmp_spec.rb +72 -0
  116. data/spec/matchers/base_spec.rb +180 -0
  117. data/spec/matchers/be_ancestor_of_spec.rb +28 -0
  118. data/spec/matchers/be_close_spec.rb +46 -0
  119. data/spec/matchers/be_empty_spec.rb +26 -0
  120. data/spec/matchers/be_false_spec.rb +28 -0
  121. data/spec/matchers/be_kind_of_spec.rb +29 -0
  122. data/spec/matchers/be_nil_spec.rb +27 -0
  123. data/spec/matchers/be_true_spec.rb +28 -0
  124. data/spec/matchers/complain_spec.rb +52 -0
  125. data/spec/matchers/eql_spec.rb +33 -0
  126. data/spec/matchers/equal_spec.rb +33 -0
  127. data/spec/matchers/equal_utf16_spec.rb +47 -0
  128. data/spec/matchers/include_spec.rb +37 -0
  129. data/spec/matchers/output_spec.rb +74 -0
  130. data/spec/matchers/output_to_fd_spec.rb +33 -0
  131. data/spec/matchers/raise_error_spec.rb +56 -0
  132. data/spec/mocks/mock_spec.rb +272 -0
  133. data/spec/mocks/proxy_spec.rb +259 -0
  134. data/spec/runner/actions/debug_spec.rb +61 -0
  135. data/spec/runner/actions/filter_spec.rb +84 -0
  136. data/spec/runner/actions/gdb_spec.rb +61 -0
  137. data/spec/runner/actions/tag_spec.rb +253 -0
  138. data/spec/runner/actions/tally_spec.rb +107 -0
  139. data/spec/runner/actions/timer_spec.rb +42 -0
  140. data/spec/runner/filters/a.yaml +4 -0
  141. data/spec/runner/filters/b.yaml +11 -0
  142. data/spec/runner/filters/match_spec.rb +44 -0
  143. data/spec/runner/filters/profile_spec.rb +117 -0
  144. data/spec/runner/filters/regexp_spec.rb +13 -0
  145. data/spec/runner/filters/tag_spec.rb +77 -0
  146. data/spec/runner/formatters/dotted_spec.rb +184 -0
  147. data/spec/runner/formatters/html_spec.rb +191 -0
  148. data/spec/runner/formatters/specdoc_spec.rb +57 -0
  149. data/spec/runner/formatters/spinner_spec.rb +78 -0
  150. data/spec/runner/formatters/summary_spec.rb +29 -0
  151. data/spec/runner/formatters/unit_spec.rb +71 -0
  152. data/spec/runner/formatters/yaml_spec.rb +123 -0
  153. data/spec/runner/mspec_spec.rb +393 -0
  154. data/spec/runner/shared_spec.rb +41 -0
  155. data/spec/runner/state_spec.rb +535 -0
  156. data/spec/runner/tag_spec.rb +93 -0
  157. data/spec/runner/tags.txt +3 -0
  158. data/spec/spec_helper.rb +46 -0
  159. data/spec/utils/name_map_spec.rb +178 -0
  160. data/spec/utils/options_spec.rb +862 -0
  161. data/spec/utils/script_spec.rb +240 -0
  162. metadata +217 -0
@@ -0,0 +1,48 @@
1
+ class RaiseErrorMatcher
2
+ def initialize(exception, message, &block)
3
+ @exception = exception
4
+ @message = message
5
+ @block = block
6
+ end
7
+
8
+ def matches?(proc)
9
+ proc.call
10
+ return false
11
+ rescue Exception => @actual
12
+ return false unless @exception === @actual
13
+ if @message then
14
+ case @message
15
+ when String then
16
+ return false if @message != @actual.message
17
+ when Regexp then
18
+ return false if @message !~ @actual.message
19
+ end
20
+ end
21
+
22
+ @block[@actual] if @block
23
+
24
+ return true
25
+ end
26
+
27
+ def failure_message
28
+ message = ["Expected #{@exception}#{%[ (#{@message})] if @message}"]
29
+
30
+ if @actual then
31
+ message << "but got #{@actual.class}#{%[ (#{@actual.message})] if @actual.message}"
32
+ else
33
+ message << "but no exception was raised"
34
+ end
35
+
36
+ message
37
+ end
38
+
39
+ def negative_failure_message
40
+ ["Expected to not get #{@exception}#{%[ (#{@message})] if @message}", ""]
41
+ end
42
+ end
43
+
44
+ class Object
45
+ def raise_error(exception=Exception, message=nil, &block)
46
+ RaiseErrorMatcher.new(exception, message, &block)
47
+ end
48
+ end
@@ -0,0 +1,3 @@
1
+ require 'mspec/mocks/mock'
2
+ require 'mspec/mocks/proxy'
3
+ require 'mspec/mocks/object'
@@ -0,0 +1,123 @@
1
+ require 'mspec/expectations/expectations'
2
+
3
+ module Mock
4
+ def self.reset
5
+ @expects = nil
6
+ end
7
+
8
+ def self.expects
9
+ @expects ||= Hash.new { |h,k| h[k] = [] }
10
+ end
11
+
12
+ def self.replaced_name(sym)
13
+ :"__ms_#{sym}__"
14
+ end
15
+
16
+ def self.install_method(obj, sym, type = :mock)
17
+ meta = class << obj; self; end
18
+
19
+ if (sym.to_sym == :respond_to? or obj.respond_to?(sym)) and !meta.instance_methods.include?(replaced_name(sym).to_s)
20
+ meta.__send__ :alias_method, replaced_name(sym), sym.to_sym
21
+ end
22
+
23
+ meta.class_eval <<-END
24
+ def #{sym}(*args, &block)
25
+ Mock.verify_call self, :#{sym}, *args, &block
26
+ end
27
+ END
28
+
29
+ MSpec.actions :expectation, MSpec.current.state
30
+
31
+ proxy = MockProxy.new
32
+
33
+ if type == :stub
34
+ expects[[obj, sym]] << proxy
35
+ proxy.at_least(0)
36
+ else
37
+ expects[[obj, sym]].unshift proxy
38
+ proxy.exactly(1)
39
+ end
40
+ end
41
+
42
+ def self.verify_count
43
+ expects.each do |key, proxies|
44
+ obj, sym = key.first, key.last
45
+
46
+ proxies.each do |proxy|
47
+ qualifier, count = proxy.count
48
+ pass = case qualifier
49
+ when :at_least
50
+ proxy.calls >= count
51
+ when :at_most
52
+ proxy.calls <= count
53
+ when :exactly
54
+ proxy.calls == count
55
+ else
56
+ false
57
+ end
58
+ unless pass
59
+ Expectation.fail_with("Mock #{obj.inspect}\nexpected to receive #{sym} #{qualifier.to_s.sub('_', ' ')} #{count} times",
60
+ "but received it #{proxy.calls} times")
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ def self.verify_call(obj, sym, *args, &block)
67
+ compare = *args
68
+
69
+ expects[[obj, sym]].each do |proxy|
70
+ pass = case proxy.arguments
71
+ when :any_args
72
+ true
73
+ when :no_args
74
+ compare.nil?
75
+ else
76
+ proxy.arguments == compare
77
+ end
78
+
79
+ if proxy.yielding?
80
+ if block
81
+ proxy.yielding.each do |args_to_yield|
82
+ if block.arity == -1 || block.arity == args_to_yield.size
83
+ block.call(*args_to_yield)
84
+ else
85
+ Expectation.fail_with("Mock #{obj.inspect} asked to yield |#{proxy.yielding.join(', ')}| on #{sym}\n",
86
+ "but a block with arity #{block.arity} was passed")
87
+ end
88
+ end
89
+ else
90
+ Expectation.fail_with("Mock #{obj.inspect} asked to yield |[#{proxy.yielding.join('], [')}]| on #{sym}\n",
91
+ "but no block was passed")
92
+ end
93
+ end
94
+
95
+ if pass
96
+ proxy.called
97
+ return proxy.returning
98
+ end
99
+ end
100
+
101
+ if sym.to_sym == :respond_to?
102
+ return obj.__send__(replaced_name(sym), compare)
103
+ else
104
+ Expectation.fail_with("Mock #{obj.inspect}: method #{sym}\n",
105
+ "called with unexpected arguments (#{Array(compare).join(' ')})")
106
+ end
107
+ end
108
+
109
+ def self.cleanup
110
+ expects.keys.each do |obj, sym|
111
+ meta = class << obj; self; end
112
+
113
+ replaced = replaced_name(sym)
114
+ if meta.instance_methods.include?(replaced.to_s)
115
+ meta.__send__ :alias_method, sym.to_sym, replaced
116
+ meta.__send__ :remove_method, replaced
117
+ else
118
+ meta.__send__ :remove_method, sym.to_sym
119
+ end
120
+ end
121
+ reset
122
+ end
123
+ end
@@ -0,0 +1,28 @@
1
+ require 'mspec/mocks/proxy'
2
+
3
+ class MockObject
4
+ def initialize(name)
5
+ @name = name
6
+ end
7
+ end
8
+
9
+ class Object
10
+ def stub!(sym)
11
+ Mock.install_method self, sym, :stub
12
+ end
13
+
14
+ def should_receive(sym)
15
+ Mock.install_method self, sym
16
+ end
17
+
18
+ def should_not_receive(sym)
19
+ proxy = Mock.install_method self, sym
20
+ proxy.exactly(0).times
21
+ # return nil so that further chained calls will raise
22
+ nil
23
+ end
24
+
25
+ def mock(name)
26
+ MockObject.new(name)
27
+ end
28
+ end
@@ -0,0 +1,112 @@
1
+ class MockProxy
2
+ def initialize
3
+ @multiple_returns = nil
4
+ @returning = nil
5
+ @yielding = []
6
+ @arguments = :any_args
7
+ end
8
+
9
+ def count
10
+ @count ||= [:exactly, 0]
11
+ end
12
+
13
+ def arguments
14
+ @arguments
15
+ end
16
+
17
+ def returning
18
+ if @multiple_returns
19
+ if @returning.size == 1
20
+ @multiple_returns = false
21
+ return @returning = @returning.shift
22
+ end
23
+ return @returning.shift
24
+ end
25
+ @returning
26
+ end
27
+
28
+ def times
29
+ self
30
+ end
31
+
32
+ def calls
33
+ @calls ||= 0
34
+ end
35
+
36
+ def called
37
+ @calls = calls + 1
38
+ end
39
+
40
+ def exactly(n)
41
+ @count = [:exactly, n_times(n)]
42
+ self
43
+ end
44
+
45
+ def at_least(n)
46
+ @count = [:at_least, n_times(n)]
47
+ self
48
+ end
49
+
50
+ def at_most(n)
51
+ @count = [:at_most, n_times(n)]
52
+ self
53
+ end
54
+
55
+ def once
56
+ exactly 1
57
+ end
58
+
59
+ def twice
60
+ exactly 2
61
+ end
62
+
63
+ def any_number_of_times
64
+ at_least 0
65
+ end
66
+
67
+ def with(*args)
68
+ raise ArgumentError, "you must specify the expected arguments" if args.empty?
69
+ @arguments = *args
70
+ self
71
+ end
72
+
73
+ def and_return(*args)
74
+ case args.size
75
+ when 0
76
+ @returning = nil
77
+ when 1
78
+ @returning = args[0]
79
+ else
80
+ @multiple_returns = true
81
+ @returning = args
82
+ count[1] = args.size if count[1] < args.size
83
+ end
84
+ self
85
+ end
86
+
87
+ def and_yield(*args)
88
+ @yielding << args
89
+ self
90
+ end
91
+
92
+ def yielding
93
+ @yielding
94
+ end
95
+
96
+ def yielding?
97
+ !@yielding.empty?
98
+ end
99
+
100
+ private
101
+
102
+ def n_times(n)
103
+ case n
104
+ when :once
105
+ 1
106
+ when :twice
107
+ 2
108
+ else
109
+ Integer n
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,13 @@
1
+ require 'mspec/mocks'
2
+ require 'mspec/runner/mspec'
3
+ require 'mspec/runner/object'
4
+ require 'mspec/runner/formatters'
5
+ require 'mspec/runner/actions'
6
+ require 'mspec/runner/filters'
7
+ require 'mspec/runner/shared'
8
+ require 'mspec/runner/tag'
9
+
10
+ def $stderr.write(str)
11
+ # The 'useless use of' warnings are a crime against OO.
12
+ str =~ /useless use of/ ? nil : super
13
+ end
@@ -0,0 +1,6 @@
1
+ require 'mspec/runner/actions/tally'
2
+ require 'mspec/runner/actions/timer'
3
+ require 'mspec/runner/actions/filter'
4
+ require 'mspec/runner/actions/tag'
5
+ require 'mspec/runner/actions/debug'
6
+ require 'mspec/runner/actions/gdb'
@@ -0,0 +1,17 @@
1
+ require 'mspec/runner/actions/filter'
2
+
3
+ class DebugAction < ActionFilter
4
+ def before(state)
5
+ Kernel.debugger if self === state.description
6
+ end
7
+
8
+ def register
9
+ super
10
+ MSpec.register :before, self
11
+ end
12
+
13
+ def unregister
14
+ super
15
+ MSpec.unregister :before, self
16
+ end
17
+ end
@@ -0,0 +1,40 @@
1
+ require 'mspec/runner/filters/match'
2
+
3
+ # ActionFilter is a base class for actions that are triggered by
4
+ # specs that match the filter. The filter may be specified by
5
+ # strings that match spec descriptions or by tags for strings
6
+ # that match spec descriptions.
7
+ #
8
+ # Unlike TagFilter and RegexpFilter, ActionFilter instances do
9
+ # not affect the specs that are run. The filter is only used to
10
+ # trigger the action.
11
+
12
+ class ActionFilter
13
+ def initialize(tags=nil, descs=nil)
14
+ @tags = Array(tags)
15
+ descs = Array(descs)
16
+ @sfilter = MatchFilter.new(nil, *descs) unless descs.empty?
17
+ end
18
+
19
+ def ===(string)
20
+ @sfilter === string or @tfilter === string
21
+ end
22
+
23
+ def load
24
+ @tfilter = nil
25
+ return if @tags.empty?
26
+
27
+ desc = MSpec.read_tags(*@tags).map { |t| t.description }
28
+ return if desc.empty?
29
+
30
+ @tfilter = MatchFilter.new(nil, *desc)
31
+ end
32
+
33
+ def register
34
+ MSpec.register :load, self
35
+ end
36
+
37
+ def unregister
38
+ MSpec.unregister :load, self
39
+ end
40
+ end
@@ -0,0 +1,17 @@
1
+ require 'mspec/runner/actions/filter'
2
+
3
+ class GdbAction < ActionFilter
4
+ def before(state)
5
+ Kernel.yield_gdb(true) if self === state.description
6
+ end
7
+
8
+ def register
9
+ super
10
+ MSpec.register :before, self
11
+ end
12
+
13
+ def unregister
14
+ super
15
+ MSpec.unregister :before, self
16
+ end
17
+ end
@@ -0,0 +1,97 @@
1
+ require 'mspec/runner/actions/filter'
2
+
3
+ # TagAction - Write tagged spec description string to a
4
+ # tag file associated with each spec file.
5
+ #
6
+ # The action is triggered by specs whose descriptions
7
+ # match the filter created with 'tags' and/or 'desc'
8
+ #
9
+ # The action fires in the :after event, after the spec
10
+ # had been run. The action fires if the outcome of
11
+ # running the spec matches 'outcome'.
12
+ #
13
+ # The arguments are:
14
+ #
15
+ # action: :add, :del
16
+ # outcome: :pass, :fail, :all
17
+ # tag: the tag to create/delete
18
+ # comment: the comment to create
19
+ # tags: zero or more tags to get matching
20
+ # spec description strings from
21
+ # desc: zero or more strings to match the
22
+ # spec description strings
23
+
24
+ class TagAction < ActionFilter
25
+ def initialize(action, outcome, tag, comment, tags=nil, descs=nil)
26
+ super tags, descs
27
+ @action = action
28
+ @outcome = outcome
29
+ @tag = tag
30
+ @comment = comment
31
+ @report = []
32
+ end
33
+
34
+ def ===(string)
35
+ return true unless @sfilter or @tfilter
36
+ @sfilter === string or @tfilter === string
37
+ end
38
+
39
+ def after(state)
40
+ if self === state.description and outcome? state
41
+ tag = SpecTag.new
42
+ tag.tag = @tag
43
+ tag.comment = @comment
44
+ tag.description = state.description
45
+
46
+ case @action
47
+ when :add
48
+ changed = MSpec.write_tag tag
49
+ when :del
50
+ changed = MSpec.delete_tag tag
51
+ end
52
+
53
+ @report << state.description if changed
54
+ end
55
+ end
56
+
57
+ def outcome?(state)
58
+ @outcome == :all or
59
+ (@outcome == :pass and not state.exception?) or
60
+ (@outcome == :fail and state.exception?)
61
+ end
62
+
63
+ def report
64
+ @report.join("\n") + "\n"
65
+ end
66
+ private :report
67
+
68
+ def finish
69
+ case @action
70
+ when :add
71
+ if @report.empty?
72
+ print "\nTagAction: no specs were tagged with '#{@tag}'\n"
73
+ else
74
+ print "\nTagAction: specs tagged with '#{@tag}':\n\n"
75
+ print report
76
+ end
77
+ when :del
78
+ if @report.empty?
79
+ print "\nTagAction: no tags '#{@tag}' were deleted\n"
80
+ else
81
+ print "\nTagAction: tag '#{@tag}' deleted for specs:\n\n"
82
+ print report
83
+ end
84
+ end
85
+ end
86
+
87
+ def register
88
+ super
89
+ MSpec.register :after, self
90
+ MSpec.register :finish, self
91
+ end
92
+
93
+ def unregister
94
+ super
95
+ MSpec.unregister :after, self
96
+ end
97
+ end