Class: Lucid::CLI::Options

Inherits:
Object show all
Defined in:
lib/lucid/cli/options.rb

Constant Summary collapse

INDENT =
' ' * 53
LUCID_FORMATS =
{
  'html'        => ['Lucid::Formatter::Html',        'Generates an HTML report.'],
  'standard'    => ['Lucid::Formatter::Standard',    'Prints the spec as-is, using color if available.'],
  'condensed'   => ['Lucid::Formatter::Condensed',   'Output only spec file and scenarios.'],
  'progress'    => ['Lucid::Formatter::Progress',    'Prints one character per scenario.'],
  'rerun'       => ['Lucid::Formatter::Rerun',       'Prints failing specs with line numbers.'],
  'usage'       => ['Lucid::Formatter::Usage',       "Prints where test definitions are used.\n" +
                                                        "#{INDENT}The slowest test definitions (with duration) are\n" +
                                                        "#{INDENT}listed first. If --dry-run is used the duration\n" +
                                                        "#{INDENT}is not shown, and test definitions are sorted by\n" +
                                                        "#{INDENT}file name instead."],
  'testdefs'    => ['Lucid::Formatter::Testdefs',    "Prints all test definitions with their locations. Same as\n" +
                                                        "#{INDENT}the usage formatter, except that steps are not printed."],
  'junit'       => ['Lucid::Formatter::Junit',       'Generates a report similar to Ant+JUnit.'],
  'json'        => ['Lucid::Formatter::Json',        'Prints the spec as JSON.'],
  'json_pretty' => ['Lucid::Formatter::JsonPretty',  'Prints the spec as prettified JSON.'],
  'debug'       => ['Lucid::Formatter::Debug',       'Prints the calls made to the listeners.']
}
FORMAT_LIST =
(LUCID_FORMATS.keys.sort.map do |key|
  "  #{key}#{' ' * (largest - key.length)} : #{LUCID_FORMATS[key][1]}"
end) + ['Use --format rerun --out rerun.txt to write out failing',
        'specs. You can rerun them with lucid @rerun.txt.',
        'FORMAT can also be the fully qualified class name of',
        "your own custom formatter. If the class isn't loaded,",
        'Lucid will attempt to require a file with a relative',
        'file name that is the underscore name of the class name.',
        '  Example: --format Formatter::WordDoc',
        'With that, Lucid will look for formatter/word_doc.rb',
        'You can place the file with this relative path',
        'underneath your common/support directory or anywhere',
        "on Ruby's LOAD_PATH."
]
PROFILE_SHORT_FLAG =
'-p'
NO_PROFILE_SHORT_FLAG =
'-P'
PROFILE_LONG_FLAG =
'--profile'
NO_PROFILE_LONG_FLAG =
'--no-profile'
OPTIONS_WITH_ARGS =
['-r', '--require', '--i18n', '-f', '--format', '-o', '--out',
'-t', '--tags', '-n', '--name', '-e', '--exclude',
PROFILE_SHORT_FLAG, PROFILE_LONG_FLAG,
'--lines', '--port',
'-I', '--matcher-type']

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(out_stream = STDOUT, error_stream = STDERR, options = {}) ⇒ Options

Returns a new instance of Options.



57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/lucid/cli/options.rb', line 57

def initialize(out_stream = STDOUT, error_stream = STDERR, options = {})
  @out_stream   = out_stream
  @error_stream = error_stream

  @default_profile = options[:default_profile]
  @profiles = []
  @overridden_paths = []
  @options = default_options
  @profile_loader = options[:profile_loader]
  @options[:skip_profile_information] = options[:skip_profile_information]

  @quiet = @disable_profile_loading = nil
end

Class Method Details

.parse(args, out_stream, error_stream, options = {}) ⇒ Object



53
54
55
# File 'lib/lucid/cli/options.rb', line 53

def self.parse(args, out_stream, error_stream, options = {})
  new(out_stream, error_stream, options).parse(args)
end

Instance Method Details

#[](key) ⇒ Object



71
72
73
# File 'lib/lucid/cli/options.rb', line 71

def [](key)
  @options[key]
end

#[]=(key, value) ⇒ Object



75
76
77
# File 'lib/lucid/cli/options.rb', line 75

def []=(key, value)
  @options[key] = value
end

#custom_profilesObject



347
348
349
# File 'lib/lucid/cli/options.rb', line 347

def custom_profiles
  @profiles - [@default_profile]
end

#filtersObject

See Also:

  • Configuration.filters


352
353
354
# File 'lib/lucid/cli/options.rb', line 352

def filters
  @options.values_at(:name_regexps, :tag_expressions).select{|v| !v.empty?}.first || []
end

#parse(args) ⇒ Object



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
# File 'lib/lucid/cli/options.rb', line 79

def parse(args)
  @args = args
  @expanded_args = @args.dup

  @args.extend(::OptionParser::Arguable)

  @args.options do |opts|
    opts.banner = ['Lucid: Test Description Language Execution Engine',
                   'Usage: lucid [options] [ [FILE|DIR|URL][:LINE[:LINE]*] ]+', '', ''
    ].join("\n")

    opts.on('--library-path PATH', 'Location of spec project library files.') do |path|
      @options[:library_path] = path
    end

    opts.on('--spec-type TYPE', 'The file type (extension) for Lucid specifications.') do |type|
      #@options[:spec_type] = type
      @options[:spec_type] << type
    end

    opts.on('--driver-file FILE', 'The file for Lucid to connect to an execution library.') do |file|
      @options[:driver_file] = file
    end

    opts.separator ''

    opts.on('-r LIBRARY|DIR', '--require LIBRARY|DIR',
            'Require files before executing the features. If this option',
            'is not specified, all *.rb files that are siblings or below',
            'the features will be loaded automatically. Automatic loading',
            'is disabled when this option is specified. That means all',
            'loading becomes explicit.',
            'Assuming a default specs repo configuration, files under',
            "directories named \"common\\support\" will always be loaded",
            'before any others.',
            'This option can be specified multiple times.') do |v|
      @options[:require] << v
      if(Lucid::JRUBY && File.directory?(v))
        require 'java'
        $CLASSPATH << v
      end
    end

    opts.separator ''

    opts.on('-f FORMAT', '--format FORMAT',
            'How Lucid will format spec execution output.',
            '(Default: standard). Available formats:',
            *FORMAT_LIST
    ) do |v|
      @options[:formats] << [v, @out_stream]
    end

    opts.on('-o', '--out [FILE|DIR]',
            'Write output to a file or directory instead of to standard',
            'console output. This option applies to any specified format',
            'option (via the --format switch) or to the default format',
            'if no format was specified. You can check the specific',
            'documentation for a given formatter to see whether to pass',
            'a file or a directory.'
    ) do |v|
      @options[:formats] << ['standard', nil] if @options[:formats].empty?
      @options[:formats][-1][1] = v
    end

    opts.separator ''

    opts.on('-d', '--dry-run', 'Invokes formatters without executing the steps.',
            'This also omits the loading of your common/support/driver.rb file if it exists.') do
      @options[:dry_run] = true
    end

    opts.on('-n NAME', '--name NAME',
            'Lucid will only execute features or abilities that match with the name',
            'provided. The match can be done on partial information. If this option',
            'is provided multiple times, then the match will be performed against',
            'each set of provided names.'
    ) do |v|
      @options[:name_regexps] << /#{v}/
    end

    opts.on('-l', '--lines LINES', 'Run given line numbers. Equivalent to FILE:LINE syntax') do |lines|
      @options[:lines] = lines
    end

    opts.on('-e', '--exclude PATTERN',
            'Lucid will not use files that match the PATTERN.') do |v|
      @options[:excludes] << Regexp.new(v)
    end

    opts.on('-t TAG_EXPRESSION', '--tags TAG_EXPRESSION',
            'Lucid will only execute features or scenarios with tags that match the',
            'tag expression provided. A single tag expressions can have several tags',
            'separated by a comma, which represents a logical OR. If this option is',
            'provided more than once, this represents a logical AND. A tag expression',
            'can be prefaced with a ~ character, which represents a logical NOT.',
            'Examples:',
            ' --tags @smoke.',
            ' --tags ~@wip',
            ' --tags @smoke,@wip',
            ' --tags @smoke,~@wip --tags @regression',
            'If you want to use multiple exclusion tags, you must use the logical',
            'AND approach, as in: --tags ~@wip --tags ~@failing',
            'Positive tags can be given a threshold to limit the number of occurrences.',
            'Example: --tags @critical:3',
            'That will fail if there are more than three occurrences of the @critical tag.'
    ) do |v|
      @options[:tag_expressions] << v
    end

    opts.separator ''

    opts.on(PROFILE_SHORT_FLAG, "#{PROFILE_LONG_FLAG} PROFILE",
            'Pull commandline arguments from lucid.yml which can be defined as',
            'strings or arrays. When a default profile is defined and no profile',
            'is specified it is always used. (Unless disabled, see -P below.)',
            'When feature files are defined in a profile and on the command line',
            'then only the ones from the command line are used.'
    ) do |v|
      @profiles << v
    end

    opts.on(NO_PROFILE_SHORT_FLAG, NO_PROFILE_LONG_FLAG,
      'Disables all profile loading to avoid using the default profile.') do |v|
      @disable_profile_loading = true
    end

    opts.separator ''

    opts.on('-c', '--[no-]color',
            'Specifies whether or not to use ANSI color in the output. If this',
            'option is not specified, Lucid makes the decision on colored output',
            'based on your platform and the output destination.'
    ) do |v|
      Lucid::Term::ANSIColor.coloring = v
    end

    opts.on('-m', '--no-multiline',
            'Lucid will not print multiline strings and tables under steps.') do
      @options[:no_multiline] = true
    end

    opts.on('-s', '--no-source',
            'Lucid will not print the file and line of the test definition with the steps.') do
      @options[:source] = false
    end

    opts.on('-i', '--no-matchers',
            'Lucid will not print matchers for pending steps.') do
      @options[:matchers] = false
    end

    opts.on('-I', '--matchers-type TYPE',
            'Use different matcher type (Default: regexp).',
            'Available types:',
            *Lucid::InterfaceRb::RbLanguage.cli_matcher_type_options
    ) do |v|
      @options[:matcher_type] = v.to_sym
    end

    opts.on('-q', '--quiet', 'Alias for --no-matchers --no-source.') do
      @quiet = true
    end

    opts.on('-S', '--strict', 'Fail if there are any undefined or pending steps.') do
      @options[:strict] = true
    end

    opts.on('-w', '--wip', 'Fail if there are any passing scenarios.') do
      @options[:wip] = true
    end

    opts.on('-g', '--guess', 'Guess best match for ambiguous steps.') do
      @options[:guess] = true
    end

    opts.on('-x', '--expand', 'Expand Scenario Outline tables in output.') do
      @options[:expand] = true
    end

    opts.separator ''

    opts.on('--testdefs DIR', 'Lucid will write test definition metadata to the DIR.') do |dir|
      @options[:testdefs] = dir
    end

    if(Lucid::JRUBY)
      opts.on('-j DIR', '--jars DIR',
              'Load all the jars under the specified directory.') do |jars|
        Dir["#{jars}/**/*.jar"].each {|jar| require jar}
      end
    end

    opts.on('--i18n LANG',
            'List keywords for a particular language.',
            'Run with "--i18n help" to see all languages') do |lang|
      if lang == 'help'
        list_languages_and_exit
      else
        list_keywords_and_exit(lang)
      end
    end

    opts.separator ''

    opts.on('-b', '--backtrace', 'Show full backtrace for all errors during Lucid execution.') do
      Lucid.use_full_backtrace = true
    end

    opts.on('-v', '--verbose', 'Show detailed information about Lucid execution.') do
      @options[:verbose] = true
    end

    opts.on('--debug', 'Show behind-the-scenes information about Lucid execution.') do
      @options[:debug] = true
    end

    opts.separator ''

    opts.on_tail('--version', 'Show Lucid version information.') do
      @out_stream.puts Lucid::VERSION
      Kernel.exit(0)
    end

    opts.on_tail('-h', '--help', 'Show Lucid execution options.') do
      @out_stream.puts opts.help
      Kernel.exit(0)
    end
  end
  #end.parse!

  begin
    @args.parse!
  rescue OptionParser::InvalidOption
    if $!.to_s =~ /invalid option\:\s+((?:-)?-\S+)/
      puts "You specified an invalid option: #{$1}"
      puts 'Please run lucid --help to see the list of available options.'
    end

  rescue OptionParser::MissingArgument
    if $!.to_s =~ /missing argument\:\s+((?:-)?-\S+)/
      puts "You specified an valid option (#{$1}), but with an invalid argument."
      puts 'Make sure you are providing the expected argument for the option.'
      puts 'Run lucid --help to see the list of available options.'
    end

    Kernel.exit(1)
  end

  if @quiet
    @options[:matchers] = @options[:source] = false
  else
    @options[:matchers] = true if @options[:matchers].nil?
    @options[:source]   = true if @options[:source].nil?
  end
  @args.map! { |a| "#{a}:#{@options[:lines]}" } if @options[:lines]

  extract_environment_variables

  # This line grabs whatever is left over on the command line. That
  # would have to be the spec repo.
  @options[:spec_source] = @args.dup

  establish_profile

  self
end