mspec 1.4.0 → 1.5.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.
@@ -2,7 +2,7 @@
2
2
 
3
3
  MSPEC_HOME = File.expand_path(File.dirname(__FILE__) + '/../../..')
4
4
 
5
- require 'optparse'
5
+ require 'mspec/version'
6
6
  require 'mspec/utils/options'
7
7
  require 'mspec/utils/script'
8
8
  require 'mspec/helpers/tmp'
@@ -20,24 +20,19 @@ class MSpecMain < MSpecScript
20
20
  end
21
21
 
22
22
  def options(argv=ARGV)
23
- if ["ci", "run", "tag"].include? argv[0]
24
- config[:command] = argv.shift
25
- config[:options] << "-h" if argv.delete("-h") || argv.delete("--help")
26
- config[:options] << "-v" if argv.delete("-v") || argv.delete("--version")
27
- end
23
+ config[:command] = argv.shift if ["ci", "run", "tag"].include?(argv[0])
28
24
 
29
- options = MSpecOptions.new config, "[COMMAND]", "", 28, " "
25
+ options = MSpecOptions.new "mspec [COMMAND] [options] (FILE|DIRECTORY|GLOB)+", 30, config
30
26
 
31
- options.separator ""
32
- options.separator " The mspec command sets up and invokes the sub-commands"
33
- options.separator " (see below) to enable, for instance, running the specs"
34
- options.separator " with different implementations like ruby, jruby, rbx, etc.\n"
27
+ options.doc " The mspec command sets up and invokes the sub-commands"
28
+ options.doc " (see below) to enable, for instance, running the specs"
29
+ options.doc " with different implementations like ruby, jruby, rbx, etc.\n"
35
30
 
36
- options.add_config do |f|
31
+ options.configure do |f|
37
32
  config[:options] << '-B' << f
38
33
  end
39
34
 
40
- options.add_targets
35
+ options.targets
41
36
 
42
37
  options.on("-D", "--gdb", "Run under gdb") do
43
38
  config[:flags] << '--gdb'
@@ -53,21 +48,32 @@ class MSpecMain < MSpecScript
53
48
  config[:multi] = true
54
49
  config[:options] << "-fy"
55
50
  end
56
- options.add_version
57
- options.on("-h", "--help", "Show this message") do
58
- puts options.parser
59
- exit
51
+ options.version MSpec::VERSION do
52
+ if config[:command]
53
+ config[:options] << "-v"
54
+ else
55
+ puts options
56
+ exit
57
+ end
58
+ end
59
+ options.help do
60
+ if config[:command]
61
+ config[:options] << "-h"
62
+ else
63
+ puts options
64
+ exit 1
65
+ end
60
66
  end
61
67
 
62
68
  # The rest of the help output
63
- options.separator "\n where COMMAND is one of:\n"
64
- options.separator " run - Run the specified specs (default)"
65
- options.separator " ci - Run the known good specs"
66
- options.separator " tag - Add or remove tags\n"
67
- options.separator " mspec COMMAND -h for more options\n"
68
-
69
- config[:options] += options.parser.filter! argv
70
- options.parse argv
69
+ options.doc "\n where COMMAND is one of:\n"
70
+ options.doc " run - Run the specified specs (default)"
71
+ options.doc " ci - Run the known good specs"
72
+ options.doc " tag - Add or remove tags\n"
73
+ options.doc " mspec COMMAND -h for more options\n"
74
+
75
+ options.on_extra { |o| config[:options] << o }
76
+ config[:options].concat options.parse(argv)
71
77
  end
72
78
 
73
79
  def register; end
@@ -126,11 +132,14 @@ class MSpecMain < MSpecScript
126
132
 
127
133
  def run
128
134
  ENV['MSPEC_RUNNER'] = '1'
135
+ ENV['RUBY_EXE'] = config[:target]
136
+ ENV['RUBY_FLAGS'] = config[:flags].join " "
129
137
 
130
- argv = ["-v"]
138
+ argv = []
131
139
  argv.concat config[:flags]
132
140
  argv.concat config[:includes]
133
141
  argv.concat config[:requires]
142
+ argv << "-v"
134
143
  argv << "#{MSPEC_HOME}/bin/mspec-#{ config[:command] || "run" }"
135
144
  argv.concat config[:options]
136
145
 
data/lib/mspec/guards.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require 'mspec/ruby_name'
1
2
  require 'mspec/guards/bug'
2
3
  require 'mspec/guards/compliance'
3
4
  require 'mspec/guards/extensions'
@@ -1,21 +1,6 @@
1
1
  require 'mspec/runner/mspec'
2
2
  require 'mspec/runner/actions/tally'
3
3
 
4
- unless defined?(RUBY_NAME) and RUBY_NAME
5
- if defined?(RUBY_ENGINE) and RUBY_ENGINE
6
- RUBY_NAME = RUBY_ENGINE
7
- if defined?(ARG0)
8
- RUBY_CLI = /rubinius|rbx/.match(ARG0) ? "shotgun/rubinius" : ARG0
9
- else
10
- RUBY_CLI = RUBY_NAME
11
- end
12
- else
13
- require 'rbconfig'
14
- RUBY_NAME = Config::CONFIG["RUBY_INSTALL_NAME"] || Config::CONFIG["ruby_install_name"]
15
- RUBY_CLI = RUBY_NAME
16
- end
17
- end
18
-
19
4
  class SpecGuard
20
5
  def self.register
21
6
  unless @registered
@@ -81,6 +66,8 @@ class SpecGuard
81
66
  RUBY_NAME =~ /^ruby(1.9)?/ and RUBY_VERSION =~ /^1.9/
82
67
  when :jruby
83
68
  RUBY_NAME =~ /^jruby/
69
+ when :ironruby, :ir
70
+ RUBY_NAME =~ /^ironruby/
84
71
  else
85
72
  false
86
73
  end
data/lib/mspec/helpers.rb CHANGED
@@ -4,3 +4,4 @@ require 'mspec/helpers/io'
4
4
  require 'mspec/helpers/scratch'
5
5
  require 'mspec/helpers/tmp'
6
6
  require 'mspec/helpers/const_lookup'
7
+ require 'mspec/helpers/ruby_exe'
@@ -0,0 +1,101 @@
1
+ require 'mspec/ruby_name'
2
+
3
+ # The ruby_exe helper provides a wrapper for invoking the
4
+ # same Ruby interpreter as the one running the specs and
5
+ # getting the output from running the code. If +code+ is a
6
+ # file that exists, it will be run. Otherwise, +code+ should
7
+ # be Ruby code that will be run with the -e command line
8
+ # option. For example:
9
+ #
10
+ # ruby_exe('path/to/some/file.rb')
11
+ #
12
+ # will be executed as
13
+ #
14
+ # `#{RUBY_EXE} #{'path/to/some/file.rb'}`
15
+ #
16
+ # while
17
+ #
18
+ # ruby_exe('puts "hello, world."')
19
+ #
20
+ # will be executed as
21
+ #
22
+ # `#{RUBY_EXE} -e #{'puts "hello, world."'}`
23
+ #
24
+ # The RUBY_EXE constant can be set explicitly since the value
25
+ # is used each time ruby_exe is invoked. The mspec runner script
26
+ # will set ENV['RUBY_EXE'] to the name of the executable used
27
+ # to invoke the mspec-run script. The value of RUBY_EXE will be
28
+ # constructed as follows:
29
+ #
30
+ # 1. the value of ENV['RUBY_EXE']
31
+ # 2. an explicit value based on RUBY_NAME
32
+ # 3. cwd/(RUBY_NAME + $(EXEEXT) || $(exeext) || '')
33
+ # 4. $(bindir)/$(RUBY_INSTALL_NAME)
34
+ #
35
+ # The value will only be used if the file exists and is executable.
36
+ #
37
+ # These 4 ways correspond to the following scenarios:
38
+ #
39
+ # 1. Using the MSpec runner scripts, the name of the
40
+ # executable is explicitly passed by ENV['RUBY_EXE']
41
+ # so there is no ambiguity.
42
+ #
43
+ # Otherwise, if using RSpec (or something else)
44
+ #
45
+ # 2. Running the specs while developing an alternative
46
+ # Ruby implementation. This explicitly names the
47
+ # executable in the development directory based on
48
+ # the value of RUBY_NAME, which is probably initialized
49
+ # from the value of RUBY_ENGINE.
50
+ # 3. Running the specs within the source directory for
51
+ # some implementation. (E.g. a local build directory.)
52
+ # 4. Running the specs against some installed Ruby
53
+ # implementation.
54
+
55
+ class Object
56
+ def ruby_exe_options(option)
57
+ case option
58
+ when :env
59
+ ENV['RUBY_EXE']
60
+ when :engine
61
+ case RUBY_NAME
62
+ when 'rbx'
63
+ "bin/rbx"
64
+ when 'jruby'
65
+ "bin/jruby"
66
+ when 'ironruby'
67
+ "ir"
68
+ end
69
+ when :name
70
+ bin = RUBY_NAME + (Config::CONFIG['EXEEXT'] || Config::CONFIG['exeext'] || '')
71
+ File.join(".", bin)
72
+ when :install_name
73
+ bin = Config::CONFIG["RUBY_INSTALL_NAME"] || Config::CONFIG["ruby_install_name"]
74
+ bin << (Config::CONFIG['EXEEXT'] || Config::CONFIG['exeext'] || '')
75
+ File.join(Config::CONFIG['bindir'], bin)
76
+ end
77
+ end
78
+
79
+ def resolve_ruby_exe
80
+ [:env, :engine, :name, :install_name].each do |option|
81
+ exe = ruby_exe_options option
82
+ return exe if exe and File.exists?(exe) and File.executable?(exe)
83
+ end
84
+ nil
85
+ end
86
+
87
+ def ruby_exe(code)
88
+ if File.exists?(code) and File.executable?(code)
89
+ `#{RUBY_EXE} #{ENV['RUBY_FLAGS']} #{code}`
90
+ else
91
+ `#{RUBY_EXE} #{ENV['RUBY_FLAGS']} -e #{code.inspect}`
92
+ end
93
+ end
94
+
95
+ unless Object.const_defined?(:RUBY_EXE) and RUBY_EXE
96
+ require 'rbconfig'
97
+
98
+ RUBY_EXE = resolve_ruby_exe or
99
+ raise Exception, "Unable to find a suitable ruby executable."
100
+ end
101
+ end
@@ -0,0 +1,8 @@
1
+ unless Object.const_defined?(:RUBY_NAME) and RUBY_NAME
2
+ if Object.const_defined?(:RUBY_ENGINE) and RUBY_ENGINE
3
+ RUBY_NAME = RUBY_ENGINE
4
+ else
5
+ require 'rbconfig'
6
+ RUBY_NAME = Config::CONFIG["RUBY_INSTALL_NAME"] || Config::CONFIG["ruby_install_name"]
7
+ end
8
+ end
@@ -2,5 +2,6 @@ require 'mspec/runner/actions/tally'
2
2
  require 'mspec/runner/actions/timer'
3
3
  require 'mspec/runner/actions/filter'
4
4
  require 'mspec/runner/actions/tag'
5
+ require 'mspec/runner/actions/taglist'
5
6
  require 'mspec/runner/actions/debug'
6
7
  require 'mspec/runner/actions/gdb'
@@ -24,7 +24,7 @@ class ActionFilter
24
24
  @tfilter = nil
25
25
  return if @tags.empty?
26
26
 
27
- desc = MSpec.read_tags(*@tags).map { |t| t.description }
27
+ desc = MSpec.read_tags(@tags).map { |t| t.description }
28
28
  return if desc.empty?
29
29
 
30
30
  @tfilter = MatchFilter.new(nil, *desc)
@@ -0,0 +1,56 @@
1
+ require 'mspec/runner/actions/filter'
2
+
3
+ # TagListAction - prints out the descriptions for any specs
4
+ # tagged with +tags+. If +tags+ is an empty list, prints out
5
+ # descriptions for any specs that are tagged.
6
+ class TagListAction
7
+ def initialize(tags=nil)
8
+ @tags = tags.nil? || tags.empty? ? nil : Array(tags)
9
+ @filter = nil
10
+ end
11
+
12
+ # Returns true. This enables us to match any tag when loading
13
+ # tags from the file.
14
+ def include?(arg)
15
+ true
16
+ end
17
+
18
+ # Returns true if any tagged descriptions matches +string+.
19
+ def ===(string)
20
+ @filter === string
21
+ end
22
+
23
+ # Prints a banner about matching tagged specs.
24
+ def start
25
+ if @tags
26
+ print "\nListing specs tagged with #{@tags.map { |t| "'#{t}'" }.join(", ") }\n\n"
27
+ else
28
+ print "\nListing all tagged specs\n\n"
29
+ end
30
+ end
31
+
32
+ # Creates a MatchFilter for specific tags or for all tags.
33
+ def load
34
+ @filter = nil
35
+ desc = MSpec.read_tags(@tags || self).map { |t| t.description }
36
+ @filter = MatchFilter.new(nil, *desc) unless desc.empty?
37
+ end
38
+
39
+ # Prints the spec description if it matches the filter.
40
+ def after(state)
41
+ return unless self === state.description
42
+ print state.description, "\n"
43
+ end
44
+
45
+ def register
46
+ MSpec.register :start, self
47
+ MSpec.register :load, self
48
+ MSpec.register :after, self
49
+ end
50
+
51
+ def unregister
52
+ MSpec.unregister :start, self
53
+ MSpec.unregister :load, self
54
+ MSpec.unregister :after, self
55
+ end
56
+ end
@@ -7,7 +7,7 @@ class TagFilter
7
7
  end
8
8
 
9
9
  def load
10
- desc = MSpec.read_tags(*@tags).map { |t| t.description }
10
+ desc = MSpec.read_tags(@tags).map { |t| t.description }
11
11
 
12
12
  @filter = MatchFilter.new(@what, *desc)
13
13
  @filter.register
@@ -237,7 +237,9 @@ module MSpec
237
237
  end
238
238
  end
239
239
 
240
- def self.read_tags(*keys)
240
+ # Returns a list of tags matching any tag string in +keys+ based
241
+ # on the return value of <tt>keys.include?("tag_name")</tt>
242
+ def self.read_tags(keys)
241
243
  tags = []
242
244
  file = tags_file
243
245
  if File.exist? file
@@ -1,215 +1,341 @@
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
1
+ require 'mspec/version'
2
+
3
+ class MSpecOption
4
+ attr_reader :short, :long, :arg, :description, :block
5
+
6
+ def initialize(short, long, arg, description, block)
7
+ @short = short
8
+ @long = long
9
+ @arg = arg
10
+ @description = description
11
+ @block = block
12
+ end
13
+
14
+ def arg?
15
+ @arg != nil
16
+ end
17
+
18
+ def match?(opt)
19
+ opt == @short or opt == @long
20
+ end
21
+ end
22
+
23
+ # MSpecOptions provides a parser for command line options. It also
24
+ # provides a composable set of options from which the runner scripts
25
+ # can select for their particular functionality.
26
+ class MSpecOptions
27
+ # Raised if incorrect or incomplete formats are passed to #on.
28
+ class OptionError < Exception; end
29
+
30
+ # Raised if an unrecognized option is encountered.
31
+ class ParseError < Exception; end
32
+
33
+ attr_accessor :config, :banner, :width, :options
34
+
35
+ def initialize(banner="", width=30, config=nil)
36
+ @banner = banner
37
+ @config = config
38
+ @width = width
39
+ @options = []
40
+ @doc = []
41
+ @extra = []
42
+ @on_extra = lambda { |x|
43
+ raise ParseError, "Unrecognized option: #{x}" if x[0] == ?-
44
+ @extra << x
45
+ }
46
+
47
+ yield self if block_given?
48
+ end
49
+
50
+ # Registers an option. Acceptable formats for arguments are:
51
+ #
52
+ # on "-a", "description"
53
+ # on "-a", "--abdc", "description"
54
+ # on "-a", "ARG", "description"
55
+ # on "--abdc", "ARG", "description"
56
+ # on "-a", "--abdc", "ARG", "description"
57
+ #
58
+ # If an block is passed, it will be invoked when the option is
59
+ # matched. Not passing a block is permitted, but nonsensical.
60
+ def on(*args, &block)
61
+ raise OptionError, "option and description are required" if args.size < 2
62
+
63
+ description = args.pop
64
+ short, long, argument = nil
65
+ args.each do |arg|
66
+ if arg[0] == ?-
67
+ if arg[1] == ?-
68
+ long = arg
69
+ else
70
+ short = arg
71
+ end
23
72
  else
24
- return 0
73
+ argument = arg
25
74
  end
26
75
  end
76
+
77
+ add short, long, argument, description, block
27
78
  end
28
79
 
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
80
+ # Adds documentation text for an option and adds an +MSpecOption+
81
+ # instance to the list of registered options.
82
+ def add(short, long, arg, description, block)
83
+ s = short ? short.dup : " "
84
+ s << (short ? ", " : " ") if long
85
+ doc " #{s}#{long} #{arg}".ljust(@width-1) + " #{description}"
86
+ @options << MSpecOption.new(short, long, arg, description, block)
87
+ end
88
+
89
+ # Searches all registered options to find a match for +opt+. Returns
90
+ # +nil+ if no registered options match.
91
+ def match?(opt)
92
+ @options.find { |o| o.match? opt }
93
+ end
94
+
95
+ # Processes an option. Calles the #on_extra block (or default) for
96
+ # unrecognized options. For registered options, possibly fetches an
97
+ # argument and invokes the option's block if it is not nil.
98
+ def process(argv, entry, opt, arg)
99
+ unless option = match?(opt)
100
+ @on_extra[entry]
101
+ else
102
+ if option.arg?
103
+ arg = argv.shift if arg.nil?
104
+ raise ParseError, "No argument provided for #{opt}" unless arg
34
105
  end
35
- list
106
+ option.block[arg] if option.block
36
107
  end
108
+ option
109
+ end
37
110
 
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
111
+ # Splits a string at +n+ characters into the +opt+ and the +rest+.
112
+ # The +arg+ is set to +nil+ if +rest+ is an empty string.
113
+ def split(str, n)
114
+ opt = str[0, n]
115
+ rest = str[n, str.size]
116
+ arg = rest == "" ? nil : rest
117
+ return opt, arg, rest
118
+ end
119
+
120
+ # Parses an array of command line entries, calling blocks for
121
+ # registered options.
122
+ def parse(argv=ARGV)
123
+ argv = Array(argv).dup
124
+
125
+ while entry = argv.shift
126
+ # collect everything that is not an option
127
+ if entry[0] != ?- or entry.size < 2
128
+ @on_extra[entry]
129
+ next
130
+ end
131
+
132
+ # this is a long option
133
+ if entry[1] == ?-
134
+ opt, arg = entry.split "="
135
+ process argv, entry, opt, arg
136
+ next
137
+ end
138
+
139
+ # disambiguate short option group from short option with argument
140
+ opt, arg, rest = split entry, 2
141
+
142
+ # process first option
143
+ option = process argv, entry, opt, arg
144
+ next unless option and not option.arg?
145
+
146
+ # process the rest of the options
147
+ while rest.size > 0
148
+ opt, arg, rest = split rest, 1
149
+ opt = "-" + opt
150
+ option = process argv, opt, opt, arg
151
+ break if option.arg?
49
152
  end
50
153
  end
51
- argv.replace recognized
52
- filtered
154
+
155
+ @extra
156
+ rescue ParseError => e
157
+ puts self
158
+ puts e
159
+ exit 1
53
160
  end
54
- end
55
161
 
56
- require 'mspec/version'
162
+ # Adds a string of documentation text inline in the text generated
163
+ # from the options. See #on and #add.
164
+ def doc(str)
165
+ @doc << str
166
+ end
57
167
 
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
168
+ # Convenience method for providing -v, --version options.
169
+ def version(version, &block)
170
+ show = block || lambda { puts "#{File.basename $0} #{version}"; exit }
171
+ on "-v", "--version", "Show version", &show
172
+ end
62
173
 
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
174
+ # Convenience method for providing -h, --help options.
175
+ def help(&block)
176
+ help = block || lambda { puts self; exit 1 }
177
+ on "-h", "--help", "Show this message", &help
178
+ end
68
179
 
69
- @config = config
180
+ # Stores a block that will be called with unrecognized options
181
+ def on_extra(&block)
182
+ @on_extra = block
70
183
  end
71
184
 
72
- def add_config(&block)
73
- on("-B", "--config FILE", String,
185
+ # Returns a string representation of the options and doc strings.
186
+ def to_s
187
+ @banner + "\n\n" + @doc.join("\n") + "\n"
188
+ end
189
+
190
+ # The methods below provide groups of options that
191
+ # are composed by the particular runners to provide
192
+ # their functionality
193
+
194
+ def configure(&block)
195
+ on("-B", "--config", "FILE",
74
196
  "Load FILE containing configuration options", &block)
75
197
  end
76
198
 
77
- def add_name
78
- on("-n", "--name RUBY_NAME", String,
199
+ def name
200
+ on("-n", "--name", "RUBY_NAME",
79
201
  "Set the value of RUBY_NAME (used to determine the implementation)") do |n|
80
202
  Object.const_set :RUBY_NAME, n
81
203
  end
82
204
  end
83
205
 
84
- def add_targets
85
- on("-t", "--target TARGET", String,
206
+ def targets
207
+ on("-t", "--target", "TARGET",
86
208
  "Implementation to run the specs, where:") do |t|
87
209
  case t
88
210
  when 'r', 'ruby'
89
- @config[:target] = 'ruby'
90
- @config[:flags] << '-v'
211
+ config[:target] = 'ruby'
91
212
  when 'r19', 'ruby19'
92
- @config[:target] = 'ruby19'
213
+ config[:target] = 'ruby19'
93
214
  when 'x', 'rubinius'
94
- @config[:target] = 'shotgun/rubinius'
215
+ config[:target] = './bin/rbx'
95
216
  when 'X', 'rbx'
96
- @config[:target] = 'rbx'
217
+ config[:target] = 'rbx'
97
218
  when 'j', 'jruby'
98
- @config[:target] = 'jruby'
219
+ config[:target] = 'jruby'
220
+ when 'i','ironruby'
221
+ config[:target] = 'ir'
99
222
  else
100
- @config[:target] = t
223
+ config[:target] = t
101
224
  end
102
225
  end
103
226
 
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"
227
+ doc ""
228
+ doc " r or ruby invokes ruby in PATH"
229
+ doc " r19 or ruby19 invokes ruby19 in PATH"
230
+ doc " x or rubinius invokes ./bin/rbx"
231
+ doc " X or rbx invokes rbx in PATH"
232
+ doc " j or jruby invokes jruby in PATH"
233
+ doc " i or ironruby invokes ir in PATH\n"
110
234
 
111
- on("-T", "--target-opt OPT", String,
235
+ on("-T", "--target-opt", "OPT",
112
236
  "Pass OPT as a flag to the target implementation") do |t|
113
- @config[:flags] << t
237
+ config[:flags] << t
114
238
  end
115
- on("-I", "--include DIR", String,
239
+ on("-I", "--include", "DIR",
116
240
  "Pass DIR through as the -I option to the target") do |d|
117
- @config[:includes] << "-I#{d}"
241
+ config[:includes] << "-I#{d}"
118
242
  end
119
- on("-r", "--require LIBRARY", String,
243
+ on("-r", "--require", "LIBRARY",
120
244
  "Pass LIBRARY through as the -r option to the target") do |f|
121
- @config[:requires] << "-r#{f}"
245
+ config[:requires] << "-r#{f}"
122
246
  end
123
247
  end
124
248
 
125
- def add_formatters
126
- on("-f", "--format FORMAT", String,
249
+ def formatters
250
+ on("-f", "--format", "FORMAT",
127
251
  "Formatter for reporting, where FORMAT is one of:") do |o|
128
252
  case o
129
253
  when 's', 'spec', 'specdoc'
130
- @config[:formatter] = SpecdocFormatter
254
+ config[:formatter] = SpecdocFormatter
131
255
  when 'h', 'html'
132
- @config[:formatter] = HtmlFormatter
256
+ config[:formatter] = HtmlFormatter
133
257
  when 'd', 'dot', 'dotted'
134
- @config[:formatter] = DottedFormatter
258
+ config[:formatter] = DottedFormatter
135
259
  when 'u', 'unit', 'unitdiff'
136
- @config[:formatter] = UnitdiffFormatter
260
+ config[:formatter] = UnitdiffFormatter
137
261
  when 'm', 'summary'
138
- @config[:formatter] = SummaryFormatter
262
+ config[:formatter] = SummaryFormatter
139
263
  when 'a', '*', 'spin'
140
- @config[:formatter] = SpinnerFormatter
264
+ config[:formatter] = SpinnerFormatter
141
265
  when 'y', 'yaml'
142
- @config[:formatter] = YamlFormatter
266
+ config[:formatter] = YamlFormatter
143
267
  else
144
268
  puts "Unknown format: #{o}"
145
269
  puts @parser
146
270
  exit
147
271
  end
148
272
  end
149
- separator("")
150
- separator(" s, spec, specdoc SpecdocFormatter")
151
- separator(" h, html, HtmlFormatter")
152
- separator(" d, dot, dotted DottedFormatter")
153
- separator(" u, unit, unitdiff UnitdiffFormatter")
154
- separator(" m, summary SummaryFormatter")
155
- separator(" a, *, spin SpinnerFormatter")
156
- separator(" y, yaml YamlFormatter\n")
157
- on("-o", "--output FILE", String,
273
+
274
+ doc ""
275
+ doc " s, spec, specdoc SpecdocFormatter"
276
+ doc " h, html, HtmlFormatter"
277
+ doc " d, dot, dotted DottedFormatter"
278
+ doc " u, unit, unitdiff UnitdiffFormatter"
279
+ doc " m, summary SummaryFormatter"
280
+ doc " a, *, spin SpinnerFormatter"
281
+ doc " y, yaml YamlFormatter\n"
282
+
283
+ on("-o", "--output", "FILE",
158
284
  "Write formatter output to FILE") do |f|
159
- @config[:output] = f
285
+ config[:output] = f
160
286
  end
161
287
  end
162
288
 
163
- def add_filters
164
- on("-e", "--example STR", String,
289
+ def filters
290
+ on("-e", "--example", "STR",
165
291
  "Run examples with descriptions matching STR") do |o|
166
- @config[:includes] << o
292
+ config[:includes] << o
167
293
  end
168
- on("-E", "--exclude STR", String,
294
+ on("-E", "--exclude", "STR",
169
295
  "Exclude examples with descriptions matching STR") do |o|
170
- @config[:excludes] << o
296
+ config[:excludes] << o
171
297
  end
172
- on("-p", "--pattern PATTERN", Regexp,
298
+ on("-p", "--pattern", "PATTERN",
173
299
  "Run examples with descriptions matching PATTERN") do |o|
174
- @config[:patterns] << o
300
+ config[:patterns] << Regexp.new(o)
175
301
  end
176
- on("-P", "--excl-pattern PATTERN", Regexp,
302
+ on("-P", "--excl-pattern", "PATTERN",
177
303
  "Exclude examples with descriptions matching PATTERN") do |o|
178
- @config[:xpatterns] << o
304
+ config[:xpatterns] << Regexp.new(o)
179
305
  end
180
- on("-g", "--tag TAG", String,
306
+ on("-g", "--tag", "TAG",
181
307
  "Run examples with descriptions matching ones tagged with TAG") do |o|
182
- @config[:tags] << o
308
+ config[:tags] << o
183
309
  end
184
- on("-G", "--excl-tag TAG", String,
310
+ on("-G", "--excl-tag", "TAG",
185
311
  "Exclude examples with descriptions matching ones tagged with TAG") do |o|
186
- @config[:xtags] << o
312
+ config[:xtags] << o
187
313
  end
188
- on("-w", "--profile FILE", String,
314
+ on("-w", "--profile", "FILE",
189
315
  "Run examples for methods listed in the profile FILE") do |f|
190
- @config[:profiles] << f
316
+ config[:profiles] << f
191
317
  end
192
- on("-W", "--excl-profile FILE", String,
318
+ on("-W", "--excl-profile", "FILE",
193
319
  "Exclude examples for methods listed in the profile FILE") do |f|
194
- @config[:xprofiles] << f
320
+ config[:xprofiles] << f
195
321
  end
196
322
  end
197
323
 
198
- def add_pretend
324
+ def pretend
199
325
  on("-Z", "--dry-run",
200
326
  "Invoke formatters and other actions, but don't execute the specs") do
201
327
  MSpec.register_mode :pretend
202
328
  end
203
329
  end
204
330
 
205
- def add_randomize
331
+ def randomize
206
332
  on("-H", "--random",
207
333
  "Randomize the list of spec files") do
208
334
  MSpec.randomize
209
335
  end
210
336
  end
211
337
 
212
- def add_verbose
338
+ def verbose
213
339
  on("-V", "--verbose", "Output the name of each file processed") do
214
340
  obj = Object.new
215
341
  def obj.start
@@ -223,7 +349,7 @@ class MSpecOptions
223
349
  MSpec.register :load, obj
224
350
  end
225
351
 
226
- on("-m", "--marker MARKER", String,
352
+ on("-m", "--marker", "MARKER",
227
353
  "Output MARKER for each file processed") do |o|
228
354
  obj = Object.new
229
355
  obj.instance_variable_set :@marker, o
@@ -234,104 +360,41 @@ class MSpecOptions
234
360
  end
235
361
  end
236
362
 
237
- def add_interrupt
363
+ def interrupt
238
364
  on("--int-spec", "Control-C interupts the current spec only") do
239
- @config[:abort] = false
365
+ config[:abort] = false
240
366
  end
241
367
  end
242
368
 
243
- def add_verify
369
+ def verify
244
370
  on("-Y", "--verify",
245
371
  "Verify that guarded specs pass and fail as expected") do
246
- MSpec.set_mode :verify
372
+ MSpec.register_mode :verify
247
373
  end
248
374
  on("-O", "--report", "Report guarded specs") do
249
- MSpec.set_mode :report
250
- end
251
- end
252
-
253
- def add_tagging
254
- on("-N", "--add TAG", String,
255
- "Add TAG with format 'tag' or 'tag(comment)' (see -Q, -F, -L)") do |o|
256
- @config[:tagger] = :add
257
- @config[:tag] = "#{o}:"
258
- end
259
- on("-R", "--del TAG", String,
260
- "Delete TAG (see -Q, -F, -L)") do |o|
261
- @config[:tagger] = :del
262
- @config[:tag] = "#{o}:"
263
- @config[:outcome] = :pass
264
- end
265
- on("-Q", "--pass", "Apply action to specs that pass (default for --del)") do
266
- @config[:outcome] = :pass
267
- end
268
- on("-F", "--fail", "Apply action to specs that fail (default for --add)") do
269
- @config[:outcome] = :fail
270
- end
271
- on("-L", "--all", "Apply action to all specs") do
272
- @config[:outcome] = :all
375
+ MSpec.register_mode :report
273
376
  end
274
377
  end
275
378
 
276
- def add_action_filters
277
- on("-K", "--action-tag TAG", String,
379
+ def action_filters
380
+ on("-K", "--action-tag", "TAG",
278
381
  "Spec descriptions marked with TAG will trigger the specified action") do |o|
279
- @config[:atags] << o
382
+ config[:atags] << o
280
383
  end
281
- on("-S", "--action-string STR", String,
384
+ on("-S", "--action-string", "STR",
282
385
  "Spec descriptions matching STR will trigger the specified action") do |o|
283
- @config[:astrings] << o
386
+ config[:astrings] << o
284
387
  end
285
388
  end
286
389
 
287
- def add_actions
390
+ def actions
288
391
  on("--spec-debug",
289
392
  "Invoke the debugger when a spec description matches (see -K, -S)") do
290
- @config[:debugger] = true
393
+ config[:debugger] = true
291
394
  end
292
395
  on("--spec-gdb",
293
396
  "Invoke Gdb when a spec description matches (see -K, -S)") do
294
- @config[:gdb] = true
397
+ config[:gdb] = true
295
398
  end
296
399
  end
297
-
298
- def add_version
299
- on("-v", "--version", "Show version") do
300
- puts "#{File.basename $0} #{MSpec::VERSION}"
301
- exit
302
- end
303
- end
304
-
305
- def add_help
306
- on("-h", "--help", "Show this message") do
307
- puts @parser
308
- exit
309
- end
310
- end
311
-
312
- def on(*args, &block)
313
- @parser.on(*args, &block)
314
- end
315
-
316
- def separator(str)
317
- @parser.separator str
318
- end
319
-
320
- def parse(argv=ARGV)
321
- result = @parser.parse argv
322
-
323
- if (@config[:debugger] || @config[:gdb]) &&
324
- @config[:atags].empty? && @config[:astrings].empty?
325
- puts "Missing --action-tag or --action-string."
326
- puts @parser
327
- exit 1
328
- end
329
-
330
- result
331
- rescue OptionParser::ParseError => e
332
- puts @parser
333
- puts
334
- puts e
335
- exit 1
336
- end
337
400
  end