Class: Cucumber::Cli::Options

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

Constant Summary collapse

INDENT =
' ' * 53
BUILTIN_FORMATS =

rubocop:disable Layout/MultilineOperationIndentation

{
  'html'        => ['Cucumber::Formatter::Html',        'Generates a nice looking HTML report.'],
  'pretty'      => ['Cucumber::Formatter::Pretty',      'Prints the feature as is - in colours.'],
  'progress'    => ['Cucumber::Formatter::Progress',    'Prints one character per scenario.'],
  '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'],
  'json_pretty' => ['Cucumber::Formatter::JsonPretty',  'Prints the feature as prettified JSON'],
  'summary'     => ['Cucumber::Formatter::Summary',     'Summary output of feature and scenarios']
}
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."
]
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'
NO_PROFILE_SHORT_FLAG =
'-P'
PROFILE_LONG_FLAG =
'--profile'
NO_PROFILE_LONG_FLAG =
'--no-profile'
FAIL_FAST_FLAG =
'--fail-fast'
RETRY_FLAG =
'--retry'
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'
]
ORDER_TYPES =
%w{defined random}
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



68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/cucumber/cli/options.rb', line 68

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



64
65
66
# File 'lib/cucumber/cli/options.rb', line 64

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

Instance Method Details

#[](key) ⇒ Object



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

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

#[]=(key, value) ⇒ Object



86
87
88
# File 'lib/cucumber/cli/options.rb', line 86

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

#check_formatter_stream_conflictsObject



174
175
176
177
178
# File 'lib/cucumber/cli/options.rb', line 174

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



166
167
168
# File 'lib/cucumber/cli/options.rb', line 166

def custom_profiles
  @profiles - [@default_profile]
end

#filtersObject



170
171
172
# File 'lib/cucumber/cli/options.rb', line 170

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

#parse!(args) ⇒ Object

rubocop:disable Metrics/AbcSize



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

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

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

  @args.options do |opts|
    opts.banner = banner
    opts.on('-r LIBRARY|DIR', '--require LIBRARY|DIR', *require_files_msg) { |lib| require_files(lib) }

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

    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
      unless ORDER_TYPES.include?(@options[:order])
        fail "'#{@options[:order]}' is not a recognised order type. Please use one of #{ORDER_TYPES.join(", ")}."
      end
    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



180
181
182
# File 'lib/cucumber/cli/options.rb', line 180

def to_hash
  Hash(@options)
end