class Lucid::CLI::Options

Constants

FORMAT_LIST
INDENT
LUCID_FORMATS
NO_PROFILE_LONG_FLAG
NO_PROFILE_SHORT_FLAG
OPTIONS_WITH_ARGS
PROFILE_LONG_FLAG
PROFILE_SHORT_FLAG

Attributes

expanded_args[R]
options[R]
profiles[R]

Public Class Methods

new(out_stream = STDOUT, error_stream = STDERR, options = {}) click to toggle source
# File lib/lucid/cli/options.rb, line 58
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
parse(args, out_stream, error_stream, options = {}) click to toggle source
# File lib/lucid/cli/options.rb, line 54
def self.parse(args, out_stream, error_stream, options = {})
  new(out_stream, error_stream, options).parse(args)
end

Public Instance Methods

[](key) click to toggle source
# File lib/lucid/cli/options.rb, line 72
def [](key)
  @options[key]
end
[]=(key, value) click to toggle source
# File lib/lucid/cli/options.rb, line 76
def []=(key, value)
  @options[key] = value
end
custom_profiles() click to toggle source
# File lib/lucid/cli/options.rb, line 348
def custom_profiles
  @profiles - [@default_profile]
end
filters() click to toggle source

@see Lucid::CLI::Context.filters

# File lib/lucid/cli/options.rb, line 353
def filters
  @options.values_at(:name_regexps, :tag_expressions).select{|v| !v.empty?}.first || []
end
parse(args) click to toggle source
# File lib/lucid/cli/options.rb, line 80
def parse(args)
  @args = args
  @expanded_args = @args.dup

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

  @args.options do |opts|
    opts.banner = ['Lucid Framework',
                   'Test Description Language Specification and 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('--definition-path PATH', 'Location of spec project definition files.') do |path|
      @options[:definitions_path] = path
    end

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

    opts.on('--spec-type TYPE', 'The file type (extension) for Lucid specifications.') do |type|
      @options[:spec_types] << 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 resources (paths or individual files) prior to executing',
            'the test specs. If no require options are passed, then Lucid will',
            'use its default path and file settings via automatic loading. If',
            'require options are passed, however, then automatic loading will',
            'be disabled, which means loading any resources must be done via',
            'explicit uses of this option. The require option can be specified',
            'multiple times.') do |resource|
      @options[:require] << resource
      if(Lucid::JRUBY && File.directory?(resource))
        require 'java'
        $CLASSPATH << resource
      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', 'Performs spec parsing without test execution.',
            'Performing a dry run omits loading of the driver file as well as',
            'any page or activity definitions.') 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

  begin
    @args.parse!
  rescue OptionParser::InvalidOption
    invalid_option($ERROR_INFO)
  rescue OptionParser::MissingArgument
    missing_argument($ERROR_INFO)
  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

  # The next statement is critical because it takes whatever is left
  # from the command line when all the valid options are parsed. This
  # would have to be the spec repository. The empty check is because
  # even if no args are passed, an empty array will be passed to the
  # spec_repos key, which overwrites the default option.
  @options[:spec_source] = @args.dup #unless args.empty?

  establish_profile

  self
end

Private Instance Methods

default_options() click to toggle source
# File lib/lucid/cli/options.rb, line 479
def default_options
  {
    :strict           => false,
    :require          => [],
    :dry_run          => false,
    :formats          => [],
    :excludes         => [],
    :tag_expressions  => [],
    :name_regexps     => [],
    :env_vars         => {},
    :diff_enabled     => true,
    :spec_types       => %w(feature spec story),
    :library_path     => 'common',
    :definitions_path => 'pages',
    :steps_path       => 'steps',
    :driver_file      => 'driver'
  }
end
disable_profile_loading?() click to toggle source
# File lib/lucid/cli/options.rb, line 397
def disable_profile_loading?
  @disable_profile_loading
end
establish_profile() click to toggle source
# File lib/lucid/cli/options.rb, line 401
def establish_profile
  if @disable_profile_loading
    @out_stream.puts 'Disabling profiles...'
    return
  end

  @profiles << @default_profile if using_default_profile?

  @profiles.each do |profile|
    merge_with_profile(profile)
  end

  @options[:profiles] = @profiles
end
extract_environment_variables() click to toggle source
# File lib/lucid/cli/options.rb, line 388
def extract_environment_variables
  @args.delete_if do |arg|
    if arg =~ /^(\w+)=(.*)$/
      @options[:env_vars][$1] = $2
      true
    end
  end
end
invalid_option(error) click to toggle source
# File lib/lucid/cli/options.rb, line 364
def invalid_option(error)
  if error.to_s =~ /invalid option:\s+((?:-)?-\S+)/
    puts "You specified an #{$MATCH}\n\n"
    puts 'Run lucid --help to see the list of available options.'
  end
  Kernel.exit(1)
end
list_keywords_and_exit(lang) click to toggle source
# File lib/lucid/cli/options.rb, line 467
def list_keywords_and_exit(lang)
  require 'gherkin/i18n'
  @out_stream.write(Gherkin::I18n.get(lang).keyword_table)
  Kernel.exit(0)
end
list_languages_and_exit() click to toggle source
# File lib/lucid/cli/options.rb, line 473
def list_languages_and_exit
  require 'gherkin/i18n'
  @out_stream.write(Gherkin::I18n.language_table)
  Kernel.exit(0)
end
merge_with_profile(profile) click to toggle source
# File lib/lucid/cli/options.rb, line 416
def merge_with_profile(profile)
  profile_args = profile_loader.args_from(profile)
  profile_options = Options.parse(
    profile_args, @out_stream, @error_stream,
    :skip_profile_information => true,
    :profile_loader => profile_loader
  )
  reverse_merge(profile_options)
end
missing_argument(error) click to toggle source
# File lib/lucid/cli/options.rb, line 372
def missing_argument(error)
  if error.to_s =~ /(?:missing argument:\s+)((?:-)?-\S+)/
    puts "Valid option with #{$MATCH}\n\n"
    puts 'Run lucid --help to see the list of available options.'
  end
  Kernel.exit(1)
end
non_stdout_formats() click to toggle source
# File lib/lucid/cli/options.rb, line 380
def non_stdout_formats
  @options[:formats].select {|format, output| output != @out_stream }
end
profile_loader() click to toggle source
# File lib/lucid/cli/options.rb, line 432
def profile_loader
  @profile_loader ||= Profile.new
end
reverse_merge(other_options) click to toggle source
# File lib/lucid/cli/options.rb, line 436
def reverse_merge(other_options)
  @options = other_options.options.merge(@options)
  @options[:require] += other_options[:require]

  @options[:excludes] += other_options[:excludes]
  @options[:name_regexps] += other_options[:name_regexps]
  @options[:tag_expressions] += other_options[:tag_expressions]
  @options[:env_vars] = other_options[:env_vars].merge(@options[:env_vars])
  if @options[:spec_source].empty?
    @options[:spec_source] = other_options[:spec_source]
  else
    @overridden_paths += (other_options[:spec_source] - @options[:spec_source])
  end
  @options[:source] &= other_options[:source]
  @options[:matchers] &= other_options[:matchers]
  @options[:strict] |= other_options[:strict]
  @options[:dry_run] |= other_options[:dry_run]

  @profiles += other_options.profiles
  @expanded_args += other_options.expanded_args

  if @options[:formats].empty?
    @options[:formats] = other_options[:formats]
  else
    @options[:formats] += other_options[:formats]
    @options[:formats] = stdout_formats[0..0] + non_stdout_formats
  end

  self
end
stdout_formats() click to toggle source
# File lib/lucid/cli/options.rb, line 384
def stdout_formats
  @options[:formats].select {|format, output| output == @out_stream }
end
using_default_profile?() click to toggle source
# File lib/lucid/cli/options.rb, line 426
def using_default_profile?
  @profiles.empty? &&
    profile_loader.lucid_yml_defined? &&
    profile_loader.has_profile?(@default_profile)
end