Skip to content

Commit

Permalink
Pull snippet rendering out of RbLanguage.
Browse files Browse the repository at this point in the history
  • Loading branch information
Roel van Dijk committed Mar 27, 2013
1 parent 88580ae commit 1a668f1
Show file tree
Hide file tree
Showing 4 changed files with 260 additions and 101 deletions.
45 changes: 13 additions & 32 deletions lib/cucumber/rb_support/rb_language.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
require 'cucumber/rb_support/rb_step_definition'
require 'cucumber/rb_support/rb_hook'
require 'cucumber/rb_support/rb_transform'
require 'cucumber/rb_support/snippet'

begin
require 'rspec/expectations'
Expand Down Expand Up @@ -83,32 +84,14 @@ def step_matches(name_to_match, name_to_format)
end.compact
end

ARGUMENT_PATTERNS = ['"(.*?)"', '(\d+)']

def snippet_text(code_keyword, step_name, multiline_arg_class, snippet_type = :regexp)
snippet_pattern = Regexp.escape(step_name).gsub('\ ', ' ').gsub('/', '\/')
arg_count = 0
ARGUMENT_PATTERNS.each do |pattern|
snippet_pattern = snippet_pattern.gsub(Regexp.new(pattern), pattern)
arg_count += snippet_pattern.scan(pattern).length
end

block_args = (0...arg_count).map {|n| "arg#{n+1}"}
block_args << multiline_arg_class.default_arg_name unless multiline_arg_class.nil?
block_arg_string = block_args.empty? ? "" : " |#{block_args.join(", ")}|"
multiline_class_comment = ""
if(multiline_arg_class == Ast::Table)
multiline_class_comment = "# #{multiline_arg_class.default_arg_name} is a #{multiline_arg_class.to_s}\n "
end
snippet = typed_snippet_class(snippet_type).new

pattern = typed_snippet_pattern(snippet_pattern, snippet_type)
snippet.code_keyword = code_keyword
snippet.pattern = step_name
snippet.multiline_argument_class = multiline_arg_class

do_block = ""
do_block << "do#{block_arg_string}\n"
do_block << " #{multiline_class_comment}pending # express the regexp above with the code you wish you had\n"
do_block << "end"

"#{code_keyword}#{pattern} #{do_block}"
snippet.render
end

def begin_rb_scenario(scenario)
Expand Down Expand Up @@ -192,15 +175,13 @@ def check_nil(o, proc)
end
end

def typed_snippet_pattern(pattern, type)
case type
when :percent
" %r{^#{pattern}$}"
when :legacy
" /^#{pattern}$/"
else
"(/^#{pattern}$/)"
end
def typed_snippet_class(type)
type ||= :regexp
{
regexp: Snippet::Regexp,
legacy: Snippet::Legacy,
percent: Snippet::Percent
}.fetch(type)
end
end
end
Expand Down
84 changes: 84 additions & 0 deletions lib/cucumber/rb_support/snippet.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
module Cucumber
module RbSupport
module Snippet

ARGUMENT_PATTERNS = ['"(.*?)"', '(\d+)']

class BaseSnippet

attr_accessor :code_keyword, :pattern, :multiline_argument_class

def render
replace_and_count_capturing_groups!
render_snippet
end

private

def replace_and_count_capturing_groups!
self.pattern = ::Regexp.escape(pattern).gsub('\ ', ' ').gsub('/', '\/')

arg_count = 0

ARGUMENT_PATTERNS.each do |pattern|
self.pattern = self.pattern.gsub(::Regexp.new(pattern), pattern)
arg_count += self.pattern.scan(pattern).length
end

@number_of_arguments = arg_count
end

def render_snippet
"#{code_keyword}#{typed_pattern} #{do_block}"
end

def do_block
do_block = ""
do_block << "do#{arguments}\n"
do_block << multiline_comment if multiline_argument_class?
do_block << " pending # express the regexp above with the code you wish you had\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

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?
multiline_argument_class == Ast::Table
end

end

class Regexp < BaseSnippet
def typed_pattern
"(/^#{pattern}$/)"
end
end

class Legacy < BaseSnippet
def typed_pattern
" /^#{pattern}$/"
end
end

class Percent < BaseSnippet
def typed_pattern
" %r{^#{pattern}$}"
end
end

end
end
end
101 changes: 32 additions & 69 deletions spec/cucumber/rb_support/rb_language_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,92 +15,55 @@ module RbSupport
Object.new.extend(RbSupport::RbDsl)
end

def unindented(s)
s.split("\n")[1..-2].join("\n").indent(-10)
end

describe "snippets" do

it "should wrap snippet patterns in parentheses" do
rb.snippet_text('Given', 'A "string" with 4 spaces', nil).should == unindented(%{
Given(/^A "(.*?)" with (\\d+) spaces$/) do |arg1, arg2|
pending # express the regexp above with the code you wish you had
end
})
let(:snippet) { stub.as_null_object }
before do
Snippet::Regexp.stub(:new => snippet)
end

it "should recognise numbers in name and make according regexp" do
rb.snippet_text('Given', 'Cloud 9 yeah', nil).should == unindented(%{
Given(/^Cloud (\\d+) yeah$/) do |arg1|
pending # express the regexp above with the code you wish you had
end
})
end
it "creates a regexp Snippet class by default" do
Snippet::Regexp.should_receive(:new)

it "should recognise a mix of ints, strings and why not a table too" do
rb.snippet_text('Given', 'I have 9 "awesome" cukes in 37 "boxes"', Cucumber::Ast::Table).should == unindented(%{
Given(/^I have (\\d+) "(.*?)" cukes in (\\d+) "(.*?)"$/) do |arg1, arg2, arg3, arg4, table|
# table is a Cucumber::Ast::Table
pending # express the regexp above with the code you wish you had
end
})
rb.snippet_text('Given', 'A "string" with 4 spaces', nil)
end

it "should recognise quotes in name and make according regexp" do
rb.snippet_text('Given', 'A "first" arg', nil).should == unindented(%{
Given(/^A "(.*?)" arg$/) do |arg1|
pending # express the regexp above with the code you wish you had
end
})
end
it "creates a regexp Snippet class explicitly" do
Snippet::Regexp.should_receive(:new)

it "should recognise several quoted words in name and make according regexp and args" do
rb.snippet_text('Given', 'A "first" and "second" arg', nil).should == unindented(%{
Given(/^A "(.*?)" and "(.*?)" arg$/) do |arg1, arg2|
pending # express the regexp above with the code you wish you had
end
})
rb.snippet_text('Given', 'A "string" with 4 spaces', nil, :regexp)
end

it "should not use quote group when there are no quotes" do
rb.snippet_text('Given', 'A first arg', nil).should == unindented(%{
Given(/^A first arg$/) do
pending # express the regexp above with the code you wish you had
end
})
end
it "creates a legacy Snippet class" do
Snippet::Legacy.stub(:new => stub.as_null_object)
Snippet::Legacy.should_receive(:new)

it "should be helpful with tables" do
rb.snippet_text('Given', 'A "first" arg', Cucumber::Ast::Table).should == unindented(%{
Given(/^A "(.*?)" arg$/) do |arg1, table|
# table is a Cucumber::Ast::Table
pending # express the regexp above with the code you wish you had
end
})
rb.snippet_text('Given', 'A "string" with 4 spaces', nil, :legacy)
end

it "should wrap snippet patterns in parentheses for explicit regexp snippet type" do
rb.snippet_text('Given', 'A "string" with 4 spaces', nil, :regexp).should == unindented(%{
Given(/^A "(.*?)" with (\\d+) spaces$/) do |arg1, arg2|
pending # express the regexp above with the code you wish you had
end
})
it "creates a percent Snippet class" do
Snippet::Percent.stub(:new => stub.as_null_object)
Snippet::Percent.should_receive(:new)

rb.snippet_text('Given', 'A "string" with 4 spaces', nil, :percent)
end

it "should not wrap snippet patterns in parentheses for legacy snippet type" do
rb.snippet_text('Given', 'A "string" with 4 spaces', nil, :legacy).should == unindented(%{
Given /^A "(.*?)" with (\\d+) spaces$/ do |arg1, arg2|
pending # express the regexp above with the code you wish you had
end
})
it "passes all parameters to Snippet class" do
code_keyword = stub
pattern = stub
multiline_argument_class = stub

snippet.should_receive(:code_keyword=).with(code_keyword)
snippet.should_receive(:pattern=).with(pattern)
snippet.should_receive(:multiline_argument_class=).with(multiline_argument_class)

rb.snippet_text(code_keyword, pattern, multiline_argument_class)
end

it "should wrap snippet patterns in percentage regexp for percent snippet type" do
rb.snippet_text('Given', 'A "string" with 4 spaces', nil, :percent).should == unindented(%{
Given %r{^A "(.*?)" with (\\d+) spaces$} do |arg1, arg2|
pending # express the regexp above with the code you wish you had
end
})
it "renders the snippet" do
snippet.should_receive(:render)

rb.snippet_text('Given', 'A "string" with 4 spaces', nil)
end

end
Expand Down
Loading

0 comments on commit 1a668f1

Please sign in to comment.