motion_model 0.5.1 → 0.5.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/.travis.yml +3 -1
- data/README.md +56 -0
- data/motion/date_parser.rb +14 -2
- data/motion/model/model.rb +33 -1
- data/motion/version.rb +1 -1
- data/spec/array_model_persistence_spec.rb +0 -1
- data/spec/date_spec.rb +7 -0
- data/spec/proc_defaults_spec.rb +78 -0
- metadata +5 -4
- data/lib/motion_model/date_parser.rb +0 -66
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
YmQ4MDAzNDMxNzQ2MDVhOWZkMDVhNjA0M2JhMWEwMGJmZWM4NTU1MQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
M2UzM2UyYjcyY2JjOWUyMjNhZDRlZmQ1OGE0YTUzZDY5MzY2NDNmOA==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
ZWUxMmM3OGU3ZWM5YzU5YTEwMzVmMWE3OWYwYmNkYzRkYzk2ZTRiM2UzZGYz
|
10
|
+
ZGFiYTkyYzZiNGNlMjZjNmZlYThiMjM5YzRjNjQ1MTVmYWZhMzAwNGM0NDAy
|
11
|
+
YjBjOWE0ZjU4NjAwNmRiMjE2OWRiNTFhNDZiZjU1OTM0NmI5ODU=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ODZiYjlkNTNhM2MyODBhYTdlN2RiM2I4ZDM4YTAxNGM3ZDk3Y2E3NzBhMjE4
|
14
|
+
ZGZkZGFjNTcyYmRlZjRhM2ZjZjZkYjM0MGNhODdiZDc3YWEwMzIyNWI2NDli
|
15
|
+
OTdmYTliODZkNTQ1MmU3YWFmNzQ5ZjRlZmQyZGI1ODk3Y2ZmYjU=
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -167,6 +167,62 @@ class Task
|
|
167
167
|
end
|
168
168
|
```
|
169
169
|
|
170
|
+
A note on defaults, you can specify a proc, block or symbol for your default if you want to get fancy. The most obvious use case for this is that Ruby will optimize the assignment of an array so that a default of `[]` always points to the same object. Not exactly what is intended. Wrapping this in a proc causes a new array to be created. Here's an example:
|
171
|
+
|
172
|
+
```
|
173
|
+
class Foo
|
174
|
+
include MotionModel::Model
|
175
|
+
include MotionModel::ArrayModelAdapter
|
176
|
+
columns subject: { type: :array, default: ->{ [] } }
|
177
|
+
end
|
178
|
+
```
|
179
|
+
|
180
|
+
This is not constrained to initializing arrays. You can
|
181
|
+
initialize pretty much anything using a proc or block.
|
182
|
+
If you are specifying a block, make sure to use begin/end
|
183
|
+
instead of do/end because it makes Ruby happy.
|
184
|
+
|
185
|
+
Here's a different example:
|
186
|
+
|
187
|
+
```
|
188
|
+
class Timely
|
189
|
+
include MotionModel::Model
|
190
|
+
include MotionModel::ArrayModelAdapter
|
191
|
+
columns ended_run_at: { type: :time, default: ->{ Time.now } }
|
192
|
+
end
|
193
|
+
```
|
194
|
+
Note that this uses the "stubby proc" syntax. That is pretty much equivalent
|
195
|
+
to:
|
196
|
+
|
197
|
+
```
|
198
|
+
columns ended_run_at: { type: :time, default: lambda { Time.now } }
|
199
|
+
```
|
200
|
+
|
201
|
+
for the previous example.
|
202
|
+
|
203
|
+
If you want to use a block, use the begin/end syntax:
|
204
|
+
|
205
|
+
```
|
206
|
+
columns ended_run_at: { type: :time, default:
|
207
|
+
begin
|
208
|
+
Time.now
|
209
|
+
end
|
210
|
+
}
|
211
|
+
```
|
212
|
+
Finally, you can have the default call some class method as follows:
|
213
|
+
|
214
|
+
```
|
215
|
+
class Timely
|
216
|
+
include MotionModel::Model
|
217
|
+
include MotionModel::ArrayModelAdapter
|
218
|
+
columns unique_thingie: { type: :integer, default: :randomize }
|
219
|
+
|
220
|
+
def self.randomize
|
221
|
+
rand 1_000_000
|
222
|
+
end
|
223
|
+
end
|
224
|
+
```
|
225
|
+
|
170
226
|
You can also include the `Validatable` module to get field validation. For example:
|
171
227
|
|
172
228
|
```ruby
|
data/motion/date_parser.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
module DateParser
|
2
|
+
@@isoDateFormatter = nil
|
3
|
+
|
2
4
|
# Parse a date string: E.g.:
|
3
5
|
#
|
4
6
|
# DateParser.parse_date "There is a date in here tomorrow at 9:00 AM"
|
@@ -6,8 +8,7 @@ module DateParser
|
|
6
8
|
# => 2013-02-20 09:00:00 -0800
|
7
9
|
def self.parse_date(date_string)
|
8
10
|
if date_string.match(/\d{2}T\d{2}/)
|
9
|
-
|
10
|
-
date_string = date_string.split('.').first if date_string =~ /\.\d{3}Z$/
|
11
|
+
return fractional_date(date_string) if date_string =~ /\.\d{3}Z$/
|
11
12
|
return Time.iso8601(date_string)
|
12
13
|
end
|
13
14
|
|
@@ -46,6 +47,17 @@ module DateParser
|
|
46
47
|
detector = NSDataDetector.dataDetectorWithTypes(NSTextCheckingTypeDate, error:error)
|
47
48
|
matches = detector.matchesInString(date_string, options:0, range:NSMakeRange(0, date_string.length))
|
48
49
|
end
|
50
|
+
|
51
|
+
def self.allocate_date_formatter
|
52
|
+
@@isoDateFormatter = NSDateFormatter.alloc.init
|
53
|
+
@@isoDateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ'"
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.fractional_date(date_string)
|
57
|
+
allocate_date_formatter if @@isoDateFormatter.nil?
|
58
|
+
date = @@isoDateFormatter.dateFromString date_string
|
59
|
+
return date
|
60
|
+
end
|
49
61
|
end
|
50
62
|
|
51
63
|
|
data/motion/model/model.rb
CHANGED
@@ -785,8 +785,40 @@ module MotionModel
|
|
785
785
|
def unload_relation(col)
|
786
786
|
end
|
787
787
|
|
788
|
+
def evaluate_default_value(column, value)
|
789
|
+
default = self.class.default(column)
|
790
|
+
|
791
|
+
case default
|
792
|
+
when NilClass
|
793
|
+
{column => value}
|
794
|
+
when Proc
|
795
|
+
{column => default.call}
|
796
|
+
when Symbol
|
797
|
+
{column => self.send(column)}
|
798
|
+
else
|
799
|
+
{column => default}
|
800
|
+
end
|
801
|
+
end
|
802
|
+
|
803
|
+
# issue #113. added ability to specify a proc or block
|
804
|
+
# for the default value. This allows for arrays to be
|
805
|
+
# created as unique. E.g.:
|
806
|
+
#
|
807
|
+
# class Foo
|
808
|
+
# include MotionModel::Model
|
809
|
+
# include MotionModel::ArrayModelAdapter
|
810
|
+
# columns subject: { type: :array, default: ->{ [] } }
|
811
|
+
# end
|
812
|
+
#
|
813
|
+
# ...
|
814
|
+
#
|
815
|
+
# This is not constrained to initializing arrays. You can
|
816
|
+
# initialize pretty much anything using a proc or block.
|
817
|
+
# If you are specifying a block, make sure to use begin/end
|
818
|
+
# instead of do/end because it makes Ruby happy.
|
819
|
+
|
788
820
|
def initialize_data_columns(column, value) #nodoc
|
789
|
-
self.attributes =
|
821
|
+
self.attributes = evaluate_default_value(column, value)
|
790
822
|
end
|
791
823
|
|
792
824
|
def column_as(col) #nodoc
|
data/motion/version.rb
CHANGED
@@ -39,7 +39,6 @@ describe 'persistence' do
|
|
39
39
|
|
40
40
|
PersistTask.serialize_to_file('test.dat')
|
41
41
|
tasks = PersistTask.deserialize_from_file('test.dat')
|
42
|
-
puts tasks.inspect
|
43
42
|
PersistTask.first.created_at.should == created_at
|
44
43
|
PersistTask.first.updated_at.should == updated_at
|
45
44
|
end
|
data/spec/date_spec.rb
CHANGED
@@ -74,5 +74,12 @@ describe "time conversions" do
|
|
74
74
|
m.test_date.should.not.be.nil
|
75
75
|
m.test_date.utc.to_s.should.eql '2012-04-23 18:25:43 UTC'
|
76
76
|
end
|
77
|
+
|
78
|
+
it "does not discard fractional portion of ISO8601 dates" do
|
79
|
+
m = Model.new(test_date: '2012-04-23T18:25:43.511Z')
|
80
|
+
m.test_date.should.not.be.nil
|
81
|
+
m.test_date.utc.to_s.should.eql '2012-04-23 18:25:43 UTC'
|
82
|
+
m.test_date.utc.to_s.should.not.eql '2012-04-23 18:25:51 UTC'
|
83
|
+
end
|
77
84
|
end
|
78
85
|
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
describe "proc for defaults" do
|
2
|
+
describe "accepts a proc or block for default" do
|
3
|
+
describe "accepts proc" do
|
4
|
+
class AcceptsProc
|
5
|
+
include MotionModel::Model
|
6
|
+
include MotionModel::ArrayModelAdapter
|
7
|
+
columns subject: { type: :array, default: ->{ [] } }
|
8
|
+
end
|
9
|
+
|
10
|
+
before do
|
11
|
+
@test1 = AcceptsProc.create
|
12
|
+
@test2 = AcceptsProc.create
|
13
|
+
end
|
14
|
+
|
15
|
+
it "initializes array type using proc call" do
|
16
|
+
@test1.subject.should.be == @test2.subject
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "accepts block" do
|
21
|
+
class AcceptsBlock
|
22
|
+
include MotionModel::Model
|
23
|
+
include MotionModel::ArrayModelAdapter
|
24
|
+
columns subject: {
|
25
|
+
type: :array, default: begin
|
26
|
+
[]
|
27
|
+
end
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
before do
|
32
|
+
@test1 = AcceptsBlock.create
|
33
|
+
@test2 = AcceptsBlock.create
|
34
|
+
end
|
35
|
+
|
36
|
+
it "initializes array type using begin/end block call" do
|
37
|
+
@test1.subject.should.be == @test2.subject
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "accepts symbol" do
|
42
|
+
class AcceptsSym
|
43
|
+
include MotionModel::Model
|
44
|
+
include MotionModel::ArrayModelAdapter
|
45
|
+
columns subject: { type: :integer, default: :randomize }
|
46
|
+
|
47
|
+
def self.randomize
|
48
|
+
rand 1_000_000
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
before do
|
53
|
+
@test1 = AcceptsSym.create
|
54
|
+
@test2 = AcceptsSym.create
|
55
|
+
end
|
56
|
+
|
57
|
+
it "initializes column by calling a method" do
|
58
|
+
@test1.subject.should.be == @test2.subject
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "scalar defaults still work" do
|
63
|
+
class AcceptsScalars
|
64
|
+
include MotionModel::Model
|
65
|
+
include MotionModel::ArrayModelAdapter
|
66
|
+
columns subject: { type: :integer, default: 42 }
|
67
|
+
end
|
68
|
+
|
69
|
+
before do
|
70
|
+
@test1 = AcceptsScalars.create
|
71
|
+
end
|
72
|
+
|
73
|
+
it "initializes column as normal" do
|
74
|
+
@test1.subject.should == 42
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
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.5.
|
4
|
+
version: 0.5.3
|
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-04-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bubble-wrap
|
@@ -55,7 +55,6 @@ files:
|
|
55
55
|
- Rakefile
|
56
56
|
- app/app_delegate.rb
|
57
57
|
- lib/motion_model.rb
|
58
|
-
- lib/motion_model/date_parser.rb
|
59
58
|
- motion/adapters/array_finder_query.rb
|
60
59
|
- motion/adapters/array_model_adapter.rb
|
61
60
|
- motion/adapters/array_model_persistence.rb
|
@@ -83,6 +82,7 @@ files:
|
|
83
82
|
- spec/model_hook_spec.rb
|
84
83
|
- spec/model_spec.rb
|
85
84
|
- spec/notification_spec.rb
|
85
|
+
- spec/proc_defaults_spec.rb
|
86
86
|
- spec/relation_spec.rb
|
87
87
|
- spec/transaction_spec.rb
|
88
88
|
- spec/validation_spec.rb
|
@@ -105,7 +105,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
105
105
|
version: '0'
|
106
106
|
requirements: []
|
107
107
|
rubyforge_project:
|
108
|
-
rubygems_version: 2.
|
108
|
+
rubygems_version: 2.2.2
|
109
109
|
signing_key:
|
110
110
|
specification_version: 4
|
111
111
|
summary: Simple model and validation mixins for RubyMotion
|
@@ -123,6 +123,7 @@ test_files:
|
|
123
123
|
- spec/model_hook_spec.rb
|
124
124
|
- spec/model_spec.rb
|
125
125
|
- spec/notification_spec.rb
|
126
|
+
- spec/proc_defaults_spec.rb
|
126
127
|
- spec/relation_spec.rb
|
127
128
|
- spec/transaction_spec.rb
|
128
129
|
- spec/validation_spec.rb
|
@@ -1,66 +0,0 @@
|
|
1
|
-
module DateParser
|
2
|
-
# Parse a date string: E.g.:
|
3
|
-
#
|
4
|
-
# DateParser.parse_date "There is a date in here tomorrow at 9:00 AM"
|
5
|
-
#
|
6
|
-
# => 2013-02-20 09:00:00 -0800
|
7
|
-
def self.parse_date(date_string)
|
8
|
-
detect(date_string).first.date
|
9
|
-
end
|
10
|
-
|
11
|
-
# Parse time zone from date
|
12
|
-
#
|
13
|
-
# ateParser.parse_date "There is a date in here tomorrow at 9:00 AM EDT"
|
14
|
-
#
|
15
|
-
# Caveat: This is implemented per Apple documentation. I've never really
|
16
|
-
# seen it work.
|
17
|
-
def self.parse_time_zone(date_string)
|
18
|
-
detect(date_string).first.timeZone
|
19
|
-
end
|
20
|
-
|
21
|
-
# Parse a date string: E.g.:
|
22
|
-
#
|
23
|
-
# SugarCube::DateParser.parse_date "You have a meeting from 9:00 AM to 3:00 PM"
|
24
|
-
#
|
25
|
-
# => 21600.0
|
26
|
-
#
|
27
|
-
# Divide by 3600.0 to get number of hours duration.
|
28
|
-
def self.parse_duration(date_string)
|
29
|
-
detect(date_string).first.send(:duration)
|
30
|
-
end
|
31
|
-
|
32
|
-
# Parse a date into a raw match array for further processing
|
33
|
-
def self.match(date_string)
|
34
|
-
detect(date_string)
|
35
|
-
end
|
36
|
-
|
37
|
-
private
|
38
|
-
def self.detect(date_string)
|
39
|
-
error = Pointer.new(:object)
|
40
|
-
detector = NSDataDetector.dataDetectorWithTypes(NSTextCheckingTypeDate, error:error)
|
41
|
-
matches = detector.matchesInString(date_string, options:0, range:NSMakeRange(0, date_string.length))
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
|
46
|
-
class String
|
47
|
-
# Use NSDataDetector to parse a string containing a date
|
48
|
-
# or duration. These can be of the form:
|
49
|
-
#
|
50
|
-
# "tomorrow at 7:30 PM"
|
51
|
-
# "11.23.2013"
|
52
|
-
# "from 7:30 to 10:00 AM"
|
53
|
-
#
|
54
|
-
# etc.
|
55
|
-
def to_date
|
56
|
-
DateParser.parse_date(self)
|
57
|
-
end
|
58
|
-
|
59
|
-
def to_timezone
|
60
|
-
DateParser.parse_time_zone(self)
|
61
|
-
end
|
62
|
-
|
63
|
-
def to_duration
|
64
|
-
DateParser.parse_duration(self)
|
65
|
-
end
|
66
|
-
end
|