diff --git a/lib/pickle/default_config.rb b/lib/pickle/default_config.rb new file mode 100644 index 00000000..5e576cdf --- /dev/null +++ b/lib/pickle/default_config.rb @@ -0,0 +1,10 @@ +module Pickle + # include this module to get a config attribute that defaults to Pickle.config if it is not set otherwise + module DefaultConfig + attr_writer :config + + def config + @config ||= Pickle.config + end + end +end \ No newline at end of file diff --git a/lib/pickle/dsl.rb b/lib/pickle/dsl.rb new file mode 100644 index 00000000..0aaf620a --- /dev/null +++ b/lib/pickle/dsl.rb @@ -0,0 +1,44 @@ +module Pickle + # included into cucumber scenarios via World(Pickle::Scenario) + # + # for more fine-grained access to the pickle session, see Pickle::Session::Api + module Dsl + include MakeMatcher + + # retrieve the model with the given pickle_ref from the pickle session, and re-find it from the database + # @raise Pickle::UnknownModelError + # @return Object the stored model + def model(pickle_ref) + pickle.retrieve_and_reload(pickle_ref) + end + + # does the model with given pickle_ref exist in the pickle session? + # @return falsy if pickle_ref not know, truthy otherwise + def model?(pickle_ref) + pickle.known?(pickle_ref) + end + + # make a model using the pickle_ref, and optional fields, and store it in the pickle session under its pickle_ref + # @return Object the newly made model + def make(pickle_ref, fields = nil) + pickle.make_and_store(pickle_ref, fields) + end + + # find a model using the given pickle_ref and optional fields, and store it in the pickle session under its pickle_ref + # @return Object the found object + def find(pickle_ref, fields = nil) + pickle.find_and_store(pickle_ref, fields) + end + + # find all models using the given plural factory name, and optional fields, and store them in the pickle session using the factory name + # @return Array array of found objects + def find_all(plural, fields = nil) + pickle.find_all_and_store(plural, fields) + end + + # the pickle session, @see Pickle::Session::Api + def pickle + @pickle ||= Pickle::Session.new + end + end +end \ No newline at end of file diff --git a/lib/pickle/ref.rb b/lib/pickle/ref.rb index 384a2a7b..ea14aab8 100644 --- a/lib/pickle/ref.rb +++ b/lib/pickle/ref.rb @@ -1,3 +1,6 @@ +require 'pickle/parser/matchers' +require 'pickle/parser/canonical' + module Pickle class InvalidPickleRefError < RuntimeError end @@ -23,7 +26,15 @@ def initialize(*args) args.any? ? parse_string(args.first) : parse_hash(options) validate! end - + + def to_s + "#{factory}#{" index:#{index}" if index}#{" \"#{label}\"" if label}" + end + + def inspect + "#" + end + protected def validate! raise InvalidPickleRefError, "#{inspect} requires a factory or label" if factory.blank? && label.blank? @@ -40,6 +51,7 @@ def parse_hash(orig) def parse_string(orig) str = orig.dup + apply_mappings!(str) @index = parse_index!(str) @factory = parse_factory!(str) @label = parse_label!(str) @@ -63,7 +75,8 @@ def parse_factory!(string) # parse the label, removing it if found # @return the label or nil def parse_label!(string) - remove_from_and_return_1st_capture!(string, /^(?: |: )?(#{match_quoted})/).try(:gsub, '"', '') + label = remove_from_and_return_1st_capture!(string, /^(?: |: )?(#{match_quoted})/) + label && label.gsub('"', '') end def remove_from_and_return_1st_capture!(string, regexp) @@ -80,5 +93,11 @@ def index_word_to_i(word) else word.gsub(/\D/,'').to_i - 1 end end + + def apply_mappings!(string) + config && config.mappings.each do |mapping| + string.sub! /^#{mapping.search}$/, mapping.replacement + end + end end end \ No newline at end of file diff --git a/lib/pickle/session.rb b/lib/pickle/session.rb index 727a9364..4aa59bd4 100644 --- a/lib/pickle/session.rb +++ b/lib/pickle/session.rb @@ -1,205 +1,24 @@ module Pickle - class ModelNotKnownError < RuntimeError - attr_reader :name - - def initialize(name, message = nil) - @name = name - @message = message || "The model: '#{name}' is not known in this scenario. Use #create_model to create, or #find_model to find, and store a reference in this scenario." - end - - def to_s - @message - end - end - + # a Pickle::Session holds everything together, may be included, or created as a standalone object with Pickle::Session.new + # (actually a Pickle::Session::Object) + # + # @see Pickle::Session::Api for a list of the main api methods module Session - class << self - def included(world_class) - proxy_to_pickle_parser(world_class) - end - - def extended(world_object) - proxy_to_pickle_parser(class << world_object; self; end) # metaclass is not 2.1 compatible - end - - protected - def proxy_to_pickle_parser(world_class) - world_class.class_eval do - unless methods.include?('method_missing_with_pickle_parser') - alias_method_chain :method_missing, :pickle_parser - alias_method_chain :respond_to?, :pickle_parser - end - end - end - end - - def create_model(pickle_ref, fields = nil) - factory, label = *parse_model(pickle_ref) - raise ArgumentError, "Can't create with an ordinal (e.g. 1st user)" if label.is_a?(Integer) - fields = fields.is_a?(Hash) ? parse_hash(fields) : parse_fields(fields) - record = pickle_config.factories[factory].create(fields) - store_model(factory, label, record) - record - end - - # if a column exists in the table which matches the singular factory name, this is used as the pickle ref - def create_models_from_table(plural_factory, table) - factory = plural_factory.singularize - table.hashes.map do |hash| - pickle_ref = factory + (hash[factory] ? " \"#{hash.delete(factory)}\"" : "") - create_model(pickle_ref, hash) - end - end - - def find_model(a_model_name, fields = nil) - factory, name = *parse_model(a_model_name) - - raise ArgumentError, "Can't find a model with an ordinal (e.g. 1st user)" if name.is_a?(Integer) - - model_class = pickle_config.factories[factory].klass - fields = fields.is_a?(Hash) ? parse_hash(fields) : parse_fields(fields) - conditions = convert_models_to_attributes(model_class, fields) - record = Pickle::Adapter.find_first_model(model_class, conditions) - - store_model(factory, name, record) if record - - record - end - - def find_model!(name, fields = nil) - find_model(name, fields) or raise ModelNotKnownError, name - end - - def find_models(factory, fields = nil) - factory = pickle_parser.canonical(factory) - - models_by_index(factory).clear - - model_class = pickle_config.factories[factory].klass - conditions = convert_models_to_attributes(model_class, parse_fields(fields)) - records = Pickle::Adapter.find_all_models(model_class, conditions) - - records.each {|record| store_model(factory, nil, record)} - end - - # if a column exists in the table which matches the singular factory name, this is used as the pickle ref - def find_models_from_table(plural_factory, table) - factory = plural_factory.singularize - table.hashes.map do |hash| - pickle_ref = factory + (hash[factory] ? " \"#{hash.delete(factory)}\"" : "") - find_model(pickle_ref, hash) - end - end - - # return the original model stored by create_model or find_model - def created_model(name) - factory, name_or_index = *parse_model(name) - - if name_or_index.blank? - models_by_index(factory).last - elsif name_or_index.is_a?(Integer) - models_by_index(factory)[name_or_index] - else - models_by_name(factory)[name_or_index] or raise ModelNotKnownError, name - end - end + include DefaultConfig + include Adapters + include Api - # predicate version which raises no errors - def created_model?(name) - (created_model(name) rescue nil) ? true : false + def jar + @jar ||= Pickle::Jar.new end - # return a newly selected model - def model(name) - model = created_model(name) - return nil unless model - Pickle::Adapter.get_model(model.class, model.id) - end - - # predicate version which raises no errors - def model?(name) - (model(name) rescue nil) ? true : false - end - - # like model, but raise an error if it can't be found - def model!(name) - model(name) or raise ModelNotKnownError, name - end - - # like created_model, but raise an error if it can't be found - def created_model!(name) - created_model(name) or raise ModelNotKnownError, name - end - - # return all original models of specified type - def created_models(factory) - models_by_index(factory) - end - - # return all models of specified type (freshly selected from the database) - def models(factory) - created_models(factory).map do |model| - Pickle::Adapter.get_model(model.class, model.id) - end - end - - def respond_to_with_pickle_parser?(method, include_private = false) - respond_to_without_pickle_parser?(method, include_private) || pickle_parser.respond_to?(method, include_private) - end - - protected - def method_missing_with_pickle_parser(method, *args, &block) - if pickle_parser.respond_to?(method) - pickle_parser.send(method, *args, &block) - else - method_missing_without_pickle_parser(method, *args, &block) - end - end - - def pickle_parser=(parser) - parser.session = self - @pickle_parser = parser - end - def pickle_parser - @pickle_parser or self.pickle_parser = Pickle.parser + class Object + include Pickle::Session end - def pickle_config - pickle_parser.config - end - - def convert_models_to_attributes(ar_class, attrs) - attrs.each do |key, val| - if ((defined?(ActiveRecord::Base) && val.is_a?(ActiveRecord::Base)) || - (defined?(DataMapper::Model) && val.is_a?(DataMapper::Model))) && - Pickle::Adapter.column_names(ar_class).include?("#{key}_id") - attrs["#{key}_id"] = val.id - attrs["#{key}_type"] = val.class.base_class.name if ar_class.column_names.include?("#{key}_type") - attrs.delete(key) - end - end - end - - def models_by_name(factory) - @models_by_name ||= {} - @models_by_name[pickle_parser.canonical(factory)] ||= {} - end - - def models_by_index(factory) - @models_by_index ||= {} - @models_by_index[pickle_parser.canonical(factory)] ||= [] - end - - # if the factory name != the model name, store under both names - def store_model(factory, name, record) - store_record(record.class.name, name, record) unless pickle_parser.canonical(factory) == pickle_parser.canonical(record.class.name) - store_record(factory, name, record) - end - - def store_record(factory, name, record) - models_by_name(factory)[name] = record - models_by_index(factory) << record + def self.new + Pickle::Session::Object.new end end -end +end \ No newline at end of file diff --git a/lib/pickle/session/api.rb b/lib/pickle/session/api.rb new file mode 100644 index 00000000..e305fe28 --- /dev/null +++ b/lib/pickle/session/api.rb @@ -0,0 +1,81 @@ +module Pickle + module Session + # pickle api is your gateway to making/finding/storing/retrieving models + # + # Terminology: + # make - creating a model in the db, probably using a factory/bluperint + # find - finding a model from the db + # store - remembering an existing model (in the pickle jar) + # retrieve - retrieving a remembered model (from the pickle jar) using a pickle ref + # + # Example use, in a cucumber scenario: + # + # # create and store fred, and store his site for later reference + # fred = pickle.make_and_store :factory => 'website_owner', :label => 'fred' + # pickle.store fred.site, :label => "fred's site" + # + # # check what models pickle knows of + # pickle.known?(:label => 'fred') # => true + # pickle.known?('website_owner') # => true + # pickle.known?('site') # => true + # pickle.known?('site "fred"') # => false + # + # # these are all ways of retrieving the site + # pickle.retrieve 'the site' + # pickle.retrieve :label => "fred's site" + # pickle.retrieve '"fred's site"' + # pickle.retrieve 'last site' + # pickle.retrieve('fred').site + # + # included into Pickle::Session + module Api + include Conversion + + # makes a model using the ref and fields, and stores it + def make_and_store(pickle_ref, fields = nil) + pickle_ref, fields = ref(pickle_ref), attributes(fields) + raise InvalidPickleRefError, "#{pickle_ref.inspect} must not contain an index for #make_and_store" if pickle_ref.index + jar.store make(pickle_ref, fields), pickle_ref + end + + # finds a model using the ref and fields, and stores it + def find_and_store(pickle_ref, fields = nil) + pickle_ref, fields = ref(pickle_ref), attributes(fields) + raise InvalidPickleRefError, "#{pickle_ref.inspect} must not contain an index for #make_and_store" if pickle_ref.index + jar.store find_first(pickle_ref, fields), pickle_ref + end + + # finds all models using a plural factory name and fields, and store them + def find_all_and_store(plural, fields = nil) + pickle_ref, fields = ref(plural.singularize), attributes(fields) + find_all(pickle_ref, fields).each do |model| + jar.store model, pickle_ref + end + end + + # store a given model, with the optional ref + def store(model, pickle_ref = nil) + pickle_ref ||= model.class.name + jar.store model, ref(pickle_ref) + end + + # retrieve a model that was stored previously, and re-find it + def retrieve_and_reload(pickle_ref) + pickle_ref = ref(pickle_ref) + reload jar.retrieve(pickle_ref), pickle_ref + end + + # retrieve an orignal model object that was stored previously + def retrieve(pickle_ref) + jar.retrieve ref(pickle_ref) + rescue Pickle::UnknownModelError + raise Pickle::UnknownModelError.new("#{pickle_ref.inspect} is not known in this session. Use #make_and_store, #find_and_store, or #store to store a model.") + end + + # is a model known? + def known?(pickle_ref) + jar.include? ref(pickle_ref) + end + end + end +end \ No newline at end of file diff --git a/lib/pickle/session/conversion.rb b/lib/pickle/session/conversion.rb new file mode 100644 index 00000000..f83ad9c5 --- /dev/null +++ b/lib/pickle/session/conversion.rb @@ -0,0 +1,19 @@ +module Pickle + module Session + module Conversion + # convert a string, hash, or ref into a Pickle::Ref, using config + def ref(pickle_ref) + case pickle_ref + when Pickle::Ref then pickle_ref + when Hash then Pickle::Ref.new(pickle_ref.merge(:config => config)) + else Pickle::Ref.new(pickle_ref, :config => config) + end + end + + # convert a pickle fields string, or hash, into a hash that is suitable for adapters + def attributes(fields) + fields + end + end + end +end \ No newline at end of file diff --git a/lib/pickle/world.rb b/lib/pickle/world.rb index 345ff95b..fe55a984 100644 --- a/lib/pickle/world.rb +++ b/lib/pickle/world.rb @@ -1,14 +1,14 @@ require 'pickle' # auto require for active record, datamapper and mongoid -require 'pickle/adapters/active_record' if defined?(ActiveRecord::Base) -require 'pickle/adapters/data_mapper' if defined?(DataMapper::Resource) -require 'pickle/adapters/mongoid' if defined?(Mongoid::Document) +require 'pickle/orm_adapters/active_record' if defined?(ActiveRecord::Base) +require 'pickle/orm_adapters/data_mapper' if defined?(DataMapper::Resource) +require 'pickle/orm_adapters/mongoid' if defined?(Mongoid::Document) -# make cucumber world pickle aware -World(Pickle::Session) +# make cucumber pickle aware +World(Pickle::Dsl) # shortcuts to regexps for use in step definition regexps class << self - delegate :capture_model, :capture_fields, :capture_factory, :capture_plural_factory, :capture_predicate, :capture_value, :to => 'Pickle.parser' + delegate :pickle_ref, :pickle_plural, :pickle_fields, :pickle_predicate, :to => 'Pickle.parser' end diff --git a/spec/pickle/adapter_spec.rb b/spec/pickle/adapter_spec.rb index 2617cb28..994e4bc3 100644 --- a/spec/pickle/adapter_spec.rb +++ b/spec/pickle/adapter_spec.rb @@ -3,7 +3,7 @@ require 'active_record' require 'factory_girl' require 'machinist/active_record' -require 'pickle/adapters/active_record' +require 'pickle/orm_adapters/active_record' describe Pickle::Adapter do it ".factories should raise NotImplementedError" do diff --git a/spec/pickle/config_spec.rb b/spec/pickle/config_spec.rb index 4ab3d61b..d9e25f37 100644 --- a/spec/pickle/config_spec.rb +++ b/spec/pickle/config_spec.rb @@ -9,7 +9,6 @@ its(:predicates) { should be_empty } its(:mappings) { should be_empty } its(:factories) { should be_empty } - its(:plural_factories) { should be_empty } its(:aliases) { should be_empty } its(:labels) { should be_empty } end diff --git a/spec/pickle/ref_spec.rb b/spec/pickle/ref_spec.rb index 9b54ce7f..4d706a64 100644 --- a/spec/pickle/ref_spec.rb +++ b/spec/pickle/ref_spec.rb @@ -131,8 +131,19 @@ end end - describe "(with config)" do - + describe "(config = Config.new" do + describe "{|c|.map 'I', :to => 'user: \"me\"'})" do + let(:config) { Pickle::Config.new {|c| c.map 'I', 'myself', 'the super fantastic orgazoid', :to => 'user: "me"' } } + + ['I', 'myself', 'the super fantastic orgazoid'].each do |arg| + describe ".new #{arg.inspect}, :config => config" do + subject { Pickle::Ref.new(arg, :config => config) } + its(:factory) { should == 'user' } + its(:label) { should == 'me' } + its(:index) { should be_nil } + end + end + end end end \ No newline at end of file diff --git a/spec/pickle/session/api_spec.rb b/spec/pickle/session/api_spec.rb new file mode 100644 index 00000000..9ae49e4b --- /dev/null +++ b/spec/pickle/session/api_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe Pickle::Api do + include Pickle::Api +end diff --git a/spec/pickle/session/conversion_spec.rb b/spec/pickle/session/conversion_spec.rb new file mode 100644 index 00000000..877ae31b --- /dev/null +++ b/spec/pickle/session/conversion_spec.rb @@ -0,0 +1,24 @@ +require 'spec_helper' + +describe Pickle::Session::Conversion do + include Pickle::Session::Conversion + + describe "#ref" do + it " creates a new pickle ref using the hash, and my config" do + stub!(:config).and_return(mock) + Pickle::Ref.should_receive(:new).with({:foo => :bar, :config => config}).and_return(pickle_ref = mock) + ref({:foo => :bar}).should == pickle_ref + end + + it " creates a new pickle ref using the string, and my config" do + stub!(:config).and_return(mock) + Pickle::Ref.should_receive(:new).with('foo bar', {:config => config}).and_return(pickle_ref = mock) + ref('foo bar').should == pickle_ref + end + + it " just returns the pickle_ref" do + pickle_ref = Pickle::Ref.new('factory') + ref(pickle_ref).should == pickle_ref + end + end +end diff --git a/spec/pickle/session_spec.rb b/spec/pickle/session_spec.rb index 0c8a32c8..e69de29b 100644 --- a/spec/pickle/session_spec.rb +++ b/spec/pickle/session_spec.rb @@ -1,434 +0,0 @@ -require 'spec_helper' - -# TODO: remove this and push AR stuff into ORM adapter -module ActiveRecord - class Base - end -end - -module DataMapper - class Model - end -end - -describe Pickle::Session do - include Pickle::Session - - let :user_class do - mock("User class", :name => 'User') - end - - let :user do - mock("user", :class => user_class, :id => 1) - end - - let :user_factory do - Pickle::Adapter::Orm.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) - subject.parse_model - end - - it "should raise error if pickle_parser don't know about em" do - lambda { subject.parse_infinity }.should raise_error - end - end - - describe "including Pickle::Session" do - subject do - self - end - - it_should_behave_like "Pickle::Session proxy missing methods to parser" - end - - describe "extending Pickle::Session" 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 - - describe "after storing a single user", :shared => true do - it "created_models('user') should be array containing the original user" do - created_models('user').should == [user] - end - - describe "the original user should be retrievable with" do - it "created_model('the user')" do - created_model('the user').should == user - end - - it "created_model('1st user')" do - created_model('1st user').should == user - end - - it "created_model('last user')" do - created_model('last user').should == user - end - end - - describe "(found from db)" do - let :user_from_db do - returning user.dup do |from_db| - from_db.stub!(:id).and_return(100) - end - end - - 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 - end - - it "model('1st user')" do - model('1st user').should == user_from_db - end - - 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 - - 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 - end - - describe '#find_model' do - 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) - find_models_from_table("users", table).should == [:fred, :betty] - end - end - end - - describe "#find_model!" do - it "should call find_model" do - should_receive(:find_model).with('name', 'fields').and_return(user) - find_model!('name', 'fields') - end - - it "should call raise error if find_model returns nil" do - should_receive(:find_model).with('name', 'fields').and_return(nil) - lambda { find_model!('name', 'fields') }.should raise_error(Pickle::ModelNotKnownError) - end - end - - describe "#find_models" do - before do - Pickle::Adapter.stub!(:find_all_models).with(user_class, anything).and_return([user]) - end - - it "should call User.find :all, :conditions => {'hair' => 'pink'}" do - find_models('user', 'hair: "pink"').should == [user] - end - - describe "after find," do - before { find_models('user', 'hair: "pink"') } - - it_should_behave_like "after storing a single user" - end - - it "should cope with spaces in the factory name (ie. it should make it canonical)" do - pickle_parser.stub!(:canonical).and_return('user') - pickle_parser.should_receive(:canonical).with('u ser').and_return('user') - find_models('u ser', 'hair: "pink"').should == [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 - end - - 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 - end - end - end - - describe "when 'the user: \"me\"' exists and there is a mapping from 'I', 'myself' => 'user: \"me\"" do - before do - self.pickle_parser = Pickle::Parser.new(:config => Pickle::Config.new {|c| c.map 'I', 'myself', :to => 'user: "me"'}) - config.stub(:factories).and_return('user' => user_factory) - Pickle::Adapter.stub!(:get_model).with(user_class, anything).and_return(user) - 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 - - 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 - - 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'], :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'], :const_get => ActiveRecord::Base::PickleAdapter) - end - - it "should return {'user_id' => , 'user_type' => }" do - user.class.should_receive(:base_class).and_return(mock('User base class', :name => 'UserBase')) - convert_models_to_attributes(ar_class, :user => user).should == {'user_id' => user.id, 'user_type' => 'UserBase'} - end - end - end - - it "#model!('unknown') should raise informative error message" do - lambda { model!('unknown') }.should raise_error(Pickle::ModelNotKnownError, "The model: 'unknown' is not known in this scenario. Use #create_model to create, or #find_model to find, and store a reference in this scenario.") - end - - it "#created_model!('unknown') should raise informative error message" do - lambda { created_model!('unknown') }.should raise_error(Pickle::ModelNotKnownError) - end -end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 26dc9de8..dd10d954 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -4,5 +4,4 @@ require 'active_record' $:.unshift(File.dirname(__FILE__) + '/../lib') -require 'pickle' -require 'pickle/adapters/active_record' +require 'pickle' \ No newline at end of file