machinist 1.0.5 → 1.0.6
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.
- data/.autotest +7 -0
- data/.gitignore +4 -0
- data/FAQ.markdown +18 -0
- data/MIT-LICENSE +20 -0
- data/README.markdown +317 -0
- data/Rakefile +37 -0
- data/VERSION +1 -0
- data/init.rb +2 -0
- data/lib/machinist/active_record.rb +1 -1
- data/machinist.gemspec +72 -0
- data/spec/active_record_spec.rb +194 -0
- data/spec/data_mapper_spec.rb +134 -0
- data/spec/db/.gitignore +1 -0
- data/spec/db/schema.rb +20 -0
- data/spec/log/.gitignore +1 -0
- data/spec/machinist_spec.rb +190 -0
- data/spec/sequel_spec.rb +146 -0
- data/spec/sham_spec.rb +95 -0
- data/spec/spec_helper.rb +9 -0
- metadata +47 -14
@@ -0,0 +1,194 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
require 'machinist/active_record'
|
3
|
+
require 'active_support/whiny_nil'
|
4
|
+
|
5
|
+
module MachinistActiveRecordSpecs
|
6
|
+
|
7
|
+
class Person < ActiveRecord::Base
|
8
|
+
attr_protected :password
|
9
|
+
end
|
10
|
+
|
11
|
+
class Admin < Person
|
12
|
+
end
|
13
|
+
|
14
|
+
class Post < ActiveRecord::Base
|
15
|
+
has_many :comments
|
16
|
+
end
|
17
|
+
|
18
|
+
class Comment < ActiveRecord::Base
|
19
|
+
belongs_to :post
|
20
|
+
belongs_to :author, :class_name => "Person"
|
21
|
+
end
|
22
|
+
|
23
|
+
describe Machinist, "ActiveRecord adapter" do
|
24
|
+
before(:suite) do
|
25
|
+
ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/log/test.log")
|
26
|
+
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
|
27
|
+
load(File.dirname(__FILE__) + "/db/schema.rb")
|
28
|
+
end
|
29
|
+
|
30
|
+
before(:each) do
|
31
|
+
[Person, Admin, Post, Comment].each(&:clear_blueprints!)
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "make method" do
|
35
|
+
it "should support single-table inheritance" do
|
36
|
+
Person.blueprint { }
|
37
|
+
Admin.blueprint { }
|
38
|
+
admin = Admin.make
|
39
|
+
admin.should_not be_new_record
|
40
|
+
admin.type.should == "Admin"
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should save the constructed object" do
|
44
|
+
Person.blueprint { }
|
45
|
+
person = Person.make
|
46
|
+
person.should_not be_new_record
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should create an object through belongs_to association" do
|
50
|
+
Post.blueprint { }
|
51
|
+
Comment.blueprint { post }
|
52
|
+
Comment.make.post.class.should == Post
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should create an object through belongs_to association with a class_name attribute" do
|
56
|
+
Person.blueprint { }
|
57
|
+
Comment.blueprint { author }
|
58
|
+
Comment.make.author.class.should == Person
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should create an object through belongs_to association using a named blueprint" do
|
62
|
+
Post.blueprint { }
|
63
|
+
Post.blueprint(:dummy) { title 'Dummy Post' }
|
64
|
+
Comment.blueprint { post(:dummy) }
|
65
|
+
Comment.make.post.title.should == 'Dummy Post'
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should allow creating an object through a has_many association" do
|
69
|
+
Post.blueprint do
|
70
|
+
comments { [Comment.make] }
|
71
|
+
end
|
72
|
+
Comment.blueprint { }
|
73
|
+
Post.make.comments.should have(1).instance_of(Comment)
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should allow setting a protected attribute in the blueprint" do
|
77
|
+
Person.blueprint do
|
78
|
+
password "Test"
|
79
|
+
end
|
80
|
+
Person.make.password.should == "Test"
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should allow overriding a protected attribute" do
|
84
|
+
Person.blueprint do
|
85
|
+
password "Test"
|
86
|
+
end
|
87
|
+
Person.make(:password => "New").password.should == "New"
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should allow setting the id attribute in a blueprint" do
|
91
|
+
Person.blueprint { id 12345 }
|
92
|
+
Person.make.id.should == 12345
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should allow setting the type attribute in a blueprint" do
|
96
|
+
Person.blueprint { type "Person" }
|
97
|
+
Person.make.type.should == "Person"
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "on a has_many association" do
|
101
|
+
before do
|
102
|
+
Post.blueprint { }
|
103
|
+
Comment.blueprint { post }
|
104
|
+
@post = Post.make
|
105
|
+
@comment = @post.comments.make
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should save the created object" do
|
109
|
+
@comment.should_not be_new_record
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should set the parent association on the created object" do
|
113
|
+
@comment.post.should == @post
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe "plan method" do
|
119
|
+
it "should not save the constructed object" do
|
120
|
+
person_count = Person.count
|
121
|
+
Person.blueprint { }
|
122
|
+
person = Person.plan
|
123
|
+
Person.count.should == person_count
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should create an object through a belongs_to association, and return its id" do
|
127
|
+
Post.blueprint { }
|
128
|
+
Comment.blueprint { post }
|
129
|
+
post_count = Post.count
|
130
|
+
comment = Comment.plan
|
131
|
+
Post.count.should == post_count + 1
|
132
|
+
comment[:post].should be_nil
|
133
|
+
comment[:post_id].should_not be_nil
|
134
|
+
end
|
135
|
+
|
136
|
+
describe "on a belongs_to association" do
|
137
|
+
it "should allow explicitly setting the association to nil" do
|
138
|
+
Comment.blueprint { post }
|
139
|
+
Comment.blueprint(:no_post) { post { nil } }
|
140
|
+
lambda {
|
141
|
+
@comment = Comment.plan(:no_post)
|
142
|
+
}.should_not raise_error
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
describe "on a has_many association" do
|
147
|
+
before do
|
148
|
+
Post.blueprint { }
|
149
|
+
Comment.blueprint do
|
150
|
+
post
|
151
|
+
body { "Test" }
|
152
|
+
end
|
153
|
+
@post = Post.make
|
154
|
+
@post_count = Post.count
|
155
|
+
@comment = @post.comments.plan
|
156
|
+
end
|
157
|
+
|
158
|
+
it "should not include the parent in the returned hash" do
|
159
|
+
@comment[:post].should be_nil
|
160
|
+
@comment[:post_id].should be_nil
|
161
|
+
end
|
162
|
+
|
163
|
+
it "should not create an extra parent object" do
|
164
|
+
Post.count.should == @post_count
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
describe "make_unsaved method" do
|
170
|
+
it "should not save the constructed object" do
|
171
|
+
Person.blueprint { }
|
172
|
+
person = Person.make_unsaved
|
173
|
+
person.should be_new_record
|
174
|
+
end
|
175
|
+
|
176
|
+
it "should not save associated objects" do
|
177
|
+
Post.blueprint { }
|
178
|
+
Comment.blueprint { post }
|
179
|
+
comment = Comment.make_unsaved
|
180
|
+
comment.post.should be_new_record
|
181
|
+
end
|
182
|
+
|
183
|
+
it "should save objects made within a passed-in block" do
|
184
|
+
Post.blueprint { }
|
185
|
+
Comment.blueprint { }
|
186
|
+
comment = nil
|
187
|
+
post = Post.make_unsaved { comment = Comment.make }
|
188
|
+
post.should be_new_record
|
189
|
+
comment.should_not be_new_record
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|
194
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
require 'machinist/data_mapper'
|
3
|
+
require 'dm-validations'
|
4
|
+
|
5
|
+
module MachinistDataMapperSpecs
|
6
|
+
|
7
|
+
class Person
|
8
|
+
include DataMapper::Resource
|
9
|
+
property :id, Serial
|
10
|
+
property :name, String, :length => (0..10)
|
11
|
+
property :type, Discriminator
|
12
|
+
property :password, String
|
13
|
+
property :admin, Boolean, :default => false
|
14
|
+
end
|
15
|
+
|
16
|
+
class Admin < Person
|
17
|
+
end
|
18
|
+
|
19
|
+
class Post
|
20
|
+
include DataMapper::Resource
|
21
|
+
property :id, Serial
|
22
|
+
property :title, String
|
23
|
+
property :body, Text
|
24
|
+
property :published, Boolean, :default => true
|
25
|
+
has n, :comments
|
26
|
+
end
|
27
|
+
|
28
|
+
class Comment
|
29
|
+
include DataMapper::Resource
|
30
|
+
property :id, Serial
|
31
|
+
property :post_id, Integer
|
32
|
+
property :author_id, Integer
|
33
|
+
belongs_to :post
|
34
|
+
belongs_to :author, :model => "Person", :child_key => [:author_id]
|
35
|
+
end
|
36
|
+
|
37
|
+
describe Machinist, "DataMapper adapter" do
|
38
|
+
before(:suite) do
|
39
|
+
DataMapper::Logger.new(File.dirname(__FILE__) + "/log/test.log", :debug)
|
40
|
+
DataMapper.setup(:default, "sqlite3::memory:")
|
41
|
+
DataMapper.auto_migrate!
|
42
|
+
end
|
43
|
+
|
44
|
+
before(:each) do
|
45
|
+
[Person, Admin, Post, Comment].each(&:clear_blueprints!)
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "make method" do
|
49
|
+
it "should support inheritance" do
|
50
|
+
Person.blueprint {}
|
51
|
+
Admin.blueprint {}
|
52
|
+
|
53
|
+
admin = Admin.make
|
54
|
+
admin.should_not be_new
|
55
|
+
admin.type.should_not be_nil
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should save the constructed object" do
|
59
|
+
Person.blueprint { }
|
60
|
+
person = Person.make
|
61
|
+
person.should_not be_new
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should create an object through a belongs_to association" do
|
65
|
+
Post.blueprint { }
|
66
|
+
Comment.blueprint { post }
|
67
|
+
Comment.make.post.class.should == Post
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
it "should create an object through a belongs_to association with a class_name attribute" do
|
72
|
+
Person.blueprint { }
|
73
|
+
Comment.blueprint { author }
|
74
|
+
Comment.make.author.class.should == Person
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should raise an exception if the object can't be saved" do
|
78
|
+
Person.blueprint { }
|
79
|
+
lambda { Person.make(:name => "More than ten characters") }.should raise_error(RuntimeError)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "plan method" do
|
84
|
+
it "should not save the constructed object" do
|
85
|
+
person_count = Person.all.length
|
86
|
+
Person.blueprint { }
|
87
|
+
person = Person.plan
|
88
|
+
Person.all.length.should == person_count
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should return a regular attribute in the hash" do
|
92
|
+
Post.blueprint { title "Test" }
|
93
|
+
post = Post.plan
|
94
|
+
post[:title].should == "Test"
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should create an object through a belongs_to association, and return its id" do
|
98
|
+
Post.blueprint { }
|
99
|
+
Comment.blueprint { post }
|
100
|
+
post_count = Post.all.length
|
101
|
+
comment = Comment.plan
|
102
|
+
Post.all.length.should == post_count + 1
|
103
|
+
comment[:post].should be_nil
|
104
|
+
comment[:post_id].should_not be_nil
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe "make_unsaved method" do
|
109
|
+
it "should not save the constructed object" do
|
110
|
+
Person.blueprint { }
|
111
|
+
person = Person.make_unsaved
|
112
|
+
person.should be_new
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should not save associated objects" do
|
116
|
+
Post.blueprint { }
|
117
|
+
Comment.blueprint { post }
|
118
|
+
comment = Comment.make_unsaved
|
119
|
+
comment.post.should be_new
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should save objects made within a passed-in block" do
|
123
|
+
Post.blueprint { }
|
124
|
+
Comment.blueprint { }
|
125
|
+
comment = nil
|
126
|
+
post = Post.make_unsaved { comment = Comment.make }
|
127
|
+
post.should be_new
|
128
|
+
comment.should_not be_new
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
data/spec/db/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
*.sqlite3
|
data/spec/db/schema.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
ActiveRecord::Schema.define(:version => 0) do
|
2
|
+
create_table :people, :force => true do |t|
|
3
|
+
t.column :name, :string
|
4
|
+
t.column :type, :string
|
5
|
+
t.column :password, :string
|
6
|
+
t.column :admin, :boolean, :default => false
|
7
|
+
end
|
8
|
+
|
9
|
+
create_table :posts, :force => true do |t|
|
10
|
+
t.column :title, :string
|
11
|
+
t.column :body, :text
|
12
|
+
t.column :published, :boolean, :default => true
|
13
|
+
end
|
14
|
+
|
15
|
+
create_table :comments, :force => true do |t|
|
16
|
+
t.column :post_id, :integer
|
17
|
+
t.column :author_id, :integer
|
18
|
+
t.column :body, :text
|
19
|
+
end
|
20
|
+
end
|
data/spec/log/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
*.log
|
@@ -0,0 +1,190 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
require 'machinist/object'
|
3
|
+
|
4
|
+
module MachinistSpecs
|
5
|
+
|
6
|
+
class Person
|
7
|
+
attr_accessor :name, :admin
|
8
|
+
end
|
9
|
+
|
10
|
+
class Post
|
11
|
+
attr_accessor :title, :body, :published
|
12
|
+
end
|
13
|
+
|
14
|
+
class Grandpa
|
15
|
+
attr_accessor :name
|
16
|
+
end
|
17
|
+
|
18
|
+
class Dad < Grandpa
|
19
|
+
attr_accessor :name
|
20
|
+
end
|
21
|
+
|
22
|
+
class Son < Dad
|
23
|
+
attr_accessor :name
|
24
|
+
end
|
25
|
+
|
26
|
+
describe Machinist do
|
27
|
+
before(:each) do
|
28
|
+
[Person, Post, Grandpa, Dad, Son].each(&:clear_blueprints!)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should raise for make on a class with no blueprint" do
|
32
|
+
lambda { Person.make }.should raise_error(RuntimeError)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should set an attribute on the constructed object from a constant in the blueprint" do
|
36
|
+
Person.blueprint do
|
37
|
+
name "Fred"
|
38
|
+
end
|
39
|
+
Person.make.name.should == "Fred"
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should set an attribute on the constructed object from a block in the blueprint" do
|
43
|
+
Person.blueprint do
|
44
|
+
name { "Fred" }
|
45
|
+
end
|
46
|
+
Person.make.name.should == "Fred"
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should default to calling Sham for an attribute in the blueprint" do
|
50
|
+
Sham.clear
|
51
|
+
Sham.name { "Fred" }
|
52
|
+
Person.blueprint { name }
|
53
|
+
Person.make.name.should == "Fred"
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should let the blueprint override an attribute with a default value" do
|
57
|
+
Post.blueprint do
|
58
|
+
published { false }
|
59
|
+
end
|
60
|
+
Post.make.published.should be_false
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should override an attribute from the blueprint with a passed-in attribute" do
|
64
|
+
Person.blueprint do
|
65
|
+
name "Fred"
|
66
|
+
end
|
67
|
+
Person.make(:name => "Bill").name.should == "Bill"
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should allow overridden attribute names to be strings" do
|
71
|
+
Person.blueprint do
|
72
|
+
name "Fred"
|
73
|
+
end
|
74
|
+
Person.make("name" => "Bill").name.should == "Bill"
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should not call a block in the blueprint if that attribute is passed in" do
|
78
|
+
block_called = false
|
79
|
+
Person.blueprint do
|
80
|
+
name { block_called = true; "Fred" }
|
81
|
+
end
|
82
|
+
Person.make(:name => "Bill").name.should == "Bill"
|
83
|
+
block_called.should be_false
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should call a passed-in block with the object being constructed" do
|
87
|
+
Person.blueprint { }
|
88
|
+
block_called = false
|
89
|
+
Person.make do |person|
|
90
|
+
block_called = true
|
91
|
+
person.class.should == Person
|
92
|
+
end
|
93
|
+
block_called.should be_true
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should provide access to the object being constructed from within the blueprint" do
|
97
|
+
person = nil
|
98
|
+
Person.blueprint { person = object }
|
99
|
+
Person.make
|
100
|
+
person.class.should == Person
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should allow reading of a previously assigned attribute from within the blueprint" do
|
104
|
+
Post.blueprint do
|
105
|
+
title "Test"
|
106
|
+
body { title }
|
107
|
+
end
|
108
|
+
Post.make.body.should == "Test"
|
109
|
+
end
|
110
|
+
|
111
|
+
describe "named blueprints" do
|
112
|
+
before do
|
113
|
+
@block_called = false
|
114
|
+
Person.blueprint do
|
115
|
+
name { "Fred" }
|
116
|
+
admin { @block_called = true; false }
|
117
|
+
end
|
118
|
+
Person.blueprint(:admin) do
|
119
|
+
admin { true }
|
120
|
+
end
|
121
|
+
@person = Person.make(:admin)
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should override an attribute from the parent blueprint in the child blueprint" do
|
125
|
+
@person.admin.should == true
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should not call the block for an attribute from the parent blueprint if that attribute is overridden in the child" do
|
129
|
+
@block_called.should be_false
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should set an attribute defined in the parent blueprint" do
|
133
|
+
@person.name.should == "Fred"
|
134
|
+
end
|
135
|
+
|
136
|
+
it "should return the correct list of named blueprints" do
|
137
|
+
Person.blueprint(:foo) { }
|
138
|
+
Person.blueprint(:bar) { }
|
139
|
+
Person.named_blueprints.to_set.should == [:admin, :foo, :bar].to_set
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
describe "blueprint inheritance" do
|
144
|
+
it "should inherit blueprinted attributes from the parent class" do
|
145
|
+
Dad.blueprint { name "Fred" }
|
146
|
+
Son.blueprint { }
|
147
|
+
Son.make.name.should == "Fred"
|
148
|
+
end
|
149
|
+
|
150
|
+
it "should override blueprinted attributes in the child class" do
|
151
|
+
Dad.blueprint { name "Fred" }
|
152
|
+
Son.blueprint { name "George" }
|
153
|
+
Dad.make.name.should == "Fred"
|
154
|
+
Son.make.name.should == "George"
|
155
|
+
end
|
156
|
+
|
157
|
+
it "should inherit from blueprinted attributes in ancestor class" do
|
158
|
+
Grandpa.blueprint { name "Fred" }
|
159
|
+
Son.blueprint { }
|
160
|
+
Grandpa.make.name.should == "Fred"
|
161
|
+
lambda { Dad.make }.should raise_error(RuntimeError)
|
162
|
+
Son.make.name.should == "Fred"
|
163
|
+
end
|
164
|
+
|
165
|
+
it "should follow inheritance for named blueprints correctly" do
|
166
|
+
Dad.blueprint { name "John" }
|
167
|
+
Dad.blueprint(:special) { name "Paul" }
|
168
|
+
Son.blueprint { }
|
169
|
+
Son.blueprint(:special) { }
|
170
|
+
Son.make(:special).name.should == "John"
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
describe "clear_blueprints! method" do
|
175
|
+
it "should clear the list of blueprints" do
|
176
|
+
Person.blueprint(:foo){}
|
177
|
+
Person.clear_blueprints!
|
178
|
+
Person.named_blueprints.should == []
|
179
|
+
end
|
180
|
+
|
181
|
+
it "should clear master blueprint too" do
|
182
|
+
Person.blueprint(:foo) {}
|
183
|
+
Person.blueprint {} # master
|
184
|
+
Person.clear_blueprints!
|
185
|
+
lambda { Person.make }.should raise_error(RuntimeError)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
190
|
+
end
|