Class: Cucumber::Cli::Options

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

Constant Summary collapse

INDENT =
' ' * 53
BUILTIN_FORMATS =
{
  'pretty'      => ['Cucumber::Formatter::Pretty',      'Prints the feature as is - in colours.'],
  'progress'    => ['Cucumber::Formatter::Progress',    'Prints one character per scenario.'],
  'dots'        => ['Cucumber::Formatter::Dots',        'Simple progress output to console'],
  'rerun'       => ['Cucumber::Formatter::Rerun',       'Prints failing files with line numbers.'],
  'usage'       => ['Cucumber::Formatter::Usage',       "Prints where step definitions are used.\n" \
                                                        "#{INDENT}The slowest step definitions (with duration) are\n" \
                                                        "#{INDENT}listed first. If --dry-run is used the duration\n" \
                                                        "#{INDENT}is not shown, and step definitions are sorted by\n" \
                                                        "#{INDENT}filename instead."],
  'stepdefs'    => ['Cucumber::Formatter::Stepdefs',    "Prints All step definitions with their locations. Same as\n" \
                                                        "#{INDENT}the usage formatter, except that steps are not printed."],
  'junit'       => ['Cucumber::Formatter::Junit',       'Generates a report similar to Ant+JUnit.'],
  'json'        => ['Cucumber::Formatter::Json',        'Prints the feature as JSON'],
  'summary'     => ['Cucumber::Formatter::Summary',     'Summary output of feature and scenarios']
}.freeze
FORMAT_HELP_MSG =
[
  'Use --format rerun --out rerun.txt to write out failing',
  'features. You can rerun them with cucumber @rerun.txt.',
  'FORMAT can also be the fully qualified class name of',
  "your own custom formatter. If the class isn't loaded,",
  'Cucumber will attempt to require a file with a relative',
  'file name that is the underscore name of the class name.',
  'Example: --format Foo::BarZap -> Cucumber will look for',
  'foo/bar_zap.rb. You can place the file with this relative',
  'path underneath your features/support directory or anywhere',
  "on Ruby's LOAD_PATH, for example in a Ruby gem."
].freeze
FORMAT_HELP =
(BUILTIN_FORMATS.keys.sort.map do |key|
  "  #{key}#{' ' * (max - key.length)} : #{BUILTIN_FORMATS[key][1]}"
end) + FORMAT_HELP_MSG
PROFILE_SHORT_FLAG =
'-p'.freeze
NO_PROFILE_SHORT_FLAG =
'-P'.freeze
PROFILE_LONG_FLAG =
'--profile'.freeze
NO_PROFILE_LONG_FLAG =
'--no-profile'.freeze
FAIL_FAST_FLAG =
'--fail-fast'.freeze
RETRY_FLAG =
'--retry'.freeze
OPTIONS_WITH_ARGS =
[
  '-r', '--require', '--i18n-keywords', '-f', '--format', '-o',
  '--out', '-t', '--tags', '-n', '--name', '-e', '--exclude',
  PROFILE_SHORT_FLAG, PROFILE_LONG_FLAG, RETRY_FLAG, '-l',
  '--lines', '--port', '-I', '--snippet-type'
].freeze
ORDER_TYPES =
%w[defined random].freeze
TAG_LIMIT_MATCHER =
/(?<tag_name>\@\w+):(?<limit>\d+)/x

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.


65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/cucumber/cli/options.rb', line 65

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

  @default_profile = options[:default_profile]
  @profiles = options[:profiles] || []
  @overridden_paths = []
  @options = default_options.merge(options)
  @profile_loader = options[:profile_loader]
  @options[:skip_profile_information] = options[:skip_profile_information]

  @disable_profile_loading = nil
end

Class Method Details

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


61
62
63
# File 'lib/cucumber/cli/options.rb', line 61

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

Instance Method Details

#[](key) ⇒ Object


79
80
81
# File 'lib/cucumber/cli/options.rb', line 79

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

#[]=(key, value) ⇒ Object


83
84
85
# File 'lib/cucumber/cli/options.rb', line 83

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

#check_formatter_stream_conflictsObject


167
168
169
170
171
# File 'lib/cucumber/cli/options.rb', line 167

def check_formatter_stream_conflicts
  streams = @options[:formats].uniq.map { |(_, _, stream)| stream }
  return if streams == streams.uniq
  raise 'All but one formatter must use --out, only one can print to each stream (or STDOUT)'
end

#custom_profilesObject


159
160
161
# File 'lib/cucumber/cli/options.rb', line 159

def custom_profiles
  @profiles - [@default_profile]
end

#filtersObject


163
164
165
# File 'lib/cucumber/cli/options.rb', line 163

def filters
  @options[:filters] ||= []
end

#parse!(args) ⇒ Object

rubocop:disable Metrics/AbcSize, Metrics/MethodLength


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
# File 'lib/cucumber/cli/options.rb', line 87

def parse!(args) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
  @args = args
  @expanded_args = @args.dup

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

  @args.options do |opts| # rubocop:disable Metrics/BlockLength
    opts.banner = banner
    opts.on('-r LIBRARY|DIR', '--require LIBRARY|DIR', *require_files_msg) { |lib| require_files(lib) }

    opts.on('-j DIR', '--jars DIR', 'Load all the jars under DIR') { |jars| load_jars(jars) } if Cucumber::JRUBY

    opts.on("#{RETRY_FLAG} ATTEMPTS", *retry_msg) { |v| set_option :retry, v.to_i }
    opts.on('--i18n-languages', *i18n_languages_msg) { list_languages_and_exit }
    opts.on('--i18n-keywords LANG', *i18n_keywords_msg) { |lang| language lang }
    opts.on(FAIL_FAST_FLAG, 'Exit immediately following the first failing scenario') { set_option :fail_fast }
    opts.on('-f FORMAT', '--format FORMAT', *format_msg, *FORMAT_HELP) do |v|
      add_option :formats, [*parse_formats(v), @out_stream]
    end
    opts.on('--init', *init_msg) { |_v| initialize_project }
    opts.on('-o', '--out [FILE|DIR]', *out_msg) { |v| out_stream v }
    opts.on('-t TAG_EXPRESSION', '--tags TAG_EXPRESSION', *tags_msg) { |v| add_tag v }
    opts.on('-n NAME', '--name NAME', *name_msg) { |v| add_option :name_regexps, /#{v}/ }
    opts.on('-e', '--exclude PATTERN', *exclude_msg) { |v| add_option :excludes, Regexp.new(v) }
    opts.on(PROFILE_SHORT_FLAG, "#{PROFILE_LONG_FLAG} PROFILE", *profile_short_flag_msg) { |v| add_profile v }
    opts.on(NO_PROFILE_SHORT_FLAG, NO_PROFILE_LONG_FLAG, *no_profile_short_flag_msg) { |_v| disable_profile_loading }
    opts.on('-c', '--[no-]color', *color_msg) { |v| color v }
    opts.on('-d', '--dry-run', *dry_run_msg) { set_dry_run_and_duration }
    opts.on('-m', '--no-multiline', "Don't print multiline strings and tables under steps.") { set_option :no_multiline }
    opts.on('-s', '--no-source', "Don't print the file and line of the step definition with the steps.") { set_option :source, false }
    opts.on('-i', '--no-snippets', "Don't print snippets for pending steps.") { set_option :snippets, false }
    opts.on('-I', '--snippet-type TYPE', *snippet_type_msg) { |v| set_option :snippet_type, v.to_sym }
    opts.on('-q', '--quiet', 'Alias for --no-snippets --no-source.') { shut_up }
    opts.on('--no-duration', "Don't print the duration at the end of the summary") { set_option :duration, false }
    opts.on('-b', '--backtrace', 'Show full backtrace for all errors.') { Cucumber.use_full_backtrace = true }
    opts.on('-S', '--[no-]strict', *strict_msg) { |setting| set_strict(setting) }
    opts.on('--[no-]strict-undefined', 'Fail if there are any undefined results.') { |setting| set_strict(setting, :undefined) }
    opts.on('--[no-]strict-pending', 'Fail if there are any pending results.') { |setting| set_strict(setting, :pending) }
    opts.on('--[no-]strict-flaky', 'Fail if there are any flaky results.') { |setting| set_strict(setting, :flaky) }
    opts.on('-w', '--wip', 'Fail if there are any passing scenarios.') { set_option :wip }
    opts.on('-v', '--verbose', 'Show the files and features loaded.') { set_option :verbose }
    opts.on('-g', '--guess', 'Guess best match for Ambiguous steps.') { set_option :guess }
    opts.on('-l', '--lines LINES', *lines_msg) { |lines| set_option :lines, lines }
    opts.on('-x', '--expand', 'Expand Scenario Outline Tables in output.') { set_option :expand }

    opts.on('--order TYPE[:SEED]', 'Run examples in the specified order. Available types:',
            *<<-TEXT.split("\n")) do |order|
      @options[:order], @options[:seed] = *order.split(':')
  [defined]     Run scenarios in the order they were defined (default).
  [random]      Shuffle scenarios before running.
Specify SEED to reproduce the shuffling from a previous run.
  e.g. --order random:5738
            TEXT
      raise "'#{@options[:order]}' is not a recognised order type. Please use one of #{ORDER_TYPES.join(', ')}." unless ORDER_TYPES.include?(@options[:order])
    end

    opts.on_tail('--version', 'Show version.') { exit_ok(Cucumber::VERSION) }
    opts.on_tail('-h', '--help', "You're looking at it.") { exit_ok(opts.help) }
  end.parse!

  @args.map! { |a| "#{a}:#{@options[:lines]}" } if @options[:lines]

  extract_environment_variables
  @options[:paths] = @args.dup # whatver is left over

  check_formatter_stream_conflicts

  merge_profiles

  self
end

#to_hashObject


173
174
175
# File 'lib/cucumber/cli/options.rb', line 173

def to_hash
  Hash(@options)
end