motion_model 0.6.0 → 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +21 -3
- data/Gemfile.lock +0 -2
- data/README.md +53 -111
- data/motion/adapters/array_finder_query.rb +4 -4
- data/motion/model/model_casts.rb +2 -10
- data/motion/version.rb +1 -1
- data/spec/date_spec.rb +2 -2
- data/spec/finder_spec.rb +28 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1f8aff0f64a66b3acc96dc5b3bc3539cb9ce7414
|
4
|
+
data.tar.gz: 8297cac822d64df7c823e6aeab801c54657c217c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b01dc4562a81064f0ade25f402f3bc50c84d9cb91a9132b3497ea844ee2e6f29c141259888f495794ddf11e8bc6694dc30f456607455b7a60c2c19b25822dc48
|
7
|
+
data.tar.gz: dfee05ac135e297256a9476c9f7b83c6e0bfd0ccc2646a4557338a7c1f882898100c17f4653cba221880d4d7c9d3d445c15f0308ffd8474096d634476f536432
|
data/.travis.yml
CHANGED
@@ -2,6 +2,24 @@ language: objective-c
|
|
2
2
|
before_install:
|
3
3
|
- ruby --version
|
4
4
|
- sudo chown -R travis ~/Library/RubyMotion
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
- sudo motion update
|
6
|
+
install:
|
7
|
+
- ruby -S bundle install
|
8
|
+
# rvm:
|
9
|
+
# - "1.9.3"
|
10
|
+
script:
|
11
|
+
- bundle install
|
12
|
+
- bundle exec rake clean
|
13
|
+
- bundle exec rake spec
|
14
|
+
|
15
|
+
# before_install:
|
16
|
+
# - (ruby --version)
|
17
|
+
# - sudo chown -R travis ~/Library/RubyMotion
|
18
|
+
# - mkdir -p ~/Library/RubyMotion/build
|
19
|
+
# - sudo motion update
|
20
|
+
# script:
|
21
|
+
# - bundle install
|
22
|
+
# - bundle exec rake clean
|
23
|
+
# - bundle exec rake spec
|
24
|
+
# - bundle exec rake clean
|
25
|
+
# - bundle exec rake spec osx=true
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -10,7 +10,7 @@ data validation and actually quite a bit more.
|
|
10
10
|
File | Module | Description
|
11
11
|
---------------------|---------------------------|------------------------------------
|
12
12
|
**ext.rb** | N/A | Core Extensions that provide a few Rails-like niceties. Nothing new here, moving on...
|
13
|
-
**model.rb** | MotionModel::Model | You should read about it in "[What
|
13
|
+
**model.rb** | MotionModel::Model | You should read about it in "[What Model Can Do](#what-model-can-do)". Model is the raison d'etre and the centerpiece of MotionModel.
|
14
14
|
**validatable.rb** | MotionModel::Validatable | Provides a basic validation framework for any arbitrary class. You can also create custom validations to suit your app's unique needs.
|
15
15
|
**input_helpers** | MotionModel::InputHelpers | Helps hook a collection up to a data form, populate the form, and retrieve the data afterwards. Note: *MotionModel supports Formotion for input handling as well as these input helpers*.
|
16
16
|
**formotion.rb** | MotionModel::Formotion | Provides an interface between MotionModel and Formotion
|
@@ -21,7 +21,7 @@ you like with it. See the LICENSE file in this project.
|
|
21
21
|
|
22
22
|
* [Getting Going](#getting-going)
|
23
23
|
* [Bugs, Features, and Issues, Oh My!](#bugs-features-and-issues-oh-my)
|
24
|
-
* [What
|
24
|
+
* [What Model Can Do](#what-model-can-do)
|
25
25
|
* [Model Data Types](#model-data-types)
|
26
26
|
* [Validation Methods](#validation-methods)
|
27
27
|
* [Model Instances and Unique IDs](#model-instances-and-unique-ids)
|
@@ -274,65 +274,6 @@ Currently supported types are:
|
|
274
274
|
You are really not encouraged to stuff big things in your models, which is why a blob type
|
275
275
|
is not implemented. The smaller your data, the less overhead involved in saving/loading.
|
276
276
|
|
277
|
-
### User Defined Types
|
278
|
-
|
279
|
-
*New as of 0.6*: THIS FEATURE IS EXPERIMENTAL. You can use a class name instead of the
|
280
|
-
symbols to specify your types. Thus, you can choose more complex types in much the same
|
281
|
-
way as you might in a NOSQL database. Consider these examples:
|
282
|
-
|
283
|
-
```ruby
|
284
|
-
class Address
|
285
|
-
include MotionModel::Model
|
286
|
-
include MotionModel::ArrayModelAdapter
|
287
|
-
columns street: String,
|
288
|
-
city: String,
|
289
|
-
state: String,
|
290
|
-
zip: Integer
|
291
|
-
end
|
292
|
-
|
293
|
-
class Person
|
294
|
-
include MotionModel::Model
|
295
|
-
include MotionModel::ArrayModelAdapter
|
296
|
-
|
297
|
-
columns name: String,
|
298
|
-
address: Address
|
299
|
-
end
|
300
|
-
```
|
301
|
-
|
302
|
-
You can now use this `Person` class as follows:
|
303
|
-
|
304
|
-
```ruby
|
305
|
-
p = Person.find(:name).eq('Laurent').first
|
306
|
-
p.address.country = 'Belgium'
|
307
|
-
p.save
|
308
|
-
```
|
309
|
-
|
310
|
-
> **Note** Address includes all the MotionModel goodness. That is so that any class that embeds it can also persist it. You may be able to get away with defining `encodeWithCoder(coder)` and `initWithCoder(coder)` -- it's your choice, but not currently supported.
|
311
|
-
|
312
|
-
### Native Ruby Types
|
313
|
-
|
314
|
-
You can also use native Ruby types (limited to those supported by RubyMotion so no `DateTime`):
|
315
|
-
|
316
|
-
```ruby
|
317
|
-
class Person
|
318
|
-
include MotionModel::Model
|
319
|
-
include MotionModel::ArrayModelAdapter
|
320
|
-
|
321
|
-
columns name: String,
|
322
|
-
address: Hash
|
323
|
-
end
|
324
|
-
```
|
325
|
-
|
326
|
-
and you can use the class as follows:
|
327
|
-
|
328
|
-
```ruby
|
329
|
-
Person.create(name: 'Miss Piggy', address: {street: '111 Swine Ave', city: 'Muppetville', state: 'IN'})
|
330
|
-
```
|
331
|
-
|
332
|
-
etc.
|
333
|
-
|
334
|
-
> Special note: This is a bleeding edge feature as of 0.6, and because of the semantics of copying in Ruby, there are some deep copy situations that may cause objects to be copied or updated incompletely. These should create 100% reproducible bugs in your code so they should not sneak up on you. Nevertheless, understand that the guarantee is a shallow copy. Tests show that an array inside a class copies properly. YMMV.
|
335
|
-
|
336
277
|
### Special Columns
|
337
278
|
|
338
279
|
The two column names, `created_at` and `updated_at` will be adjusted automatically if they
|
@@ -445,72 +386,73 @@ Using MotionModel
|
|
445
386
|
|
446
387
|
You can implement some aggregate functions using map/reduce:
|
447
388
|
|
448
|
-
```ruby
|
449
|
-
|
450
|
-
|
451
|
-
```
|
389
|
+
```ruby
|
390
|
+
@task.all.map{|task| task.number_of_items}.reduce(:+) # implements sum
|
391
|
+
@task.all.map{|task| task.number_of_items}.reduce(:+) / @task.count #implements average
|
392
|
+
```
|
452
393
|
|
453
394
|
* Serialization is part of MotionModel. So, in your `AppDelegate` you might do something like this:
|
454
395
|
|
455
|
-
|
456
|
-
|
457
|
-
|
396
|
+
```ruby
|
397
|
+
@tasks = Task.deserialize_from_file('tasks.dat')
|
398
|
+
```
|
458
399
|
|
459
|
-
|
400
|
+
and of course on the "save" side:
|
460
401
|
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
name so you can call these methods without the filename argument.
|
402
|
+
```ruby
|
403
|
+
Task.serialize_to_file('tasks.dat')
|
404
|
+
```
|
405
|
+
After the first serialize or deserialize, your model will remember the file
|
406
|
+
name so you can call these methods without the filename argument.
|
467
407
|
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
408
|
+
Implementation note: that the this serialization of any arbitrarily complex set of relations
|
409
|
+
is automatically handled by `NSCoder` provided you conform to the coding
|
410
|
+
protocol (which MotionModel does). When you declare your columns, `MotionModel` understands how to
|
411
|
+
serialize your data so you need take no specific action.
|
472
412
|
|
473
|
-
|
474
|
-
|
413
|
+
Persistence will serialize only one
|
414
|
+
model at a time and not your entire data store.
|
415
|
+
This is to allow you to decide what data is
|
416
|
+
serialized when.
|
475
417
|
|
476
418
|
* Relations
|
477
419
|
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
420
|
+
```ruby
|
421
|
+
class Task
|
422
|
+
include MotionModel::Model
|
423
|
+
include MotionModel::ArrayModelAdapter
|
424
|
+
columns :name => :string
|
425
|
+
has_many :assignees
|
426
|
+
end
|
485
427
|
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
428
|
+
class Assignee
|
429
|
+
include MotionModel::Model
|
430
|
+
include MotionModel::ArrayModelAdapter
|
431
|
+
columns :assignee_name => :string
|
432
|
+
belongs_to :task
|
433
|
+
end
|
492
434
|
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
435
|
+
# Create a task, then create an assignee as a
|
436
|
+
# related object on that task
|
437
|
+
a_task = Task.create(:name => "Walk the Dog")
|
438
|
+
a_task.assignees.create(:assignee_name => "Howard")
|
497
439
|
|
498
|
-
|
499
|
-
|
500
|
-
|
440
|
+
# See? It works.
|
441
|
+
a_task.assignees.assignee_name # => "Howard"
|
442
|
+
Task.first.assignees.assignee_name # => "Howard"
|
501
443
|
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
444
|
+
# Create another assignee but don't save
|
445
|
+
# Add to assignees collection. Both objects
|
446
|
+
# are saved.
|
447
|
+
another_assignee = Assignee.new(:name => "Douglas")
|
448
|
+
a_task.assignees << another_assignee # adds to relation and saves both objects
|
507
449
|
|
508
|
-
|
509
|
-
|
450
|
+
# The count of assignees accurately reflects current state
|
451
|
+
a_task.assignees.count # => 2
|
510
452
|
|
511
|
-
|
512
|
-
|
513
|
-
|
453
|
+
# And backreference access through belongs_to works.
|
454
|
+
Assignee.first.task.name # => "Walk the Dog"
|
455
|
+
```
|
514
456
|
|
515
457
|
There are four ways to delete objects from your data store:
|
516
458
|
|
@@ -97,7 +97,7 @@ module MotionModel
|
|
97
97
|
# see `eq` for notes on case sensitivity.
|
98
98
|
def gt(query_string, options = {:case_sensitive => false})
|
99
99
|
do_comparison(query_string, options) do |comparator, item|
|
100
|
-
comparator
|
100
|
+
comparator < item
|
101
101
|
end
|
102
102
|
end
|
103
103
|
alias_method :>, :gt
|
@@ -108,7 +108,7 @@ module MotionModel
|
|
108
108
|
# see `eq` for notes on case sensitivity.
|
109
109
|
def lt(query_string, options = {:case_sensitive => false})
|
110
110
|
do_comparison(query_string, options) do |comparator, item|
|
111
|
-
comparator
|
111
|
+
comparator > item
|
112
112
|
end
|
113
113
|
end
|
114
114
|
alias_method :<, :lt
|
@@ -119,7 +119,7 @@ module MotionModel
|
|
119
119
|
# see `eq` for notes on case sensitivity.
|
120
120
|
def gte(query_string, options = {:case_sensitive => false})
|
121
121
|
do_comparison(query_string, options) do |comparator, item|
|
122
|
-
comparator
|
122
|
+
comparator <= item
|
123
123
|
end
|
124
124
|
end
|
125
125
|
alias_method :>=, :gte
|
@@ -130,7 +130,7 @@ module MotionModel
|
|
130
130
|
# see `eq` for notes on case sensitivity.
|
131
131
|
def lte(query_string, options = {:case_sensitive => false})
|
132
132
|
do_comparison(query_string, options) do |comparator, item|
|
133
|
-
comparator
|
133
|
+
comparator >= item
|
134
134
|
end
|
135
135
|
end
|
136
136
|
alias_method :<=, :lte
|
data/motion/model/model_casts.rb
CHANGED
@@ -44,7 +44,7 @@ module MotionModel
|
|
44
44
|
String(arg)
|
45
45
|
end
|
46
46
|
|
47
|
-
def cast_to_arbitrary_class(arg
|
47
|
+
def cast_to_arbitrary_class(arg)
|
48
48
|
# This little oddity is because a number of built-in
|
49
49
|
# Ruby classes cannot be dup'ed. Not only that, they
|
50
50
|
# respond_to?(:dup) but raise an exception when you
|
@@ -59,13 +59,6 @@ module MotionModel
|
|
59
59
|
|
60
60
|
return arg if arg.respond_to?(:motion_model?)
|
61
61
|
|
62
|
-
# Another case is where there is a predefined cast rule
|
63
|
-
# on the type declared as a class level method motion_model_cast:
|
64
|
-
|
65
|
-
if klass.respond_to?(:motion_model_cast)
|
66
|
-
return klass.send(:motion_model_cast, arg)
|
67
|
-
end
|
68
|
-
|
69
62
|
# But if it is not a MotionModel, we either need to dup
|
70
63
|
# it (for most cases), or just assign it (for built-in
|
71
64
|
# types like Integer, Fixnum, Float, NilClass, etc.)
|
@@ -92,11 +85,10 @@ module MotionModel
|
|
92
85
|
when :text then cast_to_string(arg)
|
93
86
|
when :array then cast_to_array(arg)
|
94
87
|
when :hash then cast_to_hash(arg)
|
95
|
-
when Class then cast_to_arbitrary_class(arg
|
88
|
+
when Class then cast_to_arbitrary_class(arg)
|
96
89
|
else
|
97
90
|
raise ArgumentError.new("type #{column_name} : #{column_type(column_name)} is not possible to cast.")
|
98
91
|
end
|
99
92
|
end
|
100
93
|
end
|
101
94
|
end
|
102
|
-
|
data/motion/version.rb
CHANGED
data/spec/date_spec.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
describe "time conversions" do
|
2
|
-
it "NSDate and Time should
|
2
|
+
it "NSDate and Time should agree on minutes since epoch" do
|
3
3
|
t = Time.new
|
4
4
|
d = NSDate.dateWithTimeIntervalSince1970(t.to_f)
|
5
|
-
t.to_f.should
|
5
|
+
(t.to_f - d.timeIntervalSince1970).abs.should. < 0.001
|
6
6
|
end
|
7
7
|
|
8
8
|
it "Parsing '3/18/12 @ 7:00 PM' With Natural Language should work right" do
|
data/spec/finder_spec.rb
CHANGED
@@ -132,6 +132,34 @@ describe 'finders' do
|
|
132
132
|
it 'should returns last element' do
|
133
133
|
Task.last.should.is_a Task
|
134
134
|
end
|
135
|
+
|
136
|
+
describe 'comparison finders' do
|
137
|
+
|
138
|
+
it 'returns elements with id greater than 5' do
|
139
|
+
tasks = Task.where(:id).gt(5).all
|
140
|
+
tasks.length.should.equal(5)
|
141
|
+
tasks.reject{|t| [6,7,8,9,10].include?(t.id)}.should.be.empty
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'returns elements with id greater than or equal to 7' do
|
145
|
+
tasks = Task.where(:id).gte(7).all
|
146
|
+
tasks.length.should.equal(4)
|
147
|
+
tasks.reject{|t| [7,8,9,10].include?(t.id)}.should.be.empty
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'returns elements with id less than 5' do
|
151
|
+
tasks = Task.where(:id).lt(5).all
|
152
|
+
tasks.length.should.equal(4)
|
153
|
+
tasks.reject{|t| [1,2,3,4].include?(t.id)}.should.be.empty
|
154
|
+
end
|
155
|
+
|
156
|
+
it 'returns elements with id less than or equal to 3' do
|
157
|
+
tasks = Task.where(:id).lte(3).all
|
158
|
+
tasks.length.should.equal(3)
|
159
|
+
tasks.reject{|t| [1,2,3].include?(t.id)}.should.be.empty
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
135
163
|
|
136
164
|
describe 'block-style finders' do
|
137
165
|
before do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: motion_model
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Steve Ross
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-01-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bubble-wrap
|