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.
@@ -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
+
@@ -0,0 +1 @@
1
+ *.sqlite3
@@ -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
@@ -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