Skip to content

Commit

Permalink
Added support for Sequel.
Browse files Browse the repository at this point in the history
  • Loading branch information
pk committed Jul 3, 2009
1 parent ff7b469 commit b1c7ade
Show file tree
Hide file tree
Showing 3 changed files with 209 additions and 1 deletion.
81 changes: 81 additions & 0 deletions lib/machinist/sequel.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
require 'machinist'
require 'machinist/blueprints'
require 'sequel'

module Machinist

class SequelAdapter

def self.has_association?(object, 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)
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
else
attributes[attribute] = value
end
end
attributes
end
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
end
lathe.object(&block)
end

def make_unsaved(*args)
returning(Machinist.with_save_nerfed { make(*args) }) do |object|
yield object if block_given?
end
end

def plan(*args)
lathe = Lathe.run(Machinist::SequelAdapter, self.new, *args)
Machinist::SequelAdapter.assigned_attributes_without_associations(lathe)
end

end
end

end

class Sequel::Model
include Machinist::Blueprints
include Machinist::SequelExtensions
end
2 changes: 1 addition & 1 deletion machinist.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Gem::Specification.new do |s|
s.email = "pete@nothat.com"
s.homepage = "http://github.com/notahat/machinist"
s.summary = "Fixtures aren't fun. Machinist is."
s.files = ["lib/machinist.rb", "lib/sham.rb", "lib/machinist/blueprints.rb", "lib/machinist/object.rb", "lib/machinist/active_record.rb", "lib/machinist/data_mapper.rb"]
s.files = ["lib/machinist.rb", "lib/sham.rb", "lib/machinist/blueprints.rb", "lib/machinist/object.rb", "lib/machinist/active_record.rb", "lib/machinist/data_mapper.rb", "lib/machinist/sequel.rb"]
s.require_path = "lib"
s.has_rdoc = false
end
127 changes: 127 additions & 0 deletions spec/sequel_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
require File.dirname(__FILE__) + '/spec_helper'
require 'machinist/sequel'

DB = Sequel.sqlite

DB.create_table :people do
primary_key :id
String :name
String :type
String :password
Boolean :admin
end

DB.create_table :posts do
primary_key :id
String :title
String :body
Boolean :published
end

DB.create_table :comments do
primary_key :id
Integer :post_id
Integer :author_id
end

class Person < Sequel::Model
plugin :validation_helpers
def validate
validates_max_length 10, :name, :allow_nil => true
end
end

class Post < Sequel::Model
one_to_many :comments
end

class Comment < Sequel::Model
many_to_one :post
many_to_one :author, :class => Person, :key => :author_id
end

module MachinistSequelSpecs

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 {}
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
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)
end
end

describe "plan method" do
it "should not save the constructed object" do
lambda {
Person.blueprint { }
person = Person.plan
}.should_not change(Person,:count)
end

it "should return a regular attribute in the hash" do
Post.blueprint { title "Test" }
post = Post.plan
post[:title].should == "Test"
end

it "should create an object through a many_to_one association, and return its id" do
Post.blueprint { }
Comment.blueprint { post }
lambda {
comment = Comment.plan
comment[:post].should be_nil
comment[:post_id].should_not be_nil
}.should change(Post, :count).by(1)
end
end

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 { }
comment = nil
post = Post.make_unsaved { comment = Comment.make }
post.should be_new
comment.should_not be_new
end
end

end
end

0 comments on commit b1c7ade

Please sign in to comment.