cucumber 0.3.96 → 0.3.97

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.
Files changed (93) hide show
  1. data/History.txt +22 -3
  2. data/License.txt +2 -0
  3. data/Manifest.txt +9 -5
  4. data/config/hoe.rb +1 -0
  5. data/examples/i18n/Rakefile +5 -3
  6. data/examples/i18n/fi/features/yhteenlasku.feature +5 -4
  7. data/examples/python/features/step_definitions/fib_steps.py +3 -0
  8. data/examples/python/features/support/env.rb +21 -21
  9. data/gem_tasks/contributors.rake +8 -0
  10. data/gem_tasks/features.rake +1 -0
  11. data/gem_tasks/sdoc.rake +7 -0
  12. data/lib/README.rdoc +12 -0
  13. data/lib/cucumber/ast/background.rb +1 -1
  14. data/lib/cucumber/ast/comment.rb +1 -1
  15. data/lib/cucumber/ast/examples.rb +9 -4
  16. data/lib/cucumber/ast/feature.rb +1 -1
  17. data/lib/cucumber/ast/feature_element.rb +1 -1
  18. data/lib/cucumber/ast/features.rb +1 -1
  19. data/lib/cucumber/ast/outline_table.rb +2 -2
  20. data/lib/cucumber/ast/py_string.rb +1 -1
  21. data/lib/cucumber/ast/scenario.rb +1 -1
  22. data/lib/cucumber/ast/scenario_outline.rb +8 -7
  23. data/lib/cucumber/ast/step.rb +1 -1
  24. data/lib/cucumber/ast/step_collection.rb +1 -1
  25. data/lib/cucumber/ast/step_invocation.rb +1 -1
  26. data/lib/cucumber/ast/table.rb +65 -45
  27. data/lib/cucumber/ast/tags.rb +2 -2
  28. data/lib/cucumber/ast/visitor.rb +6 -8
  29. data/lib/cucumber/broadcaster.rb +1 -1
  30. data/lib/cucumber/cli/language_help_formatter.rb +1 -1
  31. data/lib/cucumber/cli/main.rb +15 -52
  32. data/lib/cucumber/constantize.rb +1 -1
  33. data/lib/cucumber/core_ext/exception.rb +1 -1
  34. data/lib/cucumber/core_ext/instance_exec.rb +8 -3
  35. data/lib/cucumber/core_ext/proc.rb +1 -1
  36. data/lib/cucumber/core_ext/string.rb +1 -1
  37. data/lib/cucumber/feature_file.rb +4 -3
  38. data/lib/cucumber/filter.rb +2 -1
  39. data/lib/cucumber/formatter/ansicolor.rb +6 -5
  40. data/lib/cucumber/formatter/color_io.rb +2 -2
  41. data/lib/cucumber/formatter/console.rb +2 -0
  42. data/lib/cucumber/formatter/duration.rb +3 -0
  43. data/lib/cucumber/formatter/html.rb +1 -0
  44. data/lib/cucumber/formatter/junit.rb +1 -0
  45. data/lib/cucumber/formatter/ordered_xml_markup.rb +1 -1
  46. data/lib/cucumber/formatter/pretty.rb +18 -4
  47. data/lib/cucumber/formatter/profile.rb +1 -0
  48. data/lib/cucumber/formatter/progress.rb +1 -0
  49. data/lib/cucumber/formatter/rerun.rb +2 -0
  50. data/lib/cucumber/formatter/steps.rb +1 -0
  51. data/lib/cucumber/formatter/tag_cloud.rb +2 -1
  52. data/lib/cucumber/formatter/unicode.rb +1 -1
  53. data/lib/cucumber/formatter/usage.rb +1 -0
  54. data/lib/cucumber/language_support.rb +30 -0
  55. data/lib/cucumber/language_support/language_methods.rb +34 -12
  56. data/lib/cucumber/parser/feature.rb +81 -57
  57. data/lib/cucumber/parser/feature.tt +3 -3
  58. data/lib/cucumber/parser/natural_language.rb +1 -1
  59. data/lib/cucumber/parser/table.rb +3 -0
  60. data/lib/cucumber/parser/treetop_ext.rb +6 -5
  61. data/lib/cucumber/platform.rb +1 -2
  62. data/lib/cucumber/py_support/py_dsl.py +8 -0
  63. data/lib/cucumber/py_support/py_language.py +2 -0
  64. data/lib/cucumber/py_support/py_language.rb +68 -0
  65. data/lib/cucumber/rails/world.rb +2 -1
  66. data/lib/cucumber/rake/task.rb +13 -11
  67. data/lib/cucumber/rb_support/rb_dsl.rb +27 -15
  68. data/lib/cucumber/rb_support/rb_hook.rb +1 -2
  69. data/lib/cucumber/rb_support/rb_language.rb +57 -33
  70. data/lib/cucumber/rb_support/rb_step_definition.rb +42 -38
  71. data/lib/cucumber/rb_support/rb_world.rb +93 -0
  72. data/lib/cucumber/rspec_neuter.rb +3 -3
  73. data/lib/cucumber/step_match.rb +2 -2
  74. data/lib/cucumber/step_mother.rb +91 -65
  75. data/lib/cucumber/version.rb +1 -1
  76. data/lib/cucumber/webrat/element_locator.rb +3 -3
  77. data/rails_generators/cucumber/templates/cucumber.rake +2 -0
  78. data/rails_generators/cucumber/templates/webrat_steps.rb +4 -0
  79. data/spec/cucumber/ast/background_spec.rb +8 -1
  80. data/spec/cucumber/ast/scenario_outline_spec.rb +1 -0
  81. data/spec/cucumber/ast/table_spec.rb +10 -0
  82. data/spec/cucumber/cli/options_spec.rb +1 -1
  83. data/spec/cucumber/parser/feature_parser_spec.rb +4 -0
  84. data/spec/cucumber/rb_support/rb_step_definition_spec.rb +114 -0
  85. data/spec/cucumber/step_mother_spec.rb +29 -10
  86. data/spec/cucumber/treetop_parser/with_comments.feature +14 -1
  87. data/spec/cucumber/world/pending_spec.rb +1 -1
  88. metadata +21 -7
  89. data/gem_tasks/yard.rake +0 -8
  90. data/lib/cucumber/language_support/hook_methods.rb +0 -9
  91. data/lib/cucumber/world.rb +0 -89
  92. data/spec/cucumber/ast/visitor_spec.rb +0 -27
  93. data/spec/cucumber/step_definition_spec.rb +0 -102
@@ -6,7 +6,7 @@ module Cucumber
6
6
  #
7
7
  # This gets stored internally as <tt>["invoice", "release_2"]</tt>
8
8
  #
9
- class Tags
9
+ class Tags #:nodoc:
10
10
  def self.strip_prefix(tag_name)
11
11
  tag_name =~ /^@(.*)/ ? $1 : tag_name
12
12
  end
@@ -23,7 +23,7 @@ module Cucumber
23
23
  end
24
24
 
25
25
  def accept_hook?(hook)
26
- hook.matches_tag_names?(@tag_names)
26
+ hook.tag_names.empty? || (hook.tag_names.map{|tag| Ast::Tags.strip_prefix(tag)} & @tag_names).any?
27
27
  end
28
28
 
29
29
  def count(tag)
@@ -1,20 +1,17 @@
1
1
  module Cucumber
2
2
  module Ast
3
- # A dumb visitor that implements the whole Visitor API and just walks the tree.
3
+ # Base class for formatters. This class just walks the tree depth first.
4
+ # Just override the methods you care about. Remember to call super if you
5
+ # override a method.
4
6
  class Visitor
5
- attr_accessor :options
6
- attr_reader :step_mother
7
+ attr_accessor :options #:nodoc:
8
+ attr_reader :step_mother #:nodoc:
7
9
 
8
10
  def initialize(step_mother)
9
11
  @options = {}
10
12
  @step_mother = step_mother
11
13
  end
12
14
 
13
- def matches_scenario_names?(node)
14
- scenario_name_regexps = options[:name_regexps] || []
15
- scenario_name_regexps.empty? || node.matches_scenario_names?(scenario_name_regexps)
16
- end
17
-
18
15
  def visit_features(features)
19
16
  features.accept(self)
20
17
  end
@@ -109,6 +106,7 @@ module Cucumber
109
106
  def visit_table_cell_value(value, status)
110
107
  end
111
108
 
109
+ # Print +announcement+. This method can be called from within StepDefinitions.
112
110
  def announce(announcement)
113
111
  end
114
112
 
@@ -1,5 +1,5 @@
1
1
  module Cucumber
2
- class Broadcaster
2
+ class Broadcaster #:nodoc:
3
3
  def initialize(receivers = [])
4
4
  @receivers = receivers
5
5
  end
@@ -23,7 +23,7 @@ http://wiki.github.com/aslakhellesoy/cucumber/spoken-languages
23
23
  end
24
24
 
25
25
  def self.list_keywords(io, lang)
26
- language = Parser::NaturalLanguage[lang]
26
+ language = Parser::NaturalLanguage.get(nil, lang)
27
27
  raw = Parser::NaturalLanguage::KEYWORD_KEYS.map do |key|
28
28
  [key, language.keywords(key)]
29
29
  end
@@ -1,6 +1,7 @@
1
1
  require 'optparse'
2
2
  require 'cucumber'
3
3
  require 'ostruct'
4
+ require 'logger'
4
5
  require 'cucumber/parser'
5
6
  require 'cucumber/feature_file'
6
7
  require 'cucumber/formatter/color_io'
@@ -13,6 +14,12 @@ module Cucumber
13
14
  class Main
14
15
  FAILURE = 1
15
16
 
17
+ class LogFormatter < ::Logger::Formatter
18
+ def call(severity, time, progname, msg)
19
+ msg
20
+ end
21
+ end
22
+
16
23
  class << self
17
24
  def step_mother
18
25
  @step_mother ||= StepMother.new
@@ -27,8 +34,6 @@ module Cucumber
27
34
  @args = args
28
35
  @out_stream = out_stream == STDOUT ? Formatter::ColorIO.new : out_stream
29
36
  @error_stream = error_stream
30
- $err = error_stream
31
- @unsupported_programming_languages = []
32
37
  end
33
38
 
34
39
  def execute!(step_mother)
@@ -41,13 +46,19 @@ module Cucumber
41
46
  end
42
47
  end
43
48
  step_mother.options = configuration.options
49
+
50
+ logger = Logger.new(@out_stream)
51
+ logger.formatter = LogFormatter.new
52
+ logger.level = Logger::INFO
53
+ logger.level = Logger::DEBUG if configuration.verbose?
54
+ step_mother.log = logger
44
55
 
45
56
  # Feature files must be loaded before files are required.
46
57
  # This is because i18n step methods are only aliased when
47
58
  # features are loaded. If we swap the order, the requires
48
59
  # will fail.
49
- features = load_plain_text_features(step_mother)
50
- load_step_defs(step_mother)
60
+ features = step_mother.load_plain_text_features(configuration.feature_files)
61
+ step_mother.load_code_files(configuration.step_defs_to_load)
51
62
  enable_diffing
52
63
 
53
64
  visitor = configuration.build_formatter_broadcaster(step_mother)
@@ -80,22 +91,6 @@ module Cucumber
80
91
  exceeded
81
92
  end
82
93
 
83
- def load_plain_text_features(step_mother)
84
- features = Ast::Features.new
85
-
86
- verbose_log("Features:")
87
- configuration.feature_files.each do |f|
88
- feature_file = FeatureFile.new(f)
89
- feature = feature_file.parse(step_mother, configuration.options)
90
- if feature
91
- features.add_feature(feature)
92
- verbose_log(" * #{f}")
93
- end
94
- end
95
- verbose_log("\n")
96
- features
97
- end
98
-
99
94
  def configuration
100
95
  return @configuration if @configuration
101
96
 
@@ -110,38 +105,6 @@ module Cucumber
110
105
 
111
106
  private
112
107
 
113
- def load_step_defs(step_mother)
114
- step_def_files = configuration.step_defs_to_load
115
- verbose_log("Step Definitions:")
116
- step_def_files.each do |step_def_file|
117
- load_step_def(step_mother, step_def_file)
118
- end
119
- verbose_log("\n")
120
- end
121
-
122
- def load_step_def(step_mother, step_def_file)
123
- if programming_language = programming_language_for(step_mother, step_def_file)
124
- verbose_log(" * #{step_def_file}")
125
- programming_language.load_step_def_file(step_def_file)
126
- else
127
- verbose_log(" * #{step_def_file} [NOT SUPPORTED]")
128
- end
129
- end
130
-
131
- def programming_language_for(step_mother, step_def_file) # :nodoc:
132
- if ext = File.extname(step_def_file)[1..-1]
133
- return nil if @unsupported_programming_languages.index(ext)
134
- begin
135
- step_mother.load_programming_language(ext)
136
- rescue LoadError
137
- @unsupported_programming_languages << ext
138
- nil
139
- end
140
- else
141
- nil
142
- end
143
- end
144
-
145
108
  def enable_diffing
146
109
  if configuration.diff_enabled?
147
110
  begin
@@ -1,5 +1,5 @@
1
1
  module Cucumber
2
- module Constantize
2
+ module Constantize #:nodoc:
3
3
  def constantize(camel_cased_word)
4
4
  begin
5
5
  names = camel_cased_word.split('::')
@@ -18,7 +18,7 @@
18
18
  #
19
19
  # All backtrace munging can be turned off with the <tt>--backtrace</tt> switch
20
20
  #
21
- class Exception
21
+ class Exception #:nodoc:
22
22
  CUCUMBER_FILTER_PATTERNS = [
23
23
  /vendor\/rails|lib\/cucumber|bin\/cucumber:|lib\/rspec|gems\//
24
24
  ]
@@ -1,11 +1,13 @@
1
1
  require 'cucumber/platform'
2
2
 
3
3
  module Cucumber
4
+ # Raised if the number of a StepDefinition's Regexp match groups
5
+ # is different from the number of Proc arguments.
4
6
  class ArityMismatchError < StandardError
5
7
  end
6
8
  end
7
9
 
8
- class Object
10
+ class Object #:nodoc:
9
11
  def cucumber_instance_exec(check_arity, pseudo_method, *args, &block)
10
12
  cucumber_run_with_backtrace_filtering(pseudo_method) do
11
13
  if check_arity && !cucumber_compatible_arity?(args, block)
@@ -23,7 +25,9 @@ class Object
23
25
  end
24
26
  end
25
27
  end
26
-
28
+
29
+ private
30
+
27
31
  def cucumber_arity(block)
28
32
  a = block.arity
29
33
  Cucumber::RUBY_1_9 ? a : (a == -1 ? 0 : a)
@@ -48,7 +52,8 @@ class Object
48
52
 
49
53
  unless defined? instance_exec # 1.9
50
54
  # http://eigenclass.org/hiki/bounded+space+instance_exec
51
- module InstanceExecHelper; end
55
+ module InstanceExecHelper #:nodoc:
56
+ end
52
57
  include InstanceExecHelper
53
58
  def instance_exec(*args, &block)
54
59
  begin
@@ -1,5 +1,5 @@
1
1
  # Proc extension to get more location info out of a proc
2
- class Proc
2
+ class Proc #:nodoc:
3
3
  PROC_PATTERN = /[\d\w]+@(.*):(.*)>/
4
4
 
5
5
  def to_comment_line
@@ -1,4 +1,4 @@
1
- class String
1
+ class String #:nodoc:
2
2
  def indent(n)
3
3
  if n >= 0
4
4
  gsub(/^/, ' ' * n)
@@ -3,10 +3,11 @@ require 'cucumber/filter'
3
3
 
4
4
  module Cucumber
5
5
  class FeatureFile
6
- FILE_COLON_LINE_PATTERN = /^([\w\W]*?):([\d:]+)$/
7
- LANGUAGE_PATTERN = /language:\s*(.*)/
6
+ FILE_COLON_LINE_PATTERN = /^([\w\W]*?):([\d:]+)$/ #:nodoc:
7
+ LANGUAGE_PATTERN = /language:\s*(.*)/ #:nodoc:
8
8
 
9
- # The +uri+ argument can ba a path or a path:line1:line2 etc.
9
+ # The +uri+ argument is the location of the source. It can ba a path
10
+ # or a path:line1:line2 etc. If +source+ is passed, +uri+ is ignored.
10
11
  def initialize(uri, source=nil)
11
12
  @source = source
12
13
  _, @path, @lines = *FILE_COLON_LINE_PATTERN.match(uri)
@@ -1,5 +1,6 @@
1
1
  module Cucumber
2
- class Filter
2
+ # Filters the AST based on --tags and --name
3
+ class Filter #:nodoc:
3
4
  def initialize(lines, options)
4
5
  @lines = lines
5
6
 
@@ -23,8 +23,9 @@ Term::ANSIColor.coloring = false if !STDOUT.tty? and not ENV.has_key?("AUTOTEST"
23
23
 
24
24
  module Cucumber
25
25
  module Formatter
26
- # Defines aliases for coloured output. You can tweak the colours by defining
27
- # a <tt>CUCUMBER_COLORS</tt> variable in your shell, very much like you can
26
+ # Defines aliases for coloured output. You don't invoke any methods from this
27
+ # module directly, but you can change the output colours by defining
28
+ # a <tt>CUCUMBER_COLORS</tt> variable in your shell, very much like how you can
28
29
  # tweak the familiar POSIX command <tt>ls</tt> with
29
30
  # <a href="http://mipsisrisc.com/rambling/2008/06/27/lscolorsls_colors-now-with-linux-support/">$LSCOLORS/$LS_COLORS</a>
30
31
  #
@@ -97,7 +98,7 @@ module Cucumber
97
98
  end
98
99
  end
99
100
 
100
- def self.define_grey
101
+ def self.define_grey #:nodoc:
101
102
  begin
102
103
  gem 'genki-ruby-terminfo'
103
104
  require 'terminfo'
@@ -125,8 +126,8 @@ module Cucumber
125
126
  end
126
127
  end
127
128
 
128
- def self.define_real_grey
129
- def grey(m)
129
+ def self.define_real_grey #:nodoc:
130
+ def grey(m) #:nodoc:
130
131
  if ::Term::ANSIColor.coloring?
131
132
  "\e[90m#{m}\e[0m"
132
133
  else
@@ -3,10 +3,10 @@ require 'forwardable'
3
3
  module Cucumber
4
4
  module Formatter
5
5
  # Adapter to make #puts/#print/#flush work with colours on Windows
6
- class ColorIO
6
+ class ColorIO #:nodoc:
7
7
  extend Forwardable
8
8
  def_delegators :@kernel, :puts, :print # win32console colours only work when sent to Kernel
9
- def_delegators :@stdout, :flush, :tty?, :write
9
+ def_delegators :@stdout, :flush, :tty?, :write, :close
10
10
 
11
11
  def initialize
12
12
  @kernel = Kernel
@@ -3,6 +3,8 @@ require 'cucumber/formatter/duration'
3
3
 
4
4
  module Cucumber
5
5
  module Formatter
6
+ # This module contains helper methods that are used by formatters
7
+ # that print output to the terminal.
6
8
  module Console
7
9
  extend ANSIColor
8
10
  include Duration
@@ -1,6 +1,9 @@
1
1
  module Cucumber
2
2
  module Formatter
3
3
  module Duration
4
+ # Helper method for formatters that need to
5
+ # format a duration in seconds to the UNIX
6
+ # <tt>time</tt> format.
4
7
  def format_duration(seconds)
5
8
  m, s = seconds.divmod(60)
6
9
  "#{m}m#{'%.3f' % s}s"
@@ -3,6 +3,7 @@ require 'cucumber/formatter/duration'
3
3
 
4
4
  module Cucumber
5
5
  module Formatter
6
+ # The formatter used for <tt>--format html</tt>
6
7
  class Html < Ast::Visitor
7
8
  include ERB::Util # for the #h method
8
9
  include Duration
@@ -2,6 +2,7 @@ require 'cucumber/formatter/ordered_xml_markup'
2
2
 
3
3
  module Cucumber
4
4
  module Formatter
5
+ # The formatter used for <tt>--format junit</tt>
5
6
  class Junit < Cucumber::Ast::Visitor
6
7
 
7
8
  def initialize(step_mother, io, options)
@@ -8,7 +8,7 @@ end
8
8
  module Cucumber
9
9
  module Formatter
10
10
  # Emits attributes ordered alphabetically, so that we can predicatbly test output.
11
- class OrderedXmlMarkup < Builder::XmlMarkup
11
+ class OrderedXmlMarkup < Builder::XmlMarkup #:nodoc:
12
12
  def _insert_attributes(attrs, order=[])
13
13
  return if attrs.nil?
14
14
  keys = attrs.keys.map{|k| k.to_s}
@@ -3,6 +3,8 @@ require 'fileutils'
3
3
 
4
4
  module Cucumber
5
5
  module Formatter
6
+ # The formatter used for <tt>--format pretty</tt> (the default formatter).
7
+ #
6
8
  # This formatter prints features to plain text - exactly how they were parsed,
7
9
  # just prettier. That means with proper indentation and alignment of table columns.
8
10
  #
@@ -96,15 +98,30 @@ module Cucumber
96
98
  visit_feature_element_name(keyword, name, file_colon_line, source_indent)
97
99
  end
98
100
 
101
+ def visit_examples_array(examples_array)
102
+ @indent = 4
103
+ @io.puts
104
+ examples_array[0..-2].each { |ea| super(ea) }
105
+ @last_example = true
106
+ super(examples_array.last)
107
+ @last_example = nil
108
+ end
109
+
99
110
  def visit_examples_name(keyword, name)
100
111
  names = name.strip.empty? ? [name.strip] : name.split("\n")
101
- @io.puts("\n #{keyword} #{names[0]}")
112
+ @io.puts(" #{keyword} #{names[0]}")
102
113
  names[1..-1].each {|s| @io.puts " #{s}" } unless names.empty?
103
114
  @io.flush
104
115
  @indent = 6
105
116
  @scenario_indent = 6
106
117
  end
107
118
 
119
+ def visit_outline_table(outline_table)
120
+ super
121
+ @indent = 4
122
+ @io.puts unless @last_example
123
+ end
124
+
108
125
  def visit_scenario_name(keyword, name, file_colon_line, source_indent)
109
126
  visit_feature_element_name(keyword, name, file_colon_line, source_indent)
110
127
  end
@@ -188,9 +205,6 @@ module Cucumber
188
205
  end
189
206
 
190
207
  private
191
- def cell_prefix(status)
192
- @prefixes[status]
193
- end
194
208
 
195
209
  def cell_prefix(status)
196
210
  @prefixes[status]
@@ -2,6 +2,7 @@ require 'cucumber/formatter/progress'
2
2
 
3
3
  module Cucumber
4
4
  module Formatter
5
+ # The formatter used for <tt>--format profile</tt>
5
6
  class Profile < Progress
6
7
  NUMBER_OF_STEP_DEFINITONS_TO_SHOW = 10
7
8
  NUMBER_OF_STEP_INVOCATIONS_TO_SHOW = 5
@@ -2,6 +2,7 @@ require 'cucumber/formatter/console'
2
2
 
3
3
  module Cucumber
4
4
  module Formatter
5
+ # The formatter used for <tt>--format progress</tt>
5
6
  class Progress < Ast::Visitor
6
7
  include Console
7
8
 
@@ -1,5 +1,7 @@
1
1
  module Cucumber
2
2
  module Formatter
3
+ # The formatter used for <tt>--format rerun</tt>
4
+ #
3
5
  # This formatter keeps track of all failing features and print out their location.
4
6
  # Example:
5
7
  #
@@ -1,5 +1,6 @@
1
1
  module Cucumber
2
2
  module Formatter
3
+ # The formatter used for <tt>--format steps</tt>
3
4
  class Steps < Ast::Visitor
4
5
 
5
6
  def initialize(step_mother, io, options)