aslakhellesoy-cucumber 0.1.99.15 → 0.1.99.17

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.
@@ -1,7 +1,7 @@
1
1
  require 'cucumber/formatter/pretty'
2
2
 
3
3
  module Cucumber
4
- module Cli2
4
+ module Cli
5
5
  class LanguageHelpFormatter < Formatter::Pretty
6
6
  INCOMPLETE = %{
7
7
  This language is incomplete. Please translate the missing words in
@@ -4,387 +4,97 @@ require 'ostruct'
4
4
  require 'cucumber/parser'
5
5
  require 'cucumber/formatter'
6
6
  require 'cucumber/cli/language_help_formatter'
7
+ require 'cucumber/cli/configuration'
7
8
 
8
9
  module Cucumber
9
- module Cli
10
- class YmlLoadError < StandardError; end
11
-
12
- class Main
13
- class << self
14
- def step_mother=(step_mother)
15
- @step_mother = step_mother
16
- @step_mother.extend(StepMother)
17
- @step_mother.snippet_generator = StepDefinition
18
- end
19
-
20
- def execute(args)
21
- parse(args).execute!(@step_mother)
22
- end
23
-
24
- def parse(args)
25
- cli = new
26
- cli.parse_options!(args)
27
- cli
28
- end
29
- end
30
-
31
- attr_reader :options, :paths
32
- FORMATS = %w{pretty profile progress rerun}
33
- DEFAULT_FORMAT = 'pretty'
34
-
35
- def initialize(out_stream = STDOUT, error_stream = STDERR)
36
- @out_stream = out_stream
37
-
38
- @error_stream = error_stream
39
- @paths = []
40
- @options = {
41
- :strict => false,
42
- :require => nil,
43
- :lang => 'en',
44
- :dry_run => false,
45
- :formats => {},
46
- :excludes => [],
47
- :tags => [],
48
- :scenario_names => []
49
- }
50
- @active_format = DEFAULT_FORMAT
51
- end
52
-
53
- def parse_options!(args)
54
- @args = args
55
- return parse_args_from_profile('default') if args.empty?
56
- args.extend(OptionParser::Arguable)
57
-
58
- args.options do |opts|
59
- opts.banner = ["Usage: cucumber [options] [ [FILE|DIR|URL][:LINE[:LINE]*] ]+", "",
60
- "Examples:",
61
- "cucumber examples/i18n/en/features",
62
- "cucumber --language it examples/i18n/it/features/somma.feature:6:98:113",
63
- "cucumber -n -i http://rubyurl.com/eeCl", "", "",
64
- ].join("\n")
65
- opts.on("-r LIBRARY|DIR", "--require LIBRARY|DIR",
66
- "Require files before executing the features. If this",
67
- "option is not specified, all *.rb files that are",
68
- "siblings or below the features will be loaded auto-",
69
- "matically. Automatic loading is disabled when this",
70
- "option is specified, and all loading becomes explicit.",
71
- "Files under directories named \"support\" are always",
72
- "loaded first.",
73
- "This option can be specified multiple times.") do |v|
74
- @options[:require] ||= []
75
- @options[:require] << v
76
- end
77
- opts.on("-l LANG", "--language LANG",
78
- "Specify language for features (Default: #{@options[:lang]})",
79
- %{Run with "--language help" to see all languages},
80
- %{Run with "--language LANG help" to list keywords for LANG}) do |v|
81
- if v == 'help'
82
- list_languages
83
- elsif args==['help']
84
- list_keywords(v)
85
- else
86
- @options[:lang] = v
87
- end
88
- end
89
- opts.on("-f FORMAT", "--format FORMAT",
90
- "How to format features (Default: #{DEFAULT_FORMAT})",
91
- "Available formats: #{FORMATS.join(", ")}",
92
- "You can also provide your own formatter classes as long",
93
- "as they have been previously required using --require or",
94
- "if they are in the folder structure such that cucumber",
95
- "will require them automatically.",
96
- "This option can be specified multiple times.") do |v|
97
- @options[:formats][v] = @out_stream
98
- @active_format = v
99
- end
100
- opts.on("-o", "--out FILE",
101
- "Write output to a file instead of STDOUT. This option",
102
- "applies to the previously specified --format, or the",
103
- "default format if no format is specified.") do |v|
104
- @options[:formats][@active_format] = v
105
- end
106
- opts.on("-t TAGS", "--tags TAGS",
107
- "Only execute the features or scenarios with the specified tags.",
108
- "TAGS must be comma-separated without spaces.") do |v|
109
- @options[:tags] = v.split(",")
110
- end
111
- opts.on("-s SCENARIO", "--scenario SCENARIO",
112
- "Only execute the scenario with the given name. If this option",
113
- "is given more than once, run all the specified scenarios.") do |v|
114
- @options[:scenario_names] << v
115
- end
116
- opts.on("-e", "--exclude PATTERN", "Don't run feature files matching PATTERN") do |v|
117
- @options[:excludes] << v
118
- end
119
- opts.on("-p", "--profile PROFILE", "Pull commandline arguments from cucumber.yml.") do |v|
120
- parse_args_from_profile(v)
121
- end
122
- opts.on("-c", "--[no-]color",
123
- "Whether or not to use ANSI color in the output. Cucumber decides",
124
- "based on your platform and the output destination if not specified.") do |v|
125
- Term::ANSIColor.coloring = v
126
- end
127
- opts.on("-d", "--dry-run", "Invokes formatters without executing the steps.",
128
- "Implies --quiet.") do
129
- @options[:dry_run] = true
130
- @quiet = true
10
+ module Cli
11
+ class Main
12
+ class << self
13
+ def step_mother=(step_mother)
14
+ @step_mother = step_mother
15
+ @step_mother.extend(StepMother)
16
+ @step_mother.snippet_generator = StepDefinition
131
17
  end
132
- opts.on("-a", "--autoformat DIRECTORY",
133
- "Reformats (pretty prints) feature files and write them to DIRECTORY.",
134
- "Be careful if you choose to overwrite the originals.",
135
- "Implies --dry-run --formatter pretty.") do |directory|
136
- @options[:autoformat] = directory
137
- Term::ANSIColor.coloring = false
138
- @options[:dry_run] = true
139
- @quiet = true
140
- end
141
- opts.on("-m", "--no-multiline",
142
- "Don't print multiline strings and tables under steps.") do
143
- @options[:no_multiline] = true
144
- end
145
- opts.on("-n", "--no-source",
146
- "Don't print the file and line of the step definition with the steps.") do
147
- @options[:source] = false
148
- end
149
- opts.on("-i", "--no-snippets", "Don't print snippets for pending steps.") do
150
- @options[:snippets] = false
151
- end
152
- opts.on("-q", "--quiet", "Alias for --no-snippets --no-source.") do
153
- @quiet = true
154
- end
155
- opts.on("-b", "--backtrace", "Show full backtrace for all errors.") do
156
- Exception.cucumber_full_backtrace = true
157
- end
158
- opts.on("--strict", "Fail if there are any undefined steps.") do
159
- @options[:strict] = true
160
- end
161
- opts.on("-v", "--verbose", "Show the files and features loaded.") do
162
- @options[:verbose] = true
163
- end
164
- opts.on_tail("--version", "Show version.") do
165
- @out_stream.puts VERSION::STRING
166
- Kernel.exit
167
- end
168
- opts.on_tail("--help", "You're looking at it.") do
169
- @out_stream.puts opts.help
170
- Kernel.exit
171
- end
172
- end.parse!
173
-
174
- @options[:formats]['pretty'] = @out_stream if @options[:formats].empty?
175
-
176
- @options[:snippets] = true if !@quiet && @options[:snippets].nil?
177
- @options[:source] = true if !@quiet && @options[:source].nil?
178
-
179
- # Whatever is left after option parsing is the FILE arguments
180
- @paths += args
181
- end
182
-
183
-
184
- def execute!(step_mother)
185
- Cucumber.load_language(@options[:lang])
186
- if Cucumber.language_incomplete?
187
- list_keywords(Cucumber.lang)
188
- end
189
-
190
- require_files
191
- enable_diffing
192
- features = load_plain_text_features
193
-
194
- visitor = build_formatter_broadcaster(step_mother)
195
- visitor.options = @options
196
- visitor.visit_features(features)
197
-
198
- failure = features.steps[:failed].any? || (@options[:strict] && features.steps[:undefined].length)
199
- Kernel.exit(failure ? 1 : 0)
200
- end
201
-
202
- private
203
-
204
- def cucumber_yml
205
- return @cucumber_yml if @cucumber_yml
206
- unless File.exist?('cucumber.yml')
207
- raise(YmlLoadError,"cucumber.yml was not found. Please refer to cucumber's documentaion on defining profiles in cucumber.yml. You must define a 'default' profile to use the cucumber command without any arguments.\nType 'cucumber --help' for usage.\n")
208
- end
209
-
210
- require 'yaml'
211
- begin
212
- @cucumber_yml = YAML::load(IO.read('cucumber.yml'))
213
- rescue Exception => e
214
- raise(YmlLoadError,"cucumber.yml was found, but could not be parsed. Please refer to cucumber's documentaion on correct profile usage.\n")
215
- end
216
-
217
- if @cucumber_yml.nil? || !@cucumber_yml.is_a?(Hash)
218
- raise(YmlLoadError,"cucumber.yml was found, but was blank or malformed. Please refer to cucumber's documentaion on correct profile usage.\n")
219
- end
220
-
221
- return @cucumber_yml
222
- end
223
-
224
- def parse_args_from_profile(profile)
225
- unless cucumber_yml.has_key?(profile)
226
- return(exit_with_error <<-END_OF_ERROR)
227
- Could not find profile: '#{profile}'
228
-
229
- Defined profiles in cucumber.yml:
230
- * #{cucumber_yml.keys.join("\n * ")}
231
- END_OF_ERROR
232
- end
233
-
234
- args_from_yml = cucumber_yml[profile] || ''
235
18
 
236
- if !args_from_yml.is_a?(String)
237
- exit_with_error "Profiles must be defined as a String. The '#{profile}' profile was #{args_from_yml.inspect} (#{args_from_yml.class}).\n"
238
- elsif args_from_yml =~ /^\s*$/
239
- exit_with_error "The 'foo' profile in cucumber.yml was blank. Please define the command line arguments for the 'foo' profile in cucumber.yml.\n"
240
- else
241
- parse_options!(args_from_yml.split(' '))
242
- end
243
-
244
- rescue YmlLoadError => e
245
- exit_with_error(e.message)
246
- end
247
-
248
- # Requires files - typically step files and ruby feature files.
249
- def require_files
250
- verbose_log("Ruby files required:")
251
- files_to_require.each do |lib|
252
- begin
253
- require lib
254
- verbose_log(" * #{lib}")
255
- rescue LoadError => e
256
- e.message << "\nFailed to load #{lib}"
257
- raise e
19
+ def execute(args)
20
+ new(args).execute!(@step_mother)
258
21
  end
259
22
  end
260
- verbose_log("\n")
261
- end
262
-
263
- def files_to_require
264
- requires = @options[:require] || feature_dirs
265
- files = requires.map do |path|
266
- path = path.gsub(/\\/, '/') # In case we're on windows. Globs don't work with backslashes.
267
- File.directory?(path) ? Dir["#{path}/**/*.rb"] : path
268
- end.flatten.uniq
269
- files.sort { |a,b| (b =~ %r{/support/} || -1) <=> (a =~ %r{/support/} || -1) }.reject{|f| f =~ /^http/}
270
- end
271
23
 
272
- def feature_files
273
- potential_feature_files = @paths.map do |path|
274
- path = path.gsub(/\\/, '/') # In case we're on windows. Globs don't work with backslashes.
275
- path = path.chomp('/')
276
- File.directory?(path) ? Dir["#{path}/**/*.feature"] : path
277
- end.flatten.uniq
278
-
279
- @options[:excludes].each do |exclude|
280
- potential_feature_files.reject! do |path|
281
- path =~ /#{Regexp.escape(exclude)}/
282
- end
24
+ def initialize(args, out_stream = STDOUT, error_stream = STDERR)
25
+ @args = args
26
+ @out_stream = out_stream
27
+ @error_stream = error_stream
283
28
  end
29
+
30
+ def execute!(step_mother)
31
+ configuration.load_language
32
+ step_mother.options = configuration.options
284
33
 
285
- potential_feature_files
286
- end
287
-
288
- def feature_dirs
289
- feature_files.map{|f| File.directory?(f) ? f : File.dirname(f)}.uniq
290
- end
291
-
292
- def load_plain_text_features
293
- filter = Ast::Filter.new(@options)
294
- features = Ast::Features.new(filter)
295
- parser = Parser::FeatureParser.new
34
+ require_files
35
+ enable_diffing
36
+
37
+ features = load_plain_text_features
296
38
 
297
- verbose_log("Features:")
298
- feature_files.each do |f|
299
- features.add_feature(parser.parse_file(f))
300
- verbose_log(" * #{f}")
39
+ visitor = configuration.build_formatter_broadcaster(step_mother)
40
+ visitor.visit_features(features)
41
+
42
+ failure = features.steps[:failed].any? || (configuration.strict? && features.steps[:undefined].length)
43
+ Kernel.exit(failure ? 1 : 0)
301
44
  end
302
- verbose_log("\n"*2)
303
- features
304
- end
305
45
 
306
- def build_formatter_broadcaster(step_mother)
307
- return Formatter::Pretty.new(step_mother, nil, @options) if @options[:autoformat]
308
- formatters = @options[:formats].map do |format, out|
309
- if String === out # file name
310
- out = File.open(out, Cucumber.file_mode('w'))
311
- at_exit do
312
- out.flush
313
- out.close
314
- end
315
- end
46
+ private
316
47
 
317
- case format
318
- when 'pretty'
319
- Formatter::Pretty.new(step_mother, out, @options)
320
- when 'progress'
321
- Formatter::Progress.new(step_mother, out, @options)
322
- when 'profile'
323
- Formatter::Profile.new(step_mother, out, @options)
324
- when 'rerun'
325
- Formatter::Rerun.new(step_mother, out, @options)
326
- else
48
+ def configuration
49
+ return @configuration if @configuration
50
+
51
+ @configuration = Configuration.new(@out_stream, @error_stream)
52
+ @configuration.parse!(@args)
53
+ @configuration
54
+ end
55
+
56
+ def require_files
57
+ verbose_log("Ruby files required:")
58
+ configuration.files_to_require.each do |lib|
327
59
  begin
328
- formatter_class = constantize(format)
329
- formatter_class.new(step_mother, out, @options)
330
- rescue Exception => e
331
- exit_with_error("Error creating formatter: #{format}", e)
60
+ require lib
61
+ verbose_log(" * #{lib}")
62
+ rescue LoadError => e
63
+ e.message << "\nFailed to load #{lib}"
64
+ raise e
332
65
  end
333
66
  end
67
+ verbose_log("\n")
334
68
  end
335
- Broadcaster.new(formatters)
336
- end
337
69
 
338
- def constantize(camel_cased_word)
339
- names = camel_cased_word.split('::')
340
- names.shift if names.empty? || names.first.empty?
341
-
342
- constant = Object
343
- names.each do |name|
344
- constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
345
- end
346
- constant
347
- end
70
+ def load_plain_text_features
71
+ filter = configuration.ast_filter
72
+ features = Ast::Features.new(filter)
73
+ parser = Parser::FeatureParser.new
348
74
 
349
- def verbose_log(string)
350
- @out_stream.puts(string) if @options[:verbose]
351
- end
352
-
353
- def exit_with_help
354
- parse_options!(%w{--help})
355
- end
356
-
357
- def exit_with_error(error_message, e=nil)
358
- @error_stream.puts(error_message)
359
- if e
360
- @error_stream.puts("#{e.message} (#{e.class})")
361
- @error_stream.puts(e.backtrace.join("\n"))
75
+ verbose_log("Features:")
76
+ configuration.feature_files.each do |f|
77
+ features.add_feature(parser.parse_file(f))
78
+ verbose_log(" * #{f}")
79
+ end
80
+ verbose_log("\n"*2)
81
+ features
362
82
  end
363
- Kernel.exit 1
364
- end
365
83
 
366
- def enable_diffing
367
- if defined?(::Spec)
368
- require 'spec/expectations/differs/default'
369
- options = OpenStruct.new(:diff_format => :unified, :context_lines => 3)
370
- ::Spec::Expectations.differ = ::Spec::Expectations::Differs::Default.new(options)
84
+ def verbose_log(string)
85
+ @out_stream.puts(string) if configuration.verbose?
371
86
  end
372
- end
373
-
374
- def list_languages
375
- Cli2::LanguageHelpFormatter.list_languages(@out_stream)
376
- Kernel.exit
377
- end
378
87
 
379
- def list_keywords(lang)
380
- unless Cucumber::LANGUAGES[lang]
381
- exit_with_error("No language with key #{lang}")
88
+ def enable_diffing
89
+ if defined?(::Spec)
90
+ require 'spec/expectations/differs/default'
91
+ options = OpenStruct.new(:diff_format => :unified, :context_lines => 3)
92
+ ::Spec::Expectations.differ = ::Spec::Expectations::Differs::Default.new(options)
93
+ end
382
94
  end
383
- Cli2::LanguageHelpFormatter.list_keywords(@out_stream, lang)
384
- Kernel.exit
95
+
385
96
  end
386
97
  end
387
98
  end
388
- end
389
99
 
390
100
  Cucumber::Cli::Main.step_mother = self