motion_model 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -26,6 +26,34 @@ are:
26
26
  helpers are certainly not the focus of this release, but
27
27
  I am using these in an app to create Apple-like input forms in
28
28
  static tables.
29
+
30
+ Getting Going
31
+ ================
32
+
33
+ If you are using Bundler, put this in your Gemfile:
34
+
35
+ ```
36
+ gem motion_model
37
+ ```
38
+
39
+ then do:
40
+
41
+ ```
42
+ bundle install
43
+ ```
44
+
45
+ If you are not using Bundler:
46
+
47
+ ```
48
+ gem install motion_model
49
+ ```
50
+
51
+ then put this in your Rakefile after requiring `motion/project`:
52
+
53
+ ```
54
+ require 'motion_model'
55
+ ```
56
+
29
57
 
30
58
  What Model Can Do
31
59
  ================
@@ -124,6 +152,15 @@ Things That Work
124
152
  ```ruby
125
153
  @tasks = Task.find{|task| task.name =~ /dog/i && task.assigned_to == 'Bob'}
126
154
  ```
155
+
156
+ Note that finders always return a proxy (`FinderQuery`). You must use `first`, `last`, or `all`
157
+ to get useful results.
158
+
159
+ ```ruby
160
+ @tasks = Task.where(:owner).eq('jim') # => A FinderQuery.
161
+ @tasks.all # => An array of matching results.
162
+ @tasks.first # => The first result
163
+ ```
127
164
 
128
165
  You can perform ordering using either a field name or block syntax. Here's an example:
129
166
 
@@ -141,7 +178,7 @@ Things That Work
141
178
  and of course on the "save" side:
142
179
 
143
180
  ```ruby
144
- @tasks.serialize_to_file('tasks.dat')
181
+ Task.serialize_to_file('tasks.dat')
145
182
  end
146
183
  ```
147
184
 
@@ -150,11 +187,14 @@ Things That Work
150
187
  protocol. When you declare your columns, `MotionModel` understands how to
151
188
  serialize your data so you need take no further action.
152
189
 
153
- * Relations, in principle work. This is a part I'm still noodling over
154
- so it's not really safe to use them. In any case, how I expect it will
155
- shake out is that one-to-one or one-to-many will be supported out of
156
- the box, but you will have to take some extra steps to implement
157
- many-to-many, just as you would in Rails' `has_many :through`.
190
+ * Relations, in principle work. They are more embedded documents similar
191
+ to CouchDB or MongoDB. So instead of being separate tables, the embedded
192
+ documents are model objects contained in a collection.
193
+
194
+ **Relations Are Untested**. This is completely experimental, but to use
195
+ them, just define a column as type `:array`. Initializing these properly
196
+ and testing them is a high priority for me, so expect it to be addressed
197
+ soon.
158
198
 
159
199
  * Core extensions work. The following are supplied:
160
200
 
@@ -165,6 +205,15 @@ Things That Work
165
205
  - Array#empty?
166
206
  - Hash#empty?
167
207
  - Symbol#titleize
208
+
209
+ Also in the extensions is a debug class to log stuff to the console.
210
+ This may be preferable to `puts` just because it's easier to spot in
211
+ your code and it gives you the exact level and file/line number of the
212
+ info/warning/error in your console output:
213
+
214
+ - Debug.info(message)
215
+ - Debug.warning(message)
216
+ - Debug.error(message)
168
217
 
169
218
  Things In The Pipeline
170
219
  ----------------------
@@ -178,5 +227,28 @@ Things In The Pipeline
178
227
  Problems/Comments
179
228
  ------------------
180
229
 
181
- Please raise an issue if you find something that doesn't work, some
230
+ Please **raise an issue** on GitHub if you find something that doesn't work, some
182
231
  syntax that smells, etc.
232
+
233
+ If you want to stay on the bleeding edge, clone yourself a copy (or better yet, fork
234
+ one).
235
+
236
+ Then be sure references to motion_model are commented out or removed from your Gemfile
237
+ and/or Rakefile and put this in your Rakefile:
238
+
239
+ ```
240
+ require "~/github/local//MotionModel/lib/motion_model.rb"
241
+ ```
242
+
243
+ The `~/github/local` is where I cloned it, but you can put it anyplace. Next, make
244
+ sure you are following the project on GitHub so you know when there are changes.
245
+
246
+ Submissions/Patches
247
+ ------------------
248
+
249
+ Obviously, the ideal one is a pull request from your own fork, complete with passing
250
+ specs.
251
+
252
+ Really, even a failing spec or some proposed code is fine. I really want to make
253
+ this a decent tool for RubyMotion developers who need a straightforward data
254
+ modeling and persistence framework.
@@ -35,3 +35,35 @@ class Symbol
35
35
  self.to_s.titleize
36
36
  end
37
37
  end
38
+
39
+ class Debug
40
+ @@silent = false
41
+
42
+ # Use silence if you want to keep messages from being echoed
43
+ # to the console.
44
+ def self.silence
45
+ @@silent = true
46
+ end
47
+
48
+ # Use resume when you want messages that were silenced to
49
+ # resume displaying.
50
+ def self.resume
51
+ @@silent = false
52
+ end
53
+
54
+ def self.put_message(type, message)
55
+ puts("#{type} #{caller[1]}: #{message}") unless @@silent
56
+ end
57
+
58
+ def self.info(msg)
59
+ put_message 'INFO', msg
60
+ end
61
+
62
+ def self.warning(msg)
63
+ put_message 'WARNING', msg
64
+ end
65
+
66
+ def self.error(msg)
67
+ put_message 'ERROR', msg
68
+ end
69
+ end
@@ -37,7 +37,6 @@ module MotionModel
37
37
  # Only one field mapping may be supplied for
38
38
  # a given class.
39
39
  def field(field, options = {})
40
- puts "adding field #{field}"
41
40
  label = options[:label] || field.humanize
42
41
  @binding_data << FieldBindingMap.new(:label => label, :name => field)
43
42
  end
@@ -110,10 +109,8 @@ module MotionModel
110
109
  raise ModelNotSetError.new("You must set the model before binding it.") unless @model
111
110
 
112
111
  fields do |field|
113
- puts "*** retrieving data for #{field.name} and tag #{field.tag} ***"
114
112
  view_obj = self.view.viewWithTag(field.tag)
115
- puts "view object with tag is #{view_obj.inspect}"
116
- @model.send("#{field.name}=".to_sym, view_obj.text)
113
+ @model.send("#{field.name}=".to_sym, view_obj.text) if view_obj.respond_to?(:text)
117
114
  end
118
115
  end
119
116
 
@@ -0,0 +1,22 @@
1
+ module MotionModel
2
+ module Model
3
+ class Column
4
+ attr_accessor :name
5
+ attr_accessor :type
6
+ attr_accessor :default
7
+
8
+ def initialize(name = nil, type = nil, default = nil)
9
+ @name = name
10
+ @type = type
11
+ @default = default || nil
12
+ end
13
+
14
+ def add_attr(name, type, default = nil)
15
+ @name = name
16
+ @type = type
17
+ @default = default || nil
18
+ end
19
+ alias_method :add_attribute, :add_attr
20
+ end
21
+ end
22
+ end
@@ -23,12 +23,18 @@ module MotionModel
23
23
  end
24
24
 
25
25
  ######## relational methods ########
26
- def do_comparison(query_string, options = {:case_sensitive => false})
27
- query_string = query_string.downcase if query_string.respond_to?(:downcase) && !options[:case_sensitive]
28
- @collection = @collection.select do |item|
26
+ def translate_case(item, case_sensitive)#nodoc
27
+ item = item.downcase if case_sensitive === false && item.respond_to?(:downcase)
28
+ item
29
+ end
30
+
31
+ def do_comparison(query_string, options = {:case_sensitive => false})#nodoc
32
+ query_string = translate_case(query_string, options[:case_sensitive])
33
+ @collection = @collection.collect do |item|
29
34
  comparator = item.send(@field_name.to_sym)
30
- yield query_string, comparator
31
- end
35
+ comparator = translate_case(comparator, options[:case_sensitive])
36
+ item if yield query_string, comparator
37
+ end.compact
32
38
  self
33
39
  end
34
40
 
@@ -41,25 +41,6 @@ module MotionModel
41
41
  class PersistFileError < Exception; end
42
42
 
43
43
  module Model
44
- class Column
45
- attr_accessor :name
46
- attr_accessor :type
47
- attr_accessor :default
48
-
49
- def initialize(name = nil, type = nil, default = nil)
50
- @name = name
51
- @type = type
52
- @default = default || nil
53
- end
54
-
55
- def add_attr(name, type, default = nil)
56
- @name = name
57
- @type = type
58
- @default = default || nil
59
- end
60
- alias_method :add_attribute, :add_attr
61
- end
62
-
63
44
  def self.included(base)
64
45
  base.extend(ClassMethods)
65
46
  base.instance_variable_set("@_columns", [])
@@ -98,6 +79,8 @@ module MotionModel
98
79
  case fields.first
99
80
  when Hash
100
81
  fields.first.each_pair do |name, options|
82
+ raise ArgumentError.new("you cannot use `description' as a column name because of a conflict with Cocoa.") if name.to_s == 'description'
83
+
101
84
  case options
102
85
  when Symbol, String
103
86
  add_field(name, options)
@@ -178,6 +161,7 @@ module MotionModel
178
161
  # Empties the entire store.
179
162
  def delete_all
180
163
  @collection = [] # TODO: Handle cascading or let GC take care of it.
164
+ @collection.compact!
181
165
  end
182
166
 
183
167
  # Finds row(s) within the data store. E.g.,
@@ -227,37 +211,9 @@ module MotionModel
227
211
  @collection.each{|item| yield item}
228
212
  end
229
213
 
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
214
+ def empty?
215
+ @collection.empty?
254
216
  end
255
-
256
- def documents_file(file_name)
257
- file_path = File.join NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true), file_name
258
- file_path
259
- end
260
-
261
217
  end
262
218
 
263
219
  ####### Instance Methods #######
@@ -282,6 +238,8 @@ module MotionModel
282
238
  cast_value = cast_to_type(col, options[col])
283
239
  @data[col] = cast_value
284
240
  end
241
+
242
+ dirty = true
285
243
  end
286
244
 
287
245
  def cast_to_type(column_name, arg)
@@ -298,8 +256,7 @@ module MotionModel
298
256
  return_value = arg.is_a?(Float) ? arg : arg.to_f
299
257
  when :date
300
258
  return arg if arg.is_a?(NSDate)
301
- date_string = arg += ' 00:00'
302
- return_value = @cached_date_formatter.dateFromString(date_string)
259
+ return_value = NSDate.dateWithNaturalLanguageString(arg, locale:NSUserDefaults.standardUserDefaults.dictionaryRepresentation)
303
260
  else
304
261
  raise ArgumentError.new("type #{column_name} : #{type(column_name)} is not possible to cast.")
305
262
  end
@@ -311,7 +268,16 @@ module MotionModel
311
268
  end
312
269
 
313
270
  def save
314
- self.class.instance_variable_get('@collection') << self
271
+ collection = self.class.instance_variable_get('@collection')
272
+ @dirty = false
273
+
274
+ # Existing object implies update in place
275
+ # TODO: Optimize location of existing id
276
+ if obj = collection.find{|o| o.id == @data[:id]}
277
+ obj = self
278
+ else
279
+ collection << self
280
+ end
315
281
  end
316
282
 
317
283
  def delete
@@ -341,32 +307,6 @@ module MotionModel
341
307
  def type(field_name)
342
308
  self.class.type(field_name)
343
309
  end
344
-
345
- def initWithCoder(coder)
346
- self.init
347
- columns.each do |attr|
348
- # If a model revision has taken place, don't try to decode
349
- # something that's not there.
350
- new_tag_id = 1
351
- if coder.containsValueForKey(attr.to_s)
352
- value = coder.decodeObjectForKey(attr.to_s)
353
- self.instance_variable_set('@' + attr.to_s, value || '')
354
- else
355
- self.instance_variable_set('@' + attr.to_s, '') # set to empty string if new attribute
356
- end
357
-
358
- # re-issue tags to make sure they are unique
359
- @tag = new_tag_id
360
- new_tag_id += 1
361
- end
362
- self
363
- end
364
-
365
- def encodeWithCoder(coder)
366
- columns.each do |attr|
367
- coder.encodeObject(self.send(attr), forKey: attr.to_s)
368
- end
369
- end
370
310
 
371
311
  # Modify respond_to? to add model's attributes.
372
312
  alias_method :old_respond_to?, :respond_to?
@@ -374,6 +314,10 @@ module MotionModel
374
314
  column_named(method) || old_respond_to?(method)
375
315
  end
376
316
 
317
+ def dirty?
318
+ @dirty
319
+ end
320
+
377
321
  # Handle attribute retrieval
378
322
  #
379
323
  # Gets and sets work as expected, and type casting occurs
@@ -393,6 +337,7 @@ module MotionModel
393
337
 
394
338
  if col
395
339
  if method.to_s.include?('=')
340
+ @dirty = true
396
341
  return @data[base_method] = self.cast_to_type(base_method, args[0])
397
342
  else
398
343
  return @data[base_method]
@@ -406,28 +351,6 @@ ERRORINFO
406
351
  end
407
352
  end
408
353
 
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
431
354
  end
432
355
  end
433
356
 
@@ -0,0 +1,96 @@
1
+ module MotionModel
2
+ class PersistFileError < Exception; end
3
+
4
+ module Model
5
+ module ClassMethods
6
+ # Returns the unarchived object if successful, otherwise false
7
+ #
8
+ # Note that subsequent calls to serialize/deserialize methods
9
+ # will remember the file name, so they may omit that argument.
10
+ #
11
+ # Raises a +MotionModel::PersistFileFailureError+ on failure.
12
+ def deserialize_from_file(file_name = nil)
13
+ @file_name ||= file_name
14
+
15
+ if File.exist? documents_file(@file_name)
16
+ error_ptr = Pointer.new(:object)
17
+
18
+ data = NSData.dataWithContentsOfFile(documents_file(file_name), options:NSDataReadingMappedIfSafe, error:error_ptr)
19
+
20
+ if data.nil?
21
+ error = error_ptr[0]
22
+ raise MotionModel::PersistFileFailureError.new "Error when reading the data: #{error}"
23
+ else
24
+ collection = NSKeyedUnarchiver.unarchiveObjectWithData(data)
25
+ return self
26
+ end
27
+ else
28
+ return false
29
+ end
30
+ end
31
+ # Serializes data to a persistent store (file, in this
32
+ # terminology). Serialization is synchronous, so this
33
+ # will pause your run loop until complete.
34
+ #
35
+ # +file_name+ is the name of the persistent store you
36
+ # want to use. If you omit this, it will use the last
37
+ # remembered file name.
38
+ #
39
+ # Raises a +MotionModel::PersistFileFailureError+ on failure.
40
+ def serialize_to_file(file_name = nil)
41
+ @file_name ||= file_name
42
+ error_ptr = Pointer.new(:object)
43
+
44
+ data = NSKeyedArchiver.archivedDataWithRootObject @collection
45
+ unless data.writeToFile(documents_file(file_name), options: NSDataWritingAtomic, error: error_ptr)
46
+ # De-reference the pointer.
47
+ error = error_ptr[0]
48
+
49
+ # Now we can use the `error' object.
50
+ raise MotionModel::PersistFileFailureError.new "Error when writing data: #{error}"
51
+ end
52
+ end
53
+
54
+
55
+ def documents_file(file_name)
56
+ file_path = File.join NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true), file_name
57
+ file_path
58
+ end
59
+ end
60
+
61
+ def initWithCoder(coder)
62
+ self.init
63
+
64
+ new_tag_id = 1
65
+ columns.each do |attr|
66
+ # If a model revision has taken place, don't try to decode
67
+ # something that's not there.
68
+ if coder.containsValueForKey(attr.to_s)
69
+ value = coder.decodeObjectForKey(attr.to_s)
70
+ self.send("#{attr}=", value)
71
+ else
72
+ self.send("#{attr}=", nil)
73
+ end
74
+
75
+ # re-issue tags to make sure they are unique
76
+ @tag = new_tag_id
77
+ new_tag_id += 1
78
+ end
79
+ save
80
+
81
+ self
82
+ end
83
+
84
+ # Follow Apple's recommendation not to encode missing
85
+ # values.
86
+ def encodeWithCoder(coder)
87
+ columns.each do |attr|
88
+ value = self.send(attr)
89
+ unless value.nil?
90
+ coder.encodeObject(value, forKey: attr.to_s)
91
+ end
92
+ end
93
+ end
94
+
95
+ end
96
+ end
@@ -1,3 +1,3 @@
1
1
  module MotionModel
2
- VERSION = "0.2.2"
2
+ VERSION = "0.2.3"
3
3
  end
data/spec/model_spec.rb CHANGED
@@ -133,12 +133,13 @@ describe "Creating a model" do
133
133
 
134
134
  describe 'finders' do
135
135
  before do
136
+ Task.delete_all
136
137
  10.times {|i| Task.create(:name => "task #{i}")}
137
138
  end
138
139
 
139
140
  describe 'find' do
140
141
  it 'finds elements within the collection' do
141
- Task.find(3).name.should.equal('task 3')
142
+ task = Task.find(3).name.should.equal('task 3')
142
143
  end
143
144
 
144
145
  it 'returns nil if find by id is not found' do
@@ -147,7 +148,15 @@ describe "Creating a model" do
147
148
 
148
149
  it 'looks into fields if field name supplied' do
149
150
  Task.create(:name => 'find me')
150
- Task.find(:name).eq('find me').all.length.should.equal(1)
151
+ tasks = Task.find(:name).eq('find me')
152
+ tasks.all.length.should.equal(1)
153
+ tasks.first.name.should == 'find me'
154
+ end
155
+
156
+ it "provides an array of valid model instances when doing a find" do
157
+ Task.create(:name => 'find me')
158
+ tasks = Task.find(:name).eq('find me')
159
+ tasks.first.name.should.eql 'find me'
151
160
  end
152
161
 
153
162
  it 'allows for multiple (chained) query parameters' do
@@ -168,12 +177,12 @@ describe "Creating a model" do
168
177
 
169
178
  it 'using where instead of find' do
170
179
  atask = Task.create(:name => 'find me', :details => "details 1")
171
- found_task = Task.where(:details).contain("details 1").first.details.should.equal("details 1")
180
+ found_task = Task.where(:details).contain("s 1").first.details.should == 'details 1'
172
181
  end
173
182
 
174
183
  it 'handles case-sensitive queries' do
175
184
  task = Task.create :name => 'Bob'
176
- Task.find(:name).eq('bob', :case_sensitive => true).all.should.be.empty
185
+ Task.find(:name).eq('bob', :case_sensitive => true).all.length.should == 0
177
186
  end
178
187
 
179
188
  it 'all returns all members of the collection as an array' do
@@ -248,7 +257,7 @@ describe "Creating a model" do
248
257
  it 'deletes a row' do
249
258
  target = Task.find(:name).eq('task 3').first
250
259
  target.delete
251
- Task.find(:description).eq('Task 3').should == nil
260
+ Task.find(:description).eq('Task 3').length.should.equal 0
252
261
  end
253
262
 
254
263
  it 'deleting a row changes length' do
@@ -327,20 +336,3 @@ describe "Creating a model" do
327
336
  end
328
337
  end
329
338
 
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
338
-
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
@@ -0,0 +1,84 @@
1
+ class PersistTask
2
+ include MotionModel::Model
3
+ columns :name, :desc
4
+ end
5
+
6
+ describe 'persistence' do
7
+ before do
8
+ PersistTask.delete_all
9
+ %w(one two three).each do |task|
10
+ @tasks = PersistTask.create(:name => "name #{task}")
11
+ end
12
+ end
13
+
14
+ it "serializes data" do
15
+ lambda{PersistTask.serialize_to_file('test.dat')}.should.not.raise
16
+ end
17
+
18
+ it 'reads persisted model data' do
19
+ PersistTask.serialize_to_file('test.dat')
20
+
21
+ PersistTask.delete_all
22
+
23
+ PersistTask.count.should == 0
24
+
25
+ tasks = PersistTask.deserialize_from_file('test.dat')
26
+
27
+ PersistTask.count.should == 3
28
+ PersistTask.first.name.should == 'name one'
29
+ PersistTask.last.name.should == 'name three'
30
+ end
31
+
32
+ describe 'model change resiliency' do
33
+ it 'column addition' do
34
+ class Foo
35
+ include MotionModel::Model
36
+ columns :name => :string
37
+ end
38
+ @foo = Foo.create(:name=> 'Bob')
39
+ Foo.serialize_to_file('test.dat')
40
+
41
+ @foo.should.not.respond_to :address
42
+
43
+ class Foo
44
+ include MotionModel::Model
45
+ columns :name => :string,
46
+ :address => :string
47
+ end
48
+ Foo.deserialize_from_file('test.dat')
49
+
50
+ @foo = Foo.first
51
+
52
+ @foo.name.should == 'Bob'
53
+ @foo.address.should == nil
54
+ @foo.should.respond_to :address
55
+ Foo.length.should == 1
56
+ end
57
+
58
+ it "column removal" do
59
+ class Foo
60
+ include MotionModel::Model
61
+ columns :name => :string, :desc => :string
62
+ end
63
+ @foo = Foo.create(:name=> 'Bob', :desc => 'who cares anyway?')
64
+ Foo.serialize_to_file('test.dat')
65
+
66
+ @foo.should.respond_to :desc
67
+
68
+ class Foo
69
+ include MotionModel::Model
70
+ columns :name => :string,
71
+ :address => :string
72
+ end
73
+ Foo.deserialize_from_file('test.dat')
74
+
75
+ @foo = Foo.first
76
+
77
+ @foo.name.should == 'Bob'
78
+ @foo.address.should == nil
79
+ @foo.should.not.respond_to :desc
80
+ @foo.should.respond_to :address
81
+ Foo.length.should == 1
82
+ end
83
+ end
84
+ 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.2
4
+ version: 0.2.3
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-07 00:00:00.000000000 Z
12
+ date: 2012-09-13 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Simple model and validation mixins for RubyMotion
15
15
  email:
@@ -25,13 +25,16 @@ files:
25
25
  - app/app_delegate.rb
26
26
  - lib/motion_model.rb
27
27
  - lib/motion_model/ext.rb
28
- - lib/motion_model/finder_query.rb
29
28
  - lib/motion_model/input_helpers.rb
30
- - lib/motion_model/model.rb
29
+ - lib/motion_model/model/column.rb
30
+ - lib/motion_model/model/finder_query.rb
31
+ - lib/motion_model/model/model.rb
32
+ - lib/motion_model/model/persistence.rb
31
33
  - lib/motion_model/validatable.rb
32
34
  - lib/motion_model/version.rb
33
35
  - motion_model.gemspec
34
36
  - spec/model_spec.rb
37
+ - spec/persistence_spec.rb
35
38
  homepage: https://github.com/sxross/MotionModel
36
39
  licenses: []
37
40
  post_install_message:
@@ -58,3 +61,4 @@ specification_version: 3
58
61
  summary: Simple model and validation mixins for RubyMotion
59
62
  test_files:
60
63
  - spec/model_spec.rb
64
+ - spec/persistence_spec.rb