Permalink
Browse files

Update to cucumber-core 0.2.0

This means using a null object for multiline arguments, which involved
quite a few changes. It means we do now have our own wrappers for the
DocString and DataTable classes, so we can add back those methods like
diff! that people will be looking for.
  • Loading branch information...
1 parent 2d6227c commit 707c3f55eb3720c928dc80475ca63982c343d4df @mattwynne mattwynne committed Feb 28, 2014
View
@@ -1,3 +1,5 @@
source "https://rubygems.org"
gemspec
-gem 'cucumber-core', path: '../cucumber-ruby-core' if File.dir?('../cucumber-ruby-core')
+if ENV['cucumber_dev']
+ gem 'cucumber-core', path: '../cucumber-ruby-core' if File.directory?('../cucumber-ruby-core')
+end
View
@@ -14,7 +14,7 @@ Gem::Specification.new do |s|
s.platform = Gem::Platform::RUBY
s.required_ruby_version = ">= 1.9.3"
- s.add_dependency 'cucumber-core', '~> 0.1'
+ s.add_dependency 'cucumber-core', '~> 0.2'
s.add_dependency 'builder', '>= 2.1.2'
s.add_dependency 'diff-lcs', '>= 1.1.3'
s.add_dependency 'gherkin', '~> 2.12'
@@ -135,9 +135,7 @@ def print_snippets(options)
unknown_programming_language = runtime.unknown_programming_language?
snippets = undefined.map do |step|
step_name = Undefined === step.exception ? step.exception.step_name : step.name
- step_multiline_class = step.multiline_arg ? step.multiline_arg.class : nil
- snippet = @runtime.snippet_text(step.actual_keyword, step_name, step_multiline_class)
- snippet
+ @runtime.snippet_text(step.actual_keyword, step_name, step.multiline_arg)
end.compact.uniq
text = "\nYou can implement step definitions for undefined steps with these snippets:\n\n"
@@ -254,9 +254,10 @@ def after_step_result(keyword, step_match, multiline_arg, status, exception, sou
# print snippet for undefined steps
if status == :undefined
keyword = @step.actual_keyword if @step.respond_to?(:actual_keyword)
- step_multiline_class = @step.multiline_arg ? @step.multiline_arg.class : nil
@builder.pre do |pre|
- pre << @runtime.snippet_text(keyword,step_match.instance_variable_get("@name") || '',step_multiline_class)
+ # TODO: snippet text should be an event sent to the formatter so we don't
+ # have this couping to the runtime.
+ pre << @runtime.snippet_text(keyword,step_match.instance_variable_get("@name") || '', @step.multiline_arg)
end
end
@builder << '</li>'
View
@@ -1,5 +1,6 @@
require 'cucumber/runtime'
require 'cucumber'
+require 'cucumber/multiline_argument'
module Cucumber
class Mappings
@@ -10,7 +11,8 @@ def initialize(runtime = nil)
def test_step(step, mapper)
step_match = runtime.step_match(step.name)
- mapper.map { step_match.invoke(step.multiline_arg) }
+ multiline_arg = MultilineArgument.from(step.multiline_arg)
+ mapper.map { step_match.invoke(multiline_arg) }
rescue Cucumber::Undefined
end
@@ -0,0 +1,52 @@
+require 'delegate'
+module Cucumber
+ module MultilineArgument
+ def self.from(core_multiline_arg)
+ Builder.new(core_multiline_arg).result
+ end
+
+ class Builder
+ def initialize(multiline_arg)
+ multiline_arg.describe_to self
+ end
+
+ def doc_string(string, *args)
+ @result = DocString.new(string)
+ end
+
+ def data_table(table, *args)
+ @result = DataTable.new(table)
+ end
+
+ def result
+ @result || None.new
+ end
+ end
+
+ class DocString < SimpleDelegator
+ def append_to(array)
+ array << self
+ end
+ end
+
+ class DataTable < SimpleDelegator
+ def append_to(array)
+ array << self
+ end
+
+ def to_json(options)
+ raw.to_json(options)
+ end
+ end
+
+ class None
+ def append_to(array)
+ end
+
+ def describe_to(visitor)
+ end
+ end
+
+ end
+end
+
@@ -83,9 +83,9 @@ def step_matches(name_to_match, name_to_format)
end.compact
end
- def snippet_text(code_keyword, step_name, multiline_arg_class, snippet_type = :regexp)
+ def snippet_text(code_keyword, step_name, multiline_arg, snippet_type = :regexp)
snippet_class = typed_snippet_class(snippet_type)
- snippet_class.new(code_keyword, step_name, multiline_arg_class).to_s
+ snippet_class.new(code_keyword, step_name, multiline_arg).to_s
end
def begin_rb_scenario(scenario)
@@ -35,8 +35,11 @@ def Transform(arg)
# step "the email should contain:", "Dear sir,\nYou've won a prize!\n"
# @param [String] name The name of the step
# @param [String,Cucumber::Ast::DocString,Cucumber::Ast::Table] multiline_argument
- def step(name, multiline_argument=nil)
- @__cucumber_runtime.invoke(name, multiline_argument)
+ def step(name, raw_multiline_arg=nil)
+ # TODO: this argument parsing should move up out of core
+ location = Core::Ast::Location.new(*caller[0].split(':')[0..1])
+ core_multiline_arg = Core::Ast::MultilineArgument.from(raw_multiline_arg, location)
+ @__cucumber_runtime.invoke(name, MultilineArgument.from(core_multiline_arg))
end
# Run a snippet of Gherkin
@@ -6,11 +6,11 @@ module Snippet
class BaseSnippet
- def initialize(code_keyword, pattern, multiline_argument_class)
+ def initialize(code_keyword, pattern, multiline_argument)
@number_of_arguments = 0
@code_keyword = code_keyword
@pattern = replace_and_count_capturing_groups(pattern)
- @multiline_argument_class = multiline_argument_class
+ @multiline_argument = MultilineArgumentSnippet.new(multiline_argument)
end
def to_s
@@ -27,7 +27,7 @@ def self.cli_option_string(type)
private
- attr_reader :code_keyword, :pattern, :multiline_argument_class, :number_of_arguments
+ attr_reader :code_keyword, :pattern, :multiline_argument, :number_of_arguments
def replace_and_count_capturing_groups(pattern)
modified_pattern = ::Regexp.escape(pattern).gsub('\ ', ' ').gsub('/', '\/')
@@ -43,33 +43,20 @@ def replace_and_count_capturing_groups(pattern)
def do_block
do_block = ""
do_block << "do#{arguments}\n"
- do_block << multiline_comment if multiline_argument_class?
+ multiline_argument.append_comment_to(do_block)
do_block << " pending # Write code here that turns the phrase above into concrete actions\n"
do_block << "end"
do_block
end
def arguments
block_args = (0...number_of_arguments).map { |n| "arg#{n+1}" }
-
- if multiline_argument_class
- block_args << multiline_argument_class.default_arg_name
- end
-
+ multiline_argument.append_block_argument_to(block_args)
block_args.empty? ? "" : " |#{block_args.join(", ")}|"
end
- def multiline_comment
- " # #{multiline_argument_class.default_arg_name} is a #{multiline_argument_class.to_s}\n"
- end
-
- def multiline_argument_class?
- # TODO: brittle - stop coupling to type
- multiline_argument_class == Core::Ast::DataTable
- end
-
def self.example
- new("Given", "missing step", nil).step
+ new("Given", "missing step", MultilineArgument::None.new).step
end
end
@@ -104,6 +91,59 @@ def self.description
end
end
+ module MultilineArgumentSnippet
+
+ def self.new(multiline_argument)
+ builder = Builder.new
+ multiline_argument.describe_to(builder)
+ builder.result
+ end
+
+ class Builder
+ def doc_string(*args)
+ @result = DocString.new
+ end
+
+ def data_table(table, *args)
+ @result = DataTable.new(table)
+ end
+
+ def result
+ @result || None.new
+ end
+ end
+
+ class DocString
+ def append_block_argument_to(array)
+ array << 'string'
+ end
+
+ def append_comment_to(string)
+ end
+ end
+
+ class DataTable
+ def initialize(table)
+ @table = table
+ end
+
+ def append_block_argument_to(array)
+ array << 'table'
+ end
+
+ def append_comment_to(string)
+ string << " # table is a #{@table.class.to_s}\n"
+ end
+ end
+
+ class None
+ def append_block_argument_to(array)
+ end
+
+ def append_comment_to(string)
+ end
+ end
+ end
end
end
end
@@ -343,14 +343,15 @@ def print
private
def print_multiline_arg
- return unless step_invocation.multiline_arg
MultilineArgPrinter.new(formatter, runtime).print(step_invocation.multiline_arg)
end
end
MultilineArgPrinter = Struct.new(:formatter, :runtime) do
def print(node)
+ # TODO - stop coupling to type
+ return if node.is_a?( Cucumber::Core::Ast::EmptyMultilineArgument )
formatter.node(:multiline_arg, node) do
node.describe_to(self)
end
@@ -360,7 +361,7 @@ def doc_string(doc_string)
formatter.doc_string(doc_string)
end
- def table(table)
+ def data_table(table)
table.cells_rows.each do |row|
TableRowPrinter.new(formatter, runtime, DataTableRow.new(row.map(&:value), row.line)).before.after
end
View
@@ -96,8 +96,8 @@ def unmatched_step_definitions
@support_code.unmatched_step_definitions
end
- def snippet_text(step_keyword, step_name, multiline_arg_class) #:nodoc:
- @support_code.snippet_text(::Gherkin::I18n.code_keyword_for(step_keyword), step_name, multiline_arg_class)
+ def snippet_text(step_keyword, step_name, multiline_arg) #:nodoc:
+ @support_code.snippet_text(::Gherkin::I18n.code_keyword_for(step_keyword), step_name, multiline_arg)
end
def with_hooks(scenario, skip_hooks=false)
@@ -21,7 +21,8 @@ def uri(uri)
def step(step)
location = Cucumber::Core::Ast::Location.new(*caller[0].split(':')[0..1])
- @support_code.invoke(step.name, Core::Ast::MultilineArgument.from(step.doc_string || step.rows, location))
+ core_multiline_arg = Core::Ast::MultilineArgument.from(step.doc_string || step.rows, location)
+ @support_code.invoke(step.name, MultilineArgument.from(core_multiline_arg))
end
def eof
@@ -54,10 +55,9 @@ def invoke_steps(steps_text, i18n, file_colon_line)
parser.parse(steps_text, file, line.to_i)
end
- def invoke(step_name, multiline_argument=nil)
+ def invoke(step_name, multiline_argument)
file, line = *caller[2].split(':')[0..1]
location = Core::Ast::Location.new(file, line)
- multiline_argument = Cucumber::Core::Ast::MultilineArgument.from(multiline_argument, location)
begin
step_match(step_name).invoke(multiline_argument)
rescue Exception => e
@@ -98,10 +98,10 @@ def unmatched_step_definitions
end.flatten
end
- def snippet_text(step_keyword, step_name, multiline_arg_class) #:nodoc:
+ def snippet_text(step_keyword, step_name, multiline_arg) #:nodoc:
load_programming_language('rb') if unknown_programming_language?
@programming_languages.map do |programming_language|
- programming_language.snippet_text(step_keyword, step_name, multiline_arg_class, @configuration.snippet_type)
+ programming_language.snippet_text(step_keyword, step_name, multiline_arg, @configuration.snippet_type)
end.join("\n")
end
@@ -20,8 +20,8 @@ def name
end
def invoke(multiline_arg)
- all_args = args
- all_args << multiline_arg.to_step_definition_arg if multiline_arg
+ all_args = args.dup
+ multiline_arg.append_to(all_args)
@step_definition.invoke(all_args)
end
@@ -23,9 +23,10 @@ def load_code_file(wire_file)
@connections << Connection.new(config)
end
- def snippet_text(code_keyword, step_name, multiline_arg_class)
+ def snippet_text(code_keyword, step_name, multiline_arg)
snippets = @connections.map do |remote|
- remote.snippet_text(code_keyword, step_name, multiline_arg_class.to_s)
+ # TODO: should send an empty string for an EmptyMultilineArgument
+ remote.snippet_text(code_keyword, step_name, multiline_arg.class.to_s)
end
snippets.flatten.join("\n")
end
@@ -11,16 +11,9 @@ def initialize(connection, data)
end
def invoke(args)
- prepared_args = args.map{ |arg| prepare(arg) }
- @connection.invoke(@id, prepared_args)
+ @connection.invoke(@id, args)
end
- private
-
- def prepare(arg)
- return arg unless arg.is_a?(Cucumber::Core::Ast::DataTable)
- arg.raw
- end
end
end
end
@@ -18,7 +18,7 @@ module RbSupport
end
def run_step(text)
- support_code.step_match(text).invoke(nil)
+ support_code.step_match(text).invoke(MultilineArgument::None.new)
end
it "should allow calling of other steps" do
@@ -36,7 +36,7 @@ def run_step(text)
it "should allow calling of other steps with inline arg" do
dsl.Given /Outside/ do
location = Core::Ast::Location.new(__FILE__, __LINE__)
- step "Inside", Cucumber::Core::Ast::DataTable.new([['inside']], location)
+ step "Inside", MultilineArgument.from(Cucumber::Core::Ast::DataTable.new([['inside']], location))
end
dsl.Given /Inside/ do |table|
$inside = table.raw[0][0]
Oops, something went wrong.

0 comments on commit 707c3f5

Please sign in to comment.