motion_model 0.2.2 → 0.2.3

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