aslakhellesoy-cucumber 0.1.99.15 → 0.1.99.17

Sign up to get free protection for your applications and to get access to all the features.
@@ -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