motion_model 0.2.8 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,7 +2,7 @@ module MotionModel
2
2
  class PersistFileError < Exception; end
3
3
 
4
4
  module Model
5
- module ClassMethods
5
+ module PublicClassMethods
6
6
  # Returns the unarchived object if successful, otherwise false
7
7
  #
8
8
  # Note that subsequent calls to serialize/deserialize methods
@@ -1,3 +1,3 @@
1
1
  module MotionModel
2
- VERSION = "0.2.8"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -0,0 +1,100 @@
1
+ class Assignee
2
+ include MotionModel::Model
3
+ columns :assignee_name => :string
4
+ belongs_to :task
5
+ end
6
+
7
+ class Task
8
+ include MotionModel::Model
9
+ columns :name => :string,
10
+ :details => :string,
11
+ :some_day => :date
12
+ has_many :assignees
13
+ end
14
+
15
+ class CascadingTask
16
+ include MotionModel::Model
17
+ columns :name => :string,
18
+ :details => :string,
19
+ :some_day => :date
20
+ has_many :cascaded_assignees, :dependent => :delete
21
+ end
22
+
23
+ class CascadedAssignee
24
+ include MotionModel::Model
25
+ columns :assignee_name => :string
26
+ belongs_to :cascading_task
27
+ has_many :employees
28
+ end
29
+
30
+ class Employee
31
+ include MotionModel::Model
32
+ columns :name
33
+ belongs_to :CascadedAssignee
34
+ end
35
+
36
+ describe "cascading deletes" do
37
+ # describe "when not marked for destruction" do
38
+ # it "leaves assignees alone when they are not marked for destruction" do
39
+ # Task.delete_all
40
+ # Assignee.delete_all
41
+
42
+ # task = Task.create :name => 'Walk the dog'
43
+ # task.assignees.create :assignee_name => 'Joe'
44
+ # lambda{task.destroy}.should.not.change{Assignee.length}
45
+ # end
46
+ # end
47
+
48
+ describe "when marked for destruction" do
49
+ before do
50
+ CascadingTask.delete_all
51
+ CascadedAssignee.delete_all
52
+ end
53
+
54
+ it "deletes assignees that belong to a destroyed task" do
55
+ task = CascadingTask.create(:name => 'cascading')
56
+ task.cascaded_assignees.create(:assignee_name => 'joe')
57
+ task.cascaded_assignees.create(:assignee_name => 'bill')
58
+
59
+ CascadingTask.count.should == 1
60
+ CascadedAssignee.count.should == 2
61
+
62
+ task.destroy
63
+
64
+ CascadingTask.count.should == 0
65
+ CascadedAssignee.count.should == 0
66
+ end
67
+
68
+ it "deletes all assignees when all tasks are destroyed" do
69
+ 1.upto(3) do |item|
70
+ task = CascadingTask.create :name => "Task #{item}"
71
+ 1.upto(3) do |assignee|
72
+ task.cascaded_assignees.create :name => "assignee #{assignee} for task #{task}"
73
+ end
74
+ end
75
+ CascadingTask.count.should == 3
76
+ CascadedAssignee.count.should == 9
77
+
78
+ CascadingTask.destroy_all
79
+
80
+ CascadingTask.count.should == 0
81
+ CascadedAssignee.count.should == 0
82
+ end
83
+
84
+ it "deletes only one level when a task is destroyed but dependent is delete" do
85
+ task = CascadingTask.create :name => 'dependent => :delete'
86
+ assignee = task.cascaded_assignees.create :assignee_name => 'deletable assignee'
87
+ assignee.employees.create :name => 'person who sticks around'
88
+
89
+ CascadingTask.count.should == 1
90
+ CascadedAssignee.count.should == 1
91
+ Employee.count.should == 1
92
+
93
+ task.destroy
94
+
95
+ CascadingTask.count.should == 0
96
+ CascadedAssignee.count.should == 0
97
+ Employee.count.should == 1
98
+ end
99
+ end
100
+ end
data/spec/model_spec.rb CHANGED
@@ -3,6 +3,10 @@ class Task
3
3
  columns :name => :string,
4
4
  :details => :string,
5
5
  :some_day => :date
6
+
7
+ def custom_attribute_by_method
8
+ "#{name} - #{details}"
9
+ end
6
10
  end
7
11
 
8
12
  class ATask
@@ -130,6 +134,12 @@ describe "Creating a model" do
130
134
  Task.count.should.equal(1)
131
135
  end
132
136
 
137
+ it 'instance variables have access to length and count' do
138
+ task = Task.create
139
+ task.length.should.equal(1)
140
+ task.count.should.equal(1)
141
+ end
142
+
133
143
  it 'when there is more than one element, length returned is correct' do
134
144
  10.times { Task.create }
135
145
  Task.length.should.equal(10)
@@ -137,6 +147,30 @@ describe "Creating a model" do
137
147
 
138
148
  end
139
149
 
150
+ describe 'adding or updating' do
151
+ before do
152
+ Task.delete_all
153
+ end
154
+
155
+ it 'adds to the collection when a new task is saved' do
156
+ task = Task.new
157
+ lambda{task.save}.should.change{Task.count}
158
+ end
159
+
160
+ it 'does not add to the collection when an existing task is saved' do
161
+ task = Task.create(:name => 'updateable')
162
+ task.name = 'updated'
163
+ lambda{task.save}.should.not.change{Task.count}
164
+ end
165
+
166
+ it 'updates data properly' do
167
+ task = Task.create(:name => 'updateable')
168
+ task.name = 'updated'
169
+ Task.where(:name).eq('updated').should == 0
170
+ lambda{task.save}.should.change{Task.where(:name).eq('updated')}
171
+ end
172
+ end
173
+
140
174
  describe 'deleting' do
141
175
  before do
142
176
  Task.delete_all
@@ -156,13 +190,45 @@ describe "Creating a model" do
156
190
  target = Task.find(:name).eq('task 2').first
157
191
  lambda{target.delete}.should.change{Task.length}
158
192
  end
193
+
194
+ it 'undeleting a row restores it' do
195
+ target = Task.find(:name).eq('task 3').first
196
+ target.should.not == nil
197
+ target.delete
198
+ target.undelete
199
+ Task.find(:name).eq('task 3').count.should.equal 1
200
+ end
159
201
  end
160
202
 
161
- describe 'Handling Attribute method_missing Implementation' do
203
+ describe 'Handling Attribute Implementation' do
162
204
  it 'raises a NoMethodError exception when an unknown attribute it referenced' do
163
205
  task = Task.new
164
206
  lambda{task.bar}.should.raise(NoMethodError)
165
207
  end
208
+
209
+ it 'successfully retrieves by attribute' do
210
+ task = Task.create(:name => 'my task')
211
+ task.name.should == 'my task'
212
+ end
213
+
214
+ describe "dirty" do
215
+ before do
216
+ @new_task = Task.new
217
+ end
218
+
219
+ it 'marks a new object as dirty' do
220
+ @new_task.should.be.dirty
221
+ end
222
+
223
+ it 'marks a saved object as clean' do
224
+ lambda{@new_task.save}.should.change{@new_task.dirty?}
225
+ end
226
+
227
+ it 'marks a modified object as dirty' do
228
+ @new_task.save
229
+ lambda{@new_task.name = 'now dirty'}.should.change{@new_task.dirty?}
230
+ end
231
+ end
166
232
  end
167
233
 
168
234
  describe 'Type casting' do
@@ -224,68 +290,16 @@ describe "Creating a model" do
224
290
  it 'the date field should be the same as it was in string form' do
225
291
  @convertible.a_date.to_s.should.match(/^2012-09-15/)
226
292
  end
227
-
228
293
  end
229
- end
230
294
 
231
- class NotifiableTask
232
- include MotionModel::Model
233
- columns :name
234
- has_many :assignees
235
-
236
- attr_accessor :notification_called, :notification_details
237
-
238
- def hookup_events
239
- @notification_id = NSNotificationCenter.defaultCenter.addObserver(self, selector:'dataDidChange:', name:'MotionModelDataDidChangeNotification', object:nil)
240
- @notification_details = nil
241
- end
242
-
243
- def dataDidChange(notification)
244
- @notification_called = true
245
- @notification_details = notification.userInfo
246
- end
247
-
248
- def teardown_events
249
- NSNotificationCenter.defaultCenter.removeObserver @notification_id
250
- end
251
- end
295
+ describe 'defining custom attributes' do
296
+ before do
297
+ Task.delete_all
298
+ @task = Task.create :name => 'Feed the Cat', :details => 'Get food, pour out'
299
+ end
252
300
 
253
- describe 'data change notifications' do
254
- before do
255
- @task = NotifiableTask.new
256
- @task.hookup_events
257
- end
258
-
259
- after do
260
- @task.teardown_events
261
- end
262
-
263
- it "fires a change notification when an item is added" do
264
- @task.notification_called = false
265
- lambda{@task.save}.should.change{@task.notification_called}
266
- end
267
-
268
- it "contains an add notification for new objects" do
269
- @task.save
270
- @task.notification_details[:action].should == 'add'
271
- end
272
-
273
- it "contans an update notification for an updated object" do
274
- @task.save
275
- @task.name = "Bill"
276
- @task.save
277
- @task.notification_details[:action].should == 'update'
278
- end
279
-
280
- it "contains a delete notification for a deleted object" do
281
- @task.save
282
- @task.delete
283
- @task.notification_details[:action].should == 'delete'
284
- end
285
-
286
- it "does not get a delete notification for delete_all" do
287
- @task = NotifiableTask.create :name => 'Bob'
288
- @task.notification_called = nil
289
- lambda{NotifiableTask.delete_all}.should.not.change{@task.notification_called}
301
+ it 'uses a custom attribute by method' do
302
+ @task.custom_attribute_by_method.should == 'Feed the Cat - Get food, pour out'
303
+ end
290
304
  end
291
305
  end
@@ -6,7 +6,7 @@ end
6
6
 
7
7
  class Task
8
8
  include MotionModel::Model
9
- columns :name => :string,
9
+ columns :name => :string,
10
10
  :details => :string,
11
11
  :some_day => :date
12
12
  has_many :assignees
@@ -16,7 +16,7 @@ end
16
16
  class User
17
17
  include MotionModel::Model
18
18
  columns :name => :string
19
-
19
+
20
20
  has_many :email_accounts
21
21
  end
22
22
 
@@ -25,7 +25,7 @@ class EmailAccount
25
25
  columns :name => :string
26
26
  belongs_to :user
27
27
  end
28
-
28
+
29
29
  Inflector.inflections.irregular 'assignees', 'assignee'
30
30
  Inflector.inflections.irregular 'assignee', 'assignees'
31
31
 
@@ -45,33 +45,38 @@ describe 'related objects' do
45
45
  end
46
46
 
47
47
  describe 'has_many' do
48
+ before do
49
+ Task.delete_all
50
+ Assignee.delete_all
51
+ end
52
+
48
53
  it "is wired up right" do
49
54
  lambda {Task.new}.should.not.raise
50
55
  lambda {Task.new.assignees}.should.not.raise
51
56
  end
52
-
57
+
53
58
  it 'relation objects are empty on initialization' do
54
59
  a_task = Task.create
55
60
  a_task.assignees.all.should.be.empty
56
61
  end
57
-
62
+
58
63
  it "supports creating related objects directly on parents" do
59
64
  a_task = Task.create(:name => 'Walk the Dog')
60
65
  a_task.assignees.create(:assignee_name => 'bob')
61
- a_task.assignees.length.should == 1
66
+ a_task.assignees.count.should == 1
62
67
  a_task.assignees.first.assignee_name.should == 'bob'
63
68
  Assignee.count.should == 1
64
69
  end
65
-
70
+
66
71
  describe "supporting has_many" do
67
72
  before do
68
73
  Task.delete_all
69
74
  Assignee.delete_all
70
-
75
+
71
76
  @tasks = []
72
77
  @assignees = []
73
78
  1.upto(3) do |task|
74
- t = Task.create(:name => "task #{task}")
79
+ t = Task.create(:name => "task #{task}", :id => task)
75
80
  assignee_index = 1
76
81
  @tasks << t
77
82
  1.upto(task * 2) do |assignee|
@@ -83,26 +88,28 @@ describe 'related objects' do
83
88
 
84
89
  it "is wired up right" do
85
90
  Task.count.should == 3
86
- Assignee.count.should == 12
91
+ Assignee.count.should == 12
87
92
  end
88
-
93
+
89
94
  it "has 2 assignees for the first task" do
90
95
  Task.first.assignees.count.should == 2
91
96
  end
92
-
97
+
93
98
  it "the first assignee for the second task is employee 7" do
94
99
  Task.find(2).name.should == @tasks[1].name
95
100
  Task.find(2).assignees.first.assignee_name.should == @assignees[2].assignee_name
96
101
  end
102
+
103
+ it 'supports adding related objects to parents' do
104
+ assignee = Assignee.new(:assignee_name => 'Zoe')
105
+ Task.count.should == 3
106
+ assignee_count = Task.find(3).assignees.count
107
+ Task.find(3).assignees.push(assignee)
108
+ Task.find(3).assignees.count.should == assignee_count + 1
109
+ end
110
+
97
111
  end
98
-
99
- it 'supports adding related objects to parents' do
100
- assignee = Assignee.new(:assignee_name => 'Zoe')
101
- assignee_count = Task.find(3).assignees.count
102
- Task.find(3).assignees.push(assignee)
103
- Task.find(3).assignees.count.should == assignee_count + 1
104
- end
105
-
112
+
106
113
  it "supports creating blank (empty) scratchpad associated objects" do
107
114
  task = Task.create :name => 'watch a movie'
108
115
  assignee = task.assignees.new
@@ -112,7 +119,7 @@ describe 'related objects' do
112
119
  task.assignees.first.assignee_name.should == 'Chloe'
113
120
  end
114
121
  end
115
-
122
+
116
123
  describe "supporting belongs_to" do
117
124
  before do
118
125
  Task.delete_all
@@ -172,15 +179,15 @@ describe 'related objects' do
172
179
  @a1.task.name.should == "Feed the cat"
173
180
  end
174
181
  end
175
-
176
- describe "directly assigning to child" do
182
+
183
+ describe "directly assigning to child" do
177
184
  it "directly assigning a different task to an assignee changes the assignee's task" do
178
185
  @a1.task = @t1.id
179
186
  @a1.save
180
187
  @t1.assignees.count.should == 1
181
188
  @t1.assignees.first.assignee_name.should == @a1.assignee_name
182
189
  end
183
-
190
+
184
191
  it "directly assigning an instance of a task to an assignee changes the assignee's task" do
185
192
  @a1.task = @t1
186
193
  @a1.save
@@ -188,7 +195,7 @@ describe 'related objects' do
188
195
  @t1.assignees.first.assignee_name.should == @a1.assignee_name
189
196
  end
190
197
  end
191
- end
198
+ end
192
199
  end
193
200
  end
194
201
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: motion_model
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.8
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-11-25 00:00:00.000000000 Z
12
+ date: 2012-12-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bubble-wrap
@@ -36,6 +36,7 @@ extra_rdoc_files: []
36
36
  files:
37
37
  - .gitignore
38
38
  - CHANGELOG
39
+ - LICENSE
39
40
  - README.md
40
41
  - Rakefile
41
42
  - app/app_delegate.rb
@@ -49,6 +50,7 @@ files:
49
50
  - lib/motion_model/validatable.rb
50
51
  - lib/motion_model/version.rb
51
52
  - motion_model.gemspec
53
+ - spec/cascading_delete_spec.rb
52
54
  - spec/ext_spec.rb
53
55
  - spec/finder_spec.rb
54
56
  - spec/model_spec.rb
@@ -80,6 +82,7 @@ signing_key:
80
82
  specification_version: 3
81
83
  summary: Simple model and validation mixins for RubyMotion
82
84
  test_files:
85
+ - spec/cascading_delete_spec.rb
83
86
  - spec/ext_spec.rb
84
87
  - spec/finder_spec.rb
85
88
  - spec/model_spec.rb