motion_model 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -11,3 +11,13 @@ to the column metadata.
11
11
  if not specified in new or create.
12
12
 
13
13
  2012-09-06: Added block-style finders. Added delete method.
14
+
15
+ 2012-09-07: IMPORTANT! PLEASE READ! Two new methods were added
16
+ to MotionModel to support persistence:
17
+
18
+ Task#serialize_to_file(file_name)
19
+ Task.deserialize_from_file(file_name)
20
+
21
+ Note that serialize operates on an instance and
22
+ deserialize is a class method that creates an
23
+ instance.
data/README.md CHANGED
@@ -132,44 +132,23 @@ Things That Work
132
132
  @tasks = Task.order{|one, two| two.details <=> one.details}.all # Get tasks ordered descending by :details
133
133
  ```
134
134
 
135
- * Serialization using `NSCoder` works. Basically, you might do something like this
136
- in your `AppDelegate`:
135
+ * Serialization is part of MotionModel. So, in your `AppDelegate` you might do something like this:
137
136
 
138
137
  ```ruby
139
- def load_data
140
- if File.exist? documents_file("my_fine.dat")
141
- error_ptr = Pointer.new(:object)
142
-
143
- data = NSData.dataWithContentsOfFile(documents_file('my_fine.dat'), options:NSDataReadingMappedIfSafe, error:error_ptr)
144
-
145
- if data.nil?
146
- error = error_ptr[0]
147
- show_user_scary_warning error
148
- else
149
- @my_data_tree = NSKeyedUnarchiver.unarchiveObjectWithData(data)
150
- end
151
- else
152
- show_user_first_time_welcome
153
- end
154
- end
138
+ @tasks = Task.deserialize_from_file('tasks.dat')
155
139
  ```
156
140
 
157
141
  and of course on the "save" side:
158
142
 
159
143
  ```ruby
160
- error_ptr = Pointer.new(:object)
161
-
162
- data = NSKeyedArchiver.archivedDataWithRootObject App.delegate.events
163
- unless data.writeToFile(documents_file('my_fine.dat'), options: NSDataWritingAtomic, error: error_ptr)
164
- error = error_ptr[0]
165
- show_scary_message error
144
+ @tasks.serialize_to_file('tasks.dat')
166
145
  end
167
146
  ```
168
147
 
169
- Note that the archiving of any arbitrarily complex set of relations is
170
- automatically handled by `NSCoder` provided you conform to the coding
171
- protocol. When you declare your columns, `MotionModel` understands how
172
- to serialize your data so you need take no further action.
148
+ Note that the this serialization of any arbitrarily complex set of relations
149
+ is automatically handled by `NSCoder` provided you conform to the coding
150
+ protocol. When you declare your columns, `MotionModel` understands how to
151
+ serialize your data so you need take no further action.
173
152
 
174
153
  * Relations, in principle work. This is a part I'm still noodling over
175
154
  so it's not really safe to use them. In any case, how I expect it will
data/Rakefile CHANGED
@@ -1,4 +1,5 @@
1
1
  # -*- coding: utf-8 -*-
2
+ require "bundler/gem_tasks"
2
3
  $:.unshift("/Library/RubyMotion/lib")
3
4
  require 'motion/project'
4
5
 
@@ -38,6 +38,8 @@
38
38
  #
39
39
 
40
40
  module MotionModel
41
+ class PersistFileError < Exception; end
42
+
41
43
  module Model
42
44
  class Column
43
45
  attr_accessor :name
@@ -223,6 +225,37 @@ module MotionModel
223
225
  def each(&block)
224
226
  raise ArgumentError.new("each requires a block") unless block_given?
225
227
  @collection.each{|item| yield item}
228
+ end
229
+
230
+ # Returns the unarchived object if successful, otherwise false
231
+ #
232
+ # Note that subsequent calls to serialize/deserialize methods
233
+ # will remember the file name, so they may omit that argument.
234
+ #
235
+ # Raises a +MotionModel::PersistFileFailureError+ on failure.
236
+ def deserialize_from_file(file_name = nil)
237
+ @file_name ||= file_name
238
+ new_object = self.new
239
+
240
+ if File.exist? documents_file(@file_name)
241
+ error_ptr = Pointer.new(:object)
242
+
243
+ data = NSData.dataWithContentsOfFile(documents_file(file_name), options:NSDataReadingMappedIfSafe, error:error_ptr)
244
+
245
+ if data.nil?
246
+ error = error_ptr[0]
247
+ raise MotionModel::PersistFileFailureError.new "Error when reading the data: #{error}"
248
+ else
249
+ return NSKeyedUnarchiver.unarchiveObjectWithData(data)
250
+ end
251
+ else
252
+ return false
253
+ end
254
+ end
255
+
256
+ def documents_file(file_name)
257
+ file_path = File.join NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true), file_name
258
+ file_path
226
259
  end
227
260
 
228
261
  end
@@ -311,7 +344,7 @@ module MotionModel
311
344
 
312
345
  def initWithCoder(coder)
313
346
  self.init
314
- self.class.instance_variable_get("@_columns").each do |attr|
347
+ columns.each do |attr|
315
348
  # If a model revision has taken place, don't try to decode
316
349
  # something that's not there.
317
350
  new_tag_id = 1
@@ -330,7 +363,7 @@ module MotionModel
330
363
  end
331
364
 
332
365
  def encodeWithCoder(coder)
333
- self.class.instance_variable_get("@_columns").each do |attr|
366
+ columns.each do |attr|
334
367
  coder.encodeObject(self.send(attr), forKey: attr.to_s)
335
368
  end
336
369
  end
@@ -373,6 +406,28 @@ ERRORINFO
373
406
  end
374
407
  end
375
408
 
409
+ # Serializes data to a persistent store (file, in this
410
+ # terminology). Serialization is synchronous, so this
411
+ # will pause your run loop until complete.
412
+ #
413
+ # +file_name+ is the name of the persistent store you
414
+ # want to use. If you omit this, it will use the last
415
+ # remembered file name.
416
+ #
417
+ # Raises a +MotionModel::PersistFileFailureError+ on failure.
418
+ def serialize_to_file(file_name = nil)
419
+ @file_name ||= file_name
420
+ error_ptr = Pointer.new(:object)
421
+
422
+ data = NSKeyedArchiver.archivedDataWithRootObject self
423
+ unless data.writeToFile(self.class.documents_file(file_name), options: NSDataWritingAtomic, error: error_ptr)
424
+ # De-reference the pointer.
425
+ error = error_ptr[0]
426
+
427
+ # Now we can use the `error' object.
428
+ raise MotionModel::PersistFileFailureError.new "Error when writing data: #{error}"
429
+ end
430
+ end
376
431
  end
377
432
  end
378
433
 
@@ -1,3 +1,3 @@
1
1
  module MotionModel
2
- VERSION = "0.2.1"
2
+ VERSION = "0.2.2"
3
3
  end
data/spec/model_spec.rb CHANGED
@@ -325,5 +325,22 @@ describe "Creating a model" do
325
325
  end
326
326
 
327
327
  end
328
+ end
329
+
330
+ describe 'persistence' do
331
+ before do
332
+ Task.delete_all
333
+ %w(one two three).each do |task|
334
+ @tasks = Task.create(:name => "name #{task}")
335
+ end
336
+ @tasks.serialize_to_file('test.dat')
337
+ end
328
338
 
329
- end
339
+ it 'reads persisted model data' do
340
+ tasks = Task.deserialize_from_file('test.dat')
341
+
342
+ Task.first.name.should == 'name one'
343
+ Task.last.name.should == 'name three'
344
+ Task.count.should == 3
345
+ end
346
+ end
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.1
4
+ version: 0.2.2
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-09-06 00:00:00.000000000 Z
12
+ date: 2012-09-07 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Simple model and validation mixins for RubyMotion
15
15
  email: