motion_model 0.5.3 → 0.5.4
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.
- checksums.yaml +5 -13
- data/README.md +11 -6
- data/motion/adapters/array_model_persistence.rb +19 -6
- data/motion/ext.rb +32 -30
- data/motion/model/model.rb +32 -3
- data/motion/version.rb +1 -1
- data/spec/array_model_persistence_spec.rb +17 -1
- data/spec/date_spec.rb +14 -0
- data/spec/model_spec.rb +50 -5
- metadata +9 -9
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
M2UzM2UyYjcyY2JjOWUyMjNhZDRlZmQ1OGE0YTUzZDY5MzY2NDNmOA==
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9fa1c9fe578bfec914279fad0ced2ff4f6df49a1
|
4
|
+
data.tar.gz: 9952292bdef965d7ab76ab1f8a8c906a2f69fd67
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
ZGFiYTkyYzZiNGNlMjZjNmZlYThiMjM5YzRjNjQ1MTVmYWZhMzAwNGM0NDAy
|
11
|
-
YjBjOWE0ZjU4NjAwNmRiMjE2OWRiNTFhNDZiZjU1OTM0NmI5ODU=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
ODZiYjlkNTNhM2MyODBhYTdlN2RiM2I4ZDM4YTAxNGM3ZDk3Y2E3NzBhMjE4
|
14
|
-
ZGZkZGFjNTcyYmRlZjRhM2ZjZjZkYjM0MGNhODdiZDc3YWEwMzIyNWI2NDli
|
15
|
-
OTdmYTliODZkNTQ1MmU3YWFmNzQ5ZjRlZmQyZGI1ODk3Y2ZmYjU=
|
6
|
+
metadata.gz: 41cb26133a685d546300513985f57e41fa58b4b8eb678689311d2b23bfddb6d9394d66f6f849ad4faff27369f3f95945c1525dcd7fa0105dfd801812236f2c8f
|
7
|
+
data.tar.gz: 8a1a29e8a90468f7392b1c9f54281fa3038956ad8776be4e668d5286057fbc164af9d25ca6b59efefdf2b0eb0daedff3481506264d33e9831fc64a1105d70d41
|
data/README.md
CHANGED
@@ -882,12 +882,17 @@ require "~/github/local/MotionModel/lib/motion_model.rb"
|
|
882
882
|
The `~/github/local` is where I cloned it, but you can put it anyplace. Next, make
|
883
883
|
sure you are following the project on GitHub so you know when there are changes.
|
884
884
|
|
885
|
-
Submissions/Patches
|
885
|
+
Submissions/Patches/Bug Reports
|
886
886
|
------------------
|
887
887
|
|
888
|
-
|
889
|
-
specs.
|
888
|
+
For a submission, do this:
|
890
889
|
|
891
|
-
|
892
|
-
|
893
|
-
|
890
|
+
1. Fork it
|
891
|
+
2. Create your feature branch (git checkout -b my-new-feature)
|
892
|
+
3. Commit your changes (git commit -am 'Add some feature')
|
893
|
+
4. Push to the branch (git push origin my-new-feature)
|
894
|
+
5. Create new Pull Request
|
895
|
+
|
896
|
+
For a bug report, the best bet is follow the above steps, but for #2 and 4,
|
897
|
+
use the issue number in the branch. Once you have created the pull request,
|
898
|
+
reference it in the issue.
|
@@ -44,17 +44,24 @@ module MotionModel
|
|
44
44
|
# will remember the file name, so they may omit that argument.
|
45
45
|
#
|
46
46
|
# Raises a +MotionModel::PersistFileFailureError+ on failure.
|
47
|
-
def deserialize_from_file(file_name = nil)
|
47
|
+
def deserialize_from_file(file_name = nil, directory = nil)
|
48
48
|
if schema_version != '1.0.0'
|
49
49
|
migrate
|
50
50
|
end
|
51
51
|
|
52
52
|
@file_name = file_name if file_name
|
53
|
+
@file_path =
|
54
|
+
if directory.nil?
|
55
|
+
documents_file(@file_name)
|
56
|
+
else
|
57
|
+
File.join(directory, @file_name)
|
58
|
+
end
|
59
|
+
|
53
60
|
|
54
|
-
if File.exist?
|
61
|
+
if File.exist? @file_path
|
55
62
|
error_ptr = Pointer.new(:object)
|
56
63
|
|
57
|
-
data = NSData.dataWithContentsOfFile(
|
64
|
+
data = NSData.dataWithContentsOfFile(@file_path, options:NSDataReadingMappedIfSafe, error:error_ptr)
|
58
65
|
|
59
66
|
if data.nil?
|
60
67
|
error = error_ptr[0]
|
@@ -78,12 +85,19 @@ module MotionModel
|
|
78
85
|
# remembered file name.
|
79
86
|
#
|
80
87
|
# Raises a +MotionModel::PersistFileError+ on failure.
|
81
|
-
def serialize_to_file(file_name = nil)
|
88
|
+
def serialize_to_file(file_name = nil, directory = nil)
|
82
89
|
@file_name = file_name if file_name
|
90
|
+
@file_path =
|
91
|
+
if directory.nil?
|
92
|
+
documents_file(@file_name)
|
93
|
+
else
|
94
|
+
File.join(directory, @file_name)
|
95
|
+
end
|
96
|
+
|
83
97
|
error_ptr = Pointer.new(:object)
|
84
98
|
|
85
99
|
data = NSKeyedArchiver.archivedDataWithRootObject collection
|
86
|
-
unless data.writeToFile(
|
100
|
+
unless data.writeToFile(@file_path, options: NSDataWritingAtomic, error: error_ptr)
|
87
101
|
# De-reference the pointer.
|
88
102
|
error = error_ptr[0]
|
89
103
|
|
@@ -92,7 +106,6 @@ module MotionModel
|
|
92
106
|
end
|
93
107
|
end
|
94
108
|
|
95
|
-
|
96
109
|
def documents_file(file_name)
|
97
110
|
file_path = File.join NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true), file_name
|
98
111
|
file_path
|
data/motion/ext.rb
CHANGED
@@ -300,45 +300,47 @@ class Debug
|
|
300
300
|
@@silent = false
|
301
301
|
@@colorize = true
|
302
302
|
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
303
|
+
class << self
|
304
|
+
# Use silence if you want to keep messages from being echoed
|
305
|
+
# to the console.
|
306
|
+
def silence
|
307
|
+
@@silent = true
|
308
|
+
end
|
308
309
|
|
309
|
-
|
310
|
-
|
311
|
-
|
310
|
+
def colorize
|
311
|
+
@@colorize
|
312
|
+
end
|
312
313
|
|
313
|
-
|
314
|
-
|
315
|
-
|
314
|
+
def colorize=(value)
|
315
|
+
@@colorize = value == true
|
316
|
+
end
|
316
317
|
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
318
|
+
# Use resume when you want messages that were silenced to
|
319
|
+
# resume displaying.
|
320
|
+
def resume
|
321
|
+
@@silent = false
|
322
|
+
end
|
322
323
|
|
323
|
-
|
324
|
-
|
325
|
-
|
324
|
+
def put_message(type, message, color = Ansi.reset_color)
|
325
|
+
open_color = @@colorize ? color : ''
|
326
|
+
close_color = @@colorize ? Ansi.reset_color : ''
|
326
327
|
|
327
|
-
|
328
|
-
|
328
|
+
NSLog("#{open_color}#{type} #{caller[1]}: #{message}#{close_color}") unless @@silent
|
329
|
+
end
|
329
330
|
|
330
|
-
|
331
|
-
|
332
|
-
|
331
|
+
def info(msg)
|
332
|
+
put_message 'INFO', msg, Ansi.green_color
|
333
|
+
end
|
334
|
+
alias :log :info
|
333
335
|
|
334
|
-
|
335
|
-
|
336
|
-
|
336
|
+
def warning(msg)
|
337
|
+
put_message 'WARNING', msg, Ansi.yellow_color
|
338
|
+
end
|
337
339
|
|
338
|
-
|
339
|
-
|
340
|
+
def error(msg)
|
341
|
+
put_message 'ERROR', msg, Ansi.red_color
|
342
|
+
end
|
340
343
|
end
|
341
|
-
|
342
344
|
end
|
343
345
|
|
344
346
|
# These are C macros in iOS SDK. Not workable for Ruby.
|
data/motion/model/model.rb
CHANGED
@@ -106,6 +106,28 @@ module MotionModel
|
|
106
106
|
end
|
107
107
|
end
|
108
108
|
|
109
|
+
# Use at class level, as follows:
|
110
|
+
#
|
111
|
+
# class Task
|
112
|
+
# include MotionModel::Model
|
113
|
+
# include MotionModel::ArrayModelAdapter
|
114
|
+
#
|
115
|
+
# columns :name, :details, :assignees, :created_at, :updated_at
|
116
|
+
# has_many :assignees
|
117
|
+
# protects_remote_timestamps
|
118
|
+
#
|
119
|
+
# In this case, creating or updating will not alter the values of the
|
120
|
+
# timestamps, preferring to allow the server to be the only authority
|
121
|
+
# for assigning timestamp information.
|
122
|
+
|
123
|
+
def protect_remote_timestamps
|
124
|
+
@_protect_remote_timestamps = true
|
125
|
+
end
|
126
|
+
|
127
|
+
def protect_remote_timestamps?
|
128
|
+
@_protect_remote_timestamps == true
|
129
|
+
end
|
130
|
+
|
109
131
|
# Use at class level, as follows:
|
110
132
|
#
|
111
133
|
# class Task
|
@@ -518,8 +540,10 @@ module MotionModel
|
|
518
540
|
|
519
541
|
# Set created_at and updated_at fields
|
520
542
|
def set_auto_date_field(field_name)
|
521
|
-
|
522
|
-
|
543
|
+
unless self.class.protect_remote_timestamps?
|
544
|
+
method = "#{field_name}="
|
545
|
+
self.send(method, Time.now) if self.respond_to?(method)
|
546
|
+
end
|
523
547
|
end
|
524
548
|
|
525
549
|
# Stub methods for hook protocols
|
@@ -792,7 +816,12 @@ module MotionModel
|
|
792
816
|
when NilClass
|
793
817
|
{column => value}
|
794
818
|
when Proc
|
795
|
-
|
819
|
+
begin
|
820
|
+
{column => default.call}
|
821
|
+
rescue Exception => ex
|
822
|
+
Debug.error "\n\nProblem initializing #{self.class} : #{column} with default and proc.\nException: #{ex.message}\nSorry, your app is pretty much crashing.\n"
|
823
|
+
exit
|
824
|
+
end
|
796
825
|
when Symbol
|
797
826
|
{column => self.send(column)}
|
798
827
|
else
|
data/motion/version.rb
CHANGED
@@ -238,5 +238,21 @@ describe "serialization of relations" do
|
|
238
238
|
Parent.first.children.first.name.should == 'Fergie'
|
239
239
|
Parent.first.dog.first.name.should == 'Fluffy'
|
240
240
|
end
|
241
|
-
end
|
242
241
|
|
242
|
+
it "allows to serialize and eserialize from directories" do
|
243
|
+
directory_path = '/Library/Caches'
|
244
|
+
Parent.serialize_to_file('parents.dat', directory_path)
|
245
|
+
Child.serialize_to_file('children.dat', directory_path)
|
246
|
+
Dog.serialize_to_file('dogs.dat', directory_path)
|
247
|
+
Parent.delete_all
|
248
|
+
Child.delete_all
|
249
|
+
Dog.delete_all
|
250
|
+
Parent.deserialize_from_file('parents.dat', directory_path)
|
251
|
+
Child.deserialize_from_file('children.dat', directory_path)
|
252
|
+
Dog.deserialize_from_file('dogs.dat', directory_path)
|
253
|
+
Parent.first.name.should == 'BoB'
|
254
|
+
Parent.first.children.count.should == 2
|
255
|
+
Parent.first.children.first.name.should == 'Fergie'
|
256
|
+
Parent.first.dog.first.name.should == 'Fluffy'
|
257
|
+
end
|
258
|
+
end
|
data/spec/date_spec.rb
CHANGED
@@ -27,6 +27,14 @@ describe "time conversions" do
|
|
27
27
|
:updated_at => :date
|
28
28
|
end
|
29
29
|
|
30
|
+
class ProtectedUpdateable
|
31
|
+
include MotionModel::Model
|
32
|
+
include MotionModel::ArrayModelAdapter
|
33
|
+
columns :name => :string,
|
34
|
+
:updated_at => :date
|
35
|
+
protect_remote_timestamps
|
36
|
+
end
|
37
|
+
|
30
38
|
it "Sets created_at when an item is created" do
|
31
39
|
c = Creatable.new(:name => 'test')
|
32
40
|
lambda{c.save}.should.change{c.created_at}
|
@@ -50,6 +58,12 @@ describe "time conversions" do
|
|
50
58
|
lambda{ c.save }.should.change{c.updated_at}
|
51
59
|
end
|
52
60
|
|
61
|
+
it "Honors (protects) server side timestamps" do
|
62
|
+
c = ProtectedUpdateable.create(:name => 'test')
|
63
|
+
sleep 1
|
64
|
+
c.name = 'test 1'
|
65
|
+
lambda{ c.save }.should.not.change{c.updated_at}
|
66
|
+
end
|
53
67
|
end
|
54
68
|
|
55
69
|
describe "parsing ISO8601 date formats" do
|
data/spec/model_spec.rb
CHANGED
@@ -39,7 +39,7 @@ describe "Creating a model" do
|
|
39
39
|
a_task = Task.new(:name => 'name', :details => 'details')
|
40
40
|
a_task.name.should.equal('name')
|
41
41
|
end
|
42
|
-
|
42
|
+
|
43
43
|
it 'creates a model with all attributes even if some omitted' do
|
44
44
|
atask = Task.create(:name => 'bob')
|
45
45
|
atask.should.respond_to(:details)
|
@@ -177,14 +177,14 @@ describe "Creating a model" do
|
|
177
177
|
1.upto(10) {|i| Task.create(:name => "task #{i}")}
|
178
178
|
end
|
179
179
|
end
|
180
|
-
|
180
|
+
|
181
181
|
it 'deletes a row' do
|
182
182
|
target = Task.find(:name).eq('task 3').first
|
183
183
|
target.should.not == nil
|
184
184
|
target.delete
|
185
185
|
Task.find(:name).eq('task 3').count.should.equal 0
|
186
186
|
end
|
187
|
-
|
187
|
+
|
188
188
|
it 'deleting a row changes length' do
|
189
189
|
target = Task.find(:name).eq('task 2').first
|
190
190
|
lambda{target.delete}.should.change{Task.length}
|
@@ -198,7 +198,7 @@ describe "Creating a model" do
|
|
198
198
|
Task.find(:name).eq('task 3').count.should.equal 1
|
199
199
|
end
|
200
200
|
end
|
201
|
-
|
201
|
+
|
202
202
|
describe 'Handling Attribute Implementation' do
|
203
203
|
it 'raises a NoMethodError exception when an unknown attribute it referenced' do
|
204
204
|
task = Task.new
|
@@ -243,7 +243,7 @@ describe "Creating a model" do
|
|
243
243
|
end
|
244
244
|
end
|
245
245
|
end
|
246
|
-
|
246
|
+
|
247
247
|
describe 'defining custom attributes' do
|
248
248
|
before do
|
249
249
|
Task.delete_all
|
@@ -254,4 +254,49 @@ describe "Creating a model" do
|
|
254
254
|
@task.custom_attribute_by_method.should == 'Feed the Cat - Get food, pour out'
|
255
255
|
end
|
256
256
|
end
|
257
|
+
|
258
|
+
describe 'protecting timestamps' do
|
259
|
+
class NoTimestamps
|
260
|
+
include MotionModel::Model
|
261
|
+
include MotionModel::ArrayModelAdapter
|
262
|
+
columns name: :string
|
263
|
+
protect_remote_timestamps
|
264
|
+
end
|
265
|
+
|
266
|
+
class AutoTimeable
|
267
|
+
include MotionModel::Model
|
268
|
+
include MotionModel::ArrayModelAdapter
|
269
|
+
columns name: :string,
|
270
|
+
created_at: :date,
|
271
|
+
updated_at: :date
|
272
|
+
end
|
273
|
+
|
274
|
+
class ProtectedTimestamps
|
275
|
+
include MotionModel::Model
|
276
|
+
include MotionModel::ArrayModelAdapter
|
277
|
+
columns name: :string,
|
278
|
+
created_at: :date,
|
279
|
+
updated_at: :date
|
280
|
+
protect_remote_timestamps
|
281
|
+
end
|
282
|
+
|
283
|
+
it 'does nothing to break classes with no timestamps' do
|
284
|
+
lambda{NoTimestamps.create!(name: 'no timestamps')}.should.not.raise
|
285
|
+
end
|
286
|
+
|
287
|
+
it "changes the timestamps if they are not protected" do
|
288
|
+
auto_timeable = AutoTimeable.new(name: 'auto timeable')
|
289
|
+
lambda{auto_timeable.name = 'changed auto timeable'; auto_timeable.save!}.should.change{auto_timeable.updated_at}
|
290
|
+
end
|
291
|
+
|
292
|
+
it "does not change created_at if timestamps are protected" do
|
293
|
+
protected_times = ProtectedTimestamps.new(name: 'auto timeable', created_at: Time.now, updated_at: Time.now)
|
294
|
+
lambda{protected_times.name = 'changed created at'; protected_times.save!}.should.not.change{protected_times.created_at}
|
295
|
+
end
|
296
|
+
|
297
|
+
it "does not change updated_at if timestamps are protected" do
|
298
|
+
protected_times = ProtectedTimestamps.new(name: 'auto timeable', created_at: Time.now, updated_at: Time.now)
|
299
|
+
lambda{protected_times.name = 'changed updated at'; protected_times.save!}.should.not.change{protected_times.updated_at}
|
300
|
+
end
|
301
|
+
end
|
257
302
|
end
|
metadata
CHANGED
@@ -1,41 +1,41 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: motion_model
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Steve Ross
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-07-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bubble-wrap
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - '>='
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 1.3.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - '>='
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 1.3.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: motion-support
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - '>='
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: 0.1.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - '>='
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 0.1.0
|
41
41
|
description: Simple model and validation mixins for RubyMotion
|
@@ -95,17 +95,17 @@ require_paths:
|
|
95
95
|
- lib
|
96
96
|
required_ruby_version: !ruby/object:Gem::Requirement
|
97
97
|
requirements:
|
98
|
-
- -
|
98
|
+
- - '>='
|
99
99
|
- !ruby/object:Gem::Version
|
100
100
|
version: '0'
|
101
101
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
102
102
|
requirements:
|
103
|
-
- -
|
103
|
+
- - '>='
|
104
104
|
- !ruby/object:Gem::Version
|
105
105
|
version: '0'
|
106
106
|
requirements: []
|
107
107
|
rubyforge_project:
|
108
|
-
rubygems_version: 2.
|
108
|
+
rubygems_version: 2.3.0
|
109
109
|
signing_key:
|
110
110
|
specification_version: 4
|
111
111
|
summary: Simple model and validation mixins for RubyMotion
|