mspec 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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,20 @@
1
+ class SpecTag
2
+ attr_accessor :tag, :comment, :description
3
+
4
+ def initialize(string=nil)
5
+ parse(string) if string
6
+ end
7
+
8
+ def parse(string)
9
+ m = /^([^()#:]+)(\(([^)]+)?\))?:(.*)/.match string
10
+ @tag, @comment, @description = m.values_at(1, 3, 4) if m
11
+ end
12
+
13
+ def to_s
14
+ "#{@tag}#{ "(#{@comment})" if @comment }:#{@description}"
15
+ end
16
+
17
+ def ==(o)
18
+ @tag == o.tag and @comment == o.comment and @description == o.description
19
+ end
20
+ end
@@ -0,0 +1,130 @@
1
+ require 'mspec/helpers/const_lookup'
2
+
3
+ class NameMap
4
+ MAP = {
5
+ '`' => 'backtick',
6
+ '+' => 'plus',
7
+ '-' => 'minus',
8
+ '+@' => 'uplus',
9
+ '-@' => 'uminus',
10
+ '*' => 'multiply',
11
+ '/' => 'divide',
12
+ '%' => 'modulo',
13
+ '<<' => {'Bignum' => 'left_shift',
14
+ 'Fixnum' => 'left_shift',
15
+ 'IO' => 'output',
16
+ :default => 'append' },
17
+ '>>' => 'right_shift',
18
+ '<' => 'lt',
19
+ '<=' => 'lte',
20
+ '>' => 'gt',
21
+ '>=' => 'gte',
22
+ '=' => 'assignment',
23
+ '==' => 'equal_value',
24
+ '===' => 'case_compare',
25
+ '<=>' => 'comparison',
26
+ '[]' => 'element_reference',
27
+ '[]=' => 'element_set',
28
+ '**' => 'exponent',
29
+ '!' => 'not',
30
+ '~' => {'Bignum' => 'complement',
31
+ 'Fixnum' => 'complement',
32
+ 'Regexp' => 'match',
33
+ 'String' => 'match' },
34
+ '!=' => 'not_equal',
35
+ '!~' => 'not_match',
36
+ '=~' => 'match',
37
+ '&' => {'Bignum' => 'bit_and',
38
+ 'Fixnum' => 'bit_and',
39
+ 'Array' => 'intersection',
40
+ 'TrueClass' => 'and',
41
+ 'FalseClass' => 'and',
42
+ 'NilClass' => 'and',
43
+ 'Set' => 'intersection' },
44
+ '|' => {'Bignum' => 'bit_or',
45
+ 'Fixnum' => 'bit_or',
46
+ 'Array' => 'union',
47
+ 'TrueClass' => 'or',
48
+ 'FalseClass' => 'or',
49
+ 'NilClass' => 'or',
50
+ 'Set' => 'union' },
51
+ '^' => {'Bignum' => 'bit_xor',
52
+ 'Fixnum' => 'bit_xor',
53
+ 'TrueClass' => 'xor',
54
+ 'FalseClass' => 'xor',
55
+ 'NilClass' => 'xor',
56
+ 'Set' => 'exclusion'},
57
+ }
58
+
59
+ EXCLUDED = %w[
60
+ MSpecScript
61
+ MkSpec
62
+ DTracer
63
+ NameMap
64
+ OptionParser
65
+ YAML
66
+ ]
67
+
68
+ def initialize(filter=false)
69
+ @seen = {}
70
+ @filter = filter
71
+ end
72
+
73
+ def exception?(name)
74
+ return false unless c = class_or_module(name)
75
+ c == Errno or c.ancestors.include? Exception
76
+ end
77
+
78
+ def class_or_module(c)
79
+ const = const_lookup(c)
80
+ filtered = @filter && EXCLUDED.include?(const.name)
81
+ return const if Module === const and not filtered
82
+ rescue NameError
83
+ end
84
+
85
+ def namespace(mod, const)
86
+ return const.to_s if mod.nil? or %w[Object Class Module].include? mod
87
+ "#{mod}::#{const}"
88
+ end
89
+
90
+ def map(hash, constants, mod=nil)
91
+ @seen = {} unless mod
92
+
93
+ constants.each do |const|
94
+ name = namespace mod, const
95
+ m = class_or_module name
96
+ next unless m and not @seen[m]
97
+ @seen[m] = true
98
+
99
+ ms = m.methods false
100
+ hash["#{name}."] = ms.sort unless ms.empty?
101
+
102
+ ms = m.public_instance_methods(false) +
103
+ m.private_instance_methods(false) +
104
+ m.protected_instance_methods(false)
105
+ hash["#{name}#"] = ms.sort unless ms.empty?
106
+
107
+ map hash, m.constants, name
108
+ end
109
+
110
+ hash
111
+ end
112
+
113
+ def dir_name(c, base)
114
+ return File.join(base, 'exception') if exception? c
115
+
116
+ c.split('::').inject(base) do |dir, name|
117
+ name.gsub!(/Class/, '') unless name == 'Class'
118
+ File.join dir, name.downcase
119
+ end
120
+ end
121
+
122
+ def file_name(m, c)
123
+ if MAP.key?(m)
124
+ name = MAP[m].is_a?(Hash) ? MAP[m][c.split('::').last] || MAP[m][:default] : MAP[m]
125
+ else
126
+ name = m.gsub(/[?!=]/, '')
127
+ end
128
+ "#{name}_spec.rb"
129
+ end
130
+ end
@@ -0,0 +1,344 @@
1
+ # FIXME: There are essentially two options for these runner
2
+ # scripts: 1. all in one file, 2. in separate files. The fact
3
+ # that the subcommands share a number of options weighs
4
+ # toward having a single script. However, the subcommands
5
+ # also take specialized options which can be confusing. Added
6
+ # to this the support for switches to specify a different
7
+ # implementation and the balance swings to separate scripts.
8
+ #
9
+ # Now, the fun begins. The main script needs a way to specify
10
+ # certain command line options and then pass the rest to the
11
+ # invoked subscript. Unfortunately, this possibility does not
12
+ # exist in the universe inhabited by OptionParser or GetoptLong.
13
+ #
14
+ # The #filter! method below does not properly handle optional
15
+ # arguments to a switch.
16
+ class OptionParser
17
+ class Switch
18
+ def consume?(opt)
19
+ if opt == short.to_s or opt == long.to_s
20
+ return arg ? 2 : 1
21
+ elsif opt[0..1] == short.to_s and opt.size > 2
22
+ return 1
23
+ else
24
+ return 0
25
+ end
26
+ end
27
+ end
28
+
29
+ def filter!(argv)
30
+ @stack.inject(options=[]) do |list, entry|
31
+ entry.list.each do |switch|
32
+ next unless switch.kind_of? OptionParser::Switch
33
+ list << switch
34
+ end
35
+ list
36
+ end
37
+
38
+ filtered = []
39
+ recognized = []
40
+ consume = nil
41
+ until argv.empty?
42
+ opt = argv.shift
43
+ options.find { |o| consume = o.consume?(opt); consume != 0 }
44
+ if consume == 0
45
+ filtered << opt
46
+ else
47
+ recognized << opt
48
+ recognized << argv.shift if consume == 2
49
+ end
50
+ end
51
+ argv.replace recognized
52
+ filtered
53
+ end
54
+ end
55
+
56
+ require 'mspec/version'
57
+
58
+ # MSpecOptions wraps OptionParser and provides a composable set of
59
+ # options that the runner scripts pick from.
60
+ class MSpecOptions
61
+ attr_reader :parser
62
+
63
+ def initialize(config, command, *args)
64
+ @parser = OptionParser.new(*args) do |opts|
65
+ opts.banner = "mspec #{command} [options] (FILE|DIRECTORY|GLOB)+"
66
+ opts.separator ""
67
+ end
68
+
69
+ @config = config
70
+ end
71
+
72
+ def add_config(&block)
73
+ on("-B", "--config FILE", String,
74
+ "Load FILE containing configuration options", &block)
75
+ end
76
+
77
+ def add_name
78
+ on("-n", "--name RUBY_NAME", String,
79
+ "Set the value of RUBY_NAME (used to determine the implementation)") do |n|
80
+ Object.const_set :RUBY_NAME, n
81
+ end
82
+ end
83
+
84
+ def add_targets
85
+ on("-t", "--target TARGET", String,
86
+ "Implementation to run the specs, where:") do |t|
87
+ case t
88
+ when 'r', 'ruby'
89
+ @config[:target] = 'ruby'
90
+ @config[:flags] << '-v'
91
+ when 'r19', 'ruby19'
92
+ @config[:target] = 'ruby19'
93
+ when 'x', 'rubinius'
94
+ @config[:target] = 'shotgun/rubinius'
95
+ when 'X', 'rbx'
96
+ @config[:target] = 'rbx'
97
+ when 'j', 'jruby'
98
+ @config[:target] = 'jruby'
99
+ else
100
+ @config[:target] = t
101
+ end
102
+ end
103
+
104
+ separator ""
105
+ separator " 'r' or 'ruby' invokes ruby in PATH"
106
+ separator " 'r19' or 'ruby19' invokes ruby19 in PATH"
107
+ separator " 'x' or 'rubinius' invokes ./shotgun/rubinius"
108
+ separator " 'X' or 'rbx' invokes rbx in PATH"
109
+ separator " 'j' or 'jruby' invokes jruby in PATH\n"
110
+
111
+ on("-T", "--target-opt OPT", String,
112
+ "Pass OPT as a flag to the target implementation") do |t|
113
+ @config[:flags] << t
114
+ end
115
+ on("-I", "--include DIR", String,
116
+ "Pass DIR through as the -I option to the target") do |d|
117
+ @config[:includes] << "-I#{d}"
118
+ end
119
+ on("-r", "--require LIBRARY", String,
120
+ "Pass LIBRARY through as the -r option to the target") do |f|
121
+ @config[:requires] << "-r#{f}"
122
+ end
123
+ end
124
+
125
+ def add_tags_dir
126
+ on("-X", "--tags-dir DIR", String,
127
+ "Use DIR as the path prefix for locating spec tag files") do |d|
128
+ @config[:tags_dir] = d
129
+ end
130
+ end
131
+
132
+ def add_formatters
133
+ on("-f", "--format FORMAT", String,
134
+ "Formatter for reporting, where FORMAT is one of:") do |o|
135
+ case o
136
+ when 's', 'spec', 'specdoc'
137
+ @config[:formatter] = SpecdocFormatter
138
+ when 'h', 'html'
139
+ @config[:formatter] = HtmlFormatter
140
+ when 'd', 'dot', 'dotted'
141
+ @config[:formatter] = DottedFormatter
142
+ when 'u', 'unit', 'unitdiff'
143
+ @config[:formatter] = UnitdiffFormatter
144
+ when 'm', 'summary'
145
+ @config[:formatter] = SummaryFormatter
146
+ when 'a', '*', 'spin'
147
+ @config[:formatter] = SpinnerFormatter
148
+ when 'y', 'yaml'
149
+ @config[:formatter] = YamlFormatter
150
+ else
151
+ puts "Unknown format: #{o}"
152
+ puts @parser
153
+ exit
154
+ end
155
+ end
156
+ separator("")
157
+ separator(" s, spec, specdoc SpecdocFormatter")
158
+ separator(" h, html, HtmlFormatter")
159
+ separator(" d, dot, dotted DottedFormatter")
160
+ separator(" u, unit, unitdiff UnitdiffFormatter")
161
+ separator(" m, summary SummaryFormatter")
162
+ separator(" a, *, spin SpinnerFormatter")
163
+ separator(" y, yaml YamlFormatter\n")
164
+ on("-o", "--output FILE", String,
165
+ "Write formatter output to FILE") do |f|
166
+ @config[:output] = f
167
+ end
168
+ end
169
+
170
+ def add_filters
171
+ on("-e", "--example STR", String,
172
+ "Run examples with descriptions matching STR") do |o|
173
+ @config[:includes] << o
174
+ end
175
+ on("-E", "--exclude STR", String,
176
+ "Exclude examples with descriptions matching STR") do |o|
177
+ @config[:excludes] << o
178
+ end
179
+ on("-p", "--pattern PATTERN", Regexp,
180
+ "Run examples with descriptions matching PATTERN") do |o|
181
+ @config[:patterns] << o
182
+ end
183
+ on("-P", "--excl-pattern PATTERN", Regexp,
184
+ "Exclude examples with descriptions matching PATTERN") do |o|
185
+ @config[:xpatterns] << o
186
+ end
187
+ on("-g", "--tag TAG", String,
188
+ "Run examples with descriptions matching ones tagged with TAG") do |o|
189
+ @config[:tags] << o
190
+ end
191
+ on("-G", "--excl-tag TAG", String,
192
+ "Exclude examples with descriptions matching ones tagged with TAG") do |o|
193
+ @config[:xtags] << o
194
+ end
195
+ on("-w", "--profile FILE", String,
196
+ "Run examples for methods listed in the profile FILE") do |f|
197
+ @config[:profiles] << f
198
+ end
199
+ on("-W", "--excl-profile FILE", String,
200
+ "Exclude examples for methods listed in the profile FILE") do |f|
201
+ @config[:xprofiles] << f
202
+ end
203
+ end
204
+
205
+ def add_pretend
206
+ on("-Z", "--dry-run",
207
+ "Invoke formatters and other actions, but don't execute the specs") do
208
+ MSpec.register_mode :pretend
209
+ end
210
+ end
211
+
212
+ def add_randomize
213
+ on("-H", "--random",
214
+ "Randomize the list of spec files") do
215
+ MSpec.randomize
216
+ end
217
+ end
218
+
219
+ def add_verbose
220
+ on("-V", "--verbose", "Output the name of each file processed") do
221
+ obj = Object.new
222
+ def obj.start
223
+ @width = MSpec.retrieve(:files).inject(0) { |max, f| f.size > max ? f.size : max }
224
+ end
225
+ def obj.load
226
+ file = MSpec.retrieve :file
227
+ print "\n#{file.ljust(@width)}"
228
+ end
229
+ MSpec.register :start, obj
230
+ MSpec.register :load, obj
231
+ end
232
+
233
+ on("-m", "--marker MARKER", String,
234
+ "Output MARKER for each file processed") do |o|
235
+ obj = Object.new
236
+ obj.instance_variable_set :@marker, o
237
+ def obj.load
238
+ print @marker
239
+ end
240
+ MSpec.register :load, obj
241
+ end
242
+ end
243
+
244
+ def add_interrupt
245
+ on("--int-spec", "Control-C interupts the current spec only") do
246
+ @config[:abort] = false
247
+ end
248
+ end
249
+
250
+ def add_verify
251
+ on("-Y", "--verify",
252
+ "Verify that guarded specs pass and fail as expected") do
253
+ MSpec.set_mode :verify
254
+ end
255
+ on("-O", "--report", "Report guarded specs") do
256
+ MSpec.set_mode :report
257
+ end
258
+ end
259
+
260
+ def add_tagging
261
+ on("-N", "--add TAG", String,
262
+ "Add TAG with format 'tag' or 'tag(comment)' (see -Q, -F, -L)") do |o|
263
+ @config[:tagger] = :add
264
+ @config[:tag] = "#{o}:"
265
+ end
266
+ on("-R", "--del TAG", String,
267
+ "Delete TAG (see -Q, -F, -L)") do |o|
268
+ @config[:tagger] = :del
269
+ @config[:tag] = "#{o}:"
270
+ @config[:outcome] = :pass
271
+ end
272
+ on("-Q", "--pass", "Apply action to specs that pass (default for --del)") do
273
+ @config[:outcome] = :pass
274
+ end
275
+ on("-F", "--fail", "Apply action to specs that fail (default for --add)") do
276
+ @config[:outcome] = :fail
277
+ end
278
+ on("-L", "--all", "Apply action to all specs") do
279
+ @config[:outcome] = :all
280
+ end
281
+ end
282
+
283
+ def add_action_filters
284
+ on("-K", "--action-tag TAG", String,
285
+ "Spec descriptions marked with TAG will trigger the specified action") do |o|
286
+ @config[:atags] << o
287
+ end
288
+ on("-S", "--action-string STR", String,
289
+ "Spec descriptions matching STR will trigger the specified action") do |o|
290
+ @config[:astrings] << o
291
+ end
292
+ end
293
+
294
+ def add_actions
295
+ on("--spec-debug",
296
+ "Invoke the debugger when a spec description matches (see -K, -S)") do
297
+ @config[:debugger] = true
298
+ end
299
+ on("--spec-gdb",
300
+ "Invoke Gdb when a spec description matches (see -K, -S)") do
301
+ @config[:gdb] = true
302
+ end
303
+ end
304
+
305
+ def add_version
306
+ on("-v", "--version", "Show version") do
307
+ puts "#{File.basename $0} #{MSpec::VERSION}"
308
+ exit
309
+ end
310
+ end
311
+
312
+ def add_help
313
+ on("-h", "--help", "Show this message") do
314
+ puts @parser
315
+ exit
316
+ end
317
+ end
318
+
319
+ def on(*args, &block)
320
+ @parser.on(*args, &block)
321
+ end
322
+
323
+ def separator(str)
324
+ @parser.separator str
325
+ end
326
+
327
+ def parse(argv=ARGV)
328
+ result = @parser.parse argv
329
+
330
+ if (@config[:debugger] || @config[:gdb]) &&
331
+ @config[:atags].empty? && @config[:astrings].empty?
332
+ puts "Missing --action-tag or --action-string."
333
+ puts @parser
334
+ exit 1
335
+ end
336
+
337
+ result
338
+ rescue OptionParser::ParseError => e
339
+ puts @parser
340
+ puts
341
+ puts e
342
+ exit 1
343
+ end
344
+ end