Skip to content

Commit

Permalink
Update to cucumber-core 0.2.0
Browse files Browse the repository at this point in the history
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
mattwynne committed Feb 28, 2014
1 parent 2d6227c commit 707c3f5
Show file tree
Hide file tree
Showing 18 changed files with 162 additions and 79 deletions.
4 changes: 3 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion cucumber.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
4 changes: 1 addition & 3 deletions lib/cucumber/formatter/console.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
5 changes: 3 additions & 2 deletions lib/cucumber/formatter/html.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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>'
Expand Down
4 changes: 3 additions & 1 deletion lib/cucumber/mappings.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require 'cucumber/runtime'
require 'cucumber'
require 'cucumber/multiline_argument'

module Cucumber
class Mappings
Expand All @@ -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

Expand Down
52 changes: 52 additions & 0 deletions lib/cucumber/multiline_argument.rb
Original file line number Diff line number Diff line change
@@ -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

4 changes: 2 additions & 2 deletions lib/cucumber/rb_support/rb_language.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
7 changes: 5 additions & 2 deletions lib/cucumber/rb_support/rb_world.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
78 changes: 59 additions & 19 deletions lib/cucumber/rb_support/snippet.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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('/', '\/')
Expand All @@ -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
Expand Down Expand Up @@ -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
5 changes: 3 additions & 2 deletions lib/cucumber/reports/legacy_formatter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions lib/cucumber/runtime.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
10 changes: 5 additions & 5 deletions lib/cucumber/runtime/support_code.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
4 changes: 2 additions & 2 deletions lib/cucumber/step_match.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
5 changes: 3 additions & 2 deletions lib/cucumber/wire_support/wire_language.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 1 addition & 8 deletions lib/cucumber/wire_support/wire_step_definition.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
4 changes: 2 additions & 2 deletions spec/cucumber/rb_support/rb_step_definition_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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]
Expand Down
Loading

0 comments on commit 707c3f5

Please sign in to comment.