Skip to content

Commit

Permalink
Pickle::Ref can be initialized with an options hash, for easier progr…
Browse files Browse the repository at this point in the history
…amatic manipulation

e.g.

  Given /^"(\w+)" is awesome$/ do |user_label|
    model(:label => user_label).send_the_awesome!
  end
  • Loading branch information
ianwhite committed Aug 23, 2010
1 parent 408584b commit 60bb1c4
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 48 deletions.
33 changes: 23 additions & 10 deletions lib/pickle/ref.rb
Expand Up @@ -9,28 +9,41 @@ class Ref
include Parser::Matchers
include Parser::Canonical

attr_reader :factory, :index, :index_word, :label
attr_reader :factory, :index, :label

def initialize(string)
parse_ref(string)
def initialize(arg)
arg.is_a?(Hash) ? parse_hash(arg) : parse_string(arg)
validate!
end

protected
def parse_ref(orig)
def validate!
raise InvalidPickleRefError, "#{inspect} requires a factory or label" if factory.blank? && label.blank?
raise InvalidPickleRefError, "#{inspect} can't specify both index and label" if label.present? && index.present?
end

def parse_hash(orig)
hash = orig.dup
@factory = hash.delete(:factory)
@index = hash.delete(:index)
@label = hash.delete(:label)
raise InvalidPickleRefError, "superfluous options: #{hash.inspect}" unless hash.empty?
end

def parse_string(orig)
str = orig.dup
@index_word = parse_index!(str)
@index = index_word_to_i(@index_word) if @index_word
@index = parse_index!(str)
@factory = parse_factory!(str)
@label = parse_label!(str)
raise InvalidPickleRefError, "'#{orig}' has superfluous: '#{str}'" unless str.blank?
raise InvalidPickleRefError, "'#{orig}' requires a factory or label" if @factory.blank? && @label.blank?
raise InvalidPickleRefError, "'#{orig}' can't specify both index and label" if @label.present? && @index.present?
raise InvalidPickleRefError, "superfluous: '#{str}'" unless str.blank?
end

# parse and remove the index from the given string
# @return the index or nil
def parse_index!(string)
remove_from_and_return_1st_capture!(string, /^(?:the )?(#{match_index_word}) /)
if word = remove_from_and_return_1st_capture!(string, /^(?:the )?(#{match_index_word}) /)
index_word_to_i word
end
end

# parse the factory name from the given string, remove the factory name and optional prefix
Expand Down
93 changes: 55 additions & 38 deletions spec/pickle/ref_spec.rb
Expand Up @@ -2,68 +2,85 @@

describe Pickle::Ref do
describe "(factory) " do
describe ".new 'colour'" do
subject { Pickle::Ref.new('colour') }

shared_examples_for 'pickle ref with :factory => "colour"' do
its(:index) { should be_nil }
its(:factory) { should == 'colour' }
its(:label) { should be_nil }
end

describe "with a prefix" do
['a', 'an', 'the', 'that', 'another'].each do |prefix|
describe ".new '#{prefix} colour'" do
subject { Pickle::Ref.new("#{prefix} colour") }

describe ".new 'colour'" do
subject { Pickle::Ref.new('colour') }
it_should_behave_like 'pickle ref with :factory => "colour"'

describe "(prefix)" do
['a', 'an', 'the', 'that', 'another'].each do |prefix|
describe ".new '#{prefix} colour'" do
subject { Pickle::Ref.new("#{prefix} colour") }

its(:factory) { should == 'colour' }
its(:factory) { should == 'colour' }
end
end
end
end

describe ".new 'awesome_colour'" do
subject { Pickle::Ref.new('awesome_colour') }

its(:factory) { should == 'awesome_colour' }
describe "(:factory => 'colour')" do
subject { Pickle::Ref.new(:factory => 'colour') }
it_should_behave_like 'pickle ref with :factory => "colour"'
end
end

describe "(index)" do
describe ".new('1st colour')" do
subject { Pickle::Ref.new('1st colour') }

its(:index_word) { should == '1st' }
shared_examples_for "pickle ref with :factory => 'colour', :index => 0" do
its(:index) { should == 0 }
its(:factory) { should == 'colour' }
its(:label) { should be_nil }
end

describe ".new('1st colour')" do
subject { Pickle::Ref.new('1st colour') }

it_should_behave_like "pickle ref with :factory => 'colour', :index => 0"

{'2nd' => 1, 'first' => 0, 'last' => -1, '3rd' => 2, '4th' => 3}.each do |word, index|
describe ".new('#{word} colour')" do
subject { Pickle::Ref.new("#{word} colour") }

its(:index) { should == index}
its(:index_word) { should == word }
end
end

describe "the 2nd colour" do
subject { Pickle::Ref.new('the 2nd colour') }

its(:index_word) { should == '2nd' }
its(:index) { should == 1 }
its(:factory) { should == 'colour' }
end
end

describe "(:factory => 'colour', :index => 0)" do
subject { Pickle::Ref.new(:factory => 'colour', :index => 0) }

it_should_behave_like "pickle ref with :factory => 'colour', :index => 0"
end

describe "the 2nd colour" do
subject { Pickle::Ref.new('the 2nd colour') }

its(:index) { should == 1 }
its(:factory) { should == 'colour' }
end
end

describe "(label)" do
describe "'colour: \"red\"'" do
subject { Pickle::Ref.new('colour: "red"') }

shared_examples_for "pickle ref with :factory => 'colour', :label => 'red'" do
its(:index) { should == nil }
its(:factory) { should == 'colour' }
its(:label) { should == 'red' }
end

describe "'colour: \"red\"'" do
subject { Pickle::Ref.new('colour: "red"') }
it_should_behave_like "pickle ref with :factory => 'colour', :label => 'red'"
end

describe "(:factory => 'colour', :label => 'red')" do
subject { Pickle::Ref.new(:factory => 'colour', :label => 'red') }
it_should_behave_like "pickle ref with :factory => 'colour', :label => 'red'"
end

describe "'\"red\"'" do
subject { Pickle::Ref.new('"red"') }

Expand All @@ -75,27 +92,27 @@

describe "[perverse usage]" do
describe "superflous content:" do
['awesome colour', 'the colour fred', '1st colour gday', 'a'].each do |str|
describe ".new '#{str}'" do
subject { Pickle::Ref.new(str) }
['awesome colour', 'the colour fred', '1st colour gday', 'a', {:label => 'foo', :blurg => 'bar'}].each do |arg|
describe ".new #{arg.inspect}" do
subject { Pickle::Ref.new(arg) }
it { lambda { subject }.should raise_error(Pickle::InvalidPickleRefError, /superfluous/) }
end
end
end

describe "factory or label required:" do
['', '""'].each do |str|
describe ".new '#{str}'" do
subject { Pickle::Ref.new(str) }
['', '""', {}, {:index => 2}].each do |arg|
describe ".new #{arg.inspect}" do
subject { Pickle::Ref.new(arg) }
it { lambda { subject }.should raise_error(Pickle::InvalidPickleRefError, /factory or label/) }
end
end
end

describe "can't specify both index and label:" do
['1st user "fred"', 'last user: "jim"'].each do |str|
describe ".new '#{str}'" do
subject { Pickle::Ref.new(str) }
['1st user "fred"', 'last user: "jim"', {:label => "fred", :index => 0}, {:label => "fred", :factory => "user", :index => -1}].each do |arg|
describe ".new #{arg.inspect}" do
subject { Pickle::Ref.new(arg) }
it { lambda { subject }.should raise_error(Pickle::InvalidPickleRefError, /can't specify both index and label/) }
end
end
Expand Down

0 comments on commit 60bb1c4

Please sign in to comment.