snusnu-dm-accepts_nested_attributes 0.0.1
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/.gitignore +23 -0
- data/History.txt +1 -0
- data/LICENSE +20 -0
- data/Manifest.txt +29 -0
- data/README.textile +250 -0
- data/Rakefile +32 -0
- data/TODO +3 -0
- data/lib/dm-accepts_nested_attributes.rb +18 -0
- data/lib/dm-accepts_nested_attributes/associations.rb +55 -0
- data/lib/dm-accepts_nested_attributes/nested_attributes.rb +300 -0
- data/lib/dm-accepts_nested_attributes/version.rb +7 -0
- data/spec/fixtures/person.rb +8 -0
- data/spec/fixtures/profile.rb +7 -0
- data/spec/fixtures/project.rb +8 -0
- data/spec/fixtures/project_membership.rb +8 -0
- data/spec/fixtures/task.rb +7 -0
- data/spec/integration/belongs_to_spec.rb +204 -0
- data/spec/integration/has_1_spec.rb +193 -0
- data/spec/integration/has_n_spec.rb +181 -0
- data/spec/integration/has_n_through_spec.rb +200 -0
- data/spec/shared/rspec_tmbundle_support.rb +35 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +58 -0
- data/spec/unit/accepts_nested_attributes_for_spec.rb +454 -0
- data/spec/unit/resource_spec.rb +174 -0
- data/tasks/gemspec.rb +10 -0
- data/tasks/hoe.rb +46 -0
- data/tasks/install.rb +15 -0
- data/tasks/spec.rb +25 -0
- metadata +103 -0
@@ -0,0 +1,181 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
|
3
|
+
|
4
|
+
describe DataMapper::NestedAttributes do
|
5
|
+
|
6
|
+
describe "every accessible has(n) association with a valid reject_if proc", :shared => true do
|
7
|
+
|
8
|
+
it "should not allow to create a new task via Project#tasks_attributes" do
|
9
|
+
@project.save
|
10
|
+
Project.all.size.should == 1
|
11
|
+
Task.all.size.should == 0
|
12
|
+
|
13
|
+
@project.tasks_attributes = { 'new_1' => { :name => 'write specs' } }
|
14
|
+
@project.tasks.should be_empty
|
15
|
+
@project.save
|
16
|
+
Project.all.size.should == 1
|
17
|
+
Task.all.size.should == 0
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "every accessible has(n) association with no reject_if proc", :shared => true do
|
23
|
+
|
24
|
+
it "should allow to create a new task via Project#tasks_attributes" do
|
25
|
+
@project.save
|
26
|
+
Project.all.size.should == 1
|
27
|
+
Task.all.size.should == 0
|
28
|
+
|
29
|
+
@project.tasks_attributes = { 'new_1' => { :name => 'write specs' } }
|
30
|
+
@project.tasks.should_not be_empty
|
31
|
+
@project.tasks.first.name.should == 'write specs'
|
32
|
+
@project.save
|
33
|
+
@project.tasks.first.should == Task.first
|
34
|
+
Project.all.size.should == 1
|
35
|
+
Task.all.size.should == 1
|
36
|
+
Task.first.name.should == 'write specs'
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should allow to update an existing task via Project#tasks_attributes" do
|
40
|
+
@project.save
|
41
|
+
task = Task.create(:project => @project, :name => 'write specs')
|
42
|
+
Project.all.size.should == 1
|
43
|
+
Task.all.size.should == 1
|
44
|
+
|
45
|
+
@project.tasks_attributes = { task.id.to_s => { :id => task.id, :name => 'write more specs' } }
|
46
|
+
@project.tasks.should_not be_empty
|
47
|
+
@project.tasks.first.name.should == 'write more specs'
|
48
|
+
@project.save
|
49
|
+
|
50
|
+
Project.all.size.should == 1
|
51
|
+
Task.all.size.should == 1
|
52
|
+
Task.first.name.should == 'write more specs'
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "every accessible has(n) association with :allow_destroy => false", :shared => true do
|
58
|
+
|
59
|
+
it "should not allow to delete an existing task via Profile#tasks_attributes" do
|
60
|
+
@project.save
|
61
|
+
task = Task.create(:project => @project, :name => 'write specs')
|
62
|
+
|
63
|
+
Project.all.size.should == 1
|
64
|
+
Task.all.size.should == 1
|
65
|
+
|
66
|
+
@project.reload
|
67
|
+
@project.tasks_attributes = { '1' => { :id => task.id, :_delete => true } }
|
68
|
+
@project.save
|
69
|
+
|
70
|
+
Project.all.size.should == 1
|
71
|
+
Task.all.size.should == 1
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "every accessible has(n) association with :allow_destroy => true", :shared => true do
|
77
|
+
|
78
|
+
it "should allow to delete an existing task via Profile#tasks_attributes" do
|
79
|
+
@project.save
|
80
|
+
task = Task.create(:project => @project, :name => 'write specs')
|
81
|
+
|
82
|
+
Project.all.size.should == 1
|
83
|
+
Task.all.size.should == 1
|
84
|
+
|
85
|
+
@project.reload
|
86
|
+
@project.tasks_attributes = { '1' => { :id => task.id, :_delete => true } }
|
87
|
+
@project.save
|
88
|
+
|
89
|
+
Project.all.size.should == 1
|
90
|
+
Task.all.size.should == 0
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
describe "Project.has(n, :tasks)" do
|
96
|
+
|
97
|
+
describe "accepts_nested_attributes_for(:tasks)" do
|
98
|
+
|
99
|
+
before(:each) do
|
100
|
+
DataMapper.auto_migrate!
|
101
|
+
Project.accepts_nested_attributes_for :tasks
|
102
|
+
@project = Project.new :name => 'trippings'
|
103
|
+
end
|
104
|
+
|
105
|
+
it_should_behave_like "every accessible has(n) association with no reject_if proc"
|
106
|
+
it_should_behave_like "every accessible has(n) association with :allow_destroy => false"
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
describe "accepts_nested_attributes_for(:tasks, :allow_destroy => false)" do
|
111
|
+
|
112
|
+
before(:each) do
|
113
|
+
DataMapper.auto_migrate!
|
114
|
+
Project.accepts_nested_attributes_for :tasks, :allow_destroy => false
|
115
|
+
@project = Project.new :name => 'trippings'
|
116
|
+
end
|
117
|
+
|
118
|
+
it_should_behave_like "every accessible has(n) association with no reject_if proc"
|
119
|
+
it_should_behave_like "every accessible has(n) association with :allow_destroy => false"
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
describe "accepts_nested_attributes_for(:tasks, :allow_destroy => true)" do
|
124
|
+
|
125
|
+
before(:each) do
|
126
|
+
DataMapper.auto_migrate!
|
127
|
+
Project.accepts_nested_attributes_for :tasks, :allow_destroy => true
|
128
|
+
@project = Project.new :name => 'trippings'
|
129
|
+
end
|
130
|
+
|
131
|
+
it_should_behave_like "every accessible has(n) association with no reject_if proc"
|
132
|
+
it_should_behave_like "every accessible has(n) association with :allow_destroy => true"
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
describe "accepts_nested_attributes_for :tasks, " do
|
137
|
+
|
138
|
+
describe ":reject_if => :foo" do
|
139
|
+
|
140
|
+
before(:each) do
|
141
|
+
DataMapper.auto_migrate!
|
142
|
+
Project.accepts_nested_attributes_for :tasks, :reject_if => :foo
|
143
|
+
@project = Project.new :name => 'trippings'
|
144
|
+
end
|
145
|
+
|
146
|
+
it_should_behave_like "every accessible has(n) association with no reject_if proc"
|
147
|
+
it_should_behave_like "every accessible has(n) association with :allow_destroy => false"
|
148
|
+
|
149
|
+
end
|
150
|
+
|
151
|
+
describe ":reject_if => lambda { |attrs| true }" do
|
152
|
+
|
153
|
+
before(:each) do
|
154
|
+
DataMapper.auto_migrate!
|
155
|
+
Project.accepts_nested_attributes_for :tasks, :reject_if => lambda { |attrs| true }
|
156
|
+
@project = Project.new :name => 'trippings'
|
157
|
+
end
|
158
|
+
|
159
|
+
it_should_behave_like "every accessible has(n) association with a valid reject_if proc"
|
160
|
+
it_should_behave_like "every accessible has(n) association with :allow_destroy => false"
|
161
|
+
|
162
|
+
end
|
163
|
+
|
164
|
+
describe ":reject_if => lambda { |attrs| false }" do
|
165
|
+
|
166
|
+
before(:each) do
|
167
|
+
DataMapper.auto_migrate!
|
168
|
+
Project.accepts_nested_attributes_for :tasks, :reject_if => lambda { |attrs| false }
|
169
|
+
@project = Project.new :name => 'trippings'
|
170
|
+
end
|
171
|
+
|
172
|
+
it_should_behave_like "every accessible has(n) association with no reject_if proc"
|
173
|
+
it_should_behave_like "every accessible has(n) association with :allow_destroy => false"
|
174
|
+
|
175
|
+
end
|
176
|
+
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
@@ -0,0 +1,200 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
|
3
|
+
|
4
|
+
describe DataMapper::NestedAttributes do
|
5
|
+
|
6
|
+
describe "every accessible has(n, :through) association with a valid reject_if proc", :shared => true do
|
7
|
+
|
8
|
+
it "should not allow to create a new project via Person#projects_attributes" do
|
9
|
+
@person.save
|
10
|
+
Person.all.size.should == 1
|
11
|
+
ProjectMembership.all.size.should == 0
|
12
|
+
Project.all.size.should == 0
|
13
|
+
|
14
|
+
@person.projects_attributes = { 'new_1' => { :name => 'dm-accepts_nested_attributes' } }
|
15
|
+
@person.projects.should be_empty
|
16
|
+
@person.save
|
17
|
+
|
18
|
+
Person.all.size.should == 1
|
19
|
+
ProjectMembership.all.size.should == 0
|
20
|
+
Project.all.size.should == 0
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "every accessible has(n, :through) association with no reject_if proc", :shared => true do
|
26
|
+
|
27
|
+
it "should allow to create a new project via Person#projects_attributes" do
|
28
|
+
@person.save
|
29
|
+
Person.all.size.should == 1
|
30
|
+
ProjectMembership.all.size.should == 0
|
31
|
+
Project.all.size.should == 0
|
32
|
+
|
33
|
+
@person.projects_attributes = { 'new_1' => { :name => 'dm-accepts_nested_attributes' } }
|
34
|
+
@person.projects.should_not be_empty
|
35
|
+
@person.projects.first.name.should == 'dm-accepts_nested_attributes'
|
36
|
+
@person.save
|
37
|
+
@person.projects.first.should == Project.first
|
38
|
+
|
39
|
+
Person.all.size.should == 1
|
40
|
+
ProjectMembership.all.size.should == 1
|
41
|
+
Project.all.size.should == 1
|
42
|
+
|
43
|
+
Project.first.name.should == 'dm-accepts_nested_attributes'
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should allow to update an existing project via Person#projects_attributes" do
|
47
|
+
@person.save
|
48
|
+
project = Project.create(:name => 'dm-accepts_nested_attributes')
|
49
|
+
project_membership = ProjectMembership.create(:person => @person, :project => project)
|
50
|
+
Person.all.size.should == 1
|
51
|
+
Project.all.size.should == 1
|
52
|
+
ProjectMembership.all.size.should == 1
|
53
|
+
|
54
|
+
@person.reload
|
55
|
+
|
56
|
+
@person.projects_attributes = { project.id.to_s => { :id => project.id, :name => 'still dm-accepts_nested_attributes' } }
|
57
|
+
@person.projects.should_not be_empty
|
58
|
+
@person.projects.first.name.should == 'still dm-accepts_nested_attributes'
|
59
|
+
@person.save
|
60
|
+
|
61
|
+
Person.all.size.should == 1
|
62
|
+
ProjectMembership.all.size.should == 1
|
63
|
+
Project.all.size.should == 1
|
64
|
+
|
65
|
+
Project.first.name.should == 'still dm-accepts_nested_attributes'
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "every accessible has(n, :through) association with :allow_destroy => false", :shared => true do
|
71
|
+
|
72
|
+
it "should not allow to delete an existing project via Person#projects_attributes" do
|
73
|
+
@person.save
|
74
|
+
project = Project.create(:name => 'dm-accepts_nested_attributes')
|
75
|
+
project_membership = ProjectMembership.create(:person => @person, :project => project)
|
76
|
+
|
77
|
+
Person.all.size.should == 1
|
78
|
+
ProjectMembership.all.size.should == 1
|
79
|
+
Project.all.size.should == 1
|
80
|
+
|
81
|
+
@person.reload
|
82
|
+
@person.projects_attributes = { '1' => { :id => project.id, :_delete => true } }
|
83
|
+
@person.save
|
84
|
+
|
85
|
+
Person.all.size.should == 1
|
86
|
+
ProjectMembership.all.size.should == 1
|
87
|
+
Project.all.size.should == 1
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "every accessible has(n, :through) association with :allow_destroy => true", :shared => true do
|
93
|
+
|
94
|
+
it "should allow to delete an existing project via Person#projects_attributes" do
|
95
|
+
@person.save
|
96
|
+
project = Project.create(:name => 'dm-accepts_nested_attributes')
|
97
|
+
project_membership = ProjectMembership.create(:person => @person, :project => project)
|
98
|
+
|
99
|
+
Person.all.size.should == 1
|
100
|
+
ProjectMembership.all.size.should == 1
|
101
|
+
Project.all.size.should == 1
|
102
|
+
|
103
|
+
@person.reload
|
104
|
+
@person.projects_attributes = { '1' => { :id => project.id, :_delete => true } }
|
105
|
+
@person.save
|
106
|
+
|
107
|
+
Person.all.size.should == 1
|
108
|
+
ProjectMembership.all.size.should == 0
|
109
|
+
Project.all.size.should == 0
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
describe "Person.has(n, :projects, :through => :project_memberships)" do
|
115
|
+
|
116
|
+
describe "accepts_nested_attributes_for(:projects)" do
|
117
|
+
|
118
|
+
before(:each) do
|
119
|
+
DataMapper.auto_migrate!
|
120
|
+
Person.accepts_nested_attributes_for :projects
|
121
|
+
@person = Person.new :name => 'snusnu'
|
122
|
+
end
|
123
|
+
|
124
|
+
it_should_behave_like "every accessible has(n, :through) association with no reject_if proc"
|
125
|
+
it_should_behave_like "every accessible has(n, :through) association with :allow_destroy => false"
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
describe "accepts_nested_attributes_for(:projects, :allow_destroy => false)" do
|
130
|
+
|
131
|
+
before(:each) do
|
132
|
+
DataMapper.auto_migrate!
|
133
|
+
Person.accepts_nested_attributes_for :projects, :allow_destroy => false
|
134
|
+
@person = Person.new :name => 'snusnu'
|
135
|
+
end
|
136
|
+
|
137
|
+
it_should_behave_like "every accessible has(n, :through) association with no reject_if proc"
|
138
|
+
it_should_behave_like "every accessible has(n, :through) association with :allow_destroy => false"
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
describe "accepts_nested_attributes_for(:projects, :allow_destroy = true)" do
|
143
|
+
|
144
|
+
before(:each) do
|
145
|
+
DataMapper.auto_migrate!
|
146
|
+
Person.accepts_nested_attributes_for :projects, :allow_destroy => true
|
147
|
+
@person = Person.new :name => 'snusnu'
|
148
|
+
end
|
149
|
+
|
150
|
+
it_should_behave_like "every accessible has(n, :through) association with no reject_if proc"
|
151
|
+
it_should_behave_like "every accessible has(n, :through) association with :allow_destroy => true"
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
describe "accepts_nested_attributes_for :projects, " do
|
156
|
+
|
157
|
+
describe ":reject_if => :foo" do
|
158
|
+
|
159
|
+
before(:each) do
|
160
|
+
DataMapper.auto_migrate!
|
161
|
+
Person.accepts_nested_attributes_for :projects, :reject_if => :foo
|
162
|
+
@person = Person.new :name => 'snusnu'
|
163
|
+
end
|
164
|
+
|
165
|
+
it_should_behave_like "every accessible has(n, :through) association with no reject_if proc"
|
166
|
+
it_should_behave_like "every accessible has(n, :through) association with :allow_destroy => false"
|
167
|
+
|
168
|
+
end
|
169
|
+
|
170
|
+
describe ":reject_if => lambda { |attrs| true }" do
|
171
|
+
|
172
|
+
before(:each) do
|
173
|
+
DataMapper.auto_migrate!
|
174
|
+
Person.accepts_nested_attributes_for :projects, :reject_if => lambda { |attrs| true }
|
175
|
+
@person = Person.new :name => 'snusnu'
|
176
|
+
end
|
177
|
+
|
178
|
+
it_should_behave_like "every accessible has(n, :through) association with a valid reject_if proc"
|
179
|
+
it_should_behave_like "every accessible has(n, :through) association with :allow_destroy => false"
|
180
|
+
|
181
|
+
end
|
182
|
+
|
183
|
+
describe ":reject_if => lambda { |attrs| false }" do
|
184
|
+
|
185
|
+
before(:each) do
|
186
|
+
DataMapper.auto_migrate!
|
187
|
+
Person.accepts_nested_attributes_for :projects, :reject_if => lambda { |attrs| false }
|
188
|
+
@person = Person.new :name => 'snusnu'
|
189
|
+
end
|
190
|
+
|
191
|
+
it_should_behave_like "every accessible has(n, :through) association with no reject_if proc"
|
192
|
+
it_should_behave_like "every accessible has(n, :through) association with :allow_destroy => false"
|
193
|
+
|
194
|
+
end
|
195
|
+
|
196
|
+
end
|
197
|
+
|
198
|
+
end
|
199
|
+
|
200
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# -----------------------------------------------
|
2
|
+
# support for nice html output in rspec tmbundle
|
3
|
+
# -----------------------------------------------
|
4
|
+
|
5
|
+
module RSpecTmBundleHelpers
|
6
|
+
|
7
|
+
class TextmateRspecLogger < DataMapper::Logger
|
8
|
+
def prep_msg(message, level)
|
9
|
+
"#{super}<br />"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def with_dm_logger(level = :debug)
|
14
|
+
DataMapper.logger.level = level
|
15
|
+
yield
|
16
|
+
ensure
|
17
|
+
DataMapper.logger.level = :off
|
18
|
+
end
|
19
|
+
|
20
|
+
def print_call_stack(from = 2, to = nil, html = true)
|
21
|
+
(from..(to ? to : caller.length)).each do |idx|
|
22
|
+
p "[#{idx}]: #{caller[idx]}#{html ? '<br />' : ''}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def puth(html)
|
27
|
+
print "#{h(html)}<br />"
|
28
|
+
end
|
29
|
+
|
30
|
+
ESCAPE_TABLE = { '&'=>'&', '<'=>'<', '>'=>'>', '"'=>'"', "'"=>''', }
|
31
|
+
def h(value)
|
32
|
+
value.to_s.gsub(/[&<>"]/) {|s| ESCAPE_TABLE[s] }
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'rubygems'
|
3
|
+
|
4
|
+
gem 'rspec', '>=1.1.12'
|
5
|
+
require 'spec'
|
6
|
+
|
7
|
+
gem 'dm-core', '0.9.11'
|
8
|
+
require 'dm-core'
|
9
|
+
|
10
|
+
gem 'dm-validations', '0.9.11'
|
11
|
+
require 'dm-validations'
|
12
|
+
|
13
|
+
require Pathname(__FILE__).dirname.parent.expand_path + 'lib/dm-accepts_nested_attributes'
|
14
|
+
|
15
|
+
ENV["SQLITE3_SPEC_URI"] ||= 'sqlite3::memory:'
|
16
|
+
ENV["MYSQL_SPEC_URI"] ||= 'mysql://localhost/dm_core_test'
|
17
|
+
ENV["POSTGRES_SPEC_URI"] ||= 'postgres://postgres@localhost/dm_more_test'
|
18
|
+
|
19
|
+
|
20
|
+
def setup_adapter(name, default_uri = nil)
|
21
|
+
begin
|
22
|
+
DataMapper.setup(name, ENV["#{ENV['ADAPTER'].to_s.upcase}_SPEC_URI"] || default_uri)
|
23
|
+
Object.const_set('ADAPTER', ENV['ADAPTER'].to_sym) if name.to_s == ENV['ADAPTER']
|
24
|
+
true
|
25
|
+
rescue Exception => e
|
26
|
+
if name.to_s == ENV['ADAPTER']
|
27
|
+
Object.const_set('ADAPTER', nil)
|
28
|
+
warn "Could not load do_#{name}: #{e}"
|
29
|
+
end
|
30
|
+
false
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
ENV['ADAPTER'] ||= 'sqlite3'
|
35
|
+
|
36
|
+
|
37
|
+
setup_adapter(:default)
|
38
|
+
Dir[Pathname(__FILE__).dirname.to_s + "/fixtures/**/*.rb"].each { |rb| require(rb) }
|
39
|
+
|
40
|
+
|
41
|
+
# -----------------------------------------------
|
42
|
+
# support for nice html output in rspec tmbundle
|
43
|
+
# -----------------------------------------------
|
44
|
+
|
45
|
+
USE_TEXTMATE_RSPEC_BUNDLE = true # set to false if not using textmate
|
46
|
+
|
47
|
+
if USE_TEXTMATE_RSPEC_BUNDLE
|
48
|
+
|
49
|
+
require Pathname(__FILE__).dirname.expand_path + 'shared/rspec_tmbundle_support'
|
50
|
+
|
51
|
+
# use the tmbundle logger
|
52
|
+
RSpecTmBundleHelpers::TextmateRspecLogger.new(STDOUT, :off)
|
53
|
+
|
54
|
+
class Object
|
55
|
+
include RSpecTmBundleHelpers
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|