motion_model 0.2.1 → 0.2.2

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/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: