cucumber 1.2.5 → 1.3.0

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 (110) hide show
  1. checksums.yaml +14 -6
  2. data/.ruby-gemset +1 -0
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +1 -0
  5. data/.yardopts +1 -0
  6. data/CONTRIBUTING.md +2 -2
  7. data/History.md +38 -2
  8. data/bin/cucumber +2 -11
  9. data/cucumber.gemspec +3 -3
  10. data/cucumber.yml +5 -1
  11. data/examples/test_unit/Gemfile +4 -0
  12. data/examples/test_unit/features/step_definitions/test_unit_steps.rb +1 -4
  13. data/examples/watir/README.textile +2 -2
  14. data/examples/watir/features/support/env.rb +10 -7
  15. data/features/.cucumber/stepdefs.json +747 -1354
  16. data/features/assertions.feature +6 -2
  17. data/features/background.feature +3 -0
  18. data/features/backtraces.feature +3 -3
  19. data/features/before_hook.feature +43 -0
  20. data/features/bootstrap.feature +14 -2
  21. data/features/custom_formatter.feature +1 -1
  22. data/features/drb_server_integration.feature +3 -3
  23. data/features/formatter_callbacks.feature +2 -2
  24. data/features/formatter_step_file_colon_line.feature +1 -1
  25. data/features/html_formatter.feature +52 -1
  26. data/features/json_formatter.feature +93 -7
  27. data/features/load_path.feature +14 -0
  28. data/features/nested_steps.feature +75 -3
  29. data/features/nested_steps_i18n.feature +36 -0
  30. data/features/pretty_formatter.feature +31 -0
  31. data/features/progress_formatter.feature +31 -0
  32. data/features/raketask.feature +51 -0
  33. data/features/rerun_formatter.feature +1 -1
  34. data/features/stats_formatters.feature +17 -14
  35. data/features/step_definitions/cucumber_steps.rb +6 -4
  36. data/features/support/env.rb +31 -4
  37. data/features/support/feature_factory.rb +17 -0
  38. data/features/tagged_hooks.feature +37 -195
  39. data/features/transforms.feature +15 -15
  40. data/gem_tasks/cucumber.rake +2 -0
  41. data/gem_tasks/yard.rake +10 -6
  42. data/legacy_features/README.md +14 -0
  43. data/legacy_features/language_help.feature +3 -1
  44. data/legacy_features/report_called_undefined_steps.feature +1 -0
  45. data/legacy_features/snippets_when_using_star_keyword.feature +1 -0
  46. data/legacy_features/support/env.rb +4 -0
  47. data/lib/cucumber/ast/background.rb +35 -35
  48. data/lib/cucumber/ast/empty_background.rb +33 -0
  49. data/lib/cucumber/ast/examples.rb +5 -2
  50. data/lib/cucumber/ast/feature.rb +24 -35
  51. data/lib/cucumber/ast/features.rb +4 -1
  52. data/lib/cucumber/ast/has_steps.rb +9 -17
  53. data/lib/cucumber/ast/location.rb +41 -0
  54. data/lib/cucumber/ast/scenario.rb +37 -50
  55. data/lib/cucumber/ast/scenario_outline.rb +62 -49
  56. data/lib/cucumber/ast/step.rb +23 -27
  57. data/lib/cucumber/ast/step_collection.rb +16 -0
  58. data/lib/cucumber/ast/step_invocation.rb +4 -1
  59. data/lib/cucumber/ast/tree_walker.rb +7 -0
  60. data/lib/cucumber/cli/configuration.rb +15 -3
  61. data/lib/cucumber/cli/main.rb +24 -11
  62. data/lib/cucumber/cli/options.rb +24 -16
  63. data/lib/cucumber/configuration.rb +4 -0
  64. data/lib/cucumber/core_ext/disable_mini_and_test_unit_autorun.rb +10 -34
  65. data/lib/cucumber/core_ext/instance_exec.rb +4 -1
  66. data/lib/cucumber/core_ext/proc.rb +2 -0
  67. data/lib/cucumber/feature_file.rb +5 -12
  68. data/lib/cucumber/formatter/console.rb +10 -0
  69. data/lib/cucumber/formatter/gherkin_formatter_adapter.rb +4 -4
  70. data/lib/cucumber/formatter/html.rb +7 -42
  71. data/lib/cucumber/formatter/interceptor.rb +4 -0
  72. data/lib/cucumber/formatter/json_pretty.rb +0 -4
  73. data/lib/cucumber/formatter/junit.rb +8 -2
  74. data/lib/cucumber/formatter/pretty.rb +5 -1
  75. data/lib/cucumber/formatter/progress.rb +4 -0
  76. data/lib/cucumber/formatter/unicode.rb +12 -25
  77. data/lib/cucumber/formatter/usage.rb +7 -2
  78. data/lib/cucumber/js_support/js_snippets.rb +1 -1
  79. data/lib/cucumber/load_path.rb +13 -0
  80. data/lib/cucumber/parser/gherkin_builder.rb +237 -81
  81. data/lib/cucumber/platform.rb +1 -1
  82. data/lib/cucumber/py_support/py_language.rb +1 -1
  83. data/lib/cucumber/rake/task.rb +5 -1
  84. data/lib/cucumber/rb_support/rb_language.rb +20 -19
  85. data/lib/cucumber/rb_support/rb_world.rb +63 -21
  86. data/lib/cucumber/rb_support/snippet.rb +108 -0
  87. data/lib/cucumber/runtime.rb +1 -0
  88. data/lib/cucumber/runtime/support_code.rb +2 -2
  89. data/lib/cucumber/unit.rb +11 -0
  90. data/lib/cucumber/wire_support/wire_language.rb +1 -1
  91. data/spec/cucumber/ast/background_spec.rb +13 -6
  92. data/spec/cucumber/ast/feature_factory.rb +20 -10
  93. data/spec/cucumber/ast/features_spec.rb +51 -0
  94. data/spec/cucumber/ast/scenario_outline_spec.rb +13 -7
  95. data/spec/cucumber/ast/step_spec.rb +6 -4
  96. data/spec/cucumber/cli/configuration_spec.rb +34 -1
  97. data/spec/cucumber/cli/main_spec.rb +36 -26
  98. data/spec/cucumber/cli/options_spec.rb +28 -19
  99. data/spec/cucumber/core_ext/proc_spec.rb +13 -1
  100. data/spec/cucumber/formatter/interceptor_spec.rb +8 -0
  101. data/spec/cucumber/formatter/junit_spec.rb +33 -0
  102. data/spec/cucumber/formatter/pretty_spec.rb +391 -0
  103. data/spec/cucumber/rb_support/rb_language_spec.rb +21 -50
  104. data/spec/cucumber/rb_support/regexp_argument_matcher_spec.rb +2 -4
  105. data/spec/cucumber/rb_support/snippet_spec.rb +128 -0
  106. data/spec/cucumber/step_match_spec.rb +2 -6
  107. metadata +62 -113
  108. data/.rvmrc +0 -1
  109. data/features/hooks.feature +0 -59
  110. data/legacy_features/call_steps_from_stepdefs.feature +0 -154
@@ -15,7 +15,9 @@ Feature: Transforms
15
15
  """
16
16
  And a file named "features/support/person.rb" with:
17
17
  """
18
- class Person < Struct.new(:age)
18
+ class Person
19
+ attr_accessor :age
20
+
19
21
  def to_s
20
22
  "I am #{age} years old"
21
23
  end
@@ -29,18 +31,17 @@ Feature: Transforms
29
31
  And a file named "features/step_definitions/steps.rb" with:
30
32
  """
31
33
  Transform(/a Person aged (\d+)/) do |age|
32
- Person.new(age.to_i)
34
+ person = Person.new
35
+ person.age = age.to_i
36
+ person
33
37
  end
34
38
 
35
39
  Given /^(a Person aged \d+) with blonde hair$/ do |person|
36
- puts "#{person} and I have blonde hair"
40
+ person.age.should == 15
37
41
  end
38
42
  """
39
- When I run cucumber "features/foo.feature"
40
- Then it should pass with:
41
- """
42
- I am 15 years old and I have blonde hair
43
- """
43
+ When I run `cucumber features/foo.feature`
44
+ Then it should pass
44
45
 
45
46
  Scenario: Re-use Transform's Regular Expression
46
47
  If you keep a reference to the transform, you can use it in your
@@ -49,15 +50,14 @@ Feature: Transforms
49
50
  And a file named "features/step_definitions/steps.rb" with:
50
51
  """
51
52
  A_PERSON = Transform(/a Person aged (\d+)/) do |age|
52
- Person.new(age.to_i)
53
+ person = Person.new
54
+ person.age = age.to_i
55
+ person
53
56
  end
54
57
 
55
58
  Given /^(#{A_PERSON}) with blonde hair$/ do |person|
56
- puts "#{person} and I have blonde hair"
59
+ person.age.should == 15
57
60
  end
58
61
  """
59
- When I run cucumber "features/foo.feature"
60
- Then it should pass with:
61
- """
62
- I am 15 years old and I have blonde hair
63
- """
62
+ When I run `cucumber features/foo.feature`
63
+ Then it should pass
@@ -7,6 +7,8 @@ class Cucumber::Rake::Task
7
7
  Cucumber::WINDOWS ? 'jruby_win' : 'jruby'
8
8
  elsif Cucumber::WINDOWS_MRI
9
9
  'windows_mri'
10
+ elsif Cucumber::RUBY_1_8_7
11
+ 'ruby_1_8_7'
10
12
  elsif Cucumber::RUBY_1_9
11
13
  'ruby_1_9'
12
14
  elsif Cucumber::RUBY_2_0
@@ -2,26 +2,30 @@ require 'yard'
2
2
  require 'yard/rake/yardoc_task'
3
3
  require File.expand_path(File.dirname(__FILE__) + '/../lib/cucumber/platform')
4
4
 
5
+ DOC_DIR = File.expand_path(File.dirname(__FILE__) + '/../doc')
5
6
  SITE_DIR = File.expand_path(File.dirname(__FILE__) + '/../../cucumber.github.com')
6
7
  API_DIR = File.join(SITE_DIR, 'api', 'cucumber', 'ruby', 'yardoc')
7
8
  TEMPLATE_DIR = File.expand_path(File.join(File.dirname(__FILE__), 'yard'))
8
9
  YARD::Templates::Engine.register_template_path(TEMPLATE_DIR)
9
10
 
10
11
  namespace :api do
11
- task :dir do
12
+ YARD::Rake::YardocTask.new(:yard) do |yard|
13
+ yard.options = ["--out", DOC_DIR]
14
+ end
15
+
16
+ task :sync_with_git do
12
17
  unless File.directory?(SITE_DIR)
13
18
  raise "You need to git clone git@github.com:cucumber/cucumber.github.com.git #{SITE_DIR}"
14
19
  end
15
20
  Dir.chdir(SITE_DIR) do
16
21
  sh 'git pull -u'
17
- mkdir_p API_DIR
18
22
  end
19
23
  end
20
24
 
21
- YARD::Rake::YardocTask.new(:yard) do |yard|
22
- yard.options = ["--out", API_DIR]
25
+ task :copy_to_website do
26
+ rm_rf API_DIR
27
+ cp_r DOC_DIR, API_DIR
23
28
  end
24
- task :yard => :dir
25
29
 
26
30
  task :release do
27
31
  Dir.chdir(SITE_DIR) do
@@ -32,5 +36,5 @@ namespace :api do
32
36
  end
33
37
 
34
38
  desc "Generate YARD docs for Cucumber's API"
35
- task :doc => [:yard, :release]
39
+ task :doc => [:yard, :sync_with_git, :copy_to_website, :release]
36
40
  end
@@ -0,0 +1,14 @@
1
+ # Please do not add to the tests in this folder
2
+
3
+ This folder contains the acceptance tests that were written for Cucumber
4
+ before [Aruba](https://github.com/cucumber/aruba) existed.
5
+
6
+ These tests are currently run as part of the build, but should not be added to.
7
+
8
+ New acceptance tests should be added in the `features` directory. If you find a test
9
+ in here that you want to modify, please do the work to migrate it into the `features`
10
+ directory.
11
+
12
+ There is a ticket [#408](https://github.com/cucumber/cucumber/issues/408) to track
13
+ the effort to migrate all these tests into the `features` directory. We aim to have this
14
+ completed for the release of Cucumber 2.0
@@ -2,7 +2,7 @@
2
2
  Feature: Language help
3
3
  In order to figure out the keywords to use for a language
4
4
  I want to be able to get help on the language from the CLI
5
-
5
+
6
6
  Scenario: Get help for Portuguese language
7
7
  When I run cucumber --i18n pt help
8
8
  Then it should pass with
@@ -24,6 +24,7 @@ Feature: Language help
24
24
  | but (code) | "Mas" |
25
25
 
26
26
  """
27
+
27
28
  Scenario: List languages
28
29
  When I run cucumber --i18n help
29
30
  Then STDERR should be empty
@@ -51,6 +52,7 @@ Feature: Language help
51
52
  | fa | Persian | فارسی |
52
53
  | fi | Finnish | suomi |
53
54
  | fr | French | français |
55
+ | gl | Galician | galego |
54
56
  | he | Hebrew | עברית |
55
57
  | hi | Hindi | हिंदी |
56
58
  | hr | Croatian | hrvatski |
@@ -18,6 +18,7 @@ Feature: Cucumber command line
18
18
  Given call step "a step definition that calls an undefined step" # features/step_definitions/sample_steps.rb:23
19
19
  Undefined step: "this does not exist" (Cucumber::Undefined)
20
20
  ./features/step_definitions/sample_steps.rb:19:in `/^a step definition that calls an undefined step$/'
21
+ ./features/step_definitions/sample_steps.rb:24:in `/^call step "(.*)"$/'
21
22
  features/call_undefined_step_from_step_def.feature:7:in `Given call step "a step definition that calls an undefined step"'
22
23
 
23
24
  2 scenarios (2 undefined)
@@ -3,6 +3,7 @@ Feature: Use * keywords and still get snippets
3
3
  Given/When/Then, I should not get an exception
4
4
  when I have undefined steps
5
5
 
6
+ @wip-jruby
6
7
  Scenario: Use some *
7
8
  Given a standard Cucumber project directory structure
8
9
  And a file named "features/f.feature" with:
@@ -109,6 +109,10 @@ class CucumberWorld
109
109
  @last_exit_status = $?.exitstatus
110
110
  end
111
111
  @last_stderr = IO.read(stderr_file.path)
112
+ if Cucumber::JRUBY
113
+ # TODO: this actually a workaround for cucumber/gherkin#238
114
+ @last_stderr.gsub!(/^.*java_package_module_template.rb:\d+ warning: `eval' should not be aliased.*\n/, '')
115
+ end
112
116
  end
113
117
 
114
118
  def run_spork_in_background(port = nil)
@@ -1,52 +1,54 @@
1
1
  require 'cucumber/ast/has_steps'
2
2
  require 'cucumber/ast/names'
3
+ require 'cucumber/ast/location'
3
4
 
4
5
  module Cucumber
5
6
  module Ast
6
7
  class Background #:nodoc:
7
8
  include HasSteps
8
9
  include Names
9
- attr_reader :feature_elements
10
+ include HasLocation
11
+ attr_accessor :feature
10
12
 
11
- def initialize(comment, line, keyword, title, description, raw_steps)
12
- @comment, @line, @keyword, @title, @description, @raw_steps = comment, line, keyword, title, description, raw_steps
13
- @feature_elements = []
13
+ def initialize(language, location, comment, keyword, title, description, raw_steps)
14
+ @language, @location, @comment, @keyword, @title, @description, @raw_steps = language, location, comment, keyword, title, description, raw_steps
15
+ @failed = nil
16
+ @first_collection_created = false
17
+ attach_steps(@raw_steps)
14
18
  end
15
19
 
16
- def init
17
- return if @steps
18
- attach_steps(@raw_steps)
19
- @steps = StepCollection.new(@raw_steps)
20
- @step_invocations = @steps.step_invocations(true)
20
+ def feature_elements
21
+ feature.feature_elements
21
22
  end
22
23
 
23
- def step_collection(step_invocations)
24
- init
25
- unless((defined? @first_collection_created) and @first_collection_created)
26
- @first_collection_created = true
27
- @step_invocations.dup(step_invocations)
24
+ def step_invocations
25
+ @step_invocations ||= steps.step_invocations(true)
26
+ end
27
+
28
+ def step_collection(scenario_step_invocations)
29
+ if(@first_collection_created)
30
+ steps.step_invocations(true).dup(scenario_step_invocations)
28
31
  else
29
- @steps.step_invocations(true).dup(step_invocations)
32
+ @first_collection_created = true
33
+ step_invocations.dup(scenario_step_invocations)
30
34
  end
31
35
  end
32
36
 
33
37
  def accept(visitor)
34
38
  return if Cucumber.wants_to_quit
35
- init
36
39
  visitor.visit_comment(@comment) unless @comment.empty?
37
- visitor.visit_background_name(@keyword, name, file_colon_line(@line), source_indent(first_line_length))
40
+ visitor.visit_background_name(@keyword, name, file_colon_line, source_indent(first_line_length))
38
41
  with_visitor(hook_context, visitor) do
39
42
  visitor.runtime.before(hook_context)
40
43
  skip_invoke! if failed?
41
- visitor.visit_steps(@step_invocations)
42
- @failed = @step_invocations.detect{|step_invocation| step_invocation.exception || step_invocation.status != :passed }
43
- visitor.runtime.after(hook_context) if @failed || @feature_elements.empty?
44
+ visitor.visit_steps(step_invocations)
45
+ @failed = step_invocations.any? { |step_invocation| step_invocation.exception || step_invocation.status != :passed }
46
+ visitor.runtime.after(hook_context) if @failed || feature_elements.empty?
44
47
  end
45
48
  end
46
49
 
47
50
  def with_visitor(scenario, visitor)
48
51
  @current_visitor = visitor
49
- init
50
52
  if self != scenario && scenario.respond_to?(:with_visitor)
51
53
  scenario.with_visitor(visitor) do
52
54
  yield
@@ -57,39 +59,32 @@ module Cucumber
57
59
  end
58
60
 
59
61
  def accept_hook?(hook)
60
- init
61
62
  if hook_context != self
62
63
  hook_context.accept_hook?(hook)
63
64
  else
64
65
  # We have no scenarios, just ask our feature
65
- @feature.accept_hook?(hook)
66
+ feature.accept_hook?(hook)
66
67
  end
67
68
  end
68
69
 
69
70
  def skip_invoke!
70
- @step_invocations.each{|step_invocation| step_invocation.skip_invoke!}
71
+ step_invocations.each{|step_invocation| step_invocation.skip_invoke!}
71
72
  end
72
73
 
73
74
  def failed?
74
- if defined? @failed
75
- return @failed
76
- else
77
- return nil
78
- end
75
+ !!@failed
79
76
  end
80
77
 
81
78
  def hook_context
82
- @feature_elements.first || self
79
+ feature_elements.first || self
83
80
  end
84
81
 
85
82
  def to_sexp
86
- init
87
- sexp = [:background, @line, @keyword]
83
+ sexp = [:background, line, @keyword]
88
84
  sexp += [name] unless name.empty?
89
85
  comment = @comment.to_sexp
90
86
  sexp += [comment] if comment
91
- steps = @steps.to_sexp
92
- sexp += steps if steps.any?
87
+ sexp += steps.to_sexp if steps.any?
93
88
  sexp
94
89
  end
95
90
 
@@ -99,7 +94,6 @@ module Cucumber
99
94
  @current_visitor.visit_exception(@exception, :failed)
100
95
  end
101
96
 
102
-
103
97
  # Override this method, as there are situations where the background
104
98
  # wind up being the one called fore Before scenarios, and
105
99
  # backgrounds don't have tags.
@@ -111,6 +105,12 @@ module Cucumber
111
105
  source_tags.map { |tag| tag.name }
112
106
  end
113
107
 
108
+ private
109
+
110
+ def steps
111
+ @steps ||= StepCollection.new(@raw_steps)
112
+ end
113
+
114
114
  end
115
115
  end
116
116
  end
@@ -0,0 +1,33 @@
1
+ require 'cucumber/ast/step_collection'
2
+
3
+ module Cucumber
4
+ module Ast
5
+ class EmptyBackground
6
+ attr_writer :file
7
+ attr_accessor :feature
8
+
9
+ def failed?
10
+ false
11
+ end
12
+
13
+ def feature_elements
14
+ []
15
+ end
16
+
17
+ def step_collection(step_invocations)
18
+ StepCollection.new(step_invocations)
19
+ end
20
+
21
+ def step_invocations
22
+ []
23
+ end
24
+
25
+ def init
26
+ end
27
+
28
+ def accept(visitor)
29
+ end
30
+ end
31
+ end
32
+ end
33
+
@@ -4,10 +4,13 @@ module Cucumber
4
4
  module Ast
5
5
  class Examples #:nodoc:
6
6
  include Names
7
+ include HasLocation
7
8
  attr_writer :outline_table
8
9
 
9
- def initialize(comment, line, keyword, title, description, outline_table)
10
- @comment, @keyword, @title, @description, @outline_table = comment, keyword, title, description, outline_table
10
+ def initialize(location, comment, keyword, title, description, outline_table)
11
+ @location, @comment, @keyword, @title, @description, @outline_table = location, comment, keyword, title, description, outline_table
12
+ raise ArgumentError unless @location.is_a?(Location)
13
+ raise ArgumentError unless @comment.is_a?(Comment)
11
14
  end
12
15
 
13
16
  attr_reader :gherkin_statement
@@ -1,17 +1,22 @@
1
1
  require 'cucumber/ast/names'
2
+ require 'cucumber/ast/location'
3
+ require 'cucumber/ast/location'
2
4
 
3
5
  module Cucumber
4
6
  module Ast
5
7
  # Represents the root node of a parsed feature.
6
8
  class Feature #:nodoc:
7
9
  include Names
10
+ include HasLocation
8
11
 
9
12
  attr_accessor :language
10
- attr_writer :features, :background
11
- attr_reader :file, :feature_elements
13
+ attr_reader :feature_elements
12
14
 
13
- def initialize(background, comment, tags, keyword, title, description, feature_elements)
15
+ def initialize(location, background, comment, tags, keyword, title, description, feature_elements)
14
16
  @background, @comment, @tags, @keyword, @title, @description, @feature_elements = background, comment, tags, keyword, title, description, feature_elements
17
+ @background.feature = self
18
+ @location = location
19
+ @feature_elements.each { |e| e.feature = self }
15
20
  end
16
21
 
17
22
  attr_reader :gherkin_statement
@@ -19,26 +24,16 @@ module Cucumber
19
24
  @gherkin_statement ||= statement
20
25
  end
21
26
 
22
- def init
23
- @background.feature = self if @background
24
- @background.init if @background
25
- @feature_elements.each do |feature_element|
26
- feature_element.init
27
- feature_element.feature = self
28
- end
29
- end
30
-
31
- def add_feature_element(feature_element)
32
- @feature_elements << feature_element
27
+ def step_count
28
+ units.inject(0) { |total, unit| total += unit.step_count }
33
29
  end
34
30
 
35
31
  def accept(visitor)
36
32
  return if Cucumber.wants_to_quit
37
- init
38
33
  visitor.visit_comment(@comment) unless @comment.empty?
39
34
  visitor.visit_tags(@tags)
40
35
  visitor.visit_feature_name(@keyword, indented_name)
41
- visitor.visit_background(@background) if @background
36
+ visitor.visit_background(@background) if !@background.is_a?(EmptyBackground)
42
37
  @feature_elements.each do |feature_element|
43
38
  visitor.visit_feature_element(feature_element)
44
39
  end
@@ -65,24 +60,8 @@ module Cucumber
65
60
  @tags.accept_hook?(hook)
66
61
  end
67
62
 
68
- def next_feature_element(feature_element, &proc)
69
- init
70
- index = @feature_elements.index(feature_element)
71
- next_one = @feature_elements[index+1]
72
- proc.call(next_one) if next_one
73
- end
74
-
75
63
  def backtrace_line(step_name, line)
76
- "#{file_colon_line(line)}:in `#{step_name}'"
77
- end
78
-
79
- def file=(file)
80
- file = file.gsub(/\//, '\\') if Cucumber::WINDOWS && file && !ENV['CUCUMBER_FORWARD_SLASH_PATHS']
81
- @file = file
82
- end
83
-
84
- def file_colon_line(line)
85
- "#{@file}:#{line}"
64
+ "#{location.on_line(line)}:in `#{step_name}'"
86
65
  end
87
66
 
88
67
  def short_name
@@ -95,8 +74,7 @@ module Cucumber
95
74
  end
96
75
 
97
76
  def to_sexp
98
- init
99
- sexp = [:feature, @file, name]
77
+ sexp = [:feature, file, name]
100
78
  comment = @comment.to_sexp
101
79
  sexp += [comment] if comment
102
80
  tags = @tags.to_sexp
@@ -105,6 +83,17 @@ module Cucumber
105
83
  sexp += @feature_elements.map{|fe| fe.to_sexp}
106
84
  sexp
107
85
  end
86
+
87
+ private
88
+
89
+ attr_reader :background
90
+
91
+ def units
92
+ @units ||= @feature_elements.map do |element|
93
+ element.to_units(background)
94
+ end.flatten
95
+ end
96
+
108
97
  end
109
98
  end
110
99
  end