pickle 0.1.16

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 (60) hide show
  1. data/.gitignore +2 -0
  2. data/History.txt +165 -0
  3. data/License.txt +20 -0
  4. data/README.rdoc +205 -0
  5. data/Rakefile +116 -0
  6. data/Todo.txt +4 -0
  7. data/VERSION +1 -0
  8. data/features/app/app.rb +112 -0
  9. data/features/app/blueprints.rb +11 -0
  10. data/features/app/factories.rb +23 -0
  11. data/features/app/views/notifier/email.erb +1 -0
  12. data/features/app/views/notifier/user_email.erb +6 -0
  13. data/features/email/email.feature +38 -0
  14. data/features/generator/generators.feature +54 -0
  15. data/features/path/models_page.feature +44 -0
  16. data/features/path/named_route_page.feature +10 -0
  17. data/features/pickle/create_from_active_record.feature +20 -0
  18. data/features/pickle/create_from_factory_girl.feature +43 -0
  19. data/features/pickle/create_from_machinist.feature +38 -0
  20. data/features/step_definitions/email_steps.rb +50 -0
  21. data/features/step_definitions/extra_email_steps.rb +7 -0
  22. data/features/step_definitions/fork_steps.rb +4 -0
  23. data/features/step_definitions/generator_steps.rb +42 -0
  24. data/features/step_definitions/path_steps.rb +14 -0
  25. data/features/step_definitions/pickle_steps.rb +41 -0
  26. data/features/support/env.rb +34 -0
  27. data/features/support/paths.rb +46 -0
  28. data/garlic.rb +36 -0
  29. data/init.rb +0 -0
  30. data/lib/pickle.rb +26 -0
  31. data/lib/pickle/adapter.rb +87 -0
  32. data/lib/pickle/config.rb +48 -0
  33. data/lib/pickle/email.rb +36 -0
  34. data/lib/pickle/email/parser.rb +18 -0
  35. data/lib/pickle/email/world.rb +13 -0
  36. data/lib/pickle/parser.rb +65 -0
  37. data/lib/pickle/parser/matchers.rb +87 -0
  38. data/lib/pickle/path.rb +44 -0
  39. data/lib/pickle/path/world.rb +5 -0
  40. data/lib/pickle/session.rb +151 -0
  41. data/lib/pickle/session/parser.rb +24 -0
  42. data/lib/pickle/version.rb +6 -0
  43. data/lib/pickle/world.rb +9 -0
  44. data/pickle.gemspec +107 -0
  45. data/rails_generators/pickle/pickle_generator.rb +41 -0
  46. data/rails_generators/pickle/templates/email_steps.rb +50 -0
  47. data/rails_generators/pickle/templates/env.rb +14 -0
  48. data/rails_generators/pickle/templates/paths.rb +20 -0
  49. data/rails_generators/pickle/templates/pickle_steps.rb +41 -0
  50. data/spec/lib/pickle_adapter_spec.rb +164 -0
  51. data/spec/lib/pickle_config_spec.rb +97 -0
  52. data/spec/lib/pickle_email_parser_spec.rb +49 -0
  53. data/spec/lib/pickle_email_spec.rb +131 -0
  54. data/spec/lib/pickle_parser_matchers_spec.rb +70 -0
  55. data/spec/lib/pickle_parser_spec.rb +154 -0
  56. data/spec/lib/pickle_path_spec.rb +77 -0
  57. data/spec/lib/pickle_session_spec.rb +337 -0
  58. data/spec/lib/pickle_spec.rb +24 -0
  59. data/spec/spec_helper.rb +38 -0
  60. metadata +122 -0
@@ -0,0 +1,41 @@
1
+ class PickleGenerator < Rails::Generator::Base
2
+ def initialize(args, options)
3
+ super(args, options)
4
+ File.exists?('features/support/env.rb') or raise "features/support/env.rb not found, try running script/generate cucumber"
5
+ @generate_email_steps = args.include?('email')
6
+ if @generate_path_steps = args.include?('path') || args.include?('paths')
7
+ File.exists?('features/support/paths.rb') or raise "features/support/paths.rb not found, is your cucumber up to date?"
8
+ end
9
+ end
10
+
11
+ def manifest
12
+ record do |m|
13
+ m.directory File.join('features/step_definitions')
14
+
15
+ current_env = File.read('features/support/env.rb')
16
+ env_assigns = {:current_env => current_env, :pickle => false, :pickle_path => false, :pickle_email => false}
17
+
18
+ if @generate_path_steps
19
+ env_assigns[:pickle_path] = true unless current_env.include?("require 'pickle/path/world'")
20
+ current_paths = File.read('features/support/paths.rb')
21
+ unless current_paths.include?('#{capture_model}')
22
+ if current_paths =~ /^(.*)(\n\s+else\n\s+raise "Can't find.*".*$)/m
23
+ env_assigns[:current_paths_header] = $1
24
+ env_assigns[:current_paths_footer] = $2
25
+ m.template 'paths.rb', File.join('features/support', "paths.rb"), :assigns => env_assigns, :collision => :force
26
+ end
27
+ end
28
+ end
29
+
30
+ if @generate_email_steps
31
+ env_assigns[:pickle_email] = true unless current_env.include?("require 'pickle/email/world'")
32
+ m.template 'email_steps.rb', File.join('features/step_definitions', "email_steps.rb")
33
+ end
34
+
35
+ env_assigns[:pickle] = true unless current_env.include?("require 'pickle/world'")
36
+ m.template 'pickle_steps.rb', File.join('features/step_definitions', "pickle_steps.rb")
37
+
38
+ m.template 'env.rb', File.join('features/support', "env.rb"), :assigns => env_assigns, :collision => :force
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,50 @@
1
+ # this file generated by script/generate pickle email
2
+
3
+ ActionMailer::Base.delivery_method = :test
4
+ ActionMailer::Base.perform_deliveries = true
5
+
6
+ Before do
7
+ ActionMailer::Base.deliveries.clear
8
+ end
9
+
10
+ Given(/^all emails? (?:have|has) been delivered$/) do
11
+ ActionMailer::Base.deliveries.clear
12
+ end
13
+
14
+ Given(/^(\d)+ emails? should be delivered$/) do |count|
15
+ emails.size.should == count.to_i
16
+ end
17
+
18
+ Then(/^(\d)+ emails? should be delivered to (.*)$/) do |count, to|
19
+ to =~ /^#{capture_model}$/ && to = model($1).email
20
+ emails("to: \"#{to}\"").size.should == count.to_i
21
+ end
22
+
23
+ Then(/^(\d)+ emails? should be delivered with #{capture_fields}$/) do |count, fields|
24
+ emails(fields).size.should == count.to_i
25
+ end
26
+
27
+ Then(/^#{capture_email} should be delivered to (.+)$/) do |email_ref, to|
28
+ to =~ /^#{capture_model}$/ && to = model($1).email
29
+ email(email_ref, "to: \"#{to}\"").should_not be_nil
30
+ end
31
+
32
+ Then(/^#{capture_email} should have #{capture_fields}$/) do |email_ref, fields|
33
+ email(email_ref, fields).should_not be_nil
34
+ end
35
+
36
+ Then(/^#{capture_email} should contain "(.*)"$/) do |email_ref, text|
37
+ email(email_ref).body.should =~ /#{text}/
38
+ end
39
+
40
+ Then(/^#{capture_email} should not contain "(.*)"$/) do |email_ref, text|
41
+ email(email_ref).body.should_not =~ /#{text}/
42
+ end
43
+
44
+ Then(/^#{capture_email} should link to (.+)$/) do |email_ref, page|
45
+ email(email_ref).body.should =~ /#{path_to(page)}/
46
+ end
47
+
48
+ Then(/^show me the emails?$/) do
49
+ save_and_open_emails
50
+ end
@@ -0,0 +1,14 @@
1
+ <%= current_env -%>
2
+ <%- if pickle -%>
3
+ require 'pickle/world'
4
+ # Example of configuring pickle:
5
+ #
6
+ # Pickle.configure do |config|
7
+ # config.adapters = [:machinist]
8
+ # config.map 'I', 'myself', 'me', 'my', :to => 'user: "me"'
9
+ # end
10
+ <%- end -%>
11
+ <%- if pickle_path -%>require 'pickle/path/world'
12
+ <%- end -%>
13
+ <%- if pickle_email -%>require 'pickle/email/world'
14
+ <%- end -%>
@@ -0,0 +1,20 @@
1
+ <%= current_paths_header %>
2
+ # added by script/generate pickle path
3
+
4
+ when /^#{capture_model}(?:'s)? page$/ # eg. the forum's page
5
+ path_to_pickle $1
6
+
7
+ when /^#{capture_model}(?:'s)? #{capture_model}(?:'s)? page$/ # eg. the forum's post's page
8
+ path_to_pickle $1, $2
9
+
10
+ when /^#{capture_model}(?:'s)? #{capture_model}'s (.+?) page$/ # eg. the forum's post's comments page
11
+ path_to_pickle $1, $2, :extra => $3 # or the forum's post's edit page
12
+
13
+ when /^#{capture_model}(?:'s)? (.+?) page$/ # eg. the forum's posts page
14
+ path_to_pickle $1, :extra => $2 # or the forum's edit page
15
+
16
+ when /^the (.+?) page$/ # translate to named route
17
+ send "#{$1.downcase.gsub(' ','_')}_path"
18
+
19
+ # end added by pickle path
20
+ <%= current_paths_footer %>
@@ -0,0 +1,41 @@
1
+ # this file generated by script/generate pickle
2
+
3
+ # create a model
4
+ Given(/^#{capture_model} exists?(?: with #{capture_fields})?$/) do |name, fields|
5
+ create_model(name, fields)
6
+ end
7
+
8
+ # create n models
9
+ Given(/^(\d+) #{capture_plural_factory} exist(?: with #{capture_fields})?$/) do |count, plural_factory, fields|
10
+ count.to_i.times { create_model(plural_factory.singularize, fields) }
11
+ end
12
+
13
+ # find a model
14
+ Then(/^#{capture_model} should exist(?: with #{capture_fields})?$/) do |name, fields|
15
+ find_model(name, fields).should_not be_nil
16
+ end
17
+
18
+ # find exactly n models
19
+ Then(/^(\d+) #{capture_plural_factory} should exist(?: with #{capture_fields})?$/) do |count, plural_factory, fields|
20
+ find_models(plural_factory.singularize, fields).size.should == count.to_i
21
+ end
22
+
23
+ # assert model is in another model's has_many assoc
24
+ Then(/^#{capture_model} should be (?:in|one of|amongst) #{capture_model}'s (\w+)$/) do |target, owner, association|
25
+ model(owner).send(association).should include(model(target))
26
+ end
27
+
28
+ # assert model is another model's has_one/belongs_to assoc
29
+ Then(/^#{capture_model} should be #{capture_model}'s (\w+)$/) do |target, owner, association|
30
+ model(owner).send(association).should == model(target)
31
+ end
32
+
33
+ # assert model.predicate?
34
+ Then(/^#{capture_model} should (?:be|have) (?:an? )?#{capture_predicate}$/) do |name, predicate|
35
+ model(name).should send("be_#{predicate.gsub(' ', '_')}")
36
+ end
37
+
38
+ # assert not model.predicate?
39
+ Then(/^#{capture_model} should not (?:be|have) (?:an? )?#{capture_predicate}$/) do |name, predicate|
40
+ model(name).should_not send("be_#{predicate.gsub(' ', '_')}")
41
+ end
@@ -0,0 +1,164 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
2
+
3
+ describe Pickle::Adapter do
4
+ it ".factories should raise NotImplementedError" do
5
+ lambda{ Pickle::Adapter.factories }.should raise_error(NotImplementedError)
6
+ end
7
+
8
+ it "#create should raise NotImplementedError" do
9
+ lambda{ Pickle::Adapter.new.create }.should raise_error(NotImplementedError)
10
+ end
11
+
12
+ describe ".model_classes" do
13
+ before do
14
+ Pickle::Adapter.model_classes = nil
15
+ end
16
+
17
+ if defined?(CGI::Session::ActiveRecordStore::Session)
18
+ it "should not include CGI::Session::ActiveRecordStore::Session" do
19
+ Pickle::Adapter.model_classes.should_not include(CGI::Session::ActiveRecordStore)
20
+ end
21
+ end
22
+
23
+ if defined?(ActiveRecord::SessionStore::Session)
24
+ it "should not include ActiveRecord::SessionStore::Session" do
25
+ Pickle::Adapter.model_classes.should_not include(ActiveRecord::SessionStore::Session)
26
+ end
27
+ end
28
+
29
+ it "should not include classes without a table" do
30
+ klass = Class.new(ActiveRecord::Base)
31
+ Pickle::Adapter.model_classes.should_not include(klass)
32
+ end
33
+
34
+ it "should not include abstract classes without a table" do
35
+ klass = Class.new(ActiveRecord::Base)
36
+ klass.abstract_class = true
37
+ Pickle::Adapter.model_classes.should_not include(klass)
38
+ end
39
+ end
40
+
41
+ describe "adapters: " do
42
+ before do
43
+ @klass1 = returning(Class.new(ActiveRecord::Base)) {|k| k.stub!(:name).and_return('One')}
44
+ @klass2 = returning(Class.new(ActiveRecord::Base)) {|k| k.stub!(:name).and_return('One::Two')}
45
+ @klass3 = returning(Class.new(ActiveRecord::Base)) {|k| k.stub!(:name).and_return('Three')}
46
+ end
47
+
48
+ describe 'ActiveRecord' do
49
+ before do
50
+ Pickle::Adapter::ActiveRecord.stub!(:model_classes).and_return([@klass1, @klass2, @klass3])
51
+ end
52
+
53
+ it ".factories should create one for each active record class" do
54
+ Pickle::Adapter::ActiveRecord.should_receive(:new).with(@klass1).once
55
+ Pickle::Adapter::ActiveRecord.should_receive(:new).with(@klass2).once
56
+ Pickle::Adapter::ActiveRecord.should_receive(:new).with(@klass3).once
57
+ Pickle::Adapter::ActiveRecord.factories
58
+ end
59
+
60
+ describe ".new(Class)" do
61
+ before do
62
+ @factory = Pickle::Adapter::ActiveRecord.new(@klass2)
63
+ end
64
+
65
+ it "should have underscored (s/_) name of Class as #name" do
66
+ @factory.name.should == 'one_two'
67
+ end
68
+
69
+ it "#create(attrs) should call Class.create!(attrs)" do
70
+ @klass2.should_receive(:create!).with({:key => "val"})
71
+ @factory.create(:key => "val")
72
+ end
73
+ end
74
+ end
75
+
76
+ describe 'FactoryGirl' do
77
+ before do
78
+ Pickle::Adapter::FactoryGirl.stub!(:model_classes).and_return([@klass1, @klass2, @klass3])
79
+ @orig_factories, Factory.factories = Factory.factories, {}
80
+
81
+ Factory.define(:one, :class => @klass1) {}
82
+ Factory.define(:two, :class => @klass2) {}
83
+ @factory1 = Factory.factories[:one]
84
+ @factory2 = Factory.factories[:two]
85
+ end
86
+
87
+ after do
88
+ Factory.factories = @orig_factories
89
+ end
90
+
91
+ it ".factories should create one for each factory" do
92
+ Pickle::Adapter::FactoryGirl.should_receive(:new).with(@factory1).once
93
+ Pickle::Adapter::FactoryGirl.should_receive(:new).with(@factory2).once
94
+ Pickle::Adapter::FactoryGirl.factories
95
+ end
96
+
97
+ describe ".new(factory)" do
98
+ before do
99
+ @factory = Pickle::Adapter::FactoryGirl.new(@factory1)
100
+ end
101
+
102
+ it "should have name of factory_name" do
103
+ @factory.name.should == 'one'
104
+ end
105
+
106
+ it "should have klass of build_class" do
107
+ @factory.klass.should == @klass1
108
+ end
109
+
110
+ it "#create(attrs) should call Factory(<:key>, attrs)" do
111
+ Factory.should_receive(:create).with("one", {:key => "val"})
112
+ @factory.create(:key => "val")
113
+ end
114
+ end
115
+ end
116
+
117
+ describe 'Machinist' do
118
+ before do
119
+ Pickle::Adapter::Machinist.stub!(:model_classes).and_return([@klass1, @klass2, @klass3])
120
+
121
+ @klass1.blueprint {}
122
+ @klass3.blueprint {}
123
+ @klass3.blueprint(:special) {}
124
+ end
125
+
126
+ it ".factories should create one for each master blueprint, and special case" do
127
+ Pickle::Adapter::Machinist.should_receive(:new).with(@klass1, :master).once
128
+ Pickle::Adapter::Machinist.should_receive(:new).with(@klass3, :master).once
129
+ Pickle::Adapter::Machinist.should_receive(:new).with(@klass3, :special).once
130
+ Pickle::Adapter::Machinist.factories
131
+ end
132
+
133
+ describe ".new(Class, :master)" do
134
+ before do
135
+ @factory = Pickle::Adapter::Machinist.new(@klass1, :master)
136
+ end
137
+
138
+ it "should have underscored (s/_) name of Class as #name" do
139
+ @factory.name.should == 'one'
140
+ end
141
+
142
+ it "#create(attrs) should call Class.make(:master, attrs)" do
143
+ @klass1.should_receive(:make).with(:master, {:key => "val"})
144
+ @factory.create(:key => "val")
145
+ end
146
+ end
147
+
148
+ describe ".new(Class, :special)" do
149
+ before do
150
+ @factory = Pickle::Adapter::Machinist.new(@klass3, :special)
151
+ end
152
+
153
+ it "should have 'special_<Class name>' as #name" do
154
+ @factory.name.should == 'special_three'
155
+ end
156
+
157
+ it "#create(attrs) should call Class.make(:special, attrs)" do
158
+ @klass3.should_receive(:make).with(:special, {:key => "val"})
159
+ @factory.create(:key => "val")
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,97 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
2
+
3
+ describe Pickle::Config do
4
+ before do
5
+ @config = Pickle::Config.new
6
+ end
7
+
8
+ it "#adapters should default to :machinist, :factory_girl, :active_record" do
9
+ @config.adapters.should == [:machinist, :factory_girl, :active_record]
10
+ end
11
+
12
+ it "#adapter_classes should default to Adapter::Machinist, Adapter::FactoryGirl, Adapter::ActiveRecord" do
13
+ @config.adapter_classes.should == [Pickle::Adapter::Machinist, Pickle::Adapter::FactoryGirl, Pickle::Adapter::ActiveRecord]
14
+ end
15
+
16
+ describe "setting adapters to [:machinist, SomeAdapter]" do
17
+ class SomeAdapter; end
18
+
19
+ before do
20
+ @config.adapters = [:machinist, SomeAdapter]
21
+ end
22
+
23
+ it "#adapter_classes should be Adapter::Machinist, SomeAdapter" do
24
+ @config.adapter_classes.should == [Pickle::Adapter::Machinist, SomeAdapter]
25
+ end
26
+ end
27
+
28
+ describe "#factories" do
29
+ it "should call adaptor.factories for each adaptor" do
30
+ Pickle::Adapter::Machinist.should_receive(:factories).and_return([])
31
+ Pickle::Adapter::FactoryGirl.should_receive(:factories).and_return([])
32
+ Pickle::Adapter::ActiveRecord.should_receive(:factories).and_return([])
33
+ @config.factories
34
+ end
35
+
36
+ it "should aggregate factories into a hash using factory name as key" do
37
+ Pickle::Adapter::Machinist.should_receive(:factories).and_return([@machinist = mock('machinist', :name => 'machinist')])
38
+ Pickle::Adapter::FactoryGirl.should_receive(:factories).and_return([@factory_girl = mock('factory_girl', :name => 'factory_girl')])
39
+ Pickle::Adapter::ActiveRecord.should_receive(:factories).and_return([@active_record = mock('active_record', :name => 'active_record')])
40
+ @config.factories.should == {'machinist' => @machinist, 'factory_girl' => @factory_girl, 'active_record' => @active_record}
41
+ end
42
+
43
+ it "should give preference to adaptors first in the list" do
44
+ Pickle::Adapter::Machinist.should_receive(:factories).and_return([@machinist_one = mock('one', :name => 'one')])
45
+ Pickle::Adapter::FactoryGirl.should_receive(:factories).and_return([@factory_girl_one = mock('one', :name => 'one'), @factory_girl_two = mock('two', :name => 'two')])
46
+ Pickle::Adapter::ActiveRecord.should_receive(:factories).and_return([@active_record_two = mock('two', :name => 'two'), @active_record_three = mock('three', :name => 'three')])
47
+ @config.factories.should == {'one' => @machinist_one, 'two' => @factory_girl_two, 'three' => @active_record_three}
48
+ end
49
+ end
50
+
51
+ it "#mappings should default to []" do
52
+ @config.mappings.should == []
53
+ end
54
+
55
+ describe '#predicates' do
56
+ it "should be list of all non object ? public instance methods + columns methods of Adapter.model_classes" do
57
+ class1 = mock('Class1', :public_instance_methods => ['nope', 'foo?', 'bar?'], :column_names => ['one', 'two'])
58
+ class2 = mock('Class2', :public_instance_methods => ['not', 'foo?', 'faz?'], :column_names => ['two', 'three'])
59
+ Pickle::Adapter.stub!(:model_classes).and_return([class1, class2])
60
+
61
+ @config.predicates.to_set.should == ['foo?', 'faz?', 'bar?', 'one', 'two', 'three'].to_set
62
+ end
63
+
64
+ it "should be overridable" do
65
+ @config.predicates = %w(lame?)
66
+ @config.predicates.should == %w(lame?)
67
+ end
68
+ end
69
+
70
+ describe "#map 'foo', :to => 'faz'" do
71
+ before do
72
+ @config.map 'foo', :to => 'faz'
73
+ end
74
+
75
+ it "should create OpenStruct(search: 'foo', replace: 'faz') mapping" do
76
+ @config.mappings.first.should == OpenStruct.new(:search => 'foo', :replacement => 'faz')
77
+ end
78
+ end
79
+
80
+ describe "#map 'foo', 'bar' :to => 'faz'" do
81
+ before do
82
+ @config.map 'foo', 'bar', :to => 'faz'
83
+ end
84
+
85
+ it "should create 2 mappings" do
86
+ @config.mappings.first.should == OpenStruct.new(:search => 'foo', :replacement => 'faz')
87
+ @config.mappings.last.should == OpenStruct.new(:search => 'bar', :replacement => 'faz')
88
+ end
89
+ end
90
+
91
+ it "#configure(&block) should execiute on self" do
92
+ @config.should_receive(:foo).with(:bar)
93
+ @config.configure do |c|
94
+ c.foo :bar
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,49 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
2
+
3
+ describe Pickle::Email::Parser do
4
+ include Pickle::Parser::Matchers
5
+ include Pickle::Email::Parser
6
+
7
+ describe "#match_email" do
8
+ it "should match 'the email'" do
9
+ 'the email'.should match(/^#{match_email}$/)
10
+ end
11
+
12
+ it "should match 'the first email'" do
13
+ 'the first email'.should match(/^#{match_email}$/)
14
+ end
15
+
16
+ it "should match 'the last email'" do
17
+ 'the last email'.should match(/^#{match_email}$/)
18
+ end
19
+
20
+ it "should match 'the 3rd email'" do
21
+ 'the 3rd email'.should match(/^#{match_email}$/)
22
+ end
23
+
24
+ it "should match 'an email'" do
25
+ 'an email'.should match(/^#{match_email}$/)
26
+ end
27
+ end
28
+
29
+ it "#capture_email should just capture match_email" do
30
+ capture_email.should == "(#{match_email})"
31
+ end
32
+
33
+ describe "#capture_index_in_email" do
34
+ it "should extract the '2nd' from 'the 2nd email'" do
35
+ match = 'the 2nd email'.match(/^#{capture_index_in_email}$/)
36
+ match[1].should == '2nd'
37
+ end
38
+
39
+ it "should extract nil from 'the email'" do
40
+ match = 'the email'.match(/^#{capture_index_in_email}$/)
41
+ match[1].should == nil
42
+ end
43
+
44
+ it "should extract the 'last' from 'the last email'" do
45
+ match = 'the last email'.match(/^#{capture_index_in_email}$/)
46
+ match[1].should == 'last'
47
+ end
48
+ end
49
+ end