cucumber 0.3.101 → 0.3.102

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 (62) hide show
  1. data/History.txt +31 -2
  2. data/Manifest.txt +7 -4
  3. data/config/hoe.rb +2 -2
  4. data/examples/pure_java/README.textile +2 -2
  5. data/examples/self_test/features/step_definitions/sample_steps.rb +0 -12
  6. data/examples/self_test/features/support/env.rb +0 -6
  7. data/features/cucumber_cli.feature +11 -24
  8. data/features/custom_formatter.feature +38 -3
  9. data/features/default_snippets.feature +42 -0
  10. data/features/html_formatter/a.html +1 -1
  11. data/features/negative_tagged_hooks.feature +61 -0
  12. data/features/step_definitions/cucumber_steps.rb +1 -1
  13. data/features/support/env.rb +1 -1
  14. data/features/transform.feature +88 -12
  15. data/features/usage.feature +0 -6
  16. data/lib/cucumber/ast/feature.rb +4 -0
  17. data/lib/cucumber/ast/feature_element.rb +49 -42
  18. data/lib/cucumber/ast/step_invocation.rb +1 -1
  19. data/lib/cucumber/ast/tags.rb +25 -3
  20. data/lib/cucumber/cli/drb_client.rb +7 -1
  21. data/lib/cucumber/cli/main.rb +5 -3
  22. data/lib/cucumber/cli/options.rb +15 -24
  23. data/lib/cucumber/constantize.rb +8 -2
  24. data/lib/cucumber/core_ext/instance_exec.rb +2 -1
  25. data/lib/cucumber/core_ext/string.rb +12 -22
  26. data/lib/cucumber/filter.rb +2 -12
  27. data/lib/cucumber/formatter/console.rb +21 -21
  28. data/lib/cucumber/formatter/html.rb +1 -1
  29. data/lib/cucumber/formatter/pdf.rb +1 -1
  30. data/lib/cucumber/formatter/pretty.rb +1 -1
  31. data/lib/cucumber/language_support/language_methods.rb +19 -2
  32. data/lib/cucumber/language_support/step_definition_methods.rb +2 -25
  33. data/lib/cucumber/parser/feature.rb +13 -50
  34. data/lib/cucumber/parser/feature.tt +13 -47
  35. data/lib/cucumber/parser/natural_language.rb +1 -1
  36. data/lib/cucumber/rails/action_controller.rb +33 -0
  37. data/lib/cucumber/rails/active_record.rb +27 -0
  38. data/lib/cucumber/rails/rspec.rb +1 -1
  39. data/lib/cucumber/rails/test_unit.rb +9 -0
  40. data/lib/cucumber/rails/world.rb +7 -78
  41. data/lib/cucumber/rb_support/rb_dsl.rb +6 -4
  42. data/lib/cucumber/rb_support/rb_group.rb +11 -0
  43. data/lib/cucumber/rb_support/rb_language.rb +8 -2
  44. data/lib/cucumber/rb_support/rb_step_definition.rb +23 -8
  45. data/lib/cucumber/rb_support/rb_transform.rb +35 -0
  46. data/lib/cucumber/rb_support/rb_world.rb +7 -1
  47. data/lib/cucumber/step_match.rb +25 -6
  48. data/lib/cucumber/step_mother.rb +9 -32
  49. data/lib/cucumber/version.rb +1 -1
  50. data/rails_generators/cucumber/templates/cucumber_environment.rb +2 -2
  51. data/rails_generators/cucumber/templates/env.rb +1 -8
  52. data/spec/cucumber/ast/feature_element_spec.rb +24 -23
  53. data/spec/cucumber/ast/scenario_outline_spec.rb +1 -1
  54. data/spec/cucumber/cli/options_spec.rb +5 -14
  55. data/spec/cucumber/core_ext/string_spec.rb +11 -13
  56. data/spec/cucumber/parser/feature_parser_spec.rb +6 -6
  57. data/spec/cucumber/step_mother_spec.rb +41 -38
  58. metadata +11 -8
  59. data/examples/self_test/features/transform_sample.feature +0 -10
  60. data/spec/cucumber/rails/stubs/mini_rails.rb +0 -18
  61. data/spec/cucumber/rails/stubs/test_help.rb +0 -1
  62. data/spec/cucumber/rails/world_spec.rb +0 -16
@@ -1,5 +1,3 @@
1
- require 'cucumber/rb_support/rb_hook'
2
-
3
1
  module Cucumber
4
2
  module RbSupport
5
3
  # This module defines the methods you can use to define pure Ruby
@@ -21,6 +19,10 @@ module Cucumber
21
19
  @rb_language.register_rb_hook(phase, tag_names, proc)
22
20
  end
23
21
 
22
+ def register_rb_transform(regexp, proc)
23
+ @rb_language.register_rb_transform(regexp, proc)
24
+ end
25
+
24
26
  def register_rb_step_definition(regexp, proc)
25
27
  @rb_language.register_rb_step_definition(regexp, proc)
26
28
  end
@@ -71,8 +73,8 @@ module Cucumber
71
73
  # the pattern contains captures then they will be yielded as arguments to the
72
74
  # provided proc. The return value of the proc is consequently yielded to the
73
75
  # step definition.
74
- def Transform(*args, &proc)
75
- StepMother.register_transform(*args, &proc)
76
+ def Transform(regexp, &proc)
77
+ RbDsl.register_rb_transform(regexp, proc)
76
78
  end
77
79
 
78
80
  # Registers a proc that will run after Cucumber is configured. You can register as
@@ -0,0 +1,11 @@
1
+ module Cucumber
2
+ module RbSupport
3
+ class RbGroup
4
+ attr_reader :val, :start
5
+
6
+ def initialize(val, start)
7
+ @val, @start = val, start
8
+ end
9
+ end
10
+ end
11
+ end
@@ -1,6 +1,8 @@
1
1
  require 'cucumber/rb_support/rb_dsl'
2
2
  require 'cucumber/rb_support/rb_world'
3
3
  require 'cucumber/rb_support/rb_step_definition'
4
+ require 'cucumber/rb_support/rb_hook'
5
+ require 'cucumber/rb_support/rb_transform'
4
6
 
5
7
  module Cucumber
6
8
  module RbSupport
@@ -82,6 +84,10 @@ module Cucumber
82
84
  add_hook(phase, RbHook.new(self, tag_names, proc))
83
85
  end
84
86
 
87
+ def register_rb_transform(regexp, proc)
88
+ add_transform(RbTransform.new(self, regexp, proc))
89
+ end
90
+
85
91
  def register_rb_step_definition(regexp, proc)
86
92
  add_step_definition(RbStepDefinition.new(self, regexp, proc))
87
93
  end
@@ -98,7 +104,7 @@ module Cucumber
98
104
  protected
99
105
 
100
106
  def load_code_file(code_file)
101
- require code_file # This will cause self.add_step_definition and self.add_hook to be called from RbDsl
107
+ require code_file # This will cause self.add_step_definition, self.add_hook, and self.add_transform to be called from RbDsl
102
108
  end
103
109
 
104
110
  def begin_scenario
@@ -150,4 +156,4 @@ module Cucumber
150
156
  end
151
157
  end
152
158
  end
153
- end
159
+ end
@@ -1,6 +1,7 @@
1
1
  require 'cucumber/step_match'
2
2
  require 'cucumber/core_ext/string'
3
3
  require 'cucumber/core_ext/proc'
4
+ require 'cucumber/rb_support/rb_group'
4
5
 
5
6
  module Cucumber
6
7
  module RbSupport
@@ -23,24 +24,38 @@ module Cucumber
23
24
  end
24
25
  end
25
26
 
26
- attr_reader :proc
27
+ attr_reader :proc, :regexp
27
28
 
28
- def initialize(rb_language, pattern, proc)
29
+ def initialize(rb_language, regexp, proc)
29
30
  raise MissingProc if proc.nil?
30
- if String === pattern
31
- p = pattern.gsub(/\$\w+/, '(.*)') # Replace $var with (.*)
32
- pattern = Regexp.new("^#{p}$")
31
+ if String === regexp
32
+ p = regexp.gsub(/\$\w+/, '(.*)') # Replace $var with (.*)
33
+ regexp = Regexp.new("^#{p}$")
33
34
  end
34
- @rb_language, @regexp, @proc = rb_language, pattern, proc
35
+ @rb_language, @regexp, @proc = rb_language, regexp, proc
35
36
  end
36
37
 
37
- def regexp
38
- @regexp
38
+ def ==(step_definition)
39
+ self.regexp == step_definition.regexp
40
+ end
41
+
42
+ def groups(step_name)
43
+ match = regexp.match(step_name)
44
+ if match
45
+ n = 0
46
+ match.captures.map do |val|
47
+ n += 1
48
+ RbGroup.new(val, match.offset(n)[0])
49
+ end
50
+ else
51
+ nil
52
+ end
39
53
  end
40
54
 
41
55
  def invoke(args)
42
56
  args = args.map{|arg| Ast::PyString === arg ? arg.to_s : arg}
43
57
  begin
58
+ args = @rb_language.execute_transforms(args)
44
59
  @rb_language.current_world.cucumber_instance_exec(true, regexp.inspect, *args, &@proc)
45
60
  rescue Cucumber::ArityMismatchError => e
46
61
  e.backtrace.unshift(self.backtrace_line)
@@ -0,0 +1,35 @@
1
+ module Cucumber
2
+ module RbSupport
3
+ # A Ruby Transform holds a Regexp and a Proc, and is created
4
+ # by calling <tt>Transform in the <tt>support</tt> ruby files.
5
+ # See also RbDsl.
6
+ #
7
+ # Example:
8
+ #
9
+ # Transform /^(\d+) cucumbers$/ do |cucumbers_string|
10
+ # cucumbers_string.to_i
11
+ # end
12
+ #
13
+ class RbTransform
14
+ class MissingProc < StandardError
15
+ def message
16
+ "Transforms must always have a proc with at least one argument"
17
+ end
18
+ end
19
+
20
+ attr_reader :proc, :regexp
21
+
22
+ def initialize(rb_language, pattern, proc)
23
+ raise MissingProc if proc.nil? || proc.arity < 1
24
+ @rb_language, @regexp, @proc = rb_language, Regexp.new(pattern), proc
25
+ end
26
+
27
+ def invoke(arg)
28
+ if matched = regexp.match(arg)
29
+ args = Array(matched.captures.empty? ? arg : matched.captures)
30
+ @rb_language.current_world.cucumber_instance_exec(true, regexp.inspect, *args, &@proc)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -7,6 +7,12 @@ module Cucumber
7
7
  alias_method adverb, :__cucumber_invoke
8
8
  end
9
9
  end
10
+
11
+ # Call a Transform with a string from another Transform definition
12
+ def Transform(arg)
13
+ rb = @__cucumber_step_mother.load_programming_language('rb')
14
+ rb.execute_transforms([arg]).first
15
+ end
10
16
 
11
17
  attr_writer :__cucumber_step_mother
12
18
 
@@ -90,4 +96,4 @@ module Cucumber
90
96
  end
91
97
  end
92
98
  end
93
- end
99
+ end
@@ -1,9 +1,13 @@
1
1
  module Cucumber
2
2
  class StepMatch #:nodoc:
3
- attr_reader :step_definition, :args
3
+ attr_reader :step_definition
4
4
 
5
- def initialize(step_definition, step_name, formatted_step_name, args)
6
- @step_definition, @step_name, @formatted_step_name, @args = step_definition, step_name, formatted_step_name, args
5
+ def initialize(step_definition, step_name, formatted_step_name, groups)
6
+ @step_definition, @step_name, @formatted_step_name, @groups = step_definition, step_name, formatted_step_name, groups
7
+ end
8
+
9
+ def args
10
+ @groups.map{|g| g.val}
7
11
  end
8
12
 
9
13
  def name
@@ -11,13 +15,28 @@ module Cucumber
11
15
  end
12
16
 
13
17
  def invoke(multiline_arg)
14
- all_args = @args.dup
18
+ all_args = args
15
19
  all_args << multiline_arg if multiline_arg
16
20
  @step_definition.invoke(all_args)
17
21
  end
18
22
 
23
+ # Formats the matched arguments of the associated Step. This method
24
+ # is usually called from visitors, which render output.
25
+ #
26
+ # The +format+ can either be a String or a Proc.
27
+ #
28
+ # If it is a String it should be a format string according to
29
+ # <tt>Kernel#sprinf</tt>, for example:
30
+ #
31
+ # '<span class="param">%s</span></tt>'
32
+ #
33
+ # If it is a Proc, it should take one argument and return the formatted
34
+ # argument, for example:
35
+ #
36
+ # lambda { |param| "[#{param}]" }
37
+ #
19
38
  def format_args(format = lambda{|a| a})
20
- @formatted_step_name || @step_definition.format_args(@step_name, format)
39
+ @formatted_step_name || @step_name.gzub(@groups, format)
21
40
  end
22
41
 
23
42
  def file_colon_line
@@ -58,4 +77,4 @@ module Cucumber
58
77
  @step.text_length
59
78
  end
60
79
  end
61
- end
80
+ end
@@ -50,9 +50,7 @@ module Cucumber
50
50
 
51
51
  # This is the meaty part of Cucumber that ties everything together.
52
52
  class StepMother
53
- include Constantize
54
- @@transforms = []
55
- StepArgumentTransform = Struct.new(:pattern, :transformer)
53
+ include Constantize
56
54
  attr_writer :options, :visitor, :log
57
55
 
58
56
  def initialize
@@ -61,32 +59,6 @@ module Cucumber
61
59
  @language_map = {}
62
60
  load_natural_language('en')
63
61
  end
64
-
65
- def self.register_transform(pattern, &transformer)
66
- raise Cucumber::ArityMismatchError.new('Transform must be registered with at least a one-argument block') if !block_given? || transformer.arity < 1
67
- @@transforms.unshift StepArgumentTransform.new(Regexp.new(pattern), transformer.to_proc)
68
- end
69
-
70
- def self.transform_arguments(step_args)
71
- matched = nil
72
- step_args.map do |step_arg|
73
- if transform = @@transforms.detect {|t| matched = t.pattern.match(step_arg) if step_arg.is_a?(String) }
74
- if matched.captures.empty?
75
- unless transform.transformer.arity == 1
76
- raise Cucumber::ArityMismatchError.new("Transforms without Regexp captures only accept a single argument (the step argument)")
77
- end
78
- transform.transformer.call(step_arg)
79
- else
80
- if transform.transformer.arity != matched.captures.size
81
- raise Cucumber::ArityMismatchError.new("Number of arguments in Transform (#{transform.transformer.arity}) does not match number of Regexp captures (#{matched.captures.size})")
82
- end
83
- transform.transformer.call(*matched.captures)
84
- end
85
- else
86
- step_arg
87
- end
88
- end
89
- end
90
62
 
91
63
  def load_plain_text_features(feature_files)
92
64
  features = Ast::Features.new
@@ -215,11 +187,16 @@ module Cucumber
215
187
  end
216
188
 
217
189
  def snippet_text(step_keyword, step_name, multiline_arg_class) #:nodoc:
190
+ load_programming_language('rb') if unknown_programming_language?
218
191
  @programming_languages.map do |programming_language|
219
192
  programming_language.snippet_text(step_keyword, step_name, multiline_arg_class)
220
193
  end.join("\n")
221
194
  end
222
195
 
196
+ def unknown_programming_language?
197
+ @programming_languages.empty?
198
+ end
199
+
223
200
  def before_and_after(scenario, skip_hooks=false) #:nodoc:
224
201
  before(scenario) unless skip_hooks
225
202
  yield scenario
@@ -263,8 +240,8 @@ module Cucumber
263
240
  @programming_languages.each do |programming_language|
264
241
  programming_language.after_configuration(configuration)
265
242
  end
266
- end
267
-
243
+ end
244
+
268
245
  private
269
246
 
270
247
  # Registers a StepDefinition. This can be a Ruby StepDefintion,
@@ -272,7 +249,7 @@ module Cucumber
272
249
  # contract (API).
273
250
  def register_step_definition(step_definition)
274
251
  step_definitions.each do |already|
275
- raise Redundant.new(already, step_definition) if already.same_regexp?(step_definition.regexp)
252
+ raise Redundant.new(already, step_definition) if already == step_definition
276
253
  end
277
254
  step_definitions << step_definition
278
255
  step_definition
@@ -2,7 +2,7 @@ module Cucumber #:nodoc:
2
2
  class VERSION #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 3
5
- TINY = 101
5
+ TINY = 102
6
6
  PATCH = nil # Set to nil for official release
7
7
 
8
8
  STRING = [MAJOR, MINOR, TINY, PATCH].compact.join('.')
@@ -18,8 +18,8 @@ config.action_mailer.delivery_method = :test
18
18
  config.gem 'cucumber', :lib => false, :version => '>=<%= cucumber_version %>' unless File.directory?(File.join(Rails.root, 'vendor/plugins/cucumber'))
19
19
  config.gem 'webrat', :lib => false, :version => '>=0.5.0' unless File.directory?(File.join(Rails.root, 'vendor/plugins/webrat'))
20
20
  <% if framework == :rspec -%>
21
- config.gem 'rspec', :lib => false, :version => '>=1.2.6' unless File.directory?(File.join(Rails.root, 'vendor/plugins/rspec'))
22
- config.gem 'rspec-rails', :lib => 'spec/rails', :version => '>=1.2.6' unless File.directory?(File.join(Rails.root, 'vendor/plugins/rspec-rails'))
21
+ config.gem 'rspec', :lib => false, :version => '>=1.2.8' unless File.directory?(File.join(Rails.root, 'vendor/plugins/rspec'))
22
+ config.gem 'rspec-rails', :lib => false, :version => '>=1.2.7.1' unless File.directory?(File.join(Rails.root, 'vendor/plugins/rspec-rails'))
23
23
  <% end %>
24
24
  <% if spork? -%>
25
25
  config.gem 'spork', :lib => false, :version => '>=0.5.9' unless File.directory?(File.join(Rails.root, 'vendor/plugins/spork'))
@@ -6,19 +6,12 @@ require 'cucumber/rails/world'
6
6
  # Comment out the next line if you don't want Cucumber Unicode support
7
7
  require 'cucumber/formatter/unicode'
8
8
 
9
- # Comment out the next line if you don't want transactions to
10
- # open/roll back around each scenario
11
- Cucumber::Rails.use_transactional_fixtures
12
-
13
- # Comment out the next line if you want Rails' own error handling
14
- # (e.g. rescue_action_in_public / rescue_responses / rescue_from)
15
- Cucumber::Rails.bypass_rescue
16
-
17
9
  require 'webrat'
18
10
  require 'cucumber/webrat/element_locator' # Lets you do table.diff!(element_at('#my_table_or_dl_or_ul_or_ol').to_table)
19
11
 
20
12
  Webrat.configure do |config|
21
13
  config.mode = :rails
14
+ config.open_error_files = false # Set to true if you want error pages to pop up in the browser
22
15
  end
23
16
  <% if framework == :rspec -%>
24
17
 
@@ -3,38 +3,39 @@ require 'cucumber/step_mother'
3
3
  require 'cucumber/ast'
4
4
 
5
5
  module Cucumber
6
- describe FeatureElement do
7
- include FeatureElement
6
+ module Ast
7
+ describe FeatureElement do
8
+ include FeatureElement
8
9
 
9
- describe "with multiline names" do
10
- it "should select the longest line as the text length" do
11
- @keyword = "key"
12
- @name = "short\nvery longer\ntiny"
13
- text_length.should == 11 + Ast::Step::INDENT - 1
14
- end
10
+ describe "with multiline names" do
11
+ it "should select the longest line as the text length" do
12
+ @keyword = "key"
13
+ @name = "short\nvery longer\ntiny"
14
+ text_length.should == 11 + Ast::Step::INDENT - 1
15
+ end
15
16
 
16
- it "should add keyword to first lines length" do
17
- @keyword = "key"
18
- @name = "short\nvery longer\ntiny"
17
+ it "should add keyword to first lines length" do
18
+ @keyword = "key"
19
+ @name = "short\nvery longer\ntiny"
19
20
 
20
- first_line_length.should == (@keyword.jlength) + (first_line_name_length = 5)
21
+ first_line_length.should == (@keyword.jlength) + (first_line_name_length = 5)
22
+ end
21
23
  end
22
- end
23
24
 
24
- describe "with empty name" do
25
- it "should only return the length of the keyword" do
26
- @name = ""
27
- @keyword = "key"
25
+ describe "with empty name" do
26
+ it "should only return the length of the keyword" do
27
+ @name = ""
28
+ @keyword = "key"
28
29
 
29
- text_length.should == 3
30
+ text_length.should == 3
31
+ end
30
32
  end
31
- end
32
33
 
33
- it "should support checking if its name matches a list of regexps" do
34
- @name = 'test'
35
- matches_scenario_names?([/es/]).should be_true
34
+ it "should support checking if its name matches a list of regexps" do
35
+ @name = 'test'
36
+ matches_scenario_names?([/es/]).should be_true
37
+ end
36
38
  end
37
-
38
39
  end
39
40
  end
40
41
 
@@ -64,7 +64,7 @@ module Cucumber
64
64
 
65
65
  it "should pretty print" do
66
66
  require 'cucumber/formatter/pretty'
67
- visitor = Formatter::Pretty.new(@step_mother, STDOUT, {:comment => true, :include_tags => {}, :exclude_tags => {}})
67
+ visitor = Formatter::Pretty.new(@step_mother, STDOUT, {:comment => true, :tag_names => {}})
68
68
  visitor.visit_feature_element(@scenario_outline)
69
69
  end
70
70
  end
@@ -92,11 +92,8 @@ module Cli
92
92
  end
93
93
 
94
94
  context '-t TAGS --tags TAGS' do
95
- it "removes the @ prefix" do
96
- after_parsing('-t @foo,bar') { options[:include_tags].should == {'foo' => nil, 'bar' => nil} }
97
- end
98
95
  it "designates tags prefixed with ~ as tags to be excluded" do
99
- after_parsing('--tags ~@foo,bar') { options[:exclude_tags].should == {'foo' => nil} }
96
+ after_parsing('--tags ~@foo,@bar') { options[:tag_names].should == {'~@foo' => nil, '@bar' => nil} }
100
97
  end
101
98
  end
102
99
 
@@ -160,16 +157,10 @@ module Cli
160
157
  options[:require].should == %w[foo.rb features dog.rb]
161
158
  end
162
159
 
163
- it "combines the include_tags of both" do
164
- given_cucumber_yml_defined_as('baz' => %w[-t bar])
165
- options.parse!(%w[--tags foo -p baz])
166
- options[:include_tags].should == {'foo' => nil, 'bar' => nil}
167
- end
168
-
169
- it "combines the exclude_tags of both" do
170
- given_cucumber_yml_defined_as('baz' => %w[-t ~bar])
171
- options.parse!(%w[--tags ~foo -p baz])
172
- options[:exclude_tags].should == {'foo' => nil, 'bar' => nil}
160
+ it "combines the tag names of both" do
161
+ given_cucumber_yml_defined_as('baz' => %w[-t @bar])
162
+ options.parse!(%w[--tags @foo -p baz])
163
+ options[:tag_names].should == {'@foo' => nil, '@bar' => nil}
173
164
  end
174
165
 
175
166
  it "only takes the paths from the original options, and disgregards the profiles" do