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