motion_model 0.2.8 → 0.3.0

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.
@@ -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