Permalink
Browse files

Merged with knaveofdiamonds/master

  • Loading branch information...
2 parents b1c7ade + b3587be commit 454ba38a92435e7591198c2c02c05e547a5194c6 @pk pk committed Jul 6, 2009
Showing with 71 additions and 71 deletions.
  1. +2 −2 README.markdown
  2. +7 −26 lib/machinist/sequel.rb
  3. +62 −43 spec/sequel_spec.rb
View
4 README.markdown
@@ -65,7 +65,7 @@ Create a `blueprints.rb` file to hold your blueprints in your test (or spec) dir
require 'machinist/active_record'
require 'sham'
-Substitute `data_mapper` for `active_record` if that's your weapon of choice.
+Substitute `data_mapper` or `sequel` for `active_record` if that's your weapon of choice.
Require `blueprints.rb` in your `test_helper.rb` (or `spec_helper.rb`):
@@ -154,7 +154,7 @@ If you don't supply a block for an attribute in the blueprint, Machinist will lo
body
end
-If you want to generate an object without saving it to the database, replace `make` with `make_unsaved`. (`make_unsaved` also ensures that any associated objects that need to be generated are not saved. See the section on associations below.)
+If you want to generate an object without saving it to the database, replace `make` with `make_unsaved`. (`make_unsaved` also ensures that any associated objects that need to be generated are not saved - although not if you are using Sequel. See the section on associations below.)
You can refer to already assigned attributes when constructing a new attribute:
View
33 lib/machinist/sequel.rb
@@ -3,37 +3,22 @@
require 'sequel'
module Machinist
-
class SequelAdapter
-
def self.has_association?(object, attribute)
- object.class.associations.include? attribute
+ object.class.associations.include?(attribute)
end
def self.class_for_association(object, attribute)
- association = object.class.association_reflection(attribute)
- association && Module.const_get(association[:class_name].to_sym)
+ object.class.association_reflection(attribute).associated_class
end
- # This method takes care of converting any associated objects,
- # in the hash returned by Lathe#assigned_attributes, into their
- # object ids.
- #
- # For example, let's say we have blueprints like this:
- #
- # Post.blueprint { }
- # Comment.blueprint { post }
- #
- # Lathe#assigned_attributes will return { :post => ... }, but
- # we want to pass { :post_id => 1 } to a controller.
- #
- # This method takes care of cleaning this up.
def self.assigned_attributes_without_associations(lathe)
attributes = {}
lathe.assigned_attributes.each_pair do |attribute, value|
association = lathe.object.class.association_reflection(attribute)
if association && association[:type] == :many_to_one
- attributes[association[:key]] = value.id
+ key = association[:key] || association.default_key
+ attributes[key] = value.send(association.primary_key)
else
attributes[attribute] = value
end
@@ -43,18 +28,16 @@ def self.assigned_attributes_without_associations(lathe)
end
module SequelExtensions
-
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
-
def make(*args, &block)
lathe = Lathe.run(Machinist::SequelAdapter, self.new, *args)
unless Machinist.nerfed?
- lathe.object.save || raise("Save failed")
- lathe.object.reload
+ lathe.object.save
+ lathe.object.refresh
end
lathe.object(&block)
end
@@ -68,11 +51,9 @@ def make_unsaved(*args)
def plan(*args)
lathe = Lathe.run(Machinist::SequelAdapter, self.new, *args)
Machinist::SequelAdapter.assigned_attributes_without_associations(lathe)
- end
-
+ end
end
end
-
end
class Sequel::Model
View
105 spec/sequel_spec.rb
@@ -1,77 +1,97 @@
require File.dirname(__FILE__) + '/spec_helper'
require 'machinist/sequel'
-DB = Sequel.sqlite
+# We have to define this here because Sequel needs a DB connection
+# setup before you can define models
+DB = Sequel.sqlite(:logger => Logger.new(File.dirname(__FILE__) + "/log/test.log"))
DB.create_table :people do
primary_key :id
- String :name
- String :type
- String :password
- Boolean :admin
+ String :name
+ String :type
+ String :password
+ Boolean :admin, :default => false
end
DB.create_table :posts do
primary_key :id
- String :title
- String :body
- Boolean :published
+ String :title
+ String :body
+ Boolean :published, :default => true
end
DB.create_table :comments do
primary_key :id
- Integer :post_id
- Integer :author_id
+ Integer :post_id
+ Integer :author_id
+ String :body
end
-
-class Person < Sequel::Model
- plugin :validation_helpers
- def validate
- validates_max_length 10, :name, :allow_nil => true
+
+module MachinistSequelSpecs
+
+ class Person < Sequel::Model
+ set_restricted_columns :password
end
-end
-class Post < Sequel::Model
- one_to_many :comments
-end
+ class Post < Sequel::Model
+ one_to_many :comments, :class => "MachinistSequelSpecs::Comment"
+ end
-class Comment < Sequel::Model
- many_to_one :post
- many_to_one :author, :class => Person, :key => :author_id
-end
+ class Comment < Sequel::Model
+ many_to_one :post, :class => "MachinistSequelSpecs::Post"
+ many_to_one :author, :class => "MachinistSequelSpecs::Person"
+ end
-module MachinistSequelSpecs
+ describe Machinist, "Sequel adapter" do
- describe Machinist, "Sequel adapter" do
before(:each) do
Person.clear_blueprints!
Post.clear_blueprints!
Comment.clear_blueprints!
end
describe "make method" do
- it "should save constructed object" do
- Person.blueprint {}
+ it "should save the constructed object" do
+ Person.blueprint { }
person = Person.make
person.should_not be_new
end
-
+
it "should create and object through a many_to_one association" do
Post.blueprint { }
Comment.blueprint { post }
Comment.make.post.class.should == Post
end
-
- it "should create an object through a belongs_to association with a class_name attribute" do
+
+ it "should create an object through belongs_to association with a class_name attribute" do
Person.blueprint { }
Comment.blueprint { author }
Comment.make.author.class.should == Person
end
-
- it "should raise an exception if the object can't be saved" do
- Person.blueprint { }
- lambda { Person.make(:name => "More than ten characters") }.should raise_error(Sequel::ValidationFailed)
+
+ it "should allow setting a protected attribute in the blueprint" do
+ Person.blueprint do
+ password "Test"
+ end
+ Person.make.password.should == "Test"
+ end
+
+ it "should allow overriding a protected attribute" do
+ Person.blueprint do
+ password "Test"
+ end
+ Person.make(:password => "New").password.should == "New"
end
+
+ it "should allow setting the id attribute in a blueprint" do
+ Person.blueprint { id 12345 }
+ Person.make.id.should == 12345
+ end
+
+# it "should allow setting the type attribute in a blueprint" do
+# Person.blueprint { type "Person" }
+# Person.make.type.should == "Person"
+# end
end
describe "plan method" do
@@ -99,20 +119,20 @@ module MachinistSequelSpecs
end
end
+ # Note that building up an unsaved object graph using just the
+ # association methods is not possible in Sequel, so
+ # make_unsaved will break in amusing ways unless you manually
+ # override the setters.
+ #
+ # From sequel-talk "Sequel does not have such an API and will not be adding one"
+ # Feb 17
describe "make_unsaved method" do
it "should not save the constructed object" do
Person.blueprint { }
person = Person.make_unsaved
person.should be_new
end
-
- it "should not save associated objects" do
- Post.blueprint { }
- Comment.blueprint { post }
- comment = Comment.make_unsaved
- comment.post.should be_new
- end
-
+
it "should save objects made within a passed-in block" do
Post.blueprint { }
Comment.blueprint { }
@@ -122,6 +142,5 @@ module MachinistSequelSpecs
comment.should_not be_new
end
end
-
end
end

0 comments on commit 454ba38

Please sign in to comment.