diff --git a/README.rdoc b/README.rdoc
index 72119f28..0537f1f4 100644
--- a/README.rdoc
+++ b/README.rdoc
@@ -35,7 +35,7 @@ Install pickle either as a rails plugin, or a gem
# plugin
script/plugin install git://github.com/ianwhite/pickle.git
-
+
# or, plugin as submodule
git submodule add git://github.com/ianwhite/pickle.git vendor/plugins/pickle
@@ -48,7 +48,7 @@ It's tested against all stable branches of 2.x rails, and edge, with the latest
To run the specs do:
rake spec
-
+
To run the features (rails 2.3 only ATM):
rake cucumber
@@ -77,9 +77,11 @@ If you want path steps and email steps then just add 'paths' and/or 'email'. Th
written to features/env/paths.rb and
features/step_definitions/email_steps.rb respectively.
-=== Using with plain ole Active Record
+=== Using with plain ole Active Record or DataMapper
-If you have an AR called 'Post', with required fields 'title', and 'body', then you can now write
+Pickle comes with adapters for Active Record and DataMapper.
+
+If you have an AR/DM called 'Post', with required fields 'title', and 'body', then you can now write
steps like this
Given a post exists with title: "My Post", body: "My body"
@@ -98,7 +100,7 @@ you've written, you can just do stuff like
==== Machinst: require your blueprints and reset Shams
-(The latest version of pickle supports {multiple blueprints}[http://github.com/notahat/machinist/commit/d6492e6927a8aa1819926e48b22377171fd20496], for
+(The latest version of pickle supports {multiple blueprints}[http://github.com/notahat/machinist/commit/d6492e6927a8aa1819926e48b22377171fd20496], for
earlier versions of machinist use pickle <= 0.1.10)
In your features/support/env.rb add the following lines at the bottom
@@ -115,6 +117,19 @@ If that doesn't solve loading issues then require your factories.rb file directl
# example features/support/factory_girl.rb
require File.dirname(__FILE__) + '/../../spec/factories'
+=== Using with an ORM other than ActiveRecord or DataMapper
+
+Pickle can be used with any Modeling library provided there is an adapter written for it.
+
+Adapters are very simple and exist a module or class with the name "PickleAdapter" available to the class. For example
+
+User.const_get(:PickleAdapter) #=> should return a pickle adapter
+
+The Active Record and DataMapper ones can be found at
+ActiveRecord::Base::PickleAdapter and DataMapper::Resource::PickleAdapter respectively.
+
+See how to implement one by looking at the ones provided in the pickle source in lib/pickle/adapters/*
+
=== Configuring Pickle
You can tell pickle to use another factory adapter (see Pickle::Adapter), or
@@ -129,7 +144,7 @@ In: features/support/pickle.rb
config.adapters = [:machinist, YourOwnAdapterClass]
config.map 'me', 'myself', 'my', 'I', :to => 'user: "me"'
end
-
+
Out of the box pickle looks for machinist, then factory-girl, then finally active-record 'factories'.
If you find that your steps aren't working with your factories, it's probably the case that your factory
setup is not being included in your cucumber environment (see comments above regarding machinist and factory-girl).
@@ -147,29 +162,29 @@ When you run script/generate pickle you get the following steps
Given a user exists
Given a user: "fred" exists
Given the user exists
-
+
"Given a model exists with fields", e.g.
Given a user exists with name: "Fred"
Given a user exists with name: "Fred", activated: false
-
+
You can refer to other models in the fields
Given a user exists
And a post exists with author: the user
-
+
Given a person: "fred" exists
And a person: "ethel" exists
And a fatherhood exists with parent: user "fred", child: user "ethel"
-
+
"Given n models exist", e.g.
-
+
Given 10 users exist
-
+
"Given n models exist with fields", examples:
Given 10 users exist with activated: false
-
+
"Given the following models exist:", examples:
Given the following users exist
@@ -188,21 +203,21 @@ You can refer to other models in the fields
"Then a model should exist with fields", e.g.
Then a user: "fred" should exist with name: "Fred" # we can label the found user for later use
-
+
You can use other models, booleans, numerics, and strings as fields
Then a person should exist with child: person "ethel"
Then a user should exist with activated: false
Then a user should exist with activated: true, email: "fred@gmail.com"
-
+
"Then n models should exist", e.g.
Then 10 events should exist
-
+
"Then n models should exist with fields", e.g.
Then 2 people should exist with father: person "fred"
-
+
"Then the following models exist". This allows the creation of multiple models
using a table syntax. Using a column with the singularized name of the model creates a referenceable model. E.g.
@@ -213,30 +228,30 @@ using a table syntax. Using a column with the singularized name of the model cre
Then the following users exist:
| user | name | activated |
| Fred | Freddy | false |
-
+
===== Asserting associations
One-to-one assocs: "Then a model should be other model's association", e.g.
Then the person: "fred" should be person: "ethel"'s father
-
+
Many-to-one assocs: "Then a model should be [in|one of] other model's association", e.g.
Then the person: "ethel" should be one of person: "fred"'s children
Then the comment should be in the post's comments
-
+
===== Asserting predicate methods
"Then a model should [be|have] [a|an] predicate", e.g.
-
+
Then the user should have a status # => user.status.should be_present
Then the user should have a stale password # => user.should have_stale_password
Then the car: "batmobile" should be fast # => car.should be_fast
-
+
"Then a model should not [be|have] [a|an] predicate", e.g.
Then person: "fred" should not be childless # => fred.should_not be_childless
-
+
=== Regexps for use in your own steps
By default you get some regexps available in the main namespace for use
@@ -263,7 +278,7 @@ Pickle::Parser::Matchers for the methods available)
post = model!(post)
forum = model!(forum)
forum.posts.should include(post)
- end
+ end
*capture_fields*
@@ -276,4 +291,4 @@ can build up composite objects with ease
# example of use
Given a user exists
- And a post exists with author: the user # this step will assign the above user as :author on the post
\ No newline at end of file
+ And a post exists with author: the user # this step will assign the above user as :author on the post
diff --git a/lib/pickle/adapter.rb b/lib/pickle/adapter.rb
index a405395a..30fe26ef 100644
--- a/lib/pickle/adapter.rb
+++ b/lib/pickle/adapter.rb
@@ -4,7 +4,7 @@ module Pickle
# Abstract Factory adapter class, if you have a factory type setup, you
# can easily create an adaptor to make it work with Pickle.
#
- # The factory adaptor must have a #factories class method that returns
+ # The factory adaptor must have a #factories class method that returns
# its instances, and each instance must respond to:
#
# #name : identifies the factory by name (default is attr_reader)
@@ -12,88 +12,65 @@ module Pickle
# #create(attrs = {}) : returns a newly created object
class Adapter
attr_reader :name, :klass
-
+
def create(attrs = {})
raise NotImplementedError, "create and return an object with the given attributes"
end
-
+
if respond_to?(:class_attribute)
class_attribute :model_classes
else
cattr_writer :model_classes
end
-
+
self.model_classes = nil
-
+
+ # Include this module into your adapter
+ # this will register the adapter with pickle and it will be picked up for you
+ # To create an adapter you should create an inner constant "PickleAdapter"
+ #
+ # e.g. ActiveRecord::Base::PickleAdapter
+ #
+ # @see pickle/adapters/active_record
+ # @see pickle/adapters/datamapper
+ module Base
+ def self.included(base)
+ adapters << base
+ end
+
+ # A collection of registered adapters
+ def self.adapters
+ @@adapters ||= []
+ end
+ end
+
class << self
def factories
raise NotImplementedError, "return an array of factory adapter objects"
end
def model_classes
- @@model_classes ||=
- if defined?(::ActiveRecord::Base)
- ::ActiveRecord::Base.send(:subclasses).select {|klass| suitable_for_pickle?(klass)}
- elsif defined?(::DataMapper::Model)
- ::DataMapper::Model.descendants.to_a
- else
- []
- end
- end
-
- # return true if a klass should be used by pickle
- def suitable_for_pickle?(klass)
- !klass.abstract_class? && klass.table_exists? && !framework_class?(klass)
- end
-
- # return true if the passed class is a special framework class
- def framework_class?(klass)
- ((defined?(CGI::Session::ActiveRecordStore::Session) && klass == CGI::Session::ActiveRecordStore::Session)) ||
- ((defined?(::ActiveRecord::SessionStore::Session) && klass == ::ActiveRecord::SessionStore::Session))
+ @@model_classes ||= self::Base.adapters.map{ |a| a.model_classes }.flatten
end
# Returns the column names for the given ORM model class.
def column_names(klass)
- if defined?(::ActiveRecord::Base)
- klass.column_names
- elsif defined?(::DataMapper::Model)
- klass.properties.map(&:name)
- else
- []
- end
+ klass.const_get(:PickleAdapter).column_names(klass)
end
def get_model(klass, id)
- if defined?(ActiveRecord::Base)
- klass.find(id)
- elsif defined?(DataMapper::Model)
- klass.get(id)
- else
- nil
- end
+ klass.const_get(:PickleAdapter).get_model(klass, id)
end
def find_first_model(klass, conditions)
- if defined?(ActiveRecord::Base)
- klass.find(:first, :conditions => conditions)
- elsif defined?(DataMapper::Model)
- klass.first(conditions)
- else
- nil
- end
+ klass.const_get(:PickleAdapter).find_first_model(klass, conditions)
end
def find_all_models(klass, conditions)
- if defined?(ActiveRecord::Base)
- klass.find(:all, :conditions => conditions)
- elsif defined?(DataMapper::Model)
- klass.all(conditions)
- else
- []
- end
+ klass.const_get(:PickleAdapter).find_all_models(klass, conditions)
end
end
-
+
# machinist adapter
class Machinist < Adapter
def self.factories
@@ -105,37 +82,37 @@ def self.factories
end
factories
end
-
+
def initialize(klass, blueprint)
@klass, @blueprint = klass, blueprint
@name = @klass.name.underscore.gsub('/','_')
@name = "#{@blueprint}_#{@name}" unless @blueprint == :master
end
-
+
def create(attrs = {})
@klass.send(:make, @blueprint, attrs)
end
end
-
+
# factory-girl adapter
class FactoryGirl < Adapter
def self.factories
(::Factory.factories.values rescue []).map {|factory| new(factory)}
end
-
+
def initialize(factory)
@klass, @name = factory.build_class, factory.factory_name.to_s
end
-
+
def create(attrs = {})
Factory.create(@name, attrs)
end
end
-
+
# fallback active record adapter
class ActiveRecord < Adapter
def self.factories
- model_classes.map {|klass| new(klass) }
+ ::ActiveRecord::Base::PickleAdapter.model_classes.map{|k| new(k)}
end
def initialize(klass)
diff --git a/lib/pickle/adapters/active_record.rb b/lib/pickle/adapters/active_record.rb
new file mode 100644
index 00000000..652871ad
--- /dev/null
+++ b/lib/pickle/adapters/active_record.rb
@@ -0,0 +1,46 @@
+begin
+ require 'activerecord'
+rescue LoadError
+ require 'active_record'
+end
+
+class ActiveRecord::Base
+ module PickleAdapter
+ include Pickle::Adapter::Base
+
+ # Do not consider these to be part of the class list
+ def self.except_classes
+ @@except_classes ||= [
+ "CGI::Session::ActiveRecordStore::Session",
+ "ActiveRecord::SessionStore::Session"
+ ]
+ end
+
+ # Gets a list of the available models for this adapter
+ def self.model_classes
+ ::ActiveRecord::Base.__send__(:subclasses).select do |klass|
+ !klass.abstract_class? && klass.table_exists? && !except_classes.include?(klass.name)
+ end
+ end
+
+ # get a list of column names for a given class
+ def self.column_names(klass)
+ klass.column_names
+ end
+
+ # Get an instance by id of the model
+ def self.get_model(klass, id)
+ klass.find(id)
+ end
+
+ # Find the first instance matching conditions
+ def self.find_first_model(klass, conditions)
+ klass.find(:first, :conditions => conditions)
+ end
+
+ # Find all models matching conditions
+ def self.find_all_models(klass, conditions)
+ klass.find(:all, :conditions => conditions)
+ end
+ end
+end
diff --git a/lib/pickle/adapters/data_mapper.rb b/lib/pickle/adapters/data_mapper.rb
new file mode 100644
index 00000000..2f2747b0
--- /dev/null
+++ b/lib/pickle/adapters/data_mapper.rb
@@ -0,0 +1,37 @@
+require 'dm-core'
+
+module DataMapper::Resource
+ module PickleAdapter
+ include Pickle::Adapter::Base
+
+ # Do not consider these to be part of the class list
+ def self.except_classes
+ @@except_classes ||= []
+ end
+
+ # Gets a list of the available models for this adapter
+ def self.model_classes
+ ::DataMapper::Model.descendants.to_a.select{|k| !except_classes.include?(k.name)}
+ end
+
+ # get a list of column names for a given class
+ def self.column_names(klass)
+ klass.properties.map(&:name)
+ end
+
+ # Get an instance by id of the model
+ def self.get_model(klass, id)
+ klass.get(id)
+ end
+
+ # Find the first instance matching conditions
+ def self.find_first_model(klass, conditions)
+ klass.first(conditions)
+ end
+
+ # Find all models matching conditions
+ def self.find_all_models(klass, conditions)
+ klass.all(conditions)
+ end
+ end
+end
diff --git a/lib/pickle/email.rb b/lib/pickle/email.rb
index d87340d0..ec30f07f 100644
--- a/lib/pickle/email.rb
+++ b/lib/pickle/email.rb
@@ -11,7 +11,7 @@ def email(ref, fields = nil)
index = parse_index(match[1])
email_has_fields?(@emails[index], fields) ? @emails[index] : nil
end
-
+
def email_has_fields?(email, fields)
parse_fields(fields).each do |key, val|
return false unless (Array(email.send(key)) & Array(val)).any?
@@ -28,7 +28,7 @@ def click_first_link_in_email(email)
request_uri = URI::parse(link).request_uri
visit request_uri
end
-
+
protected
def open_in_browser(path) # :nodoc
require "launchy"
@@ -36,7 +36,7 @@ def open_in_browser(path) # :nodoc
rescue LoadError
warn "Sorry, you need to install launchy to open emails: `gem install launchy`"
end
-
+
# Saves the emails out to RAILS_ROOT/tmp/ and opens it in the default
# web browser if on OS X. (depends on webrat)
def save_and_open_emails
@@ -76,4 +76,4 @@ def links_in_email(email, protos=['http', 'https'])
end
end
-end
\ No newline at end of file
+end
diff --git a/lib/pickle/world.rb b/lib/pickle/world.rb
index 8a1fc222..ed6138de 100644
--- a/lib/pickle/world.rb
+++ b/lib/pickle/world.rb
@@ -1,5 +1,9 @@
require 'pickle'
+# auto require for active record and datamapper
+require 'pickle/adapters/active_record' if defined?(ActiveRecord::Base)
+require 'pickle/adapters/data_mapper' if defined?(DataMapper::Resource)
+
# make cucumber world pickle aware
World(Pickle::Session)
diff --git a/spec/pickle/adapter_spec.rb b/spec/pickle/adapter_spec.rb
index 3d01cb55..c1d600fa 100644
--- a/spec/pickle/adapter_spec.rb
+++ b/spec/pickle/adapter_spec.rb
@@ -3,176 +3,156 @@
require 'active_record'
require 'factory_girl'
require 'machinist/active_record'
+require 'pickle/adapters/active_record'
describe Pickle::Adapter do
it ".factories should raise NotImplementedError" do
lambda{ Pickle::Adapter.factories }.should raise_error(NotImplementedError)
end
-
+
it "#create should raise NotImplementedError" do
lambda{ Pickle::Adapter.new.create }.should raise_error(NotImplementedError)
end
-
- describe ".suitable_for_pickle?(klass)" do
- let :klass do
- mock('Class', :abstract_class? => false, :table_exists? => true)
- end
-
- before do
- Pickle::Adapter.stub!(:framework_class?).and_return(false)
- end
-
- it "a non abstract class that has a table, and is not a framework class, is suitable_for_pickle" do
- Pickle::Adapter.should be_suitable_for_pickle(klass)
- end
-
- it "an abtract_class is not suitable_for_pickle" do
- klass.stub!(:abstract_class?).and_return(true)
- Pickle::Adapter.should_not be_suitable_for_pickle(klass)
- end
-
- it "a class with no table is not suitable_for_pickle" do
- klass.stub!(:table_exists?).and_return(false)
- Pickle::Adapter.should_not be_suitable_for_pickle(klass)
- end
-
- it "an frame_work class is not suitable_for_pickle" do
- Pickle::Adapter.should_receive(:framework_class?).with(klass).and_return(true)
- Pickle::Adapter.should_not be_suitable_for_pickle(klass)
- end
- end
-
+
describe ".model_classes" do
before do
Pickle::Adapter.model_classes = nil
end
-
+
it "should only include #suitable_for_pickle classes" do
klass1 = Class.new(ActiveRecord::Base)
klass2 = Class.new(ActiveRecord::Base)
- Pickle::Adapter.should_receive(:suitable_for_pickle?).with(klass1).and_return(true)
- Pickle::Adapter.should_receive(:suitable_for_pickle?).with(klass2).and_return(false)
- Pickle::Adapter.model_classes.should include(klass1)
- Pickle::Adapter.model_classes.should_not include(klass2)
+ klass3 = Class.new(ActiveRecord::Base)
+ klass4 = Class.new(ActiveRecord::Base)
+ klass5 = Class.new(ActiveRecord::Base)
+ klass6 = Class.new(ActiveRecord::Base)
+ [klass1, klass2,klass3,klass4, klass5, klass6].each{|k| k.stub!(:table_exists?).and_return(true)}
+
+ klass2.stub!(:name).and_return("CGI::Session::ActiveRecordStore::Session")
+ klass3.stub!(:name).and_return("ActiveRecord::SessionStore::Session")
+ klass4.stub!(:table_exists?).and_return(false)
+ klass5.stub!(:abstract_class?).and_return(true)
+ Pickle::Adapter.model_classes.should include(klass1, klass6)
+ Pickle::Adapter.model_classes.should_not include(klass2, klass3, klass4, klass5)
end
end
-
+
describe "adapters: " do
before do
@klass1 = returning(Class.new(ActiveRecord::Base)) {|k| k.stub!(:name).and_return('One')}
@klass2 = returning(Class.new(ActiveRecord::Base)) {|k| k.stub!(:name).and_return('One::Two')}
@klass3 = returning(Class.new(ActiveRecord::Base)) {|k| k.stub!(:name).and_return('Three')}
end
-
+
describe 'ActiveRecord' do
before do
- Pickle::Adapter::ActiveRecord.stub!(:model_classes).and_return([@klass1, @klass2, @klass3])
+ ActiveRecord::Base::PickleAdapter.stub!(:model_classes).and_return([@klass1, @klass2, @klass3])
end
-
+
it ".factories should create one for each active record class" do
Pickle::Adapter::ActiveRecord.should_receive(:new).with(@klass1).once
Pickle::Adapter::ActiveRecord.should_receive(:new).with(@klass2).once
Pickle::Adapter::ActiveRecord.should_receive(:new).with(@klass3).once
Pickle::Adapter::ActiveRecord.factories
end
-
+
describe ".new(Class)" do
before do
@factory = Pickle::Adapter::ActiveRecord.new(@klass2)
end
-
+
it "should have underscored (s/_) name of Class as #name" do
@factory.name.should == 'one_two'
end
-
+
it "#create(attrs) should call Class.create!(attrs)" do
@klass2.should_receive(:create!).with({:key => "val"})
@factory.create(:key => "val")
end
end
end
-
+
describe 'FactoryGirl' do
before do
Pickle::Adapter::FactoryGirl.stub!(:model_classes).and_return([@klass1, @klass2, @klass3])
@orig_factories, Factory.factories = Factory.factories, {}
-
+
Factory.define(:one, :class => @klass1) {}
Factory.define(:two, :class => @klass2) {}
@factory1 = Factory.factories[:one]
@factory2 = Factory.factories[:two]
end
-
+
after do
Factory.factories = @orig_factories
end
-
+
it ".factories should create one for each factory" do
Pickle::Adapter::FactoryGirl.should_receive(:new).with(@factory1).once
Pickle::Adapter::FactoryGirl.should_receive(:new).with(@factory2).once
Pickle::Adapter::FactoryGirl.factories
end
-
+
describe ".new(factory)" do
before do
@factory = Pickle::Adapter::FactoryGirl.new(@factory1)
end
-
+
it "should have name of factory_name" do
@factory.name.should == 'one'
end
-
+
it "should have klass of build_class" do
@factory.klass.should == @klass1
end
-
+
it "#create(attrs) should call Factory(<:key>, attrs)" do
Factory.should_receive(:create).with("one", {:key => "val"})
@factory.create(:key => "val")
end
end
end
-
+
describe 'Machinist' do
before do
Pickle::Adapter::Machinist.stub!(:model_classes).and_return([@klass1, @klass2, @klass3])
-
+
@klass1.blueprint {}
@klass3.blueprint {}
@klass3.blueprint(:special) {}
end
-
+
it ".factories should create one for each master blueprint, and special case" do
Pickle::Adapter::Machinist.should_receive(:new).with(@klass1, :master).once
Pickle::Adapter::Machinist.should_receive(:new).with(@klass3, :master).once
Pickle::Adapter::Machinist.should_receive(:new).with(@klass3, :special).once
Pickle::Adapter::Machinist.factories
end
-
+
describe ".new(Class, :master)" do
before do
@factory = Pickle::Adapter::Machinist.new(@klass1, :master)
end
-
+
it "should have underscored (s/_) name of Class as #name" do
@factory.name.should == 'one'
end
-
+
it "#create(attrs) should call Class.make(:master, attrs)" do
@klass1.should_receive(:make).with(:master, {:key => "val"})
@factory.create(:key => "val")
end
end
-
+
describe ".new(Class, :special)" do
before do
@factory = Pickle::Adapter::Machinist.new(@klass3, :special)
end
-
+
it "should have 'special_' as #name" do
@factory.name.should == 'special_three'
end
-
+
it "#create(attrs) should call Class.make(:special, attrs)" do
@klass3.should_receive(:make).with(:special, {:key => "val"})
@factory.create(:key => "val")
@@ -180,4 +160,4 @@
end
end
end
-end
\ No newline at end of file
+end
diff --git a/spec/pickle/config_spec.rb b/spec/pickle/config_spec.rb
index 3e203349..63ef578e 100644
--- a/spec/pickle/config_spec.rb
+++ b/spec/pickle/config_spec.rb
@@ -4,27 +4,27 @@
before do
@config = Pickle::Config.new
end
-
+
it "#adapters should default to :machinist, :factory_girl, :active_record" do
@config.adapters.should == [:machinist, :factory_girl, :active_record]
end
-
+
it "#adapter_classes should default to Adapter::Machinist, Adapter::FactoryGirl, Adapter::ActiveRecord" do
@config.adapter_classes.should == [Pickle::Adapter::Machinist, Pickle::Adapter::FactoryGirl, Pickle::Adapter::ActiveRecord]
end
-
+
describe "setting adapters to [:machinist, SomeAdapter]" do
class SomeAdapter; end
-
+
before do
@config.adapters = [:machinist, SomeAdapter]
end
-
+
it "#adapter_classes should be Adapter::Machinist, SomeAdapter" do
@config.adapter_classes.should == [Pickle::Adapter::Machinist, SomeAdapter]
end
end
-
+
describe "#factories" do
it "should call adaptor.factories for each adaptor" do
Pickle::Adapter::Machinist.should_receive(:factories).and_return([])
@@ -32,14 +32,14 @@ class SomeAdapter; end
Pickle::Adapter::ActiveRecord.should_receive(:factories).and_return([])
@config.factories
end
-
+
it "should aggregate factories into a hash using factory name as key" do
Pickle::Adapter::Machinist.should_receive(:factories).and_return([@machinist = mock('machinist', :name => 'machinist')])
Pickle::Adapter::FactoryGirl.should_receive(:factories).and_return([@factory_girl = mock('factory_girl', :name => 'factory_girl')])
Pickle::Adapter::ActiveRecord.should_receive(:factories).and_return([@active_record = mock('active_record', :name => 'active_record')])
@config.factories.should == {'machinist' => @machinist, 'factory_girl' => @factory_girl, 'active_record' => @active_record}
end
-
+
it "should give preference to adaptors first in the list" do
Pickle::Adapter::Machinist.should_receive(:factories).and_return([@machinist_one = mock('one', :name => 'one')])
Pickle::Adapter::FactoryGirl.should_receive(:factories).and_return([@factory_girl_one = mock('one', :name => 'one'), @factory_girl_two = mock('two', :name => 'two')])
@@ -47,51 +47,59 @@ class SomeAdapter; end
@config.factories.should == {'one' => @machinist_one, 'two' => @factory_girl_two, 'three' => @active_record_three}
end
end
-
+
it "#mappings should default to []" do
@config.mappings.should == []
end
describe '#predicates' do
it "should be list of all non object ? public instance methods + columns methods of Adapter.model_classes" do
- class1 = mock('Class1', :public_instance_methods => ['nope', 'foo?', 'bar?'], :column_names => ['one', 'two'])
- class2 = mock('Class2', :public_instance_methods => ['not', 'foo?', 'faz?'], :column_names => ['two', 'three'])
+ class1 = mock('Class1',
+ :public_instance_methods => ['nope', 'foo?', 'bar?'],
+ :column_names => ['one', 'two'],
+ :const_get => ::ActiveRecord::Base::PickleAdapter
+ )
+ class2 = mock('Class2',
+ :public_instance_methods => ['not', 'foo?', 'faz?'],
+ :column_names => ['two', 'three'],
+ :const_get => ::ActiveRecord::Base::PickleAdapter
+ )
Pickle::Adapter.stub!(:model_classes).and_return([class1, class2])
-
+
@config.predicates.to_set.should == ['foo?', 'faz?', 'bar?', 'one', 'two', 'three'].to_set
end
-
+
it "should be overridable" do
@config.predicates = %w(lame?)
@config.predicates.should == %w(lame?)
end
end
-
+
describe "#map 'foo', :to => 'faz'" do
before do
@config.map 'foo', :to => 'faz'
end
-
+
it "should create OpenStruct(search: 'foo', replace: 'faz') mapping" do
@config.mappings.first.should == OpenStruct.new(:search => 'foo', :replacement => 'faz')
end
end
-
+
describe "#map 'foo', 'bar' :to => 'faz'" do
before do
@config.map 'foo', 'bar', :to => 'faz'
end
-
+
it "should create 2 mappings" do
@config.mappings.first.should == OpenStruct.new(:search => 'foo', :replacement => 'faz')
@config.mappings.last.should == OpenStruct.new(:search => 'bar', :replacement => 'faz')
end
end
-
+
it "#configure(&block) should execiute on self" do
@config.should_receive(:foo).with(:bar)
@config.configure do |c|
c.foo :bar
end
end
-end
\ No newline at end of file
+end
diff --git a/spec/pickle/email_spec.rb b/spec/pickle/email_spec.rb
index b4c8b4a4..ae60c8be 100644
--- a/spec/pickle/email_spec.rb
+++ b/spec/pickle/email_spec.rb
@@ -13,22 +13,25 @@
@email1 = mock("Email 1")
@email2 = mock("Email 2")
ActionMailer::Base.stub!(:deliveries).and_return([@email1, @email2])
+ if defined?(ActiveRecord::Base)
+ ActiveRecord::Base::PickleAdapter.stub!(:model_classes).and_return([])
+ end
end
-
+
describe "#emails" do
it "should return ordered deliveries" do
emails.should == [@email1, @email2]
end
-
+
describe "(after)" do
before do
emails
end
-
+
it "#email('the email') should return the last delivery" do
email('the email').should == @email2
end
-
+
it "#email('the 1st email') should return the first delivery" do
email('the 1st email').should == @email1
end
@@ -40,36 +43,36 @@
it "#email('the 2nd email') should return the second delivery" do
email('the 2nd email').should == @email2
end
-
+
it "#email('the last email') should return the second delivery" do
email('the last email').should == @email2
end
-
+
it "#email2('the 3rd email') should be nil" do
email('the 3rd email').should == nil
end
end
-
+
describe "when email1 is to fred & joe, and email2 is to joe" do
before do
@email1.stub!(:to).and_return(['fred@gmail.com', 'joe@gmail.com'])
@email2.stub!(:to).and_return('joe@gmail.com')
end
-
+
it "#emails('to: \"fred@gmail.com\"') should just return email1" do
emails('to: "fred@gmail.com"').should == [@email1]
end
-
+
describe "after #emails('to: \"fred@gmail.com\"')" do
before do
emails('to: "fred@gmail.com"')
end
-
+
it "#email('first') should be #email('last')" do
email('first email').should == email('last email')
email('first email').should == @email1
end
-
+
it "#email('the email', 'to: \"blah\") should be nil" do
email('the email', 'to: "blah"').should == nil
end
@@ -78,28 +81,28 @@
email('the email', 'to: "fred@gmail.com"').should == @email1
end
end
-
+
it "#emails('to: \"joe@gmail.com\"') should return both emails" do
emails('to: "joe@gmail.com"').should == [@email1, @email2]
end
-
+
describe "and emails have subjects 'email1', 'email2'" do
before do
@email1.stub!(:subject).and_return('email1')
@email2.stub!(:subject).and_return('email2')
end
-
+
it "#emails('to: \"joe@gmail.com\", subject: \"email1\"') should return email1" do
emails('to: "joe@gmail.com", subject: "email1"').should == [@email1]
end
-
+
it "#emails('to: \"fred@gmail.com\", subject: \"email2\"') should return empty array" do
emails('to: "fred@gmail.com", subject: "email2"').should == []
end
end
end
end
-
+
describe "#save_and_open_emails" do
before do
stub!(:open_in_browser)
@@ -107,21 +110,21 @@
@now = "2008-01-01".to_time
Time.stub!(:now).and_return(@now)
end
-
+
it "should call #emails to get emails" do
should_receive(:emails).and_return([])
save_and_open_emails
end
-
+
describe "when emails have been already been found" do
before { @emails = [] }
-
+
it "should not call #emails" do
should_not_receive(:emails)
save_and_open_emails
end
end
-
+
it "should create a file in Rails/tmp with the emails in it" do
save_and_open_emails
File.read("pickle-email-#{@now.to_i}.html").should == "Email 1
Contents of Email 1
"
@@ -132,13 +135,13 @@
save_and_open_emails
end
end
-
+
describe "following links in emails" do
before do
stub!(:open_in_browser)
@email1.stub!(:body).and_return('some text example page more text')
end
-
+
it "should find a link for http://example.com/page" do
should_receive(:visit).with('/page')
visit_in_email(@email1, 'http://example.com/page')
@@ -148,7 +151,7 @@
should_receive(:visit).with('/page')
visit_in_email(@email1, 'example page')
end
-
+
it "should follow the first link in an email" do
should_receive(:visit).with('/page')
click_first_link_in_email(@email1)
diff --git a/spec/pickle/session_spec.rb b/spec/pickle/session_spec.rb
index d1af27d2..bc646728 100644
--- a/spec/pickle/session_spec.rb
+++ b/spec/pickle/session_spec.rb
@@ -3,7 +3,7 @@
# TODO: remove this and push AR stuff into ORM adapter
module ActiveRecord
class Base
- end
+ end
end
module DataMapper
@@ -13,7 +13,7 @@ class Model
describe Pickle::Session do
include Pickle::Session
-
+
let :user_class do
mock("User class", :name => 'User')
end
@@ -21,15 +21,15 @@ class Model
let :user do
mock("user", :class => user_class, :id => 1)
end
-
+
let :user_factory do
Pickle::Adapter::ActiveRecord.new(user_class)
end
-
+
before do
config.stub(:factories).and_return('user' => user_factory)
end
-
+
describe "Pickle::Session proxy missing methods to parser", :shared => true do
it "should forward to pickle_parser it responds_to them" do
subject.pickle_parser.should_receive(:parse_model)
@@ -45,17 +45,17 @@ class Model
subject do
self
end
-
+
it_should_behave_like "Pickle::Session proxy missing methods to parser"
end
describe "extending Pickle::Session" do
- subject do
+ subject do
returning Object.new do |object|
object.extend Pickle::Session
end
end
-
+
it_should_behave_like "Pickle::Session proxy missing methods to parser"
end
@@ -88,11 +88,11 @@ class Model
before do
Pickle::Adapter.stub!(:get_model).with(user_class, 100).and_return(user_from_db)
end
-
+
it "models('user') should be array containing user" do
models('user').should == [user_from_db]
end
-
+
describe "user should be retrievable with" do
it "model('the user')" do
model('the user').should == user_from_db
@@ -105,79 +105,79 @@ class Model
it "model('last user')" do
model('last user').should == user_from_db
end
-
+
it "model!('last user')" do
model('last user').should == user_from_db
end
end
end
end
-
+
describe "#create_model" do
before do
user_factory.stub!(:create).and_return(user)
end
-
+
describe "('a user')" do
it "should call user_factory.create({})" do
user_factory.should_receive(:create).with({})
create_model('a user')
end
-
+
describe "after create," do
before { create_model('a user') }
-
+
it_should_behave_like "after storing a single user"
end
end
-
+
describe "('1 user', 'foo: \"bar\", baz: \"bing bong\"')" do
it "should call user_factory.create({'foo' => 'bar', 'baz' => 'bing bong'})" do
user_factory.should_receive(:create).with({'foo' => 'bar', 'baz' => 'bing bong'})
create_model('1 user', 'foo: "bar", baz: "bing bong"')
end
-
+
describe "after create," do
before { create_model('1 user', 'foo: "bar", baz: "bing bong"') }
-
+
it_should_behave_like "after storing a single user"
end
- end
+ end
describe "('an user: \"fred\")" do
it "should call user_factory.create({})" do
user_factory.should_receive(:create).with({})
create_model('an user: "fred"')
end
-
+
describe "after create," do
before { create_model('an user: "fred"') }
-
+
it_should_behave_like "after storing a single user"
-
+
it "created_model('the user: \"fred\"') should retrieve the user" do
created_model('the user: "fred"').should == user
end
-
+
it "created_model?('the user: \"shirl\"') should be false" do
created_model?('the user: "shirl"').should == false
end
-
+
it "model?('the user: \"shirl\"') should be false" do
model?('the user: "shirl"').should == false
end
end
end
-
+
describe "with hash" do
it "should call user_factory.create({'foo' => 'bar'})" do
user_factory.should_receive(:create).with({'foo' => 'bar'})
create_model('a user', {'foo' => 'bar'}).should == user
end
-
+
describe "after create," do
before { create_model('a user', {'foo' => 'bar'}) }
-
+
it_should_behave_like "after storing a single user"
end
end
@@ -187,60 +187,60 @@ class Model
before do
Pickle::Adapter.stub!(:find_first_model).with(user_class, anything).and_return(user)
end
-
+
it "should call user_class.find :first, :conditions => {}" do
find_model('a user', 'hair: "pink"').should == user
end
-
+
describe "after find," do
before { find_model('a user', 'hair: "pink"') }
-
+
it_should_behave_like "after storing a single user"
end
-
+
describe "with hash" do
it "should call user_class.find('user', {'foo' => 'bar'})" do
find_model('a user', {'foo' => 'bar'})
end
-
+
describe "after find," do
before { find_model('a user', {'foo' => 'bar'}) }
-
+
it_should_behave_like "after storing a single user"
end
end
end
-
+
describe "create and find using plural_factory and table" do
context "when given a table without a matching pickle ref column" do
let :table do
mock(:hashes => [{'name' => 'Fred'}, {'name' => 'Betty'}])
end
-
+
it "#create_models_from_table(, ) should call create_model for each of the table hashes with plain factory name and return the models" do
should_receive(:create_model).with("user", 'name' => "Fred").once.ordered.and_return(:fred)
should_receive(:create_model).with("user", 'name' => "Betty").once.ordered.and_return(:betty)
create_models_from_table("users", table).should == [:fred, :betty]
end
-
+
it "#find_models_from_table(, ) should call find_model for each of the table hashes with plain factory name and return the models" do
should_receive(:find_model).with("user", 'name' => "Fred").once.ordered.and_return(:fred)
should_receive(:find_model).with("user", 'name' => "Betty").once.ordered.and_return(:betty)
find_models_from_table("users", table).should == [:fred, :betty]
end
end
-
+
context "when given a table with a matching pickle ref column" do
let :table do
mock(:hashes => [{'user' => "fred", 'name' => 'Fred'}, {'user' => "betty", 'name' => 'Betty'}])
end
-
+
it "#create_models_from_table(, ) should call create_model for each of the table hashes with labelled pickle ref" do
should_receive(:create_model).with("user \"fred\"", 'name' => "Fred").once.ordered.and_return(:fred)
should_receive(:create_model).with("user \"betty\"", 'name' => "Betty").once.ordered.and_return(:betty)
create_models_from_table("users", table).should == [:fred, :betty]
end
-
+
it "#find_models_from_table(, ) should call find_model for each of the table hashes with labelled pickle ref" do
should_receive(:find_model).with("user \"fred\"", 'name' => "Fred").once.ordered.and_return(:fred)
should_receive(:find_model).with("user \"betty\"", 'name' => "Betty").once.ordered.and_return(:betty)
@@ -248,7 +248,7 @@ class Model
end
end
end
-
+
describe "#find_model!" do
it "should call find_model" do
should_receive(:find_model).with('name', 'fields').and_return(user)
@@ -260,7 +260,7 @@ class Model
lambda { find_model!('name', 'fields') }.should raise_error(RuntimeError, "Can't find pickle model: 'name' in this scenario")
end
end
-
+
describe "#find_models" do
before do
Pickle::Adapter.stub!(:find_all_models).with(user_class, anything).and_return([user])
@@ -276,47 +276,47 @@ class Model
it_should_behave_like "after storing a single user"
end
end
-
+
describe 'creating \'a super admin: "fred"\', then \'a user: "shirl"\', \'then 1 super_admin\' (super_admin is factory that returns users)' do
let(:fred) { mock("fred", :class => user_class, :id => 2) }
let(:shirl) { mock("shirl", :class => user_class, :id => 3) }
let(:noname) { mock("noname", :class => user_class, :is => 4) }
-
+
let(:super_admin_factory) do
Pickle::Adapter::FactoryGirl.new(mock(:build_class => user_class, :factory_name => :super_admin))
end
-
+
before do
config.stub(:factories).and_return(user_factory.name => user_factory, super_admin_factory.name => super_admin_factory)
user_factory.stub(:create).and_return(shirl)
super_admin_factory.stub(:create).and_return(fred, noname)
end
-
+
def do_create_users
create_model('a super admin: "fred"')
create_model('a user: "shirl"')
create_model('1 super_admin')
end
-
+
it "should call Factory.create with <'super_admin'>, <'user'>, <'super_admin'>" do
super_admin_factory.should_receive(:create).with({}).twice
user_factory.should_receive(:create).with({}).once
do_create_users
end
-
+
describe "after create," do
before do
do_create_users
end
-
+
it "created_models('user') should == [fred, shirl, noname]" do
created_models('user').should == [fred, shirl, noname]
end
-
+
it "created_models('super_admin') should == [fred, noname]" do
created_models('super_admin').should == [fred, noname]
end
-
+
describe "#created_model" do
it "'that user' should be noname (the last user created - as super_admins are users)" do
created_model('that user').should == noname
@@ -325,27 +325,27 @@ def do_create_users
it "'the super admin' should be noname (the last super admin created)" do
created_model('that super admin').should == noname
end
-
+
it "'the 1st super admin' should be fred" do
created_model('the 1st super admin').should == fred
end
-
+
it "'the first user' should be fred" do
created_model('the first user').should == fred
end
-
+
it "'the 2nd user' should be shirl" do
created_model('the 2nd user').should == shirl
end
-
+
it "'the last user' should be noname" do
created_model('the last user').should == noname
end
-
+
it "'the user: \"fred\" should be fred" do
created_model('the user: "fred"').should == fred
end
-
+
it "'the user: \"shirl\" should be shirl" do
created_model('the user: "shirl"').should == shirl
end
@@ -361,7 +361,7 @@ def do_create_users
user_factory.stub!(:create).and_return(user)
create_model('the user: "me"')
end
-
+
it 'model("I") should return the user' do
model('I').should == user
end
@@ -369,11 +369,11 @@ def do_create_users
it 'model("myself") should return the user' do
model('myself').should == user
end
-
+
it "#parser.parse_fields 'author: user \"JIM\"' should raise Error, as model deos not refer" do
lambda { pickle_parser.parse_fields('author: user "JIM"') }.should raise_error
end
-
+
it "#parser.parse_fields 'author: the user' should return {\"author\" => }" do
pickle_parser.parse_fields('author: the user').should == {"author" => user}
end
@@ -381,34 +381,34 @@ def do_create_users
it "#parser.parse_fields 'author: myself' should return {\"author\" => }" do
pickle_parser.parse_fields('author: myself').should == {"author" => user}
end
-
+
it "#parser.parse_fields 'author: the user, approver: I, rating: \"5\"' should return {'author' => , 'approver' => , 'rating' => '5'}" do
pickle_parser.parse_fields('author: the user, approver: I, rating: "5"').should == {'author' => user, 'approver' => user, 'rating' => '5'}
end
-
+
it "#parser.parse_fields 'author: user: \"me\", approver: \"\"' should return {'author' => , 'approver' => \"\"}" do
pickle_parser.parse_fields('author: user: "me", approver: ""').should == {'author' => user, 'approver' => ""}
end
end
-
+
describe "convert_models_to_attributes(ar_class, :user => )" do
before do
user.stub(:is_a?).with(ActiveRecord::Base).and_return(true)
end
-
+
describe "(when ar_class has column 'user_id')" do
let :ar_class do
- mock('ActiveRecord', :column_names => ['user_id'])
+ mock('ActiveRecord', :column_names => ['user_id'], :const_get => ActiveRecord::Base::PickleAdapter)
end
-
+
it "should return {'user_id' => }" do
convert_models_to_attributes(ar_class, :user => user).should == {'user_id' => user.id}
end
end
-
+
describe "(when ar_class has columns 'user_id', 'user_type')" do
let :ar_class do
- mock('ActiveRecord', :column_names => ['user_id', 'user_type'])
+ mock('ActiveRecord', :column_names => ['user_id', 'user_type'], :const_get => ActiveRecord::Base::PickleAdapter)
end
it "should return {'user_id' => , 'user_type' => }" do
@@ -417,7 +417,7 @@ def do_create_users
end
end
end
-
+
it "#model!('unknown') should raise informative error message" do
lambda { model!('unknown') }.should raise_error("Can't find pickle model: 'unknown' in this scenario")
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 26832b4b..26dc9de8 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -1,6 +1,8 @@
require 'rubygems'
require 'spec'
require 'active_support'
+require 'active_record'
$:.unshift(File.dirname(__FILE__) + '/../lib')
require 'pickle'
+require 'pickle/adapters/active_record'